Add knowledge port and single-file adapter
The knowledge.Source port answers "who am I; what are my priorities?". The FileSource adapter reads one profile file (path selectable per call), treats a missing/blank file as absent (not an error), and caps the text. Leaf package mirroring tasks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package knowledge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadPresentFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
p := filepath.Join(dir, "knowledge.md")
|
||||
if err := os.WriteFile(p, []byte(" I am a focus-tool author.\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := NewFileSource(p).Load(context.Background(), "")
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if got.Text != "I am a focus-tool author." {
|
||||
t.Errorf("Text = %q (whitespace should be trimmed)", got.Text)
|
||||
}
|
||||
if got.Path != p {
|
||||
t.Errorf("Path = %q, want %q", got.Path, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadAbsentFileIsNotError(t *testing.T) {
|
||||
p := filepath.Join(t.TempDir(), "missing.md")
|
||||
got, err := NewFileSource(p).Load(context.Background(), "")
|
||||
if err != nil {
|
||||
t.Fatalf("absent file must not error: %v", err)
|
||||
}
|
||||
if got.Text != "" {
|
||||
t.Errorf("Text = %q, want empty for absent file", got.Text)
|
||||
}
|
||||
if got.Path != p {
|
||||
t.Errorf("Path = %q, want %q even when absent", got.Path, p)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadExplicitPathBeatsDefault(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
def := filepath.Join(dir, "default.md")
|
||||
other := filepath.Join(dir, "other.md")
|
||||
if err := os.WriteFile(def, []byte("default"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(other, []byte("explicit"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := NewFileSource(def).Load(context.Background(), other)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if got.Text != "explicit" || got.Path != other {
|
||||
t.Fatalf("explicit path ignored: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTruncatesOversize(t *testing.T) {
|
||||
p := filepath.Join(t.TempDir(), "big.md")
|
||||
if err := os.WriteFile(p, []byte(strings.Repeat("a", maxProfileBytes+500)), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := NewFileSource(p).Load(context.Background(), "")
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if len(got.Text) > maxProfileBytes+len("\n…(truncated)") {
|
||||
t.Errorf("Text not truncated: %d bytes", len(got.Text))
|
||||
}
|
||||
if !strings.HasSuffix(got.Text, "(truncated)") {
|
||||
t.Errorf("missing truncation marker: %q", got.Text[len(got.Text)-20:])
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadWhitespaceOnlyIsAbsent(t *testing.T) {
|
||||
p := filepath.Join(t.TempDir(), "blank.md")
|
||||
if err := os.WriteFile(p, []byte(" \n\t\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := NewFileSource(p).Load(context.Background(), "")
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if got.Text != "" {
|
||||
t.Errorf("whitespace-only should be empty, got %q", got.Text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadReadErrorIsError(t *testing.T) {
|
||||
dir := t.TempDir() // a directory is not readable as a file
|
||||
if _, err := NewFileSource(dir).Load(context.Background(), ""); err == nil {
|
||||
t.Fatal("reading a directory should error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user