@nanonets/graft 0.5.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +29 -7
  2. package/dist/ask/ask.d.ts +52 -1
  3. package/dist/ask/ask.d.ts.map +1 -1
  4. package/dist/ask/ask.js +274 -83
  5. package/dist/ask/ask.js.map +1 -1
  6. package/dist/ask/fuse.d.ts +59 -17
  7. package/dist/ask/fuse.d.ts.map +1 -1
  8. package/dist/ask/fuse.js +51 -25
  9. package/dist/ask/fuse.js.map +1 -1
  10. package/dist/ask/graphrank.d.ts +6 -0
  11. package/dist/ask/graphrank.d.ts.map +1 -1
  12. package/dist/ask/graphrank.js +5 -1
  13. package/dist/ask/graphrank.js.map +1 -1
  14. package/dist/claude/format.js +1 -1
  15. package/dist/claude/format.js.map +1 -1
  16. package/dist/claude/hooks.d.ts +16 -0
  17. package/dist/claude/hooks.d.ts.map +1 -1
  18. package/dist/claude/hooks.js +57 -2
  19. package/dist/claude/hooks.js.map +1 -1
  20. package/dist/claude/init.d.ts +3 -0
  21. package/dist/claude/init.d.ts.map +1 -1
  22. package/dist/claude/init.js +6 -1
  23. package/dist/claude/init.js.map +1 -1
  24. package/dist/claude/skill-template.d.ts.map +1 -1
  25. package/dist/claude/skill-template.js +20 -9
  26. package/dist/claude/skill-template.js.map +1 -1
  27. package/dist/cli.d.ts +3 -14
  28. package/dist/cli.d.ts.map +1 -1
  29. package/dist/cli.js +99 -70
  30. package/dist/cli.js.map +1 -1
  31. package/dist/context/savings.d.ts +34 -0
  32. package/dist/context/savings.d.ts.map +1 -0
  33. package/dist/context/savings.js +49 -0
  34. package/dist/context/savings.js.map +1 -0
  35. package/dist/engine.d.ts +1 -0
  36. package/dist/engine.d.ts.map +1 -1
  37. package/dist/engine.js +7 -1
  38. package/dist/engine.js.map +1 -1
  39. package/dist/graph/build.d.ts.map +1 -1
  40. package/dist/graph/build.js +33 -0
  41. package/dist/graph/build.js.map +1 -1
  42. package/dist/graph/map.d.ts +38 -2
  43. package/dist/graph/map.d.ts.map +1 -1
  44. package/dist/graph/map.js +111 -24
  45. package/dist/graph/map.js.map +1 -1
  46. package/dist/graph/scopes.d.ts +15 -0
  47. package/dist/graph/scopes.d.ts.map +1 -1
  48. package/dist/graph/scopes.js +23 -0
  49. package/dist/graph/scopes.js.map +1 -1
  50. package/dist/graph/traverse-cli.d.ts +28 -18
  51. package/dist/graph/traverse-cli.d.ts.map +1 -1
  52. package/dist/graph/traverse-cli.js +68 -43
  53. package/dist/graph/traverse-cli.js.map +1 -1
  54. package/dist/graph/traverse.d.ts +35 -14
  55. package/dist/graph/traverse.d.ts.map +1 -1
  56. package/dist/graph/traverse.js +46 -20
  57. package/dist/graph/traverse.js.map +1 -1
  58. package/dist/graph/types.d.ts +12 -0
  59. package/dist/graph/types.d.ts.map +1 -1
  60. package/dist/graph/workspace-cli.d.ts +37 -0
  61. package/dist/graph/workspace-cli.d.ts.map +1 -0
  62. package/dist/graph/workspace-cli.js +70 -0
  63. package/dist/graph/workspace-cli.js.map +1 -0
  64. package/dist/graph/workspace.d.ts +128 -0
  65. package/dist/graph/workspace.d.ts.map +1 -0
  66. package/dist/graph/workspace.js +395 -0
  67. package/dist/graph/workspace.js.map +1 -0
  68. package/dist/hosts/instructions.d.ts.map +1 -1
  69. package/dist/hosts/instructions.js +7 -3
  70. package/dist/hosts/instructions.js.map +1 -1
  71. package/dist/hosts/mcp-config.d.ts +5 -0
  72. package/dist/hosts/mcp-config.d.ts.map +1 -1
  73. package/dist/hosts/mcp-config.js +2 -2
  74. package/dist/hosts/mcp-config.js.map +1 -1
  75. package/dist/mcp/tools.d.ts.map +1 -1
  76. package/dist/mcp/tools.js +94 -66
  77. package/dist/mcp/tools.js.map +1 -1
  78. package/dist/search/grep-cli.d.ts.map +1 -1
  79. package/dist/search/grep-cli.js +4 -0
  80. package/dist/search/grep-cli.js.map +1 -1
  81. package/dist/search/grep.d.ts +4 -0
  82. package/dist/search/grep.d.ts.map +1 -1
  83. package/dist/search/grep.js +2 -0
  84. package/dist/search/grep.js.map +1 -1
  85. package/package.json +1 -1
@@ -5,6 +5,7 @@ import { readWiring } from './stats.js';
5
5
  import { formatBlastRadius, relevantRetrieval, formatOrientation } from './format.js';
6
6
  import { patchStats, readStats, acquireLock, readSession, writeSession } from './state.js';
7
7
  import { graftCliPath, claudeScriptPath } from './paths.js';
8
+ import { scopeOf, scopesOfGraph } from '../graph/scopes.js';
8
9
  /** Prompts shorter than this never trigger retrieval — they are almost always
9
10
  * conversational ("yes go ahead", "thanks") and the coverage gate can't judge
10
11
  * them reliably with so few terms. */
@@ -34,7 +35,12 @@ export function underGraft(dir, file) {
34
35
  }
35
36
  function graftJson(dir, args) {
36
37
  try {
37
- const out = execFileSync(process.execPath, [graftCliPath(), ...args], { cwd: dir, encoding: 'utf8', timeout: 8000, stdio: ['ignore', 'pipe', 'ignore'] });
38
+ // GRAFT_TEST_CLI is a test seam (mirrors GRAFT_TEST_STDIN/GRAFT_TEST_SYNC_RUN) so
39
+ // tests can point the prompt hook's `graft ask`/`graft check` calls at a stub
40
+ // script and observe the exact args it was invoked with, instead of shelling
41
+ // out to the real CLI (which isn't built relative to the TS source under test).
42
+ const cliPath = process.env.GRAFT_TEST_CLI ?? graftCliPath();
43
+ const out = execFileSync(process.execPath, [cliPath, ...args], { cwd: dir, encoding: 'utf8', timeout: 8000, stdio: ['ignore', 'pipe', 'ignore'] });
38
44
  return JSON.parse(out);
39
45
  }
40
46
  catch (e) {
@@ -69,6 +75,49 @@ async function handlePostEdit(input, dir) {
69
75
  emit('PostToolUse', br);
70
76
  }
71
77
  }
78
+ /**
79
+ * The "you're working in backend/, weight it" hint: on a multi-scope repo,
80
+ * narrow the prompt hook's `ask` call to whatever scope the last-edited file
81
+ * (`stats.lastFile`, captured at {@link handlePostEdit}) sits in.
82
+ *
83
+ * `lastFile` is only a basename (not a repo-relative path — see
84
+ * `handlePostEdit`), so this is a best-effort lookup against the CURRENT
85
+ * graph: any file node whose path ends in `/<lastFile>` (or equals it, for a
86
+ * repo-root file). Fails soft in every direction a hook must never crash on —
87
+ * no graph, a single-scope graph, a lastFile no longer in the graph (moved,
88
+ * deleted, or edited before the first build), or a basename that lands in
89
+ * more than one scope (ambiguous: could be either sub-project) all skip the
90
+ * hint silently, logging one line to stderr so the miss is visible without
91
+ * ever failing the hook.
92
+ */
93
+ export function lastFileScopeHint(dir, lastFile) {
94
+ if (!lastFile)
95
+ return null;
96
+ try {
97
+ const w = readWiring(dir);
98
+ if (!w)
99
+ return null;
100
+ const scopes = scopesOfGraph(w);
101
+ if (scopes.length <= 1)
102
+ return null; // single-scope: no hint, no --in
103
+ const matches = (w.nodes ?? []).filter((n) => n.kind === 'file' && (n.path === lastFile || n.path.endsWith(`/${lastFile}`)));
104
+ if (matches.length === 0) {
105
+ console.error(`[graft] prompt hook: lastFile "${lastFile}" not found in the graph — skipping scope hint`);
106
+ return null;
107
+ }
108
+ const prefixes = new Set(matches.map((n) => scopeOf(n.path, scopes).prefix));
109
+ if (prefixes.size > 1) {
110
+ console.error(`[graft] prompt hook: lastFile "${lastFile}" matches more than one scope — skipping scope hint`);
111
+ return null;
112
+ }
113
+ const [prefix] = prefixes;
114
+ return prefix === '' ? null : prefix; // root scope: nothing to narrow
115
+ }
116
+ catch (e) {
117
+ console.error(`[graft] prompt hook: scope hint lookup failed (${e?.message ?? e}) — skipping`);
118
+ return null;
119
+ }
120
+ }
72
121
  function handleStop(dir) {
73
122
  // sync-run.js ships next to this module inside the package, so it resolves in
74
123
  // any repo that installs graft (not just graft's own). Defensive existsSync:
@@ -119,7 +168,13 @@ export async function main(event) {
119
168
  // pulls spans itself via `graft ask --source` when a pointer looks right.
120
169
  // relevantRetrieval then drops the pack entirely when the prompt barely
121
170
  // overlaps the top hit or when every hit was already injected this session.
122
- const ask = graftJson(dir, ['ask', prompt, '.', '--json', '-n', '3']);
171
+ const askArgs = ['ask', prompt, '.', '--json', '-n', '3'];
172
+ // "You're working in backend/, weight it": only fires on a multi-scope
173
+ // repo whose lastFile resolves cleanly to one scope — see lastFileScopeHint.
174
+ const scopeHint = lastFileScopeHint(dir, readStats(dir)?.lastFile);
175
+ if (scopeHint)
176
+ askArgs.push('--in', scopeHint);
177
+ const ask = graftJson(dir, askArgs);
123
178
  if (!ask)
124
179
  return;
125
180
  const id = input.session_id || 'default';
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,10 @@
1
+ import { type McpWrite } from '../hosts/mcp-config.js';
1
2
  export interface InitResult {
2
3
  settingsPath: string;
3
4
  shims: string[];
4
5
  skill: string;
6
+ /** the `.mcp.json` write registering the graft MCP server for Claude Code. */
7
+ mcp: McpWrite;
5
8
  warnings: string[];
6
9
  built: boolean;
7
10
  }
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,UAAU,CAgCjG"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"AAOA,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEnF,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,GAAG,EAAE,QAAQ,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,UAAU,CAqCjG"}
@@ -5,6 +5,7 @@ import { mergeGraftSettings } from './settings-merge.js';
5
5
  import { statuslineShim, hooksShim } from './shim-template.js';
6
6
  import { skillTemplate } from './skill-template.js';
7
7
  import { claudeDistDir } from './paths.js';
8
+ import { mergeJsonKey, SERVER_ENTRY } from '../hosts/mcp-config.js';
8
9
  export function runInit(dir, opts = {}) {
9
10
  const helpersDir = join(dir, '.claude', 'helpers');
10
11
  mkdirSync(helpersDir, { recursive: true });
@@ -29,6 +30,10 @@ export function runInit(dir, opts = {}) {
29
30
  mkdirSync(skillDir, { recursive: true });
30
31
  const skillPath = join(skillDir, 'SKILL.md');
31
32
  writeFileSync(skillPath, skillTemplate());
33
+ // Register the graft MCP server in the project's .mcp.json so Claude Code
34
+ // exposes graft_ask/graft_callers/etc. as tools — the same keyed merge the
35
+ // other hosts use (existing servers preserved; unparseable files skipped).
36
+ const mcp = mergeJsonKey('claude', join(dir, '.mcp.json'), 'mcpServers', SERVER_ENTRY);
32
37
  let built = false;
33
38
  const wiring = join(dir, 'graft', '.graph', 'wiring.json');
34
39
  if (opts.build !== false && opts.cliPath && !existsSync(wiring)) {
@@ -38,6 +43,6 @@ export function runInit(dir, opts = {}) {
38
43
  }
39
44
  catch { /* build best-effort; user can run `graft build` manually */ }
40
45
  }
41
- return { settingsPath, shims: [sl, hk], skill: skillPath, warnings, built };
46
+ return { settingsPath, shims: [sl, hk], skill: skillPath, mcp, warnings, built };
42
47
  }
43
48
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../../src/claude/skill-template.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,MAAM,CA2EtC"}
1
+ {"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../../src/claude/skill-template.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,MAAM,CAsFtC"}
@@ -31,12 +31,17 @@ same understanding costs thousands.
31
31
  ask is top-N and WILL miss instances; grep is the tool for "find them all".
32
32
  - **A file's whole API surface** → \`graft skeleton <file>\` — every signature in
33
33
  ~200 tokens. One call beats several asks when you just need "what's in here".
34
- - **Who uses / what breaks if I change X** → \`graft callers <symbol>\` or
35
- \`graft impact <symbol>\`; what X itself depends on → \`graft callees <symbol>\`.
36
- Run one of these before editing a symbol.
34
+ - **Who uses / what breaks if I change X** → \`graft callers <symbol>\` (add
35
+ \`--depth N\` to walk transitively for the full blast radius); what X itself
36
+ depends on → \`graft callers <symbol> --direction out\`. Run one before
37
+ editing a symbol.
37
38
  - **First contact with an unfamiliar repo** → \`graft map\` — token-budgeted
38
39
  orientation (dir clusters, hubs, hotspots). Read the hub cards it names rather
39
40
  than asking per subsystem.
41
+ - **Monorepos / a folder of multiple repos** → graft ranks fairly across
42
+ sub-projects instead of letting the biggest one drown the rest; hits carry
43
+ \`[scope/]\` labels naming which sub-project they're from. Know where you're
44
+ working? Narrow with \`graft ask "<task>" --in <scope>/\`.
40
45
 
41
46
  You can also grep / ls / cat inside \`graft/\` directly (the nodes are plain
42
47
  markdown; \`graft/INDEX.md\` lists them) — but the commands above are faster and
@@ -62,13 +67,19 @@ exhaustive where it matters, so reach for them first.
62
67
  that is expected, not a graft failure.
63
68
 
64
69
  **Precise graph modes** — for structural questions, skip ranking and go
65
- straight to precomputed edges:
70
+ straight to precomputed edges. It's all one command, \`graft callers\`:
66
71
 
67
- - \`graft callers <symbol>\` / \`graft callees <symbol>\` — who breaks if this
68
- changes / what does this call — precomputed edges, exact answers; structural
69
- phrasing inside ask ("who calls X") routes here too.
70
- - \`graft impact <symbol> [-d N]\` — BFS over incoming edges out to depth N: the
71
- full blast radius of a change.
72
+ - \`graft callers <symbol>\` — who calls/references this (exact edges, not text);
73
+ structural phrasing inside ask ("who calls X") routes here too.
74
+ - \`graft callers <symbol> --direction out\` — the reverse: what this symbol
75
+ itself calls/depends on (the old \`callees\`).
76
+ - \`graft callers <symbol> --depth N\` — walk transitively out to depth N for the
77
+ full blast radius of a change (the old \`impact\`).
78
+
79
+ When the graft MCP server is connected, the same operations are exposed as
80
+ tools — \`graft_ask\`, \`graft_callers\` (with \`direction\`/\`depth\`),
81
+ \`graft_grep\`, \`graft_skeleton\`, \`graft_map\` — prefer whichever surface is
82
+ available.
72
83
 
73
84
  If a returned span is truncated ("+N more lines"), open the file at that exact
74
85
  range before finalizing.
@@ -1 +1 @@
1
- {"version":3,"file":"skill-template.js","sourceRoot":"","sources":["../../src/claude/skill-template.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,0FAA0F;AAC1F,sFAAsF;AACtF,uFAAuF;AACvF,oCAAoC;AACpC,MAAM,UAAU,aAAa;IAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyER,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"skill-template.js","sourceRoot":"","sources":["../../src/claude/skill-template.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,0FAA0F;AAC1F,sFAAsF;AACtF,uFAAuF;AACvF,oCAAoC;AACpC,MAAM,UAAU,aAAa;IAC3B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFR,CAAC;AACF,CAAC"}
package/dist/cli.d.ts CHANGED
@@ -1,19 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * `graft` CLI. Commands:
4
- *
5
- * build build graft/ from your code (structural graph; --deep adds LLM summaries).
6
- * ask query the graph ($0, no LLM).
7
- * check fail if graft/ has drifted from the code — for CI.
8
- * viz serve the interactive graph viewer.
9
- * mcp serve the graph over MCP (stdio) for coding agents.
10
- * callers / callees / impact precise graph traversal for a symbol ($0, no LLM).
11
- * grep regex search over indexed files, grouped by enclosing symbol, ranked by coupling ($0, no LLM).
12
- * map token-budgeted repo orientation — dir clusters, hubs, hotspots ($0, no LLM).
13
- * init set up the Claude Code integration (.claude/ statusline + hooks) in this repo.
14
- *
15
- * Git is the sync: commit graft/ and anyone who clones the repo has the
16
- * graph, with no setup.
3
+ * `graft` CLI. Commands: build, ask, check, viz, mcp, callers, skeleton, grep,
4
+ * map, init. Git is the sync: commit graft/ and a clone has the graph. A
5
+ * workspace parent (≥2 git children) federates query commands across children.
17
6
  */
18
7
  import "dotenv/config";
19
8
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,eAAe,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,eAAe,CAAC"}
package/dist/cli.js CHANGED
@@ -1,19 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * `graft` CLI. Commands:
4
- *
5
- * build build graft/ from your code (structural graph; --deep adds LLM summaries).
6
- * ask query the graph ($0, no LLM).
7
- * check fail if graft/ has drifted from the code — for CI.
8
- * viz serve the interactive graph viewer.
9
- * mcp serve the graph over MCP (stdio) for coding agents.
10
- * callers / callees / impact precise graph traversal for a symbol ($0, no LLM).
11
- * grep regex search over indexed files, grouped by enclosing symbol, ranked by coupling ($0, no LLM).
12
- * map token-budgeted repo orientation — dir clusters, hubs, hotspots ($0, no LLM).
13
- * init set up the Claude Code integration (.claude/ statusline + hooks) in this repo.
14
- *
15
- * Git is the sync: commit graft/ and anyone who clones the repo has the
16
- * graph, with no setup.
3
+ * `graft` CLI. Commands: build, ask, check, viz, mcp, callers, skeleton, grep,
4
+ * map, init. Git is the sync: commit graft/ and a clone has the graph. A
5
+ * workspace parent (≥2 git children) federates query commands across children.
17
6
  */
18
7
  import "dotenv/config";
19
8
  import { Command } from "commander";
@@ -28,6 +17,8 @@ import { runHostsInit } from "./hosts/init.js";
28
17
  import { hostIds } from "./hosts/registry.js";
29
18
  import { contextDirFor } from "./context/node-file.js";
30
19
  import { loadGraphCached } from "./graph/load.js";
20
+ import { isWorkspaceBuildRoot, readWorkspace } from "./graph/workspace.js";
21
+ import { runWorkspaceAsk, runWorkspaceBuild, runWorkspaceCallers, runWorkspaceCheck, runWorkspaceGrep, runWorkspaceMap, } from "./graph/workspace-cli.js";
31
22
  import { formatInitEpilogue } from "./cli-epilogue.js";
32
23
  import { formatUpgradeReport, formatVersionReport, getNpmViewVersion, readCurrentVersion, runUpgrade } from "./cli-meta.js";
33
24
  const program = new Command();
@@ -52,9 +43,7 @@ function cliConfig() {
52
43
  baseUrl: o.baseUrl,
53
44
  };
54
45
  }
55
- function engineFrom() {
56
- return new Graft(cliConfig());
57
- }
46
+ const engineFrom = () => new Graft(cliConfig());
58
47
  program
59
48
  .command("version")
60
49
  .description("Print the installed version and the latest published on npm")
@@ -90,8 +79,7 @@ program
90
79
  .sort((a, b) => b[1] - a[1])
91
80
  .map(([k, n]) => `${n} ${k}`)
92
81
  .join(", ");
93
- // --deep needs a key; without one, degrade to the $0 structural build
94
- // rather than failing — the wiring graph is still worth having.
82
+ // --deep needs a key; without one, degrade to the $0 structural build.
95
83
  let deep = opts.deep;
96
84
  const resolved = resolveConfig(cliConfig());
97
85
  if (deep && !resolved.apiKey) {
@@ -103,8 +91,20 @@ program
103
91
  if (deep && resolved.usedLegacyEnv) {
104
92
  console.error("⚠ using OPENROUTER_API_KEY (deprecated) — prefer GRAFT_API_KEY + GRAFT_BASE_URL.");
105
93
  }
106
- // --deep: concept nodes first (they're LLM prose; the wiring cards link up to
107
- // them), then the wiring graph rewrites the cards + INDEX with those up-links.
94
+ // Workspace parent: build each child into its OWN graft/ + a workspace index.
95
+ const buildRoot = resolve(dir);
96
+ const buildGlobalDir = program.opts().dir;
97
+ if (isWorkspaceBuildRoot(buildRoot, buildGlobalDir)) {
98
+ await runWorkspaceBuild(buildRoot, {
99
+ deep: !!deep,
100
+ extensions: opts.extensions,
101
+ concurrency,
102
+ childConfig: cliConfig(),
103
+ override: buildGlobalDir,
104
+ });
105
+ return;
106
+ }
107
+ // --deep: concept nodes first, then the wiring graph links cards up to them.
108
108
  if (deep) {
109
109
  const c = await engine.init(dir, {
110
110
  extensions: opts.extensions,
@@ -115,7 +115,7 @@ program
115
115
  for (const e of c.errors)
116
116
  console.error(`✗ ${e}`);
117
117
  }
118
- // Wiring graph (Tier-2 cards + Tier-3 wiring.json) — always. LLM meaning only with --deep.
118
+ // Wiring graph — always; LLM meaning only with --deep.
119
119
  const g = await engine.graph(dir, {
120
120
  llm: deep,
121
121
  concurrency,
@@ -141,10 +141,26 @@ program
141
141
  .option("-n, --limit <n>", "max results", "8")
142
142
  .option("--source", "inline the source at each file:line hit (retriever mode — the pack IS the answer, no need to re-open files)")
143
143
  .option("--full", "with --source: inline whole definition spans instead of the default ≤8-line crux excerpts")
144
+ .option("--in <path>", "narrow to nodes under this path prefix, filtered before scoring (segment-aware, like scopeOf)")
144
145
  .option("--json", "output the result as JSON")
145
146
  .action(async (query, dir, opts) => {
147
+ const askGlobalDir = program.opts().dir;
148
+ if (readWorkspace(resolve(dir), askGlobalDir)) {
149
+ runWorkspaceAsk(resolve(dir), askGlobalDir, query, {
150
+ limit: Number(opts.limit), source: opts.source, full: opts.full, in: opts.in, json: opts.json,
151
+ });
152
+ return;
153
+ }
146
154
  const engine = engineFrom();
147
- const r = engine.ask(dir, query, { limit: Number(opts.limit), source: opts.source, full: opts.full });
155
+ let r;
156
+ try {
157
+ r = engine.ask(dir, query, { limit: Number(opts.limit), source: opts.source, full: opts.full, in: opts.in });
158
+ }
159
+ catch (err) {
160
+ console.error(`✗ ${err instanceof Error ? err.message : String(err)}`);
161
+ process.exit(1);
162
+ return;
163
+ }
148
164
  if (opts.json) {
149
165
  console.log(JSON.stringify(r, null, 2));
150
166
  }
@@ -175,14 +191,17 @@ program
175
191
  .option("-e, --extensions <exts...>", "code extensions to include")
176
192
  .option("--json", "output the drift as JSON")
177
193
  .action((dir, opts) => {
194
+ const checkGlobalDir = program.opts().dir;
195
+ if (readWorkspace(resolve(dir), checkGlobalDir)) {
196
+ runWorkspaceCheck(resolve(dir), checkGlobalDir);
197
+ return;
198
+ }
178
199
  const engine = engineFrom();
179
200
  const r = engine.check(dir, { extensions: opts.extensions });
180
201
  const g = engine.checkGraph(dir); // graph.json is only judged when it exists
181
- // Neither layer has ever been built → nothing to check.
202
+ // A layer that IS present must be in sync; a never-built layer (keyless
203
+ // build skips the markdown layer) is informational, not a failure.
182
204
  const bothMissing = r.missing && g.missing;
183
- // A layer that IS present must be in sync; a layer that was never built
184
- // (keyless `graft build` skips the markdown/concept layer) is informational,
185
- // not a failure — the wiring graph stands on its own.
186
205
  const markdownFail = !r.missing && !r.ok;
187
206
  const wiringFail = !g.missing && !g.ok;
188
207
  if (opts.json) {
@@ -224,8 +243,7 @@ program
224
243
  console.error(`✗ no context graph at ${contextDir} — run \`graft build --deep\` first`);
225
244
  process.exit(1);
226
245
  }
227
- // dist/cli.js → dist/viewer/ (prebuilt at package build time)
228
- const viewerDir = fileURLToPath(new URL("./viewer/", import.meta.url));
246
+ const viewerDir = fileURLToPath(new URL("./viewer/", import.meta.url)); // prebuilt
229
247
  const srv = await startVizServer({
230
248
  contextDir,
231
249
  viewerDir,
@@ -240,7 +258,7 @@ program
240
258
  });
241
259
  program
242
260
  .command("mcp")
243
- .description("Serve the graph over MCP (stdio) — exposes graft_ask / graft_check / graft_blast_radius as tools")
261
+ .description("Serve the graph over MCP (stdio) — exposes graft_ask, graft_callers, graft_grep, graft_skeleton, graft_map and graft_check as tools")
244
262
  .argument("[dir]", "repository root", ".")
245
263
  .action(async (dir) => {
246
264
  const { resolve } = await import("node:path");
@@ -248,38 +266,34 @@ program
248
266
  const globalOpts = program.opts();
249
267
  startMcpServer(resolve(dir), globalOpts.dir);
250
268
  });
251
- function traverseAction(kind) {
252
- return async (symbol, dir, opts) => {
253
- const { runTraverseCommand } = await import("./graph/traverse-cli.js");
254
- const globalOpts = program.opts();
255
- runTraverseCommand(kind, symbol, dir, { in: opts.in, json: opts.json, depth: opts.depth, globalDir: globalOpts.dir });
256
- };
257
- }
258
269
  program
259
270
  .command("callers")
260
- .description("Who calls/references/imports/implements/extends a symbol ($0, no LLM)")
261
- .argument("<symbol>", "bare name, qualified (Class.method), or package-qualified (pkg.Fn)")
262
- .argument("[dir]", "repository root", ".")
263
- .option("--in <path>", "narrow matches to nodes whose path contains this substring")
264
- .option("--json", "output as JSON")
265
- .action(traverseAction("callers"));
266
- program
267
- .command("callees")
268
- .description("What a symbol calls/references/imports/implements/extends ($0, no LLM)")
269
- .argument("<symbol>", "bare name, qualified (Class.method), or package-qualified (pkg.Fn)")
270
- .argument("[dir]", "repository root", ".")
271
- .option("--in <path>", "narrow matches to nodes whose path contains this substring")
272
- .option("--json", "output as JSON")
273
- .action(traverseAction("callees"));
274
- program
275
- .command("impact")
276
- .description("BFS over incoming edges — who breaks if this symbol changes ($0, no LLM)")
271
+ .description("Who calls/references a symbol ($0, no LLM). --direction out gives callees (what it calls); --depth N walks transitively for full blast radius")
277
272
  .argument("<symbol>", "bare name, qualified (Class.method), or package-qualified (pkg.Fn)")
278
273
  .argument("[dir]", "repository root", ".")
279
- .option("-d, --depth <n>", "max BFS depth (default 2)")
274
+ .option("--direction <in|out>", 'edge direction: "in" = callers (default), "out" = callees')
275
+ .option("-d, --depth <n>", "walk transitively up to N hops for blast radius (default 1)")
280
276
  .option("--in <path>", "narrow matches to nodes whose path contains this substring")
281
277
  .option("--json", "output as JSON")
282
- .action(traverseAction("impact"));
278
+ .action(async (symbol, dir, opts) => {
279
+ const globalOpts = program.opts();
280
+ if (!opts.json && readWorkspace(resolve(dir), globalOpts.dir)) {
281
+ runWorkspaceCallers(resolve(dir), globalOpts.dir, symbol, {
282
+ direction: opts.direction === "out" ? "out" : "in",
283
+ depth: opts.depth ? Number(opts.depth) : undefined,
284
+ in: opts.in,
285
+ });
286
+ return;
287
+ }
288
+ const { runCallersCommand } = await import("./graph/traverse-cli.js");
289
+ runCallersCommand(symbol, dir, {
290
+ direction: opts.direction,
291
+ depth: opts.depth,
292
+ in: opts.in,
293
+ json: opts.json,
294
+ globalDir: globalOpts.dir,
295
+ });
296
+ });
283
297
  program
284
298
  .command("grep")
285
299
  .description("Regex search over indexed files, hits grouped by enclosing symbol and ranked by coupling ($0, no LLM)")
@@ -290,8 +304,14 @@ program
290
304
  .option("--in <path>", "narrow to files whose path contains this substring")
291
305
  .option("--json", "output as JSON")
292
306
  .action(async (pattern, dir, opts) => {
293
- const { runGrepCommand } = await import("./search/grep-cli.js");
294
307
  const globalOpts = program.opts();
308
+ if (readWorkspace(resolve(dir), globalOpts.dir)) {
309
+ runWorkspaceGrep(resolve(dir), globalOpts.dir, pattern, {
310
+ ignoreCase: opts.ignoreCase, fixed: opts.fixed, json: opts.json,
311
+ });
312
+ return;
313
+ }
314
+ const { runGrepCommand } = await import("./search/grep-cli.js");
295
315
  runGrepCommand(pattern, dir, {
296
316
  ignoreCase: opts.ignoreCase,
297
317
  fixed: opts.fixed,
@@ -307,17 +327,9 @@ program
307
327
  .option("--max-dirs <n>", "max directory entries shown, rest counted into dropped (default 16)")
308
328
  .option("--json", "output as JSON")
309
329
  .action(async (dir, opts) => {
310
- const { buildRepoMap, formatRepoMap } = await import("./graph/map.js");
311
330
  const root = resolve(dir);
312
331
  const globalOpts = program.opts();
313
- const contextDir = contextDirFor(root, globalOpts.dir);
314
- const graph = loadGraphCached(contextDir);
315
- if (!graph) {
316
- console.error("✗ no graph — run graft build first");
317
- process.exit(1);
318
- return;
319
- }
320
- let maxDirs;
332
+ let maxDirsW;
321
333
  if (opts.maxDirs !== undefined) {
322
334
  const n = parseInt(opts.maxDirs, 10);
323
335
  if (!Number.isFinite(n) || n <= 0) {
@@ -325,9 +337,21 @@ program
325
337
  process.exit(1);
326
338
  return;
327
339
  }
328
- maxDirs = n;
340
+ maxDirsW = n;
341
+ }
342
+ if (!opts.json && readWorkspace(root, globalOpts.dir)) {
343
+ runWorkspaceMap(root, globalOpts.dir, { maxDirs: maxDirsW });
344
+ return;
345
+ }
346
+ const { buildRepoMap, formatRepoMap } = await import("./graph/map.js");
347
+ const contextDir = contextDirFor(root, globalOpts.dir);
348
+ const graph = loadGraphCached(contextDir);
349
+ if (!graph) {
350
+ console.error("✗ no graph — run graft build first");
351
+ process.exit(1);
352
+ return;
329
353
  }
330
- const map = buildRepoMap(graph, { maxDirs });
354
+ const map = buildRepoMap(graph, { maxDirs: maxDirsW });
331
355
  if (opts.json) {
332
356
  console.log(JSON.stringify(map, null, 2));
333
357
  return;
@@ -336,7 +360,7 @@ program
336
360
  });
337
361
  program
338
362
  .command("init")
339
- .description("Wire Graft into the AI coding agents used with this repo (instruction files; full hooks + statusline for Claude Code)")
363
+ .description("Wire Graft into the AI coding agents used with this repo (instruction files + MCP server; full hooks + statusline + MCP for Claude Code)")
340
364
  .argument("[dir]", "target repo directory", ".")
341
365
  .option("--no-build", "skip building the graph (wire files only)")
342
366
  .option("--agents <ids...>", `only these agents (${hostIds().join(", ")}, claude)`)
@@ -369,6 +393,12 @@ program
369
393
  for (const s of res.shims)
370
394
  console.error(`✓ wrote ${s}`);
371
395
  console.error(`✓ wrote ${res.skill}`);
396
+ if (res.mcp.action === "skipped-unparseable")
397
+ console.error(`⚠ .mcp.json: ${res.mcp.path} left unchanged (not valid JSON) — add the graft server manually`);
398
+ else if (res.mcp.action === "unchanged")
399
+ console.error(`· mcp claude: ${res.mcp.path} (already registered)`);
400
+ else
401
+ console.error(`✓ mcp claude: ${res.mcp.path} (${res.mcp.action}) — restart Claude Code to load the graft MCP server`);
372
402
  console.error(res.built ? "✓ built the graph (graft build)" : "· skipped graph build");
373
403
  for (const w of res.warnings)
374
404
  console.error(`⚠ ${w}`);
@@ -385,7 +415,6 @@ program
385
415
  console.error(`✓ ${w.id}: ${w.path} (${w.action})`);
386
416
  if (!explicit && !opts.allAgents && r.written.length === 0)
387
417
  console.error("· no other agents detected (see --list-agents / --all-agents)");
388
- // r.unknown is always empty here — ids are validated above, before any writes.
389
418
  for (const m of r.mcp)
390
419
  console.error(`✓ mcp ${m.id}: ${m.path} (${m.action})`);
391
420
  for (const h of r.hooks)