@nanonets/graft 0.4.0 → 0.4.2
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.
- package/README.md +48 -22
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +35 -22
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.d.ts +1 -0
- package/dist/claude/init.d.ts.map +1 -1
- package/dist/claude/init.js +12 -3
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/paths.d.ts +4 -0
- package/dist/claude/paths.d.ts.map +1 -1
- package/dist/claude/paths.js +6 -0
- package/dist/claude/paths.js.map +1 -1
- package/dist/claude/shim-template.d.ts +2 -2
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +54 -11
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/skill-template.d.ts +2 -0
- package/dist/claude/skill-template.d.ts.map +1 -0
- package/dist/claude/skill-template.js +49 -0
- package/dist/claude/skill-template.js.map +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +65 -10
- package/dist/cli.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +24 -2
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/extract.d.ts +1 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +107 -9
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/resolve.d.ts +14 -1
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +0 -0
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/types.d.ts +2 -2
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/hosts/codex-hooks.d.ts +7 -0
- package/dist/hosts/codex-hooks.d.ts.map +1 -0
- package/dist/hosts/codex-hooks.js +75 -0
- package/dist/hosts/codex-hooks.js.map +1 -0
- package/dist/hosts/init.d.ts +21 -0
- package/dist/hosts/init.d.ts.map +1 -0
- package/dist/hosts/init.js +63 -0
- package/dist/hosts/init.js.map +1 -0
- package/dist/hosts/instructions.d.ts +9 -0
- package/dist/hosts/instructions.d.ts.map +1 -0
- package/dist/hosts/instructions.js +44 -0
- package/dist/hosts/instructions.js.map +1 -0
- package/dist/hosts/mcp-config.d.ts +9 -0
- package/dist/hosts/mcp-config.d.ts.map +1 -0
- package/dist/hosts/mcp-config.js +81 -0
- package/dist/hosts/mcp-config.js.map +1 -0
- package/dist/hosts/registry.d.ts +18 -0
- package/dist/hosts/registry.d.ts.map +1 -0
- package/dist/hosts/registry.js +69 -0
- package/dist/hosts/registry.js.map +1 -0
- package/dist/hosts/sections.d.ts +10 -0
- package/dist/hosts/sections.d.ts.map +1 -0
- package/dist/hosts/sections.js +61 -0
- package/dist/hosts/sections.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +68 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +11 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +79 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -22,52 +22,75 @@
|
|
|
22
22
|
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
flowchart LR
|
|
29
|
-
A["Your code"] -->|"graft build --deep"| B["graft/<br/>a graph of linked<br/>markdown nodes"]
|
|
30
|
-
B -->|"git commit"| C[("your repo")]
|
|
31
|
-
C -->|"git clone"| D["teammate + their agent"]
|
|
32
|
-
D -->|"reads the graph first"| E["starts already knowing<br/>how the repo fits together"]
|
|
33
|
-
```
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="assets/graft-terminal.png" alt="Two commands — npm install and graft init — then Graft rides along in a Claude Code session, statusline synced" width="820"/>
|
|
27
|
+
</p>
|
|
34
28
|
|
|
35
29
|
---
|
|
36
30
|
|
|
37
31
|
## Quick start
|
|
38
32
|
|
|
39
33
|
```bash
|
|
40
|
-
|
|
41
|
-
# the
|
|
34
|
+
npm install -g @nanonets/graft # install the CLI, once
|
|
35
|
+
graft init # build the graph + wire it into Claude Code
|
|
36
|
+
```
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
# builds graft/ from your code, one node per system, API, or concept
|
|
38
|
+
That is the whole setup. `graft init` builds `graft/` from your code and drops a statusline and hooks into `.claude/`, so from the next session on Graft rides along in Claude Code: it pulls the matching nodes into each prompt and rebuilds the graph in the background after every turn. No daemon, no re-indexing to remember, nothing to run or maintain by default — the graph is just files.
|
|
45
39
|
|
|
40
|
+
Commit `graft/` so everyone who clones the repo (and their agents) gets the map:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
46
43
|
git add graft && git commit -m "add context graph"
|
|
47
|
-
# commit it so everyone who clones the repo (and their agents) gets the graph
|
|
48
44
|
```
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
Want richer, LLM-written summaries on top of the structural graph? Point Graft at an OpenRouter key and run the deep pass whenever you like:
|
|
51
47
|
|
|
52
48
|
```bash
|
|
53
|
-
|
|
49
|
+
export OPENROUTER_API_KEY=sk-or-... # https://openrouter.ai/keys
|
|
54
50
|
graft build --deep
|
|
55
51
|
```
|
|
56
52
|
|
|
57
|
-
|
|
53
|
+
Prefer not to install globally? `npx @nanonets/graft init` works the same way.
|
|
58
54
|
|
|
59
55
|
---
|
|
60
56
|
|
|
61
|
-
##
|
|
57
|
+
## Agent integration
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
One command wires Graft into the coding agents you use:
|
|
64
60
|
|
|
65
61
|
```bash
|
|
66
62
|
npx @nanonets/graft init
|
|
67
|
-
#
|
|
63
|
+
# detects your agents and writes each one's native instruction file;
|
|
64
|
+
# Claude Code additionally gets the live statusline + hooks below
|
|
68
65
|
```
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+
`init` auto-detects which agents are present (via their config directories) and writes a marker-fenced Graft section into each one's shared instruction file — `AGENTS.md`, `GEMINI.md`, `.github/copilot-instructions.md` — or a wholly-owned rule file for the agents that use one — `.cursor/rules/graft.mdc`, `.kiro/steering/graft.md`, `.windsurf/rules/graft.md`. Re-running only updates Graft's own section (or replaces the owned file) and never touches the rest of your content.
|
|
68
|
+
|
|
69
|
+
| Flag | Effect |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `--agents <ids...>` | wire only these — ids: `agents`, `cursor`, `gemini`, `copilot`, `kiro`, `windsurf`, `claude` |
|
|
72
|
+
| `--all-agents` | write instruction files for every known agent, detected or not |
|
|
73
|
+
| `--no-agents` | Claude Code wiring only; skip other agents |
|
|
74
|
+
| `--list-agents` | print the known agent ids and exit |
|
|
75
|
+
| `--no-mcp` | skip MCP server registration |
|
|
76
|
+
| `--no-hooks` | skip hook installation |
|
|
77
|
+
|
|
78
|
+
### MCP server
|
|
79
|
+
|
|
80
|
+
`graft init` also registers Graft's MCP server with agents that support it, so
|
|
81
|
+
`graft_ask`, `graft_check`, and `graft_blast_radius` appear as native tools —
|
|
82
|
+
no shell required. Skip with `--no-mcp`. Run it manually with `graft mcp [dir]`,
|
|
83
|
+
or register it by hand:
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{ "mcpServers": { "graft": { "command": "npx", "args": ["-y", "@nanonets/graft", "mcp"] } } }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Where a CLI agent supports user-level `hooks.json`, `init` also installs Graft's post-edit hook — blast-radius warnings and automatic `$0` graph re-sync after edits (skip with `--no-hooks`).
|
|
90
|
+
|
|
91
|
+
### Claude Code (deep integration)
|
|
92
|
+
|
|
93
|
+
`graft init` always wires up Claude Code, and Claude Code gets more than an instruction file. From then on, any Claude Code session opened in the repo gets:
|
|
71
94
|
|
|
72
95
|
- **a live statusline** — graph size, % enriched, and a `⚠ N stale` warning when the code has moved ahead of the graph
|
|
73
96
|
- **auto-sync** — after you edit code, Graft rebuilds the graph in the background at the end of the turn (structural, `$0` — it never calls the LLM on its own)
|
|
@@ -178,8 +201,11 @@ graft check --json # print the drift report as JSON
|
|
|
178
201
|
graft viz [dir] # see the graph: serves an interactive viewer on localhost
|
|
179
202
|
graft viz --port 5000 --no-open # pick a port; don't auto-open the browser
|
|
180
203
|
|
|
181
|
-
graft init [dir] #
|
|
204
|
+
graft init [dir] # wire Graft into the coding agents detected in this repo (Claude Code always gets full hooks + statusline)
|
|
182
205
|
graft init --no-build # wire the files only; don't build the graph
|
|
206
|
+
graft init --agents cursor kiro # wire only these agents (ids: agents, cursor, gemini, copilot, kiro, windsurf, claude)
|
|
207
|
+
graft init --all-agents # wire every known agent, detected or not
|
|
208
|
+
graft init --list-agents # list known agent ids and exit
|
|
183
209
|
|
|
184
210
|
# global
|
|
185
211
|
graft --dir <path> # use a context dir other than <repo>/graft
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"AAkBA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7D;
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"AAkBA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7D;AAgDD,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwCvD"}
|
package/dist/claude/hooks.js
CHANGED
|
@@ -53,6 +53,34 @@ function checkStaleCount(dir) {
|
|
|
53
53
|
function emit(eventName, additionalContext) {
|
|
54
54
|
process.stdout.write(JSON.stringify({ hookSpecificOutput: { hookEventName: eventName, additionalContext } }));
|
|
55
55
|
}
|
|
56
|
+
async function handlePostEdit(input, dir) {
|
|
57
|
+
const file = input?.tool_input?.file_path;
|
|
58
|
+
if (!file || underGraft(dir, file))
|
|
59
|
+
return;
|
|
60
|
+
patchStats(dir, { dirty: true, staleCount: checkStaleCount(dir), lastFile: basename(file) });
|
|
61
|
+
const w = readWiring(dir);
|
|
62
|
+
if (w) {
|
|
63
|
+
const br = formatBlastRadius(w, file);
|
|
64
|
+
if (br)
|
|
65
|
+
emit('PostToolUse', br);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function handleStop(dir) {
|
|
69
|
+
// sync-run.js ships next to this module inside the package, so it resolves in
|
|
70
|
+
// any repo that installs graft (not just graft's own). Defensive existsSync:
|
|
71
|
+
// if the package is somehow incomplete, skip rather than wedge on syncing:true.
|
|
72
|
+
// GRAFT_TEST_SYNC_RUN is a test seam (mirrors GRAFT_TEST_STDIN) so tests can point
|
|
73
|
+
// this at a stub file inside their own sandbox instead of writing into src/claude/.
|
|
74
|
+
const syncRun = process.env.GRAFT_TEST_SYNC_RUN ?? claudeScriptPath('sync-run.js');
|
|
75
|
+
if (!existsSync(syncRun))
|
|
76
|
+
return;
|
|
77
|
+
const stats = readStats(dir);
|
|
78
|
+
if (stats?.dirty && acquireLock(dir)) {
|
|
79
|
+
patchStats(dir, { syncing: true });
|
|
80
|
+
const child = spawn(process.execPath, [syncRun, dir], { detached: true, stdio: 'ignore' });
|
|
81
|
+
child.unref();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
56
84
|
export async function main(event) {
|
|
57
85
|
const input = readStdin();
|
|
58
86
|
const dir = projectDir(input);
|
|
@@ -65,31 +93,16 @@ export async function main(event) {
|
|
|
65
93
|
return;
|
|
66
94
|
}
|
|
67
95
|
if (event === 'post-edit') {
|
|
68
|
-
|
|
69
|
-
if (!file || underGraft(dir, file))
|
|
70
|
-
return;
|
|
71
|
-
patchStats(dir, { dirty: true, staleCount: checkStaleCount(dir), lastFile: basename(file) });
|
|
72
|
-
const w = readWiring(dir);
|
|
73
|
-
if (w) {
|
|
74
|
-
const br = formatBlastRadius(w, file);
|
|
75
|
-
if (br)
|
|
76
|
-
emit('PostToolUse', br);
|
|
77
|
-
}
|
|
96
|
+
await handlePostEdit(input, dir);
|
|
78
97
|
return;
|
|
79
98
|
}
|
|
80
99
|
if (event === 'stop') {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const stats = readStats(dir);
|
|
88
|
-
if (stats?.dirty && acquireLock(dir)) {
|
|
89
|
-
patchStats(dir, { syncing: true });
|
|
90
|
-
const child = spawn(process.execPath, [syncRun, dir], { detached: true, stdio: 'ignore' });
|
|
91
|
-
child.unref();
|
|
92
|
-
}
|
|
100
|
+
handleStop(dir);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (event === 'post-edit-sync') {
|
|
104
|
+
await handlePostEdit(input, dir);
|
|
105
|
+
handleStop(dir);
|
|
93
106
|
return;
|
|
94
107
|
}
|
|
95
108
|
if (event === 'prompt') {
|
package/dist/claude/hooks.js.map
CHANGED
|
@@ -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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"}
|
package/dist/claude/init.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/claude/init.js
CHANGED
|
@@ -3,6 +3,8 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
4
|
import { mergeGraftSettings } from './settings-merge.js';
|
|
5
5
|
import { statuslineShim, hooksShim } from './shim-template.js';
|
|
6
|
+
import { skillTemplate } from './skill-template.js';
|
|
7
|
+
import { claudeDistDir } from './paths.js';
|
|
6
8
|
export function runInit(dir, opts = {}) {
|
|
7
9
|
const helpersDir = join(dir, '.claude', 'helpers');
|
|
8
10
|
mkdirSync(helpersDir, { recursive: true });
|
|
@@ -16,10 +18,17 @@ export function runInit(dir, opts = {}) {
|
|
|
16
18
|
writeFileSync(settingsPath, `${JSON.stringify(merged, null, 2)}\n`);
|
|
17
19
|
const sl = join(helpersDir, 'graft-statusline.cjs');
|
|
18
20
|
const hk = join(helpersDir, 'graft-hooks.cjs');
|
|
19
|
-
|
|
21
|
+
const bakedDir = claudeDistDir(); // absolute <pkg>/dist/claude — the shims' primary resolution path
|
|
22
|
+
writeFileSync(sl, statuslineShim(bakedDir));
|
|
20
23
|
chmodSync(sl, 0o755);
|
|
21
|
-
writeFileSync(hk, hooksShim());
|
|
24
|
+
writeFileSync(hk, hooksShim(bakedDir));
|
|
22
25
|
chmodSync(hk, 0o755);
|
|
26
|
+
// Install the graft skill — the piece that redirects the agent to graft/ before it
|
|
27
|
+
// greps source. Overwritten each run (graft owns this file), like the shims above.
|
|
28
|
+
const skillDir = join(dir, '.claude', 'skills', 'graft');
|
|
29
|
+
mkdirSync(skillDir, { recursive: true });
|
|
30
|
+
const skillPath = join(skillDir, 'SKILL.md');
|
|
31
|
+
writeFileSync(skillPath, skillTemplate());
|
|
23
32
|
let built = false;
|
|
24
33
|
const wiring = join(dir, 'graft', '.graph', 'wiring.json');
|
|
25
34
|
if (opts.build !== false && opts.cliPath && !existsSync(wiring)) {
|
|
@@ -29,6 +38,6 @@ export function runInit(dir, opts = {}) {
|
|
|
29
38
|
}
|
|
30
39
|
catch { /* build best-effort; user can run `graft build` manually */ }
|
|
31
40
|
}
|
|
32
|
-
return { settingsPath, shims: [sl, hk], warnings, built };
|
|
41
|
+
return { settingsPath, shims: [sl, hk], skill: skillPath, warnings, built };
|
|
33
42
|
}
|
|
34
43
|
//# sourceMappingURL=init.js.map
|
package/dist/claude/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/claude/init.ts"],"names":[],"mappings":"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"}
|
package/dist/claude/paths.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** Absolute path to the graft CLI (`<pkgRoot>/dist/cli.js`), resolved from this module. */
|
|
2
2
|
export declare function graftCliPath(): string;
|
|
3
|
+
/** Absolute path to this package's `dist/claude` dir. Baked into the generated shims at
|
|
4
|
+
* init time as their primary resolution candidate, so the statusline/hooks find graft
|
|
5
|
+
* without runtime guesswork — correct regardless of how Node was installed. */
|
|
6
|
+
export declare function claudeDistDir(): string;
|
|
3
7
|
/** Absolute path to a sibling script in the claude dir (e.g. `sync-run.js`). */
|
|
4
8
|
export declare function claudeScriptPath(name: string): string;
|
|
5
9
|
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/claude/paths.ts"],"names":[],"mappings":"AASA,2FAA2F;AAC3F,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/claude/paths.ts"],"names":[],"mappings":"AASA,2FAA2F;AAC3F,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;+EAE+E;AAC/E,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAErD"}
|
package/dist/claude/paths.js
CHANGED
|
@@ -9,6 +9,12 @@ const CLAUDE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
|
9
9
|
export function graftCliPath() {
|
|
10
10
|
return join(CLAUDE_DIR, '..', 'cli.js');
|
|
11
11
|
}
|
|
12
|
+
/** Absolute path to this package's `dist/claude` dir. Baked into the generated shims at
|
|
13
|
+
* init time as their primary resolution candidate, so the statusline/hooks find graft
|
|
14
|
+
* without runtime guesswork — correct regardless of how Node was installed. */
|
|
15
|
+
export function claudeDistDir() {
|
|
16
|
+
return CLAUDE_DIR;
|
|
17
|
+
}
|
|
12
18
|
/** Absolute path to a sibling script in the claude dir (e.g. `sync-run.js`). */
|
|
13
19
|
export function claudeScriptPath(name) {
|
|
14
20
|
return join(CLAUDE_DIR, name);
|
package/dist/claude/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/claude/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,4FAA4F;AAC5F,8FAA8F;AAC9F,mFAAmF;AACnF,8FAA8F;AAC9F,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE3D,2FAA2F;AAC3F,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/claude/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,4FAA4F;AAC5F,8FAA8F;AAC9F,mFAAmF;AACnF,8FAA8F;AAC9F,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE3D,2FAA2F;AAC3F,MAAM,UAAU,YAAY;IAC1B,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC;AAED;;+EAE+E;AAC/E,MAAM,UAAU,aAAa;IAC3B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare function statuslineShim(): string;
|
|
2
|
-
export declare function hooksShim(): string;
|
|
1
|
+
export declare function statuslineShim(bakedDir: string): string;
|
|
2
|
+
export declare function hooksShim(bakedDir: string): string;
|
|
3
3
|
//# sourceMappingURL=shim-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shim-template.d.ts","sourceRoot":"","sources":["../../src/claude/shim-template.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shim-template.d.ts","sourceRoot":"","sources":["../../src/claude/shim-template.ts"],"names":[],"mappings":"AA6DA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAwD;AAChH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAkE"}
|
|
@@ -1,20 +1,63 @@
|
|
|
1
|
-
|
|
1
|
+
// Generates the tiny `.cjs` shims committed into a repo's `.claude/helpers/`. Their only
|
|
2
|
+
// job is to locate the installed `@nanonets/graft` package's `dist/claude/<entry>.js` and
|
|
3
|
+
// call into it — so the real logic lives in the package and upgrades with it.
|
|
4
|
+
//
|
|
5
|
+
// Resolution order (first hit wins), designed so a global install works regardless of how
|
|
6
|
+
// Node was installed (Homebrew/Windows/volta all shipped broken before this):
|
|
7
|
+
// 1. `bakedDir` — the absolute `dist/claude` graft was running from at init time.
|
|
8
|
+
// Correct with zero guesswork for whoever ran `graft init`.
|
|
9
|
+
// 2. repo node_modules — a local dev-dep install.
|
|
10
|
+
// 3. `execDir/../lib` — the cheap legacy guess (covers nvm / classic prefix layout).
|
|
11
|
+
// 4. `npm root -g` — authoritative global dir, layout-agnostic. Only shelled out to
|
|
12
|
+
// when 1–3 miss (the baked path hits first for the installer), so it's
|
|
13
|
+
// rarely reached; queried on demand — no on-disk cache, which on a
|
|
14
|
+
// shared machine would be a world-writable path an attacker could point
|
|
15
|
+
// at their own code for us to import.
|
|
16
|
+
function shim(entryFile, call, bakedDir) {
|
|
2
17
|
return `#!/usr/bin/env node
|
|
3
18
|
const path = require('path');
|
|
19
|
+
const fs = require('fs');
|
|
20
|
+
const { pathToFileURL } = require('url');
|
|
21
|
+
const { execFileSync } = require('child_process');
|
|
4
22
|
const dir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
23
|
+
const BAKED = ${JSON.stringify(bakedDir)};
|
|
24
|
+
|
|
25
|
+
// The dist/claude dir of @nanonets/graft resolved from a base whose node_modules is searched.
|
|
26
|
+
function fromPkg(base) {
|
|
27
|
+
try {
|
|
28
|
+
const pkg = require.resolve('@nanonets/graft/package.json', { paths: [base] });
|
|
29
|
+
return path.join(path.dirname(pkg), 'dist', 'claude');
|
|
30
|
+
} catch { return null; }
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// The global node_modules dir per npm (handles Homebrew/Windows/volta). Queried on demand.
|
|
34
|
+
function globalRoot() {
|
|
35
|
+
try {
|
|
36
|
+
const root = execFileSync('npm', ['root', '-g'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'], shell: true }).trim();
|
|
37
|
+
return root || null;
|
|
38
|
+
} catch { return null; /* npm unavailable */ }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function candidates() {
|
|
42
|
+
const out = [];
|
|
43
|
+
if (BAKED) out.push(BAKED);
|
|
44
|
+
const local = fromPkg(dir); if (local) out.push(local);
|
|
45
|
+
const legacy = fromPkg(path.join(path.dirname(process.execPath), '..', 'lib')); if (legacy) out.push(legacy);
|
|
46
|
+
const gr = globalRoot(); if (gr) out.push(path.join(gr, '@nanonets', 'graft', 'dist', 'claude'));
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
5
50
|
function entry(name) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const pkg = require.resolve('@nanonets/graft/package.json', { paths: [base] });
|
|
10
|
-
return path.join(path.dirname(pkg), 'dist', 'claude', name);
|
|
11
|
-
} catch { /* try next base */ }
|
|
51
|
+
for (const d of candidates()) {
|
|
52
|
+
const f = path.join(d, name);
|
|
53
|
+
if (fs.existsSync(f)) return f;
|
|
12
54
|
}
|
|
13
|
-
return path.join(dir, 'dist', 'claude', name);
|
|
55
|
+
return path.join(dir, 'dist', 'claude', name); // last-ditch; import will no-op if absent
|
|
14
56
|
}
|
|
15
|
-
|
|
57
|
+
|
|
58
|
+
import(pathToFileURL(entry(${JSON.stringify(entryFile)})).href).then((m) => ${call}).catch(() => { /* graft unavailable — no-op */ });
|
|
16
59
|
`;
|
|
17
60
|
}
|
|
18
|
-
export function statuslineShim() { return shim('statusline.js', 'm.main()'); }
|
|
19
|
-
export function hooksShim() { return shim('hooks.js', 'm.main(process.argv[2])'); }
|
|
61
|
+
export function statuslineShim(bakedDir) { return shim('statusline.js', 'm.main()', bakedDir); }
|
|
62
|
+
export function hooksShim(bakedDir) { return shim('hooks.js', 'm.main(process.argv[2])', bakedDir); }
|
|
20
63
|
//# sourceMappingURL=shim-template.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shim-template.js","sourceRoot":"","sources":["../../src/claude/shim-template.ts"],"names":[],"mappings":"AAAA,SAAS,IAAI,CAAC,SAAiB,EAAE,IAAY;
|
|
1
|
+
{"version":3,"file":"shim-template.js","sourceRoot":"","sources":["../../src/claude/shim-template.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,0FAA0F;AAC1F,8EAA8E;AAC9E,EAAE;AACF,0FAA0F;AAC1F,8EAA8E;AAC9E,sFAAsF;AACtF,gFAAgF;AAChF,oDAAoD;AACpD,wFAAwF;AACxF,0FAA0F;AAC1F,2FAA2F;AAC3F,uFAAuF;AACvF,4FAA4F;AAC5F,0DAA0D;AAC1D,SAAS,IAAI,CAAC,SAAiB,EAAE,IAAY,EAAE,QAAgB;IAC7D,OAAO;;;;;;gBAMO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BAmCX,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,wBAAwB,IAAI;CACjF,CAAC;AACF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,IAAY,OAAO,IAAI,CAAC,eAAe,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;AAChH,MAAM,UAAU,SAAS,CAAC,QAAgB,IAAY,OAAO,IAAI,CAAC,UAAU,EAAE,yBAAyB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-template.d.ts","sourceRoot":"","sources":["../../src/claude/skill-template.ts"],"names":[],"mappings":"AAKA,wBAAgB,aAAa,IAAI,MAAM,CA0CtC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The graft Claude Code skill, bundled as a string so `graft init` can write it into a
|
|
2
|
+
// consumer repo's .claude/skills/graft/SKILL.md — no network fetch, version-locked to the
|
|
3
|
+
// installed graft. This is the single source of truth for the skill text; graft's own
|
|
4
|
+
// repo copy is regenerated from here when `init` runs in this repo. Mirrors the `.cjs`
|
|
5
|
+
// shim pattern in shim-template.ts.
|
|
6
|
+
export function skillTemplate() {
|
|
7
|
+
return `---
|
|
8
|
+
name: graft
|
|
9
|
+
description: This repo is indexed by graft/. For ANY task here — understanding
|
|
10
|
+
how something works, finding where code lives, or scoping a change — get your
|
|
11
|
+
context from graft before grepping or reading source files.
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# graft
|
|
15
|
+
|
|
16
|
+
This repo's code is summarised in \`graft/\` — small markdown nodes, each
|
|
17
|
+
explaining one part in plain prose and naming the exact files and line-spans it
|
|
18
|
+
covers. Reading a node costs a few hundred tokens; reading source to rebuild the
|
|
19
|
+
same understanding costs thousands.
|
|
20
|
+
|
|
21
|
+
**Get context from graft first — two ways, both land here:**
|
|
22
|
+
|
|
23
|
+
- Ask: \`graft ask "<your task, in plain words>"\` — returns the relevant nodes,
|
|
24
|
+
ranked, with file:line pointers. Add \`--source\` to inline the actual code at
|
|
25
|
+
each span, so the result IS the code you need — no separate file read.
|
|
26
|
+
- Or explore as usual: grep / ls / cat inside \`graft/\`. A grep for any concept,
|
|
27
|
+
symbol, or filename hits the node that covers it; \`graft/INDEX.md\` lists them
|
|
28
|
+
all.
|
|
29
|
+
|
|
30
|
+
**Then STOP at the node. It is the answer, not a lookup toward the answer.**
|
|
31
|
+
|
|
32
|
+
- **Explaining / tracing / understanding** (no code change): the node's prose
|
|
33
|
+
IS your deliverable. Cite files and functions straight from its \`covers:\`
|
|
34
|
+
list — \`covers:\` gives you the exact \`file:line\` for every symbol, so you can
|
|
35
|
+
cite precisely **without opening the source at all.** Do NOT open source to
|
|
36
|
+
"verify," "confirm," or "see the real code" — the node was generated from that
|
|
37
|
+
source and the spans are authoritative. Opening it costs thousands of tokens
|
|
38
|
+
and changes nothing in your answer.
|
|
39
|
+
- **Editing:** run \`graft ask "<symbol>" --source\` to pull the exact span's
|
|
40
|
+
code inline, and edit straight from that. Only touch the file to apply the
|
|
41
|
+
change at the named \`file:line\` — never read the whole file, never open
|
|
42
|
+
neighbouring files to "get oriented"; the pack already oriented you.
|
|
43
|
+
|
|
44
|
+
If a node genuinely lacks a detail you need, \`graft ask\` for a more specific
|
|
45
|
+
node before falling back to source. Reading whole source files to build
|
|
46
|
+
understanding is the thing graft exists to replace — it already did that work.
|
|
47
|
+
`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=skill-template.js.map
|
|
@@ -0,0 +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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwCR,CAAC;AACF,CAAC"}
|
package/dist/cli.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* ask query the graph ($0, no LLM).
|
|
7
7
|
* check fail if graft/ has drifted from the code — for CI.
|
|
8
8
|
* viz serve the interactive graph viewer.
|
|
9
|
+
* mcp serve the graph over MCP (stdio) for coding agents.
|
|
9
10
|
* init set up the Claude Code integration (.claude/ statusline + hooks) in this repo.
|
|
10
11
|
*
|
|
11
12
|
* Git is the sync: commit graft/ and anyone who clones the repo has the
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AACH,OAAO,eAAe,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* ask query the graph ($0, no LLM).
|
|
7
7
|
* check fail if graft/ has drifted from the code — for CI.
|
|
8
8
|
* viz serve the interactive graph viewer.
|
|
9
|
+
* mcp serve the graph over MCP (stdio) for coding agents.
|
|
9
10
|
* init set up the Claude Code integration (.claude/ statusline + hooks) in this repo.
|
|
10
11
|
*
|
|
11
12
|
* Git is the sync: commit graft/ and anyone who clones the repo has the
|
|
@@ -20,6 +21,8 @@ import { resolveConfig } from "./ai/providers.js";
|
|
|
20
21
|
import { formatCheckReport } from "./context/check.js";
|
|
21
22
|
import { formatGraphCheckReport } from "./graph/check.js";
|
|
22
23
|
import { runInit } from "./claude/init.js";
|
|
24
|
+
import { runHostsInit } from "./hosts/init.js";
|
|
25
|
+
import { hostIds } from "./hosts/registry.js";
|
|
23
26
|
const program = new Command();
|
|
24
27
|
program
|
|
25
28
|
.name("graft")
|
|
@@ -162,21 +165,73 @@ program
|
|
|
162
165
|
spawn(opener, [srv.url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
|
|
163
166
|
}
|
|
164
167
|
});
|
|
168
|
+
program
|
|
169
|
+
.command("mcp")
|
|
170
|
+
.description("Serve the graph over MCP (stdio) — exposes graft_ask / graft_check / graft_blast_radius as tools")
|
|
171
|
+
.argument("[dir]", "repository root", ".")
|
|
172
|
+
.action(async (dir) => {
|
|
173
|
+
const { resolve } = await import("node:path");
|
|
174
|
+
const { startMcpServer } = await import("./mcp/server.js");
|
|
175
|
+
startMcpServer(resolve(dir));
|
|
176
|
+
});
|
|
165
177
|
program
|
|
166
178
|
.command("init")
|
|
167
|
-
.description("
|
|
179
|
+
.description("Wire Graft into the AI coding agents used with this repo (instruction files; full hooks + statusline for Claude Code)")
|
|
168
180
|
.argument("[dir]", "target repo directory", ".")
|
|
169
181
|
.option("--no-build", "skip building the graph (wire files only)")
|
|
182
|
+
.option("--agents <ids...>", `only these agents (${hostIds().join(", ")}, claude)`)
|
|
183
|
+
.option("--all-agents", "write instruction files for every known agent, detected or not")
|
|
184
|
+
.option("--no-agents", "Claude Code wiring only; skip other agents")
|
|
185
|
+
.option("--list-agents", "list known agent ids and exit")
|
|
186
|
+
.option("--no-mcp", "skip MCP server registration for other agents")
|
|
187
|
+
.option("--no-hooks", "skip hook installation for other agents")
|
|
170
188
|
.action((dir, opts) => {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
189
|
+
if (opts.listAgents) {
|
|
190
|
+
for (const id of [...hostIds(), "claude"])
|
|
191
|
+
console.log(id);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const repo = resolve(dir);
|
|
195
|
+
const explicit = Array.isArray(opts.agents) ? opts.agents : undefined;
|
|
196
|
+
if (explicit) {
|
|
197
|
+
const validIds = [...hostIds(), "claude"];
|
|
198
|
+
const unknown = explicit.filter((id) => !validIds.includes(id));
|
|
199
|
+
if (unknown.length) {
|
|
200
|
+
console.error(`✗ unknown agent id(s): ${unknown.join(", ")} — valid: ${validIds.join(", ")}`);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const wantClaude = !explicit || explicit.includes("claude");
|
|
205
|
+
if (wantClaude) {
|
|
206
|
+
const cliPath = fileURLToPath(import.meta.url);
|
|
207
|
+
const res = runInit(repo, { build: opts.build, cliPath });
|
|
208
|
+
console.error(`✓ wrote ${res.settingsPath}`);
|
|
209
|
+
for (const s of res.shims)
|
|
210
|
+
console.error(`✓ wrote ${s}`);
|
|
211
|
+
console.error(`✓ wrote ${res.skill}`);
|
|
212
|
+
console.error(res.built ? "✓ built the graph (graft build)" : "· skipped graph build");
|
|
213
|
+
for (const w of res.warnings)
|
|
214
|
+
console.error(`⚠ ${w}`);
|
|
215
|
+
}
|
|
216
|
+
const skipOthers = opts.agents === false;
|
|
217
|
+
if (!skipOthers) {
|
|
218
|
+
const r = runHostsInit(repo, {
|
|
219
|
+
agents: explicit?.filter((id) => id !== "claude"),
|
|
220
|
+
all: opts.allAgents,
|
|
221
|
+
mcp: opts.mcp,
|
|
222
|
+
hooks: opts.hooks,
|
|
223
|
+
});
|
|
224
|
+
for (const w of r.written)
|
|
225
|
+
console.error(`✓ ${w.id}: ${w.path} (${w.action})`);
|
|
226
|
+
if (!explicit && !opts.allAgents && r.written.length === 0)
|
|
227
|
+
console.error("· no other agents detected (see --list-agents / --all-agents)");
|
|
228
|
+
// r.unknown is always empty here — ids are validated above, before any writes.
|
|
229
|
+
for (const m of r.mcp)
|
|
230
|
+
console.error(`✓ mcp ${m.id}: ${m.path} (${m.action})`);
|
|
231
|
+
for (const h of r.hooks)
|
|
232
|
+
console.error(`✓ hook ${h.id}: ${h.path} (${h.action})`);
|
|
233
|
+
}
|
|
234
|
+
console.error("\nDone. Claude Code gets live hooks + statusline; other agents read their instruction files.");
|
|
180
235
|
console.error("For LLM summaries: set OPENROUTER_API_KEY and run `graft build --deep`.");
|
|
181
236
|
});
|
|
182
237
|
program.parseAsync().catch((err) => {
|