refactor: extract kb_framework package, build graph in memory
Scripts become thin CLIs over kb_framework (graph, query, query_tools, vault, instructions) so the hosted read-only connector shares one implementation with the stdio server. The MCP server builds the graph from Markdown on demand and invalidates it on writes; refresh_graph rebuilds in memory and reports validation problems. Pre-commit hook validates only; index/graph.json is no longer read, written or staged (generate-graph.py --write remains for operators). Golden fixtures pin graph and tool payloads to the previous output. Agent and skill docs updated to match. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,8 @@ class ExternalVaultTests(unittest.TestCase):
|
||||
self.base = Path(self.tmp.name)
|
||||
self.framework = self.base / "framework space"
|
||||
shutil.copytree(FRAMEWORK / "scripts", self.framework / "scripts")
|
||||
shutil.copytree(FRAMEWORK / "kb_framework", self.framework / "kb_framework",
|
||||
ignore=shutil.ignore_patterns("__pycache__"))
|
||||
shutil.copy2(FRAMEWORK / "Makefile", self.framework / "Makefile")
|
||||
self.vault = self.base / "vault space"
|
||||
self.other = self.base / "other"
|
||||
@@ -115,15 +117,14 @@ class ExternalVaultTests(unittest.TestCase):
|
||||
("write_note", {"path": "../escape.md", "content": "escape"})]:
|
||||
self.assertTrue(self.tool(tool, args).get("isError"))
|
||||
|
||||
def test_refresh_uses_absolute_framework_generator_and_writes_when_validating(self):
|
||||
def test_refresh_validates_in_memory_and_never_runs_vault_tools(self):
|
||||
(self.vault / "scripts").mkdir()
|
||||
(self.vault / "scripts/generate-graph.py").write_text("raise RuntimeError('vault tool used')\n")
|
||||
result = self.tool("refresh_graph", {"validate": True})
|
||||
self.assertFalse(result.get("isError"), result)
|
||||
command = result["structuredContent"]["command"]
|
||||
self.assertEqual(command[1], str(self.framework / "scripts/generate-graph.py"))
|
||||
self.assertEqual(command[command.index("--vault-root") + 1], str(self.vault))
|
||||
self.assertTrue((self.vault / "index/graph.json").exists())
|
||||
self.assertEqual(result["structuredContent"]["vault_root"], str(self.vault))
|
||||
self.assertEqual(result["structuredContent"]["node_count"], 1)
|
||||
self.assertFalse((self.vault / "index/graph.json").exists())
|
||||
summary = self.tool("graph_summary")
|
||||
self.assertFalse(summary.get("isError"), summary)
|
||||
|
||||
@@ -178,16 +179,17 @@ class ExternalVaultTests(unittest.TestCase):
|
||||
def make(*args):
|
||||
return subprocess.run(["make", "-C", str(self.framework), f"VAULT_ROOT={self.vault}", *args],
|
||||
env=self.env, capture_output=True, text=True)
|
||||
proc = make("graph", "install-hooks")
|
||||
proc = make("validate-graph", "install-hooks")
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
hook = self.vault / ".git/hooks/pre-commit"
|
||||
self.assertTrue(hook.exists())
|
||||
self.git(self.vault, "add", "index/graph.json")
|
||||
proc = subprocess.run([str(hook)], cwd=self.other, env=self.env, capture_output=True, text=True)
|
||||
self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr)
|
||||
(self.vault / "03_resources/new.md").write_text("# new\n")
|
||||
(self.vault / "03_resources/new.md").write_text("# new\n[gone](nowhere)\n")
|
||||
proc = subprocess.run([str(hook)], cwd=self.other, env=self.env, capture_output=True, text=True)
|
||||
self.assertNotEqual(proc.returncode, 0)
|
||||
self.assertIn("nowhere", proc.stdout + proc.stderr)
|
||||
self.assertFalse((self.vault / "index/graph.json").exists())
|
||||
self.assertFalse((self.framework / "index/graph.json").exists())
|
||||
|
||||
def test_installer_preserves_unmanaged_hooks_and_reinstalls_managed_hook(self):
|
||||
|
||||
Reference in New Issue
Block a user