feat(mcp): brain_pending + brain_promote tools + REST routes (#38)
Wires the curation primitives into the MCP surface (all three sites: tools() descriptors, handleCall dispatch, package doc) and registers the GET /pending + POST /promote REST routes. brain_promote additionally re-indexes the promoted note into the graph (best-effort), matching the other write paths. brain_pending is the human-review-queue complement to the agent-facing brain_write. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -332,3 +332,61 @@ func TestSessionLogRequiresSessionID(t *testing.T) {
|
||||
resp := toolCall(t, srv, "session_log", map[string]any{"skill": "tdd"})
|
||||
require.NotNil(t, resp["error"])
|
||||
}
|
||||
|
||||
func TestBrainPendingListsRaw(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
raw := filepath.Join(brainDir, "raw")
|
||||
require.NoError(t, os.MkdirAll(raw, 0o755))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(raw, "2026-06-01-x.md"),
|
||||
[]byte("---\ncreated_at: 2026-06-01T00:00:00Z\n---\npending body\n"), 0o644))
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_pending", map[string]any{})
|
||||
require.Nil(t, resp["error"])
|
||||
text := resp["result"].(map[string]any)["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
assert.Contains(t, text, "2026-06-01-x.md")
|
||||
assert.Contains(t, text, "pending body")
|
||||
}
|
||||
|
||||
func TestBrainPendingEmpty(t *testing.T) {
|
||||
srv := mcp.NewServer(t.TempDir(), nil, nil, nil)
|
||||
resp := toolCall(t, srv, "brain_pending", map[string]any{})
|
||||
require.Nil(t, resp["error"])
|
||||
text := resp["result"].(map[string]any)["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
assert.Contains(t, text, `"pending":[]`)
|
||||
}
|
||||
|
||||
func TestBrainPromoteMovesToWiki(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
raw := filepath.Join(brainDir, "raw")
|
||||
require.NoError(t, os.MkdirAll(raw, 0o755))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(raw, "2026-06-01-decision.md"),
|
||||
[]byte("---\ncreated_at: 2026-06-01T00:00:00Z\n---\n# D\n\nbody\n"), 0o644))
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
|
||||
resp := toolCall(t, srv, "brain_promote", map[string]any{
|
||||
"filename": "2026-06-01-decision.md", "wing": "jepa-fx", "hall": "decisions",
|
||||
})
|
||||
require.Nil(t, resp["error"], "got: %v", resp["error"])
|
||||
text := resp["result"].(map[string]any)["content"].([]any)[0].(map[string]any)["text"].(string)
|
||||
assert.Contains(t, text, "wiki/jepa-fx/decisions/decision.md")
|
||||
|
||||
_, err := os.Stat(filepath.Join(brainDir, "wiki/jepa-fx/decisions/decision.md"))
|
||||
require.NoError(t, err)
|
||||
_, srcErr := os.Stat(filepath.Join(raw, "2026-06-01-decision.md"))
|
||||
assert.True(t, os.IsNotExist(srcErr), "source removed")
|
||||
}
|
||||
|
||||
func TestBrainPromoteInvalidHallErrors(t *testing.T) {
|
||||
brainDir := t.TempDir()
|
||||
raw := filepath.Join(brainDir, "raw")
|
||||
require.NoError(t, os.MkdirAll(raw, 0o755))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(raw, "x.md"), []byte("body\n"), 0o644))
|
||||
srv := mcp.NewServer(brainDir, nil, nil, nil)
|
||||
resp := toolCall(t, srv, "brain_promote", map[string]any{
|
||||
"filename": "x.md", "wing": "a", "hall": "garbage",
|
||||
})
|
||||
require.NotNil(t, resp["error"])
|
||||
_, srcErr := os.Stat(filepath.Join(raw, "x.md"))
|
||||
assert.NoError(t, srcErr, "source untouched on validation error")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user