@graphpilot-oss/graphpilot 0.0.1 → 1.0.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 (123) hide show
  1. package/CHANGELOG.md +72 -126
  2. package/README.md +290 -102
  3. package/dist/cli.js +41 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/edges.js +22 -11
  6. package/dist/edges.js.map +1 -1
  7. package/dist/indexer.js +3 -3
  8. package/dist/indexer.js.map +1 -1
  9. package/dist/init.d.ts +28 -0
  10. package/dist/init.js +112 -0
  11. package/dist/init.js.map +1 -0
  12. package/dist/interactions.d.ts +5 -4
  13. package/dist/interactions.js +0 -0
  14. package/dist/interactions.js.map +1 -1
  15. package/dist/mcp.js +119 -90
  16. package/dist/mcp.js.map +1 -1
  17. package/dist/repo-resolve.d.ts +47 -0
  18. package/dist/repo-resolve.js +195 -0
  19. package/dist/repo-resolve.js.map +1 -0
  20. package/dist/storage.js +10 -1
  21. package/dist/storage.js.map +1 -1
  22. package/dist/symbols.js +26 -2
  23. package/dist/symbols.js.map +1 -1
  24. package/dist/validation.js +30 -4
  25. package/dist/validation.js.map +1 -1
  26. package/dist/validators.d.ts +1 -5
  27. package/dist/validators.js +0 -11
  28. package/dist/validators.js.map +1 -1
  29. package/dist/watcher.d.ts +10 -0
  30. package/dist/watcher.js +70 -7
  31. package/dist/watcher.js.map +1 -1
  32. package/examples/README.md +105 -0
  33. package/examples/claude-code/README.md +125 -0
  34. package/examples/claude-code/claude-routing.md +102 -0
  35. package/examples/claude-code/claude_config.json +8 -0
  36. package/examples/cline/.clinerules +39 -0
  37. package/examples/cline/README.md +104 -0
  38. package/examples/cline/cline_mcp_settings.json +10 -0
  39. package/examples/continue/.continuerules +39 -0
  40. package/examples/continue/README.md +98 -0
  41. package/examples/continue/config.json +13 -0
  42. package/examples/cursor/.cursorrules +39 -0
  43. package/examples/cursor/README.md +98 -0
  44. package/examples/cursor/mcp.json +11 -0
  45. package/examples/windsurf/.windsurfrules +39 -0
  46. package/examples/windsurf/README.md +85 -0
  47. package/examples/windsurf/mcp_config.json +8 -0
  48. package/package.json +14 -4
  49. package/.editorconfig +0 -15
  50. package/.github/CODEOWNERS +0 -22
  51. package/.github/FUNDING.yml +0 -1
  52. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
  53. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  54. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
  55. package/.github/PULL_REQUEST_TEMPLATE.md +0 -19
  56. package/.github/dependabot.yml +0 -15
  57. package/.github/workflows/ci.yml +0 -62
  58. package/.github/workflows/release.yml +0 -50
  59. package/.prettierignore +0 -19
  60. package/.prettierrc.json +0 -20
  61. package/CODE_OF_CONDUCT.md +0 -83
  62. package/CONTRIBUTING.md +0 -111
  63. package/bench/README.md +0 -544
  64. package/bench/results/agent-tier-2026-05-22.md +0 -28
  65. package/bench/results/agent-tier-summary.md +0 -44
  66. package/bench/results/baseline-tier-2026-05-22.md +0 -23
  67. package/bench/results/baseline.json +0 -810
  68. package/bench/results/baseline.md +0 -28
  69. package/bench/run-agent-tier-automated.ts +0 -234
  70. package/bench/run-agent-tier.md +0 -125
  71. package/bench/run-baseline-tier.ts +0 -200
  72. package/bench/run.ts +0 -210
  73. package/bench/runner-baseline.ts +0 -177
  74. package/bench/runner-graphpilot.ts +0 -131
  75. package/bench/score-agent-tier.ts +0 -191
  76. package/bench/score.ts +0 -59
  77. package/bench/tasks.ts +0 -236
  78. package/dist/provenance.d.ts +0 -74
  79. package/dist/provenance.js +0 -95
  80. package/dist/provenance.js.map +0 -1
  81. package/docs/architecture.md +0 -311
  82. package/docs/limitations.md +0 -156
  83. package/docs/mcp-setup.md +0 -231
  84. package/docs/quickstart.md +0 -202
  85. package/eslint.config.js +0 -148
  86. package/lefthook.yml +0 -81
  87. package/pnpm-workspace.yaml +0 -6
  88. package/scripts/smoke-stdio.mjs +0 -97
  89. package/src/cli.ts +0 -171
  90. package/src/edges.ts +0 -202
  91. package/src/git.ts +0 -255
  92. package/src/graph-schema.ts +0 -229
  93. package/src/impact.ts +0 -218
  94. package/src/indexer.ts +0 -152
  95. package/src/interactions.ts +0 -0
  96. package/src/mcp.ts +0 -652
  97. package/src/parser.ts +0 -138
  98. package/src/provenance.ts +0 -115
  99. package/src/query.ts +0 -148
  100. package/src/redact.ts +0 -122
  101. package/src/storage.ts +0 -115
  102. package/src/symbols.ts +0 -173
  103. package/src/validation.ts +0 -69
  104. package/src/validators.ts +0 -253
  105. package/src/watcher.ts +0 -383
  106. package/tests/edges.test.ts +0 -175
  107. package/tests/fixtures/sample.ts +0 -32
  108. package/tests/git.test.ts +0 -303
  109. package/tests/graph-schema.test.ts +0 -321
  110. package/tests/impact.test.ts +0 -454
  111. package/tests/interactions.test.ts +0 -180
  112. package/tests/lint-policy.test.ts +0 -106
  113. package/tests/mcp-stdio.test.ts +0 -171
  114. package/tests/mcp.test.ts +0 -335
  115. package/tests/parser.test.ts +0 -31
  116. package/tests/provenance.test.ts +0 -132
  117. package/tests/query.test.ts +0 -160
  118. package/tests/redact.test.ts +0 -167
  119. package/tests/security.test.ts +0 -144
  120. package/tests/symbols.test.ts +0 -78
  121. package/tests/validators.test.ts +0 -193
  122. package/tests/watcher.test.ts +0 -250
  123. package/tsconfig.json +0 -18
package/dist/indexer.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import fg from 'fast-glob';
2
2
  import { realpathSync } from 'node:fs';
3
- import { resolve, relative } from 'node:path';
3
+ import { resolve, relative, sep } from 'node:path';
4
4
  import { parseFile } from './parser.js';
5
5
  import { extractSymbols } from './symbols.js';
6
6
  import { extractRawCalls, resolveCallEdges } from './edges.js';
@@ -61,7 +61,7 @@ export async function indexDirectory(rootPath, opts = {}) {
61
61
  filesFailed++;
62
62
  continue;
63
63
  }
64
- if (!realFile.startsWith(realRoot)) {
64
+ if (realFile !== realRoot && !realFile.startsWith(realRoot + sep)) {
65
65
  filesSkippedSymlink++;
66
66
  continue;
67
67
  }
@@ -71,7 +71,7 @@ export async function indexDirectory(rootPath, opts = {}) {
71
71
  const fileSymbols = extractSymbols(parsed);
72
72
  const fileCalls = extractRawCalls(parsed, fileSymbols);
73
73
  if (useRelative) {
74
- const rel = relative(absRoot, file);
74
+ const rel = relative(absRoot, file).split(sep).join('/');
75
75
  // Track id rewrites so call edges can be remapped in lockstep.
76
76
  const idRewrites = new Map();
77
77
  for (const s of fileSymbols) {
@@ -1 +1 @@
1
- {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,cAAc,EAAqB,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAA+B,MAAM,YAAY,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAgB,MAAM,UAAU,CAAC;AA4BrD,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAE/F,MAAM,cAAc,GAAG;IACrB,oBAAoB;IACpB,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,gBAAgB;IAChB,aAAa;IACb,aAAa;IACb,cAAc;IACd,WAAW;IACX,WAAW;CACZ,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,OAAqB,EAAE;IAEvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,eAAe,CAAC;IAChD,MAAM,MAAM,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3D,MAAM,WAAW,GAAG,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;IAE/C,uEAAuE;IACvE,0EAA0E;IAC1E,mCAAmC;IACnC,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAEvC,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,OAAO,EAAE;QAC9B,GAAG,EAAE,OAAO;QACZ,MAAM;QACN,QAAQ,EAAE,IAAI;QACd,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,IAAI;QACpB,gEAAgE;QAChE,mBAAmB,EAAE,KAAK;KAC3B,CAAC,CAAC;IAEH,2EAA2E;IAC3E,yEAAyE;IACzE,IAAI,KAAK,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,qBAAqB,KAAK,CAAC,MAAM,kBAAkB,mBAAmB,KAAK;YACzE,4CAA4C,CAC/C,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,mBAAmB,GAAG,CAAC,CAAC;IAE5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,0EAA0E;YAC1E,yDAAyD;YACzD,IAAI,QAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,WAAW,EAAE,CAAC;gBACd,SAAS;YACX,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnC,mBAAmB,EAAE,CAAC;gBACtB,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YAEvD,IAAI,WAAW,EAAE,CAAC;gBAChB,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;gBACpC,+DAA+D;gBAC/D,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;gBAC7C,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;oBAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC;oBACnB,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC;oBACb,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;oBAChC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9B,CAAC;gBACD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;oBAC1B,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC;oBACb,CAAC,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;gBAClD,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;YAC5B,YAAY,EAAE,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElD,mEAAmE;IACnE,kDAAkD;IAClD,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IAEjC,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,YAAY;QACZ,WAAW,EAAE,WAAW,GAAG,mBAAmB;QAC9C,OAAO;QACP,KAAK;QACL,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;QAC9B,GAAG;KACJ,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"indexer.js","sourceRoot":"","sources":["../src/indexer.ts"],"names":[],"mappings":"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"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ export type ClientId = 'cursor' | 'claude-code' | 'cline' | 'windsurf' | 'continue';
2
+ export interface ClientSpec {
3
+ name: string;
4
+ /** Path to the client's own MCP config — its existence signals the client is installed. */
5
+ configPath: string;
6
+ /** Relative path inside the package's examples/ dir (the routing template). */
7
+ templateFile: string;
8
+ /** Filename to write at the target repo root. */
9
+ outputFile: string;
10
+ }
11
+ export declare const CLIENTS: Record<ClientId, ClientSpec>;
12
+ export declare const EXAMPLES_DIR: string;
13
+ export declare function detectInstalledClients(): ClientId[];
14
+ export interface InitOptions {
15
+ repoPath: string;
16
+ clients?: ClientId[];
17
+ all?: boolean;
18
+ dryRun?: boolean;
19
+ examplesDir?: string;
20
+ prompt?: (destPath: string) => Promise<'overwrite' | 'skip'>;
21
+ }
22
+ export type WriteAction = 'written' | 'skipped' | 'dry-run';
23
+ export interface WriteResult {
24
+ client: ClientId;
25
+ action: WriteAction;
26
+ destPath: string;
27
+ }
28
+ export declare function runInit(opts: InitOptions): Promise<WriteResult[]>;
package/dist/init.js ADDED
@@ -0,0 +1,112 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { homedir, platform } from 'node:os';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { createInterface } from 'node:readline';
6
+ function clineConfigPath() {
7
+ const p = platform();
8
+ const globalStorage = join('Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json');
9
+ if (p === 'darwin')
10
+ return join(homedir(), 'Library', 'Application Support', globalStorage);
11
+ if (p === 'win32') {
12
+ return join(process.env['APPDATA'] ?? join(homedir(), 'AppData', 'Roaming'), globalStorage);
13
+ }
14
+ return join(homedir(), '.config', globalStorage);
15
+ }
16
+ export const CLIENTS = {
17
+ cursor: {
18
+ name: 'Cursor',
19
+ configPath: join(homedir(), '.cursor', 'mcp.json'),
20
+ templateFile: join('cursor', '.cursorrules'),
21
+ outputFile: '.cursorrules',
22
+ },
23
+ 'claude-code': {
24
+ name: 'Claude Code',
25
+ configPath: join(homedir(), '.claude.json'),
26
+ templateFile: join('claude-code', 'claude-routing.md'),
27
+ outputFile: 'CLAUDE.md',
28
+ },
29
+ cline: {
30
+ name: 'Cline',
31
+ configPath: clineConfigPath(),
32
+ templateFile: join('cline', '.clinerules'),
33
+ outputFile: '.clinerules',
34
+ },
35
+ windsurf: {
36
+ name: 'Windsurf',
37
+ configPath: join(homedir(), '.codeium', 'windsurf', 'mcp_config.json'),
38
+ templateFile: join('windsurf', '.windsurfrules'),
39
+ outputFile: '.windsurfrules',
40
+ },
41
+ continue: {
42
+ name: 'Continue',
43
+ configPath: join(homedir(), '.continue', 'config.json'),
44
+ templateFile: join('continue', '.continuerules'),
45
+ outputFile: '.continuerules',
46
+ },
47
+ };
48
+ export const EXAMPLES_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', 'examples');
49
+ export function detectInstalledClients() {
50
+ return Object.keys(CLIENTS).filter((id) => existsSync(CLIENTS[id].configPath));
51
+ }
52
+ async function defaultPrompt(destPath) {
53
+ if (!process.stdin.isTTY)
54
+ return 'skip';
55
+ return new Promise((resolve) => {
56
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
57
+ rl.question(` ${destPath} already exists. Overwrite? [y/N] `, (answer) => {
58
+ rl.close();
59
+ resolve(answer.toLowerCase() === 'y' ? 'overwrite' : 'skip');
60
+ });
61
+ });
62
+ }
63
+ export async function runInit(opts) {
64
+ const { repoPath, all = false, dryRun = false, examplesDir: exDir = EXAMPLES_DIR, prompt = defaultPrompt, } = opts;
65
+ let targets;
66
+ if (opts.clients && opts.clients.length > 0) {
67
+ targets = opts.clients;
68
+ }
69
+ else if (all) {
70
+ targets = Object.keys(CLIENTS);
71
+ }
72
+ else {
73
+ targets = detectInstalledClients();
74
+ if (targets.length === 0) {
75
+ process.stdout.write('No supported clients detected. Pass --all to write all rules files,\n' +
76
+ 'or --client <name> for a specific one.\n' +
77
+ 'Supported clients: cursor, claude-code, cline, windsurf, continue\n');
78
+ return [];
79
+ }
80
+ process.stdout.write(`Detected: ${targets.join(', ')}\n`);
81
+ }
82
+ const results = [];
83
+ for (const id of targets) {
84
+ const spec = CLIENTS[id];
85
+ const templatePath = join(exDir, spec.templateFile);
86
+ const destPath = join(repoPath, spec.outputFile);
87
+ if (!existsSync(templatePath)) {
88
+ process.stdout.write(` [${spec.name}] skip — template not found: ${templatePath}\n`);
89
+ results.push({ client: id, action: 'skipped', destPath });
90
+ continue;
91
+ }
92
+ const content = readFileSync(templatePath, 'utf8');
93
+ if (dryRun) {
94
+ process.stdout.write(` [dry-run] would write ${spec.outputFile} (${content.length} bytes)\n`);
95
+ results.push({ client: id, action: 'dry-run', destPath });
96
+ continue;
97
+ }
98
+ if (existsSync(destPath)) {
99
+ const decision = await prompt(destPath);
100
+ if (decision === 'skip') {
101
+ process.stdout.write(` [${spec.name}] skipped (${spec.outputFile} already exists)\n`);
102
+ results.push({ client: id, action: 'skipped', destPath });
103
+ continue;
104
+ }
105
+ }
106
+ writeFileSync(destPath, content, 'utf8');
107
+ process.stdout.write(` [${spec.name}] wrote ${spec.outputFile}\n`);
108
+ results.push({ client: id, action: 'written', destPath });
109
+ }
110
+ return results;
111
+ }
112
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -2,11 +2,12 @@
2
2
  * Append-only interaction log. One JSONL file per indexed repo:
3
3
  * ~/.graphpilot/<repo-id>/interactions.jsonl
4
4
  *
5
- * Why we keep this even though v1 never reads it: see .notes/v1-mvp-revised.md
6
- * §4 (the moat seed). Day-1 logs become day-180 personalized ranking. A fork
7
- * starting fresh can't catch up.
5
+ * Why we keep this even though v1 never reads it: day-1 logs become day-180
6
+ * personalized ranking input. A fork starting fresh can't catch up — the
7
+ * accumulated interaction history is what makes adaptive symbol ranking
8
+ * possible without retraining.
8
9
  *
9
- * Privacy constraints (do NOT relax without revisiting .notes/security.md):
10
+ * Privacy constraints (do NOT relax without re-reading SECURITY.md):
10
11
  * - Never log file contents
11
12
  * - Cap every string field at MAX_FIELD_LEN
12
13
  * - Strip control characters from string values
Binary file
@@ -1 +1 @@
1
- {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../src/interactions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"interactions.js","sourceRoot":"","sources":["../src/interactions.ts"],"names":[],"mappings":"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"}
package/dist/mcp.js CHANGED
@@ -1,40 +1,62 @@
1
+ import { statSync } from 'node:fs';
1
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
4
- import { resolve } from 'node:path';
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, RootsListChangedNotificationSchema, } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { GraphIndex } from './query.js';
6
6
  import { indexDirectory } from './indexer.js';
7
- import { loadGraph, saveGraph, repoIdFor } from './storage.js';
7
+ import { loadGraph, saveGraph, repoIdFor, graphPath } from './storage.js';
8
8
  import { validateRootPath } from './validation.js';
9
- import { validateGpIndex, validateGpRecall, validateGpCallers, validateGpImpact, validateGpStats, } from './validators.js';
9
+ import { validateGpIndex, validateGpRecall, validateGpCallers, validateGpImpact, } from './validators.js';
10
10
  import { withInteractionLog } from './interactions.js';
11
11
  import { analyzeImpact } from './impact.js';
12
12
  import { getChangedFiles, resolveIndexRoot } from './git.js';
13
+ import { formatNoIndexError, getMcpClientRoots, resolveRepoPath, rootUriToFilesystemPath, setMcpClientRoots, } from './repo-resolve.js';
13
14
  const SERVER_NAME = 'graphpilot';
14
15
  const SERVER_VERSION = '0.0.1';
15
- // ----------------------------------------------------------------------------
16
- // Per-process cache of loaded GraphIndex by absolute repo path.
17
- // ----------------------------------------------------------------------------
16
+ /** Shown on every tool's optional `path` field. */
17
+ const PATH_FIELD_DESC = 'Repo root with a GraphPilot index. Optional: when omitted, resolves via ' +
18
+ 'GRAPHPILOT_ROOT, MCP workspace roots, parent walk, or a single ~/.graphpilot index.';
18
19
  const indexCache = new Map();
20
+ /** Set when buildMcpServer wires roots handlers — used for lazy roots/list. */
21
+ let mcpServerForRoots = null;
22
+ let rootsRefreshInflight = null;
19
23
  function getOrLoadIndex(rawPath) {
24
+ const requested = resolveRepoPath(rawPath);
20
25
  // Re-root to the git worktree top so MCP tool calls from a subdir of a
21
26
  // worktree still resolve to the branch-level index. Outside git this is
22
27
  // a no-op.
23
- const { root } = resolveIndexRoot(rawPath ?? process.cwd());
28
+ const { root } = resolveIndexRoot(requested);
29
+ // Check whether graph.json changed since we last loaded it. Any external
30
+ // writer (CLI re-index, another MCP process, gp_index from a parallel
31
+ // session) will bump the mtime and trigger a cache miss here.
32
+ let currentMtimeMs = 0;
33
+ let currentSizeBytes = 0;
34
+ try {
35
+ const st = statSync(graphPath(root));
36
+ currentMtimeMs = st.mtimeMs;
37
+ currentSizeBytes = st.size;
38
+ }
39
+ catch {
40
+ // File doesn't exist yet — fall through; loadGraph will return null.
41
+ }
24
42
  const cached = indexCache.get(root);
25
- if (cached)
26
- return { idx: cached, root };
43
+ if (cached &&
44
+ currentMtimeMs !== 0 &&
45
+ cached.mtimeMs === currentMtimeMs &&
46
+ cached.sizeBytes === currentSizeBytes) {
47
+ return { idx: cached.idx, root };
48
+ }
49
+ // Cache miss or stale entry — (re)load from disk.
50
+ indexCache.delete(root);
27
51
  const graph = loadGraph(root);
28
52
  if (!graph) {
29
53
  return {
30
54
  root,
31
- error: `No GraphPilot index found for ${root}.\n` +
32
- `Ask the user to run \`graphpilot index ${rawPath ?? '.'}\` first, or ` +
33
- `call the gp_index tool to build one.`,
55
+ error: formatNoIndexError(requested, root),
34
56
  };
35
57
  }
36
58
  const idx = new GraphIndex(graph);
37
- indexCache.set(root, idx);
59
+ indexCache.set(root, { idx, mtimeMs: currentMtimeMs, sizeBytes: currentSizeBytes });
38
60
  return { idx, root };
39
61
  }
40
62
  function invalidateCache(absRoot) {
@@ -85,29 +107,17 @@ function fmtEdge(e, idx, index) {
85
107
  // Tool catalog (sent to clients via tools/list)
86
108
  // ----------------------------------------------------------------------------
87
109
  const TOOLS = [
88
- {
89
- name: 'gp_stats',
90
- description: 'Show GraphPilot index health for a repo (symbol count, edge count, ' +
91
- 'when indexed). Use this to confirm the index is fresh before asking ' +
92
- 'structural questions.',
93
- inputSchema: {
94
- type: 'object',
95
- properties: {
96
- path: { type: 'string', description: 'Repo path. Default: cwd.' },
97
- },
98
- additionalProperties: false,
99
- },
100
- },
101
110
  {
102
111
  name: 'gp_index',
103
- description: 'Index or re-index a TypeScript/JavaScript repo into GraphPilot. Call ' +
104
- 'this when the codebase has changed materially or when no index exists.',
112
+ description: 'Re-index the repo after batch edits so subsequent gp_* calls see your changes. ' +
113
+ 'Call after any non-trivial edit session. ' +
114
+ 'Do NOT call before every query — indexing is slow; only needed when source files changed.',
105
115
  inputSchema: {
106
116
  type: 'object',
107
117
  properties: {
108
118
  path: {
109
119
  type: 'string',
110
- description: 'Repo path to index. Default: cwd.',
120
+ description: PATH_FIELD_DESC,
111
121
  },
112
122
  },
113
123
  additionalProperties: false,
@@ -115,9 +125,11 @@ const TOOLS = [
115
125
  },
116
126
  {
117
127
  name: 'gp_recall',
118
- description: 'Look up symbols (functions, classes, methods, types, interfaces) by ' +
119
- 'name. Returns kind, location, and signature. Default: exact ' +
120
- 'case-insensitive. Pass substring:true for partial matches.',
128
+ description: 'Find a symbol definition by name — returns kind, file:line, and signature. ' +
129
+ 'ALWAYS use instead of `grep -rn "function X"` or reading files to locate a definition: ' +
130
+ 'pre-indexed, no false positives from comments or strings, sub-millisecond. ' +
131
+ 'Pass substring:true for partial-name searches. ' +
132
+ 'Do NOT use for "who calls X?" — use gp_callers for that.',
121
133
  inputSchema: {
122
134
  type: 'object',
123
135
  properties: {
@@ -137,7 +149,7 @@ const TOOLS = [
137
149
  },
138
150
  path: {
139
151
  type: 'string',
140
- description: 'Repo path. Default: cwd.',
152
+ description: PATH_FIELD_DESC,
141
153
  },
142
154
  },
143
155
  required: ['query'],
@@ -146,9 +158,12 @@ const TOOLS = [
146
158
  },
147
159
  {
148
160
  name: 'gp_callers',
149
- description: 'List callers of a symbol (who calls it) or callees (what it calls). ' +
150
- "Use direction='callers' for impact analysis ('what breaks if I " +
151
- "change this?'); direction='callees' to see what a function depends on.",
161
+ description: 'List every caller of a symbol (direction=callers) or everything it calls ' +
162
+ '(direction=callees). ALWAYS use instead of `grep -rn "X("` for "who calls X?" — ' +
163
+ 'pre-indexed reverse map, sub-millisecond, no false positives from comments or strings. ' +
164
+ 'Use direction=callers to find dependents before a rename; direction=callees to ' +
165
+ 'understand what a function depends on. ' +
166
+ 'Do NOT use for full blast-radius analysis across multiple hops — use gp_impact instead.',
152
167
  inputSchema: {
153
168
  type: 'object',
154
169
  properties: {
@@ -173,7 +188,7 @@ const TOOLS = [
173
188
  },
174
189
  path: {
175
190
  type: 'string',
176
- description: 'Repo path. Default: cwd.',
191
+ description: PATH_FIELD_DESC,
177
192
  },
178
193
  },
179
194
  required: ['symbol'],
@@ -182,15 +197,14 @@ const TOOLS = [
182
197
  },
183
198
  {
184
199
  name: 'gp_impact',
185
- description: 'Analyze the BLAST RADIUS of changing a symbol. Returns direct callers, ' +
186
- 'transitive callers (default depth 3), tests likely affected, and ' +
187
- 'whether the symbol is part of the public API (exported). ' +
188
- 'Use this BEFORE proposing a rename, signature change, or behavior ' +
189
- 'change it answers "what breaks if I change X?" in one call instead ' +
190
- 'of composing multiple gp_callers queries. ' +
191
- 'Pass `since: <commit|branch>` to restrict callers to files changed ' +
192
- 'since that ref ideal for PR review ("what does this branch touch?") ' +
193
- 'and refactor scoping.',
200
+ description: 'Compute the blast radius of a rename or signature change: direct callers, ' +
201
+ 'transitive callers up to depth 3, affected tests, and whether the symbol is ' +
202
+ 'exported (breaking-change risk). ALWAYS call before proposing a rename, ' +
203
+ 'signature change, or behavior change replaces `git diff | xargs grep` with ' +
204
+ 'a single structured answer. ' +
205
+ 'Pass `since: <commit|branch>` to scope callers to files changed since that ref ' +
206
+ '(ideal for PR review or refactor scoping). ' +
207
+ 'Do NOT use just to see direct callers; use gp_callers for that.',
194
208
  inputSchema: {
195
209
  type: 'object',
196
210
  properties: {
@@ -206,7 +220,7 @@ const TOOLS = [
206
220
  },
207
221
  path: {
208
222
  type: 'string',
209
- description: 'Repo path. Default: cwd.',
223
+ description: PATH_FIELD_DESC,
210
224
  },
211
225
  since: {
212
226
  type: 'string',
@@ -219,35 +233,9 @@ const TOOLS = [
219
233
  },
220
234
  },
221
235
  ];
222
- function handleGpStats(args) {
223
- const out = getOrLoadIndex(args.path);
224
- if ('error' in out) {
225
- return { text: out.error, results: 0, isError: true };
226
- }
227
- const { idx } = out;
228
- const s = idx.stats;
229
- const g = idx.graph;
230
- // Git provenance — surface branch + short SHA so the agent can cite
231
- // the exact commit the index was built against. Omitted gracefully
232
- // when the indexed root isn't a git repo.
233
- const gitLines = [];
234
- if (g.indexedBranch)
235
- gitLines.push(`Branch: ${g.indexedBranch}`);
236
- if (g.indexedSha)
237
- gitLines.push(`Commit SHA: ${g.indexedSha.slice(0, 7)}`);
238
- const text = [
239
- `Repo: ${g.rootPath}`,
240
- `Repo id: ${g.repoId}`,
241
- `Indexed at: ${g.indexedAt}`,
242
- ...gitLines,
243
- `Files: ${g.filesIndexed}`,
244
- `Symbols: ${s.symbols}`,
245
- `Calls: ${s.edges} (${s.resolvedEdges} resolved)`,
246
- ].join('\n');
247
- return { text, results: 1 };
248
- }
249
236
  async function handleGpIndex(args) {
250
- const requested = resolve(args.path ?? process.cwd());
237
+ await ensureClientRootsCached();
238
+ const requested = resolveRepoPath(args.path);
251
239
  const { root, redirected } = resolveIndexRoot(requested);
252
240
  const refusal = validateRootPath(root);
253
241
  if (refusal)
@@ -294,7 +282,8 @@ async function handleGpIndex(args) {
294
282
  ` Took: ${result.durationMs}ms`;
295
283
  return { text, results: 1 };
296
284
  }
297
- function handleGpRecall(args) {
285
+ async function handleGpRecall(args) {
286
+ await ensureClientRootsCached();
298
287
  const out = getOrLoadIndex(args.path);
299
288
  if ('error' in out) {
300
289
  return { text: out.error, results: 0, isError: true };
@@ -314,7 +303,8 @@ function handleGpRecall(args) {
314
303
  const body = matches.map((s, i) => fmtSymbol(s, idx, i)).join('\n\n');
315
304
  return { text: header + body, results: matches.length };
316
305
  }
317
- function handleGpCallers(args) {
306
+ async function handleGpCallers(args) {
307
+ await ensureClientRootsCached();
318
308
  const out = getOrLoadIndex(args.path);
319
309
  if ('error' in out) {
320
310
  return { text: out.error, results: 0, isError: true };
@@ -423,6 +413,7 @@ function fmtImpactReport(report, idx, diff = { changedFileCount: null }) {
423
413
  return lines.join('\n');
424
414
  }
425
415
  async function handleGpImpact(args) {
416
+ await ensureClientRootsCached();
426
417
  const out = getOrLoadIndex(args.path);
427
418
  if ('error' in out) {
428
419
  return { text: out.error, results: 0, isError: true };
@@ -460,10 +451,57 @@ async function handleGpImpact(args) {
460
451
  return { text, results: totalResults };
461
452
  }
462
453
  // ----------------------------------------------------------------------------
454
+ // MCP workspace roots (client → server)
455
+ // ----------------------------------------------------------------------------
456
+ /** Ensure roots/list has run when the client supports workspace roots. */
457
+ async function ensureClientRootsCached() {
458
+ if (!mcpServerForRoots?.getClientCapabilities()?.roots)
459
+ return;
460
+ if (getMcpClientRoots().length > 0)
461
+ return;
462
+ if (!rootsRefreshInflight) {
463
+ rootsRefreshInflight = refreshMcpClientRoots(mcpServerForRoots).finally(() => {
464
+ rootsRefreshInflight = null;
465
+ });
466
+ }
467
+ await rootsRefreshInflight;
468
+ }
469
+ async function refreshMcpClientRoots(server) {
470
+ const caps = server.getClientCapabilities();
471
+ if (!caps?.roots) {
472
+ setMcpClientRoots([]);
473
+ return;
474
+ }
475
+ try {
476
+ const { roots } = await server.listRoots();
477
+ const paths = roots
478
+ .map((r) => rootUriToFilesystemPath(r.uri))
479
+ .filter((p) => p !== null);
480
+ setMcpClientRoots(paths);
481
+ if (paths.length > 0) {
482
+ process.stderr.write(`[graphpilot] MCP workspace roots: ${paths.join(', ')}\n`);
483
+ }
484
+ }
485
+ catch (err) {
486
+ process.stderr.write(`[graphpilot] roots/list failed: ${err instanceof Error ? err.message : String(err)}\n`);
487
+ setMcpClientRoots([]);
488
+ }
489
+ }
490
+ function wireMcpClientRoots(server) {
491
+ mcpServerForRoots = server;
492
+ server.oninitialized = () => {
493
+ void refreshMcpClientRoots(server);
494
+ };
495
+ server.setNotificationHandler(RootsListChangedNotificationSchema, () => {
496
+ void refreshMcpClientRoots(server);
497
+ });
498
+ }
499
+ // ----------------------------------------------------------------------------
463
500
  // Server builder + dispatcher
464
501
  // ----------------------------------------------------------------------------
465
502
  export function buildMcpServer() {
466
503
  const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, { capabilities: { tools: {} } });
504
+ wireMcpClientRoots(server);
467
505
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
468
506
  tools: TOOLS,
469
507
  }));
@@ -474,21 +512,12 @@ export function buildMcpServer() {
474
512
  // so the log captures even invalid-input attempts. Fall back to cwd.
475
513
  // Resolve to the worktree top so per-tool calls from a subdir land in
476
514
  // the same interaction log as the rest of the branch's work.
477
- const requestedLogPath = typeof rawArgs.path === 'string' ? rawArgs.path : process.cwd();
515
+ const requestedLogPath = resolveRepoPath(typeof rawArgs.path === 'string' ? rawArgs.path : undefined);
478
516
  const repoRootForLog = resolveIndexRoot(requestedLogPath).root;
479
517
  return withInteractionLog(repoRootForLog, name, rawArgs, async () => {
480
518
  // Validate first
481
519
  let result;
482
520
  switch (name) {
483
- case 'gp_stats': {
484
- const v = validateGpStats(rawArgs);
485
- if (!v.ok) {
486
- result = { text: `Invalid input: ${v.error}`, results: 0, isError: true };
487
- break;
488
- }
489
- result = handleGpStats(v.value);
490
- break;
491
- }
492
521
  case 'gp_index': {
493
522
  const v = validateGpIndex(rawArgs);
494
523
  if (!v.ok) {
@@ -504,7 +533,7 @@ export function buildMcpServer() {
504
533
  result = { text: `Invalid input: ${v.error}`, results: 0, isError: true };
505
534
  break;
506
535
  }
507
- result = handleGpRecall(v.value);
536
+ result = await handleGpRecall(v.value);
508
537
  break;
509
538
  }
510
539
  case 'gp_callers': {
@@ -513,7 +542,7 @@ export function buildMcpServer() {
513
542
  result = { text: `Invalid input: ${v.error}`, results: 0, isError: true };
514
543
  break;
515
544
  }
516
- result = handleGpCallers(v.value);
545
+ result = await handleGpCallers(v.value);
517
546
  break;
518
547
  }
519
548
  case 'gp_impact': {