Skip to content

Commit 0dfb895

Browse files
committed
refactor: complete codebase hardening and remove agent-facing layers
Build & correctness: - Fix all context.Context mismatches across tests and CLI - Complete Storage interface extraction (removed DB() leak) - Add CheckCycle, GetNodesBatch, CountEdges, CountAllEdges, WithTx - graph.New(store, db) takes *sql.DB directly - Add txStore for SQL transactions Performance: - Replace O(n²) bubble/insertion sorts with sort.Slice - Fix Status() N+1 → CountAllEdges single query - Fix ExtractSubgraph() N+1 → GetNodesBatch - Fix vectorSearch() full-table scan → batched GetEmbeddingsBatch Reliability: - Return errors for critical paths in Remember/Forget (stop swallowing) - Health check actually pings DB (returns 503 on failure) - Add input validation (empty content, max length, type whitelist) - Extract magic numbers to named constants - Add structured logging (slog) REST server: - Add panic recovery, request logging, timeout middleware - Add /version endpoint - Watch command: polling → fsnotify Code organization: - Split 850-line cmd/yaad/main.go into 6 focused files - Add atomic metrics counters on Engine Removal (for direct Hawk integration): - Remove sdk/ (Go, Python, TypeScript clients) - Remove plugin/ (claude-code, hermes, opencode) - Remove internal/agentconfig/ (23+ agent config generators) - Remove internal/bridge/ (CLAUDE.md/.cursorrules sync) - Remove yaad setup, bridge-import, bridge-export commands - Remove REST bridge import/export endpoints
1 parent b96e3da commit 0dfb895

58 files changed

Lines changed: 2162 additions & 2913 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/yaad/admin.go

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"net/http"
7+
"os"
8+
"path/filepath"
9+
10+
"github.com/spf13/cobra"
11+
"github.com/GrayCodeAI/yaad/internal/bench"
12+
"github.com/GrayCodeAI/yaad/internal/engine"
13+
"github.com/GrayCodeAI/yaad/internal/exportimport"
14+
"github.com/GrayCodeAI/yaad/internal/storage"
15+
)
16+
17+
var decayCmd = &cobra.Command{
18+
Use: "decay",
19+
Short: "Apply confidence decay to all nodes",
20+
Run: func(cmd *cobra.Command, args []string) {
21+
eng := openEngine()
22+
defer eng.Store().Close()
23+
if err := engine.RunDecay(context.Background(), eng.Store(), engine.DefaultDecayConfig); err != nil {
24+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
25+
os.Exit(1)
26+
}
27+
fmt.Println("✓ Decay applied")
28+
},
29+
}
30+
31+
var gcCmd = &cobra.Command{
32+
Use: "gc",
33+
Short: "Garbage collect low-confidence nodes",
34+
Run: func(cmd *cobra.Command, args []string) {
35+
eng := openEngine()
36+
defer eng.Store().Close()
37+
n, err := engine.GarbageCollect(context.Background(), eng.Store(), engine.DefaultDecayConfig)
38+
if err != nil {
39+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
40+
os.Exit(1)
41+
}
42+
fmt.Printf("✓ Removed %d nodes\n", n)
43+
},
44+
}
45+
46+
var benchCmd = &cobra.Command{
47+
Use: "bench",
48+
Short: "Run retrieval benchmark (LongMemEval-style)",
49+
Run: func(cmd *cobra.Command, args []string) {
50+
eng := openEngine()
51+
defer eng.Store().Close()
52+
extended, _ := cmd.Flags().GetBool("extended")
53+
qas := bench.DefaultQAs()
54+
if extended {
55+
qas = bench.CodingBenchQAs()
56+
}
57+
result := bench.Run(context.Background(), eng, qas, 2, 10)
58+
fmt.Println(result.String())
59+
},
60+
}
61+
62+
var doctorCmd = &cobra.Command{
63+
Use: "doctor",
64+
Short: "Diagnose Yaad setup issues",
65+
Run: func(cmd *cobra.Command, args []string) {
66+
dir, _ := os.Getwd()
67+
ok := true
68+
check := func(label string, pass bool, fix string) {
69+
if pass {
70+
fmt.Printf(" ✅ %s\n", label)
71+
} else {
72+
fmt.Printf(" ❌ %s\n Fix: %s\n", label, fix)
73+
ok = false
74+
}
75+
}
76+
77+
fmt.Printf("yaad doctor — %s\n\n", dir)
78+
79+
_, err := os.Stat(filepath.Join(dir, ".yaad"))
80+
check(".yaad/ directory exists", err == nil, "run: yaad init")
81+
82+
dbPath := filepath.Join(dir, ".yaad", "yaad.db")
83+
_, err = os.Stat(dbPath)
84+
check("yaad.db exists", err == nil, "run: yaad init")
85+
86+
if err == nil {
87+
store, err2 := storage.NewStore(dbPath)
88+
if err2 == nil {
89+
store.Close()
90+
check("database readable", true, "")
91+
} else {
92+
check("database readable", false, "delete .yaad/yaad.db and run: yaad init")
93+
}
94+
}
95+
96+
resp, err := http.Get("http://localhost:3456/yaad/health")
97+
serverRunning := err == nil && resp.StatusCode == 200
98+
if resp != nil {
99+
resp.Body.Close()
100+
}
101+
check("REST server running (:3456)", serverRunning, "run: yaad serve (in another terminal)")
102+
103+
mcpFiles := []string{".mcp.json", "opencode.json", ".codex/config.yaml"}
104+
hasMCP := false
105+
for _, f := range mcpFiles {
106+
if _, err := os.Stat(filepath.Join(dir, f)); err == nil {
107+
hasMCP = true
108+
break
109+
}
110+
}
111+
check("agent MCP config found", hasMCP, "run: yaad setup <agent> (e.g. yaad setup hawk)")
112+
113+
_, err = os.Stat(filepath.Join(dir, ".git"))
114+
check("git repository (for staleness detection)", err == nil, "run: git init")
115+
116+
fmt.Println()
117+
if ok {
118+
fmt.Println("✅ All checks passed. Yaad is ready!")
119+
} else {
120+
fmt.Println("⚠️ Some checks failed. Fix the issues above and re-run: yaad doctor")
121+
}
122+
},
123+
}
124+
125+
var exportJSONCmd = &cobra.Command{
126+
Use: "export-json",
127+
Short: "Export graph as JSON",
128+
Run: func(cmd *cobra.Command, args []string) {
129+
eng := openEngine()
130+
defer eng.Store().Close()
131+
data, err := exportimport.ExportJSON(context.Background(), eng.Store(), "")
132+
if err != nil {
133+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
134+
os.Exit(1)
135+
}
136+
fmt.Println(string(data))
137+
},
138+
}
139+
140+
var exportMarkdownCmd = &cobra.Command{
141+
Use: "export-md",
142+
Short: "Export memories as Markdown",
143+
Run: func(cmd *cobra.Command, args []string) {
144+
eng := openEngine()
145+
defer eng.Store().Close()
146+
md, err := exportimport.ExportMarkdown(context.Background(), eng.Store(), "")
147+
if err != nil {
148+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
149+
os.Exit(1)
150+
}
151+
fmt.Println(md)
152+
},
153+
}
154+
155+
var exportObsidianCmd = &cobra.Command{
156+
Use: "export-obsidian [vault_dir]",
157+
Short: "Export memories as Obsidian vault",
158+
Args: cobra.ExactArgs(1),
159+
Run: func(cmd *cobra.Command, args []string) {
160+
eng := openEngine()
161+
defer eng.Store().Close()
162+
n, err := exportimport.ExportObsidian(context.Background(), eng.Store(), "", args[0])
163+
if err != nil {
164+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
165+
os.Exit(1)
166+
}
167+
fmt.Printf("✓ Exported %d notes to %s\n", n, args[0])
168+
},
169+
}
170+
171+
var importJSONCmd = &cobra.Command{
172+
Use: "import-json [file]",
173+
Short: "Import graph from JSON file",
174+
Args: cobra.ExactArgs(1),
175+
Run: func(cmd *cobra.Command, args []string) {
176+
data, err := os.ReadFile(args[0])
177+
if err != nil {
178+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
179+
os.Exit(1)
180+
}
181+
eng := openEngine()
182+
defer eng.Store().Close()
183+
nodes, edges, err := exportimport.ImportJSON(context.Background(), eng.Store(), data)
184+
if err != nil {
185+
fmt.Fprintf(os.Stderr, "error: %v\n", err)
186+
os.Exit(1)
187+
}
188+
fmt.Printf("✓ Imported %d nodes, %d edges\n", nodes, edges)
189+
},
190+
}

0 commit comments

Comments
 (0)