@colbymchenry/codegraph-darwin-x64 1.1.1 → 1.1.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/lib/dist/bin/codegraph.js +79 -52
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/bin/command-supervision.d.ts +12 -0
- package/lib/dist/bin/command-supervision.d.ts.map +1 -0
- package/lib/dist/bin/command-supervision.js +76 -0
- package/lib/dist/bin/command-supervision.js.map +1 -0
- package/lib/dist/db/queries.d.ts.map +1 -1
- package/lib/dist/db/queries.js +10 -2
- package/lib/dist/db/queries.js.map +1 -1
- package/lib/dist/directory.d.ts +32 -0
- package/lib/dist/directory.d.ts.map +1 -1
- package/lib/dist/directory.js +83 -0
- package/lib/dist/directory.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +13 -1
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +219 -213
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/parse-pool.d.ts +126 -0
- package/lib/dist/extraction/parse-pool.d.ts.map +1 -0
- package/lib/dist/extraction/parse-pool.js +319 -0
- package/lib/dist/extraction/parse-pool.js.map +1 -0
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +48 -19
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/mcp/daemon-paths.d.ts +30 -3
- package/lib/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/lib/dist/mcp/daemon-paths.js +50 -10
- package/lib/dist/mcp/daemon-paths.js.map +1 -1
- package/lib/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/lib/dist/mcp/daemon-registry.js +7 -3
- package/lib/dist/mcp/daemon-registry.js.map +1 -1
- package/lib/dist/mcp/daemon.d.ts +38 -0
- package/lib/dist/mcp/daemon.d.ts.map +1 -1
- package/lib/dist/mcp/daemon.js +164 -31
- package/lib/dist/mcp/daemon.js.map +1 -1
- package/lib/dist/mcp/engine.d.ts +17 -0
- package/lib/dist/mcp/engine.d.ts.map +1 -1
- package/lib/dist/mcp/engine.js +73 -1
- package/lib/dist/mcp/engine.js.map +1 -1
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +25 -43
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/ppid-watchdog.d.ts +18 -0
- package/lib/dist/mcp/ppid-watchdog.d.ts.map +1 -1
- package/lib/dist/mcp/ppid-watchdog.js +37 -0
- package/lib/dist/mcp/ppid-watchdog.js.map +1 -1
- package/lib/dist/mcp/query-pool.d.ts +94 -0
- package/lib/dist/mcp/query-pool.d.ts.map +1 -0
- package/lib/dist/mcp/query-pool.js +297 -0
- package/lib/dist/mcp/query-pool.js.map +1 -0
- package/lib/dist/mcp/query-worker.d.ts +24 -0
- package/lib/dist/mcp/query-worker.d.ts.map +1 -0
- package/lib/dist/mcp/query-worker.js +87 -0
- package/lib/dist/mcp/query-worker.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +57 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +147 -37
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/project-config.d.ts +20 -0
- package/lib/dist/project-config.d.ts.map +1 -1
- package/lib/dist/project-config.js +42 -2
- package/lib/dist/project-config.js.map +1 -1
- package/lib/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
- package/lib/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/c-fnptr-synthesizer.js +765 -79
- package/lib/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
- package/lib/dist/resolution/name-matcher.js +44 -0
- package/lib/dist/resolution/name-matcher.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
package/lib/dist/mcp/tools.js
CHANGED
|
@@ -340,6 +340,23 @@ const projectPathProperty = {
|
|
|
340
340
|
type: 'string',
|
|
341
341
|
description: 'Absolute path to the project to query (or any directory inside it) — codegraph uses the nearest .codegraph/ index at or above that path. Omit to use this session\'s default project. Pass it to query a second codebase, or when the server root has no index of its own (e.g. a monorepo where only sub-projects are indexed, so there is no default project).',
|
|
342
342
|
};
|
|
343
|
+
/**
|
|
344
|
+
* EVERY codegraph tool is query-only: it reads the pre-built index and never
|
|
345
|
+
* mutates the workspace (indexing is the user's explicit CLI call, never the
|
|
346
|
+
* agent's). Advertising this read-only contract lets clients that gate on it run
|
|
347
|
+
* the tools where a possibly-mutating tool would be blocked — most concretely,
|
|
348
|
+
* Cursor's Ask mode, which rejects any MCP tool lacking `readOnlyHint: true`
|
|
349
|
+
* (issue #1018). `idempotentHint`: a repeated query has no additional effect.
|
|
350
|
+
* `openWorldHint: false`: the domain is the closed local index, not an open
|
|
351
|
+
* external world. Shared so the contract is declared once; a hypothetical
|
|
352
|
+
* mutating tool would simply not reference it.
|
|
353
|
+
*/
|
|
354
|
+
const READ_ONLY_ANNOTATIONS = {
|
|
355
|
+
readOnlyHint: true,
|
|
356
|
+
destructiveHint: false,
|
|
357
|
+
idempotentHint: true,
|
|
358
|
+
openWorldHint: false,
|
|
359
|
+
};
|
|
343
360
|
/**
|
|
344
361
|
* All CodeGraph MCP tools
|
|
345
362
|
*
|
|
@@ -374,6 +391,7 @@ exports.tools = [
|
|
|
374
391
|
},
|
|
375
392
|
required: ['query'],
|
|
376
393
|
},
|
|
394
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
377
395
|
},
|
|
378
396
|
{
|
|
379
397
|
name: 'codegraph_callers',
|
|
@@ -398,6 +416,7 @@ exports.tools = [
|
|
|
398
416
|
},
|
|
399
417
|
required: ['symbol'],
|
|
400
418
|
},
|
|
419
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
401
420
|
},
|
|
402
421
|
{
|
|
403
422
|
name: 'codegraph_callees',
|
|
@@ -422,6 +441,7 @@ exports.tools = [
|
|
|
422
441
|
},
|
|
423
442
|
required: ['symbol'],
|
|
424
443
|
},
|
|
444
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
425
445
|
},
|
|
426
446
|
{
|
|
427
447
|
name: 'codegraph_impact',
|
|
@@ -446,6 +466,7 @@ exports.tools = [
|
|
|
446
466
|
},
|
|
447
467
|
required: ['symbol'],
|
|
448
468
|
},
|
|
469
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
449
470
|
},
|
|
450
471
|
{
|
|
451
472
|
name: 'codegraph_node',
|
|
@@ -487,6 +508,7 @@ exports.tools = [
|
|
|
487
508
|
},
|
|
488
509
|
required: [],
|
|
489
510
|
},
|
|
511
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
490
512
|
},
|
|
491
513
|
{
|
|
492
514
|
name: 'codegraph_explore',
|
|
@@ -507,6 +529,7 @@ exports.tools = [
|
|
|
507
529
|
},
|
|
508
530
|
required: ['query'],
|
|
509
531
|
},
|
|
532
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
510
533
|
},
|
|
511
534
|
{
|
|
512
535
|
name: 'codegraph_status',
|
|
@@ -517,6 +540,7 @@ exports.tools = [
|
|
|
517
540
|
projectPath: projectPathProperty,
|
|
518
541
|
},
|
|
519
542
|
},
|
|
543
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
520
544
|
},
|
|
521
545
|
{
|
|
522
546
|
name: 'codegraph_files',
|
|
@@ -550,8 +574,40 @@ exports.tools = [
|
|
|
550
574
|
projectPath: projectPathProperty,
|
|
551
575
|
},
|
|
552
576
|
},
|
|
577
|
+
annotations: READ_ONLY_ANNOTATIONS,
|
|
553
578
|
},
|
|
554
579
|
];
|
|
580
|
+
/**
|
|
581
|
+
* Return `defs` with `projectPath` marked `required` in each tool's inputSchema.
|
|
582
|
+
*
|
|
583
|
+
* Used for the NO-DEFAULT-PROJECT tool surface (issue #993): when the MCP server
|
|
584
|
+
* has no default project to fall back to — a gateway server started outside any
|
|
585
|
+
* repo, or a monorepo root whose `.codegraph/` indexes live only in sub-projects
|
|
586
|
+
* — every call MUST carry an explicit `projectPath`, so the schema should say so.
|
|
587
|
+
* A `required` field is a HIGH-salience channel (MCP clients surface and often
|
|
588
|
+
* validate it), unlike the instructions text the reporter found too weak to stop
|
|
589
|
+
* the agent omitting the param. When a default project IS open, callers leave
|
|
590
|
+
* projectPath optional and never call this.
|
|
591
|
+
*
|
|
592
|
+
* Pure: clones each tool's schema rather than mutating the shared module-level
|
|
593
|
+
* `tools` array (reused by every session and the static surface). A tool that
|
|
594
|
+
* doesn't expose projectPath, or already requires it, is returned untouched;
|
|
595
|
+
* explore's `['query']` becomes `['query', 'projectPath']`, and a tool with no
|
|
596
|
+
* `required` list (status/files) gains `['projectPath']`.
|
|
597
|
+
*/
|
|
598
|
+
function withRequiredProjectPath(defs) {
|
|
599
|
+
return defs.map((tool) => {
|
|
600
|
+
if (!tool.inputSchema.properties.projectPath)
|
|
601
|
+
return tool;
|
|
602
|
+
const required = tool.inputSchema.required ?? [];
|
|
603
|
+
if (required.includes('projectPath'))
|
|
604
|
+
return tool;
|
|
605
|
+
return {
|
|
606
|
+
...tool,
|
|
607
|
+
inputSchema: { ...tool.inputSchema, required: [...required, 'projectPath'] },
|
|
608
|
+
};
|
|
609
|
+
});
|
|
610
|
+
}
|
|
555
611
|
/**
|
|
556
612
|
* Allowlist-filtered tool definitions WITHOUT an engine — the static surface the
|
|
557
613
|
* proxy answers `tools/list` with before any project is open. Mirrors
|
|
@@ -607,9 +663,23 @@ class ToolHandler {
|
|
|
607
663
|
// huge repo can't hang the first call (#905); cleared on first await so
|
|
608
664
|
// subsequent calls don't pay any cost.
|
|
609
665
|
catchUpGate = null;
|
|
666
|
+
// Optional worker-thread pool for off-loop read-tool dispatch (daemon mode).
|
|
667
|
+
// When set + healthy, the heavy read tools run on a worker so the daemon's
|
|
668
|
+
// main loop stays free for the MCP transport under concurrent load. Null in
|
|
669
|
+
// direct/in-process mode (one client, no concurrency to parallelize).
|
|
670
|
+
queryPool = null;
|
|
610
671
|
constructor(cg) {
|
|
611
672
|
this.cg = cg;
|
|
612
673
|
}
|
|
674
|
+
/**
|
|
675
|
+
* Engine-only: attach (or detach with null) the worker-thread query pool. The
|
|
676
|
+
* shared daemon sets this once its default project is open; the workers each
|
|
677
|
+
* hold their own WAL read connection and run {@link executeReadTool}. A
|
|
678
|
+
* worker's own ToolHandler never has a pool, so there is no nested off-loading.
|
|
679
|
+
*/
|
|
680
|
+
setQueryPool(pool) {
|
|
681
|
+
this.queryPool = pool;
|
|
682
|
+
}
|
|
613
683
|
/**
|
|
614
684
|
* Update the default CodeGraph instance (e.g. after lazy initialization)
|
|
615
685
|
*/
|
|
@@ -713,8 +783,18 @@ class ToolHandler {
|
|
|
713
783
|
let visible = allow
|
|
714
784
|
? exports.tools.filter(t => allow.has(t.name.replace(/^codegraph_/, '')))
|
|
715
785
|
: exports.tools.filter(t => DEFAULT_MCP_TOOLS.has(t.name.replace(/^codegraph_/, '')));
|
|
786
|
+
// No default project loaded → no-root-index case (#993): a gateway server
|
|
787
|
+
// started outside any repo, or a monorepo root whose indexes live in
|
|
788
|
+
// sub-projects. With nothing to fall back to, EVERY call needs an explicit
|
|
789
|
+
// projectPath, so mark it required in the schema — a high-salience nudge the
|
|
790
|
+
// agent acts on, where SERVER_INSTRUCTIONS_NO_ROOT_INDEX's prose alone
|
|
791
|
+
// wasn't enough (the reporter had to add an AGENTS.md note). `this.cg` is
|
|
792
|
+
// settled by `retryInitIfNeeded()` before `handleToolsList` calls us, so a
|
|
793
|
+
// null here means "genuinely no default", not a startup race. When a default
|
|
794
|
+
// IS open we leave projectPath optional (below): a bare call falls back to
|
|
795
|
+
// it, exactly as in the common single-project launch.
|
|
716
796
|
if (!this.cg)
|
|
717
|
-
return visible;
|
|
797
|
+
return withRequiredProjectPath(visible);
|
|
718
798
|
try {
|
|
719
799
|
const stats = this.cg.getStats();
|
|
720
800
|
const budget = getExploreBudget(stats.fileCount);
|
|
@@ -1113,43 +1193,26 @@ class ToolHandler {
|
|
|
1113
1193
|
if (typeof check === 'object' && check !== undefined)
|
|
1114
1194
|
return check;
|
|
1115
1195
|
}
|
|
1116
|
-
//
|
|
1117
|
-
//
|
|
1118
|
-
//
|
|
1119
|
-
//
|
|
1120
|
-
//
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
switch (toolName) {
|
|
1124
|
-
case 'codegraph_search':
|
|
1125
|
-
result = await this.handleSearch(args);
|
|
1126
|
-
break;
|
|
1127
|
-
case 'codegraph_callers':
|
|
1128
|
-
result = await this.handleCallers(args);
|
|
1129
|
-
break;
|
|
1130
|
-
case 'codegraph_callees':
|
|
1131
|
-
result = await this.handleCallees(args);
|
|
1132
|
-
break;
|
|
1133
|
-
case 'codegraph_impact':
|
|
1134
|
-
result = await this.handleImpact(args);
|
|
1135
|
-
break;
|
|
1136
|
-
case 'codegraph_explore':
|
|
1137
|
-
result = await this.handleExplore(args);
|
|
1138
|
-
break;
|
|
1139
|
-
case 'codegraph_node':
|
|
1140
|
-
result = await this.handleNode(args);
|
|
1141
|
-
break;
|
|
1142
|
-
case 'codegraph_status':
|
|
1143
|
-
// status embeds the pending-files list as a first-class section
|
|
1144
|
-
// (see handleStatus), so we skip the auto-banner wrapper here to
|
|
1145
|
-
// avoid duplicating the same info at the top of the response.
|
|
1146
|
-
return await this.handleStatus(args);
|
|
1147
|
-
case 'codegraph_files':
|
|
1148
|
-
result = await this.handleFiles(args);
|
|
1149
|
-
break;
|
|
1150
|
-
default:
|
|
1151
|
-
return this.errorResult(`Unknown tool: ${toolName}`);
|
|
1196
|
+
// codegraph_status reports watcher state (pending files, degraded mode,
|
|
1197
|
+
// worktree warning) and embeds its own sections — it must run on the MAIN
|
|
1198
|
+
// thread against the watched default instance, so it is NEVER off-loaded to
|
|
1199
|
+
// a worker (whose read connection has no watcher). It also skips the
|
|
1200
|
+
// auto-banner wrapper to avoid duplicating its own pending-files section.
|
|
1201
|
+
if (toolName === 'codegraph_status') {
|
|
1202
|
+
return await this.handleStatus(args);
|
|
1152
1203
|
}
|
|
1204
|
+
// Read tools: off-load the CPU-heavy dispatch to the worker pool when one
|
|
1205
|
+
// is attached and healthy (daemon mode), so the daemon's single event loop
|
|
1206
|
+
// stays free for the MCP transport under concurrent load — otherwise N
|
|
1207
|
+
// concurrent explores serialize AND starve the transport until the whole
|
|
1208
|
+
// batch drains (clients then time out). With no pool (direct mode) or a
|
|
1209
|
+
// degraded one, dispatch runs in-process exactly as before. Either way the
|
|
1210
|
+
// result flows through the cross-cutting notices — worktree-index mismatch
|
|
1211
|
+
// (#155) and per-file staleness (#403) — which need the watched MAIN
|
|
1212
|
+
// instance and so are always applied here, never in the worker.
|
|
1213
|
+
const result = (this.queryPool && this.queryPool.healthy)
|
|
1214
|
+
? await this.queryPool.run(toolName, args)
|
|
1215
|
+
: await this.executeReadTool(toolName, args);
|
|
1153
1216
|
const withWorktree = this.withWorktreeNotice(result, args.projectPath);
|
|
1154
1217
|
return this.withStalenessNotice(withWorktree, args.projectPath);
|
|
1155
1218
|
}
|
|
@@ -1169,6 +1232,53 @@ class ToolHandler {
|
|
|
1169
1232
|
'continue without codegraph for this task.');
|
|
1170
1233
|
}
|
|
1171
1234
|
}
|
|
1235
|
+
/**
|
|
1236
|
+
* Run a single read tool to completion and return its raw {@link ToolResult},
|
|
1237
|
+
* classifying expected failures the same way {@link execute}'s catch does so
|
|
1238
|
+
* the SHAPE is identical whether dispatch runs in-process or on a worker:
|
|
1239
|
+
* NotIndexed → success-shaped guidance, PathRefusal → clean error, anything
|
|
1240
|
+
* else → internal-error-with-retry. Never throws.
|
|
1241
|
+
*
|
|
1242
|
+
* This is the worker thread's entry point (see {@link ./query-worker}) and the
|
|
1243
|
+
* in-process fallback for {@link execute}. It deliberately does NOT run the
|
|
1244
|
+
* catch-up gate or the staleness/worktree notices — those need the daemon's
|
|
1245
|
+
* watched main instance and stay on the main thread. Cross-cutting allowlist +
|
|
1246
|
+
* path validation already ran in {@link execute} before routing here.
|
|
1247
|
+
*/
|
|
1248
|
+
async executeReadTool(toolName, args) {
|
|
1249
|
+
try {
|
|
1250
|
+
return await this.dispatchTool(toolName, args);
|
|
1251
|
+
}
|
|
1252
|
+
catch (err) {
|
|
1253
|
+
if (err instanceof NotIndexedError) {
|
|
1254
|
+
return this.textResult(err.message);
|
|
1255
|
+
}
|
|
1256
|
+
if (err instanceof PathRefusalError) {
|
|
1257
|
+
return this.errorResult(err.message);
|
|
1258
|
+
}
|
|
1259
|
+
return this.errorResult(`Tool execution failed: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
1260
|
+
'This is an internal codegraph error — retry the call once; if it persists, ' +
|
|
1261
|
+
'continue without codegraph for this task.');
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Pure dispatch over the read tools — the switch, with no gate, no notices, no
|
|
1266
|
+
* allowlist/validation (the caller owns those). `codegraph_status` is handled
|
|
1267
|
+
* on the main thread in {@link execute} and never reaches here. May throw
|
|
1268
|
+
* NotIndexed/PathRefusal, which {@link executeReadTool} classifies.
|
|
1269
|
+
*/
|
|
1270
|
+
async dispatchTool(toolName, args) {
|
|
1271
|
+
switch (toolName) {
|
|
1272
|
+
case 'codegraph_search': return await this.handleSearch(args);
|
|
1273
|
+
case 'codegraph_callers': return await this.handleCallers(args);
|
|
1274
|
+
case 'codegraph_callees': return await this.handleCallees(args);
|
|
1275
|
+
case 'codegraph_impact': return await this.handleImpact(args);
|
|
1276
|
+
case 'codegraph_explore': return await this.handleExplore(args);
|
|
1277
|
+
case 'codegraph_node': return await this.handleNode(args);
|
|
1278
|
+
case 'codegraph_files': return await this.handleFiles(args);
|
|
1279
|
+
default: return this.errorResult(`Unknown tool: ${toolName}`);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1172
1282
|
/**
|
|
1173
1283
|
* Handle codegraph_search
|
|
1174
1284
|
*/
|