@nanonets/graft 0.4.1 → 0.4.3
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 +36 -6
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +64 -45
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/graphrank.d.ts.map +1 -1
- package/dist/ask/graphrank.js +10 -4
- package/dist/ask/graphrank.js.map +1 -1
- package/dist/ask/index-file.d.ts +43 -0
- package/dist/ask/index-file.d.ts.map +1 -0
- package/dist/ask/index-file.js +128 -0
- package/dist/ask/index-file.js.map +1 -0
- 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.map +1 -1
- package/dist/claude/init.js +4 -2
- 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/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +65 -11
- package/dist/cli.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +13 -0
- package/dist/graph/build.js.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 +1 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type McpWrite } from './mcp-config.js';
|
|
2
|
+
import { type HookWrite } from './codex-hooks.js';
|
|
3
|
+
export interface HostsInitResult {
|
|
4
|
+
written: {
|
|
5
|
+
id: string;
|
|
6
|
+
path: string;
|
|
7
|
+
action: string;
|
|
8
|
+
}[];
|
|
9
|
+
skipped: string[];
|
|
10
|
+
unknown: string[];
|
|
11
|
+
mcp: McpWrite[];
|
|
12
|
+
hooks: HookWrite[];
|
|
13
|
+
}
|
|
14
|
+
export declare function runHostsInit(repo: string, opts?: {
|
|
15
|
+
agents?: string[];
|
|
16
|
+
all?: boolean;
|
|
17
|
+
home?: string;
|
|
18
|
+
mcp?: boolean;
|
|
19
|
+
hooks?: boolean;
|
|
20
|
+
}): HostsInitResult;
|
|
21
|
+
//# sourceMappingURL=init.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/hosts/init.ts"],"names":[],"mappings":"AAUA,OAAO,EAAsB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,GAAG,EAAE,QAAQ,EAAE,CAAC;IAChB,KAAK,EAAE,SAAS,EAAE,CAAC;CACpB;AAiBD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7F,eAAe,CAgCjB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-host init: write each selected host's instruction file.
|
|
3
|
+
* Selection = explicit ids > all > detected. Claude Code is handled
|
|
4
|
+
* separately by src/claude/init.ts (hooks + statusline + skill).
|
|
5
|
+
*/
|
|
6
|
+
import { statSync, writeFileSync, readFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { HOSTS, detectHosts } from './registry.js';
|
|
10
|
+
import { upsertSection } from './sections.js';
|
|
11
|
+
import { registerMcpConfigs } from './mcp-config.js';
|
|
12
|
+
import { installCodexHooks } from './codex-hooks.js';
|
|
13
|
+
function probeFor(home, repo) {
|
|
14
|
+
return {
|
|
15
|
+
home, repo,
|
|
16
|
+
dirExists: (p) => { try {
|
|
17
|
+
return statSync(p).isDirectory();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return false;
|
|
21
|
+
} },
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function writeOwned(path, content) {
|
|
25
|
+
if (existsSync(path) && readFileSync(path, 'utf8') === content)
|
|
26
|
+
return 'unchanged';
|
|
27
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
28
|
+
const existed = existsSync(path);
|
|
29
|
+
writeFileSync(path, content);
|
|
30
|
+
return existed ? 'replaced' : 'created';
|
|
31
|
+
}
|
|
32
|
+
export function runHostsInit(repo, opts = {}) {
|
|
33
|
+
const home = opts.home ?? homedir();
|
|
34
|
+
const probe = probeFor(home, repo);
|
|
35
|
+
let selected;
|
|
36
|
+
let unknown = [];
|
|
37
|
+
if (opts.agents !== undefined) {
|
|
38
|
+
const byId = new Map(HOSTS.map((h) => [h.id, h]));
|
|
39
|
+
selected = opts.agents.flatMap((id) => byId.get(id) ?? []);
|
|
40
|
+
unknown = opts.agents.filter((id) => !byId.has(id));
|
|
41
|
+
}
|
|
42
|
+
else if (opts.all) {
|
|
43
|
+
selected = HOSTS;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
selected = detectHosts(probe);
|
|
47
|
+
}
|
|
48
|
+
const written = [];
|
|
49
|
+
for (const host of selected) {
|
|
50
|
+
const path = join(repo, host.relPath);
|
|
51
|
+
const action = host.kind === 'owned'
|
|
52
|
+
? writeOwned(path, host.content())
|
|
53
|
+
: upsertSection(path, host.content()).action;
|
|
54
|
+
written.push({ id: host.id, path, action });
|
|
55
|
+
}
|
|
56
|
+
const skipped = HOSTS.filter((h) => !selected.includes(h)).map((h) => h.id);
|
|
57
|
+
const mcp = opts.mcp === false ? [] : registerMcpConfigs(repo, selected.map((h) => h.id), { home });
|
|
58
|
+
const hooks = opts.hooks === false || !selected.some((h) => h.id === 'agents')
|
|
59
|
+
? []
|
|
60
|
+
: installCodexHooks(home);
|
|
61
|
+
return { written, skipped, unknown, mcp, hooks };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/hosts/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one canonical Graft instruction block, rendered into each host's
|
|
3
|
+
* native format. Content changes happen HERE only; renderers just wrap it.
|
|
4
|
+
*/
|
|
5
|
+
export declare function instructionBody(): string;
|
|
6
|
+
export declare function cursorRule(): string;
|
|
7
|
+
export declare function kiroSteering(): string;
|
|
8
|
+
export declare function windsurfRule(): string;
|
|
9
|
+
//# sourceMappingURL=instructions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,eAAe,IAAI,MAAM,CAmBxC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAOnC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one canonical Graft instruction block, rendered into each host's
|
|
3
|
+
* native format. Content changes happen HERE only; renderers just wrap it.
|
|
4
|
+
*/
|
|
5
|
+
export function instructionBody() {
|
|
6
|
+
return `## Graft — repo context graph
|
|
7
|
+
|
|
8
|
+
This repo is indexed in \`graft/\`: small linked markdown nodes that explain each
|
|
9
|
+
system and carry exact file:line spans, kept in sync with the code through git.
|
|
10
|
+
|
|
11
|
+
For ANY task here — understanding how something works, finding where code lives,
|
|
12
|
+
or scoping a change — get context from the graph before grepping or opening
|
|
13
|
+
source files:
|
|
14
|
+
|
|
15
|
+
- Run \`graft ask "<your question>" --source\` → ranked nodes with the relevant
|
|
16
|
+
code spans inlined. The node usually IS the answer; stop there.
|
|
17
|
+
- Or browse: \`graft/INDEX.md\` lists every node; follow the links.
|
|
18
|
+
|
|
19
|
+
Only open source files when a node genuinely lacks a needed detail, and then at
|
|
20
|
+
the exact file:line the node points to — never re-read whole files.
|
|
21
|
+
|
|
22
|
+
After big code changes, refresh the graph with \`graft build\` (deterministic,
|
|
23
|
+
no API key, $0).`;
|
|
24
|
+
}
|
|
25
|
+
export function cursorRule() {
|
|
26
|
+
return `---
|
|
27
|
+
description: Use the Graft context graph in graft/ before exploring source
|
|
28
|
+
alwaysApply: true
|
|
29
|
+
---
|
|
30
|
+
${instructionBody()}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
export function kiroSteering() {
|
|
34
|
+
return `---
|
|
35
|
+
inclusion: always
|
|
36
|
+
---
|
|
37
|
+
${instructionBody()}
|
|
38
|
+
`;
|
|
39
|
+
}
|
|
40
|
+
export function windsurfRule() {
|
|
41
|
+
return `${instructionBody()}
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=instructions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;;;;;;;;;;;;;;iBAiBQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;;;;EAIP,eAAe,EAAE;CAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;;;EAGP,eAAe,EAAE;CAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,GAAG,eAAe,EAAE;CAC5B,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface McpWrite {
|
|
2
|
+
id: string;
|
|
3
|
+
path: string;
|
|
4
|
+
action: 'created' | 'updated' | 'unchanged' | 'skipped-unparseable';
|
|
5
|
+
}
|
|
6
|
+
export declare function registerMcpConfigs(repo: string, ids: string[], opts?: {
|
|
7
|
+
home?: string;
|
|
8
|
+
}): McpWrite[];
|
|
9
|
+
//# sourceMappingURL=mcp-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.d.ts","sourceRoot":"","sources":["../../src/hosts/mcp-config.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,qBAAqB,CAAC;CACrE;AA0CD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EAAE,EACb,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC3B,QAAQ,EAAE,CA2BZ"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Register the graft MCP server in each host's config.
|
|
3
|
+
* JSON hosts get a keyed merge (other servers preserved; unparseable files
|
|
4
|
+
* are never rewritten). The TOML host gets an append-if-absent section.
|
|
5
|
+
*/
|
|
6
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from 'node:fs';
|
|
7
|
+
import { dirname, join } from 'node:path';
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
const SERVER_ENTRY = { command: 'npx', args: ['-y', '@nanonets/graft', 'mcp'] };
|
|
10
|
+
const OPENCODE_ENTRY = { type: 'local', command: ['npx', '-y', '@nanonets/graft', 'mcp'], enabled: true };
|
|
11
|
+
function dirExists(p) {
|
|
12
|
+
try {
|
|
13
|
+
return statSync(p).isDirectory();
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function mergeJsonKey(id, path, topKey, entry) {
|
|
20
|
+
let root = {};
|
|
21
|
+
const existed = existsSync(path);
|
|
22
|
+
if (existed) {
|
|
23
|
+
try {
|
|
24
|
+
root = JSON.parse(readFileSync(path, 'utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return { id, path, action: 'skipped-unparseable' };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const bucket = (root[topKey] ??= {});
|
|
31
|
+
if (typeof bucket !== 'object' || bucket === null || Array.isArray(bucket)) {
|
|
32
|
+
return { id, path, action: 'skipped-unparseable' };
|
|
33
|
+
}
|
|
34
|
+
if (JSON.stringify(bucket.graft) === JSON.stringify(entry))
|
|
35
|
+
return { id, path, action: 'unchanged' };
|
|
36
|
+
const action = existed ? 'updated' : 'created';
|
|
37
|
+
bucket.graft = entry;
|
|
38
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
39
|
+
writeFileSync(path, `${JSON.stringify(root, null, 2)}\n`);
|
|
40
|
+
return { id, path, action };
|
|
41
|
+
}
|
|
42
|
+
function upsertCodexToml(id, path) {
|
|
43
|
+
const existed = existsSync(path);
|
|
44
|
+
const text = existed ? readFileSync(path, 'utf8') : '';
|
|
45
|
+
if (/^\[mcp_servers\.graft\]$/m.test(text))
|
|
46
|
+
return { id, path, action: 'unchanged' };
|
|
47
|
+
const section = `[mcp_servers.graft]\ncommand = "npx"\nargs = ["-y", "@nanonets/graft", "mcp"]\n`;
|
|
48
|
+
const sep = text.length === 0 ? '' : text.endsWith('\n') ? '\n' : '\n\n';
|
|
49
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
50
|
+
writeFileSync(path, `${text}${sep}${section}`);
|
|
51
|
+
return { id, path, action: existed ? 'updated' : 'created' };
|
|
52
|
+
}
|
|
53
|
+
export function registerMcpConfigs(repo, ids, opts = {}) {
|
|
54
|
+
const home = opts.home ?? homedir();
|
|
55
|
+
const out = [];
|
|
56
|
+
for (const id of ids) {
|
|
57
|
+
switch (id) {
|
|
58
|
+
case 'cursor':
|
|
59
|
+
out.push(mergeJsonKey(id, join(repo, '.cursor', 'mcp.json'), 'mcpServers', SERVER_ENTRY));
|
|
60
|
+
break;
|
|
61
|
+
case 'gemini':
|
|
62
|
+
out.push(mergeJsonKey(id, join(repo, '.gemini', 'settings.json'), 'mcpServers', SERVER_ENTRY));
|
|
63
|
+
break;
|
|
64
|
+
case 'kiro':
|
|
65
|
+
out.push(mergeJsonKey(id, join(repo, '.kiro', 'settings', 'mcp.json'), 'mcpServers', SERVER_ENTRY));
|
|
66
|
+
break;
|
|
67
|
+
case 'agents':
|
|
68
|
+
if (dirExists(join(home, '.codex'))) {
|
|
69
|
+
out.push(upsertCodexToml('codex', join(home, '.codex', 'config.toml')));
|
|
70
|
+
}
|
|
71
|
+
if (dirExists(join(home, '.config', 'opencode'))) {
|
|
72
|
+
out.push(mergeJsonKey('opencode', join(repo, 'opencode.json'), 'mcp', OPENCODE_ENTRY));
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
default:
|
|
76
|
+
break; // copilot / windsurf / claude: no MCP target in this phase
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=mcp-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../../src/hosts/mcp-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface DetectProbe {
|
|
2
|
+
home: string;
|
|
3
|
+
repo: string;
|
|
4
|
+
dirExists(path: string): boolean;
|
|
5
|
+
}
|
|
6
|
+
export interface HostTarget {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
kind: 'section' | 'owned';
|
|
10
|
+
/** Target file, relative to the repo root. */
|
|
11
|
+
relPath: string;
|
|
12
|
+
content(): string;
|
|
13
|
+
detect(probe: DetectProbe): boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare const HOSTS: HostTarget[];
|
|
16
|
+
export declare function hostIds(): string[];
|
|
17
|
+
export declare function detectHosts(probe: DetectProbe): HostTarget[];
|
|
18
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/hosts/registry.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC;IAC1B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,IAAI,MAAM,CAAC;IAClB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC;CACrC;AAED,eAAO,MAAM,KAAK,EAAE,UAAU,EAoD7B,CAAC;AAEF,wBAAgB,OAAO,IAAI,MAAM,EAAE,CAElC;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,EAAE,CAE5D"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry of AI coding hosts Graft can write instructions for.
|
|
3
|
+
* Adding a host = adding one entry here (plus a renderer if it needs
|
|
4
|
+
* a new file format).
|
|
5
|
+
*
|
|
6
|
+
* kind: 'section' → upsert the fenced block into a shared file the user owns.
|
|
7
|
+
* kind: 'owned' → graft owns the whole file; overwrite it each run.
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { instructionBody, cursorRule, kiroSteering, windsurfRule } from './instructions.js';
|
|
11
|
+
export const HOSTS = [
|
|
12
|
+
{
|
|
13
|
+
id: 'agents',
|
|
14
|
+
name: 'AGENTS.md hosts (Codex-style CLIs, editors that read AGENTS.md)',
|
|
15
|
+
kind: 'section',
|
|
16
|
+
relPath: 'AGENTS.md',
|
|
17
|
+
content: instructionBody,
|
|
18
|
+
detect: (p) => p.dirExists(join(p.home, '.codex')) ||
|
|
19
|
+
p.dirExists(join(p.home, '.config', 'opencode')) ||
|
|
20
|
+
p.dirExists(join(p.home, '.config', 'agents')),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
id: 'cursor',
|
|
24
|
+
name: 'Cursor',
|
|
25
|
+
kind: 'owned',
|
|
26
|
+
relPath: join('.cursor', 'rules', 'graft.mdc'),
|
|
27
|
+
content: cursorRule,
|
|
28
|
+
detect: (p) => p.dirExists(join(p.home, '.cursor')) || p.dirExists(join(p.repo, '.cursor')),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'gemini',
|
|
32
|
+
name: 'Gemini CLI',
|
|
33
|
+
kind: 'section',
|
|
34
|
+
relPath: 'GEMINI.md',
|
|
35
|
+
content: instructionBody,
|
|
36
|
+
detect: (p) => p.dirExists(join(p.home, '.gemini')),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'copilot',
|
|
40
|
+
name: 'GitHub Copilot',
|
|
41
|
+
kind: 'section',
|
|
42
|
+
relPath: join('.github', 'copilot-instructions.md'),
|
|
43
|
+
content: instructionBody,
|
|
44
|
+
detect: (p) => p.dirExists(join(p.repo, '.github')),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'kiro',
|
|
48
|
+
name: 'Kiro',
|
|
49
|
+
kind: 'owned',
|
|
50
|
+
relPath: join('.kiro', 'steering', 'graft.md'),
|
|
51
|
+
content: kiroSteering,
|
|
52
|
+
detect: (p) => p.dirExists(join(p.home, '.kiro')) || p.dirExists(join(p.repo, '.kiro')),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'windsurf',
|
|
56
|
+
name: 'Windsurf',
|
|
57
|
+
kind: 'owned',
|
|
58
|
+
relPath: join('.windsurf', 'rules', 'graft.md'),
|
|
59
|
+
content: windsurfRule,
|
|
60
|
+
detect: (p) => p.dirExists(join(p.home, '.codeium', 'windsurf')) || p.dirExists(join(p.repo, '.windsurf')),
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
export function hostIds() {
|
|
64
|
+
return HOSTS.map((h) => h.id);
|
|
65
|
+
}
|
|
66
|
+
export function detectHosts(probe) {
|
|
67
|
+
return HOSTS.filter((h) => h.detect(probe));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/hosts/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const START = "<!-- graft:start -->";
|
|
2
|
+
export declare const END = "<!-- graft:end -->";
|
|
3
|
+
export type UpsertAction = 'created' | 'appended' | 'replaced' | 'unchanged';
|
|
4
|
+
type LineEnding = '\n' | '\r\n';
|
|
5
|
+
export declare function fencedBlock(body: string, eol?: LineEnding): string;
|
|
6
|
+
export declare function upsertSection(filePath: string, body: string): {
|
|
7
|
+
action: UpsertAction;
|
|
8
|
+
};
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=sections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../src/hosts/sections.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,KAAK,yBAAyB,CAAC;AAC5C,eAAO,MAAM,GAAG,uBAAuB,CAAC;AAExC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAE7E,KAAK,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAEhC,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAE,UAAiB,GAAG,MAAM,CAMxE;AAeD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CA+BtF"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Marker-fenced section upsert. Graft owns exactly the region between the
|
|
3
|
+
* markers; everything else in the file belongs to the user and is preserved.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
export const START = '<!-- graft:start -->';
|
|
8
|
+
export const END = '<!-- graft:end -->';
|
|
9
|
+
export function fencedBlock(body, eol = '\n') {
|
|
10
|
+
// Normalize any pre-existing '\r' out of the body first so callers passing
|
|
11
|
+
// a CRLF (or stray-CR) body never get doubled '\r' when eol is '\r\n'.
|
|
12
|
+
const normalizedBody = body.replace(/\r/g, '');
|
|
13
|
+
const block = `${START}\n${normalizedBody.replace(/\s+$/, '')}\n${END}`;
|
|
14
|
+
return eol === '\n' ? block : block.replace(/\n/g, '\r\n');
|
|
15
|
+
}
|
|
16
|
+
/** The file's dominant line ending: CRLF if any '\r\n' is present, else LF. */
|
|
17
|
+
function detectEol(text) {
|
|
18
|
+
return text.includes('\r\n') ? '\r\n' : '\n';
|
|
19
|
+
}
|
|
20
|
+
/** Index of a marker that sits alone on its own line, or -1. */
|
|
21
|
+
function markerLineIndex(lines, marker, from = 0) {
|
|
22
|
+
for (let i = from; i < lines.length; i++) {
|
|
23
|
+
if (lines[i].trim() === marker)
|
|
24
|
+
return i;
|
|
25
|
+
}
|
|
26
|
+
return -1;
|
|
27
|
+
}
|
|
28
|
+
export function upsertSection(filePath, body) {
|
|
29
|
+
if (!existsSync(filePath)) {
|
|
30
|
+
const block = fencedBlock(body);
|
|
31
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
32
|
+
writeFileSync(filePath, `${block}\n`);
|
|
33
|
+
return { action: 'created' };
|
|
34
|
+
}
|
|
35
|
+
const text = readFileSync(filePath, 'utf8');
|
|
36
|
+
const eol = detectEol(text);
|
|
37
|
+
// Split on either eol so lines never carry an embedded '\r' — that keeps
|
|
38
|
+
// the marker/content comparison clean and lets us rejoin deliberately with
|
|
39
|
+
// the detected eol instead of relying on '\r' characters riding along
|
|
40
|
+
// inside array elements (which broke down whenever the block-with-no-
|
|
41
|
+
// trailing-'\r' element sat next to a '\n' join, e.g. right after END, or
|
|
42
|
+
// when the block was the entire file).
|
|
43
|
+
const lines = text.split(/\r\n|\n/);
|
|
44
|
+
const s = markerLineIndex(lines, START);
|
|
45
|
+
const e = s === -1 ? -1 : markerLineIndex(lines, END, s + 1);
|
|
46
|
+
if (s !== -1 && e !== -1) {
|
|
47
|
+
const current = lines.slice(s, e + 1).join('\n');
|
|
48
|
+
if (current === fencedBlock(body))
|
|
49
|
+
return { action: 'unchanged' };
|
|
50
|
+
const block = fencedBlock(body, eol);
|
|
51
|
+
const next = [...lines.slice(0, s), ...block.split(eol), ...lines.slice(e + 1)];
|
|
52
|
+
writeFileSync(filePath, next.join(eol));
|
|
53
|
+
return { action: 'replaced' };
|
|
54
|
+
}
|
|
55
|
+
const block = fencedBlock(body, eol);
|
|
56
|
+
const doubleEol = eol + eol;
|
|
57
|
+
const sep = text.endsWith(doubleEol) ? '' : text.endsWith(eol) ? eol : doubleEol;
|
|
58
|
+
writeFileSync(filePath, `${text}${sep}${block}${eol}`);
|
|
59
|
+
return { action: 'appended' };
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=sections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/hosts/sections.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAmBA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA8CjD"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal MCP stdio server: newline-delimited JSON-RPC 2.0.
|
|
3
|
+
* stdout carries protocol messages ONLY; diagnostics go to stderr.
|
|
4
|
+
*/
|
|
5
|
+
import { createInterface } from 'node:readline';
|
|
6
|
+
import { TOOLS, callTool } from './tools.js';
|
|
7
|
+
function send(msg) {
|
|
8
|
+
process.stdout.write(`${JSON.stringify(msg)}\n`);
|
|
9
|
+
}
|
|
10
|
+
function reply(id, result) {
|
|
11
|
+
send({ jsonrpc: '2.0', id, result });
|
|
12
|
+
}
|
|
13
|
+
function replyError(id, code, message) {
|
|
14
|
+
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
15
|
+
}
|
|
16
|
+
export function startMcpServer(root) {
|
|
17
|
+
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
18
|
+
rl.on('line', (line) => {
|
|
19
|
+
const text = line.trim();
|
|
20
|
+
if (!text)
|
|
21
|
+
return;
|
|
22
|
+
let msg;
|
|
23
|
+
try {
|
|
24
|
+
msg = JSON.parse(text);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
replyError(null, -32700, 'parse error');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const { id, method, params } = msg;
|
|
31
|
+
const isNotification = id === undefined;
|
|
32
|
+
switch (method) {
|
|
33
|
+
case 'initialize':
|
|
34
|
+
reply(id, {
|
|
35
|
+
protocolVersion: params?.protocolVersion ?? '2024-11-05',
|
|
36
|
+
capabilities: { tools: {} },
|
|
37
|
+
serverInfo: { name: 'graft', version: '0' },
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
case 'notifications/initialized':
|
|
41
|
+
case 'notifications/cancelled':
|
|
42
|
+
return; // notifications get no response
|
|
43
|
+
case 'ping':
|
|
44
|
+
if (!isNotification)
|
|
45
|
+
reply(id, {});
|
|
46
|
+
return;
|
|
47
|
+
case 'tools/list':
|
|
48
|
+
if (!isNotification) {
|
|
49
|
+
reply(id, { tools: TOOLS.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })) });
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
case 'tools/call': {
|
|
53
|
+
if (isNotification)
|
|
54
|
+
return;
|
|
55
|
+
const name = String(params?.name ?? '');
|
|
56
|
+
const args = (params?.arguments ?? {});
|
|
57
|
+
const r = callTool(root, name, args);
|
|
58
|
+
reply(id, { content: [{ type: 'text', text: r.text }], isError: r.isError });
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
if (!isNotification)
|
|
63
|
+
replyError(id, -32601, `method not found: ${method}`);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
process.stdin.on('end', () => process.exit(0));
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE7C,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,KAAK,CAAC,EAAW,EAAE,MAAc;IACxC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,EAAW,EAAE,IAAY,EAAE,OAAe;IAC5D,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1E,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,IAAI,GAAoE,CAAC;QACzE,IAAI,CAAC;YACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;YACxC,OAAO;QACT,CAAC;QACD,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;QACnC,MAAM,cAAc,GAAG,EAAE,KAAK,SAAS,CAAC;QACxC,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,YAAY;gBACf,KAAK,CAAC,EAAE,EAAE;oBACR,eAAe,EAAE,MAAM,EAAE,eAAe,IAAI,YAAY;oBACxD,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;oBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE;iBAC5C,CAAC,CAAC;gBACH,OAAO;YACT,KAAK,2BAA2B,CAAC;YACjC,KAAK,yBAAyB;gBAC5B,OAAO,CAAC,gCAAgC;YAC1C,KAAK,MAAM;gBACT,IAAI,CAAC,cAAc;oBAAE,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBACnC,OAAO;YACT,KAAK,YAAY;gBACf,IAAI,CAAC,cAAc,EAAE,CAAC;oBACpB,KAAK,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBACrH,CAAC;gBACD,OAAO;YACT,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,IAAI,cAAc;oBAAE,OAAO;gBAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;gBACxC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAA4B,CAAC;gBAClE,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBACrC,KAAK,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7E,OAAO;YACT,CAAC;YACD;gBACE,IAAI,CAAC,cAAc;oBAAE,UAAU,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ToolDef {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: object;
|
|
5
|
+
}
|
|
6
|
+
export declare const TOOLS: ToolDef[];
|
|
7
|
+
export declare function callTool(root: string, name: string, args: Record<string, unknown>): {
|
|
8
|
+
text: string;
|
|
9
|
+
isError: boolean;
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,KAAK,EAAE,OAAO,EA4B1B,CAAC;AAEF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAiCpC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three MCP tools, as pure functions over the existing engine.
|
|
3
|
+
* `callTool` never throws — hosts get soft errors as isError content.
|
|
4
|
+
*/
|
|
5
|
+
import { Graft } from '../engine.js';
|
|
6
|
+
import { formatAsk } from '../ask/ask.js';
|
|
7
|
+
import { formatCheckReport } from '../context/check.js';
|
|
8
|
+
import { formatGraphCheckReport } from '../graph/check.js';
|
|
9
|
+
import { formatBlastRadius } from '../claude/format.js';
|
|
10
|
+
import { readGraph, wiringPath } from '../graph/write.js';
|
|
11
|
+
import { contextDirFor } from '../context/node-file.js';
|
|
12
|
+
export const TOOLS = [
|
|
13
|
+
{
|
|
14
|
+
name: 'graft_ask',
|
|
15
|
+
description: 'Query the repo context graph in plain words. Returns ranked nodes with exact file:line spans and the relevant source inlined — usually the full answer, no file reads needed.',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
query: { type: 'string', description: 'what you want to understand, in plain words' },
|
|
20
|
+
limit: { type: 'number', description: 'max results (default 5)' },
|
|
21
|
+
},
|
|
22
|
+
required: ['query'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'graft_check',
|
|
27
|
+
description: 'Report whether the committed graph is in sync with the code (drift check).',
|
|
28
|
+
inputSchema: { type: 'object', properties: {} },
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'graft_blast_radius',
|
|
32
|
+
description: 'List what depends on a file — who breaks if it changes.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: { file: { type: 'string', description: 'repo-relative path, e.g. src/cache.ts' } },
|
|
36
|
+
required: ['file'],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
export function callTool(root, name, args) {
|
|
41
|
+
try {
|
|
42
|
+
switch (name) {
|
|
43
|
+
case 'graft_ask': {
|
|
44
|
+
const query = String(args.query ?? '');
|
|
45
|
+
if (!query)
|
|
46
|
+
return { text: 'graft_ask requires a query', isError: true };
|
|
47
|
+
const limit = typeof args.limit === 'number' ? args.limit : 5;
|
|
48
|
+
const engine = new Graft();
|
|
49
|
+
const r = engine.ask(root, query, { limit, source: true });
|
|
50
|
+
return { text: formatAsk(r), isError: false };
|
|
51
|
+
}
|
|
52
|
+
case 'graft_check': {
|
|
53
|
+
const engine = new Graft();
|
|
54
|
+
const r = engine.check(root);
|
|
55
|
+
const g = engine.checkGraph(root);
|
|
56
|
+
const parts = [formatCheckReport(r)];
|
|
57
|
+
if (!g.missing)
|
|
58
|
+
parts.push(formatGraphCheckReport(g));
|
|
59
|
+
return { text: parts.join('\n\n'), isError: false };
|
|
60
|
+
}
|
|
61
|
+
case 'graft_blast_radius': {
|
|
62
|
+
const file = String(args.file ?? '');
|
|
63
|
+
if (!file)
|
|
64
|
+
return { text: 'graft_blast_radius requires a file', isError: true };
|
|
65
|
+
const w = readGraph(wiringPath(contextDirFor(root)));
|
|
66
|
+
if (!w)
|
|
67
|
+
return { text: 'no graph found — run `graft build` first', isError: true };
|
|
68
|
+
const br = formatBlastRadius(w, file);
|
|
69
|
+
return { text: br ?? `no known dependents of ${file}`, isError: false };
|
|
70
|
+
}
|
|
71
|
+
default:
|
|
72
|
+
return { text: `unknown tool: ${name}`, isError: true };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
return { text: err instanceof Error ? err.message : String(err), isError: true };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
|