@colbymchenry/codegraph-win32-x64 1.2.0 → 1.3.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 (209) hide show
  1. package/lib/dist/bin/codegraph.d.ts +1 -1
  2. package/lib/dist/bin/codegraph.d.ts.map +1 -1
  3. package/lib/dist/bin/codegraph.js +232 -61
  4. package/lib/dist/bin/codegraph.js.map +1 -1
  5. package/lib/dist/bin/command-supervision.d.ts.map +1 -1
  6. package/lib/dist/bin/command-supervision.js +4 -1
  7. package/lib/dist/bin/command-supervision.js.map +1 -1
  8. package/lib/dist/db/migrations.d.ts +1 -1
  9. package/lib/dist/db/migrations.d.ts.map +1 -1
  10. package/lib/dist/db/migrations.js +19 -1
  11. package/lib/dist/db/migrations.js.map +1 -1
  12. package/lib/dist/db/queries.d.ts +51 -0
  13. package/lib/dist/db/queries.d.ts.map +1 -1
  14. package/lib/dist/db/queries.js +141 -0
  15. package/lib/dist/db/queries.js.map +1 -1
  16. package/lib/dist/db/schema.sql +19 -0
  17. package/lib/dist/directory.d.ts +9 -5
  18. package/lib/dist/directory.d.ts.map +1 -1
  19. package/lib/dist/directory.js +210 -19
  20. package/lib/dist/directory.js.map +1 -1
  21. package/lib/dist/extraction/cfml-extractor.d.ts +107 -0
  22. package/lib/dist/extraction/cfml-extractor.d.ts.map +1 -0
  23. package/lib/dist/extraction/cfml-extractor.js +494 -0
  24. package/lib/dist/extraction/cfml-extractor.js.map +1 -0
  25. package/lib/dist/extraction/grammars.d.ts +9 -0
  26. package/lib/dist/extraction/grammars.d.ts.map +1 -1
  27. package/lib/dist/extraction/grammars.js +115 -3
  28. package/lib/dist/extraction/grammars.js.map +1 -1
  29. package/lib/dist/extraction/index.d.ts +46 -1
  30. package/lib/dist/extraction/index.d.ts.map +1 -1
  31. package/lib/dist/extraction/index.js +254 -3
  32. package/lib/dist/extraction/index.js.map +1 -1
  33. package/lib/dist/extraction/languages/arkts.d.ts +3 -0
  34. package/lib/dist/extraction/languages/arkts.d.ts.map +1 -0
  35. package/lib/dist/extraction/languages/arkts.js +127 -0
  36. package/lib/dist/extraction/languages/arkts.js.map +1 -0
  37. package/lib/dist/extraction/languages/c-cpp.d.ts +42 -0
  38. package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
  39. package/lib/dist/extraction/languages/c-cpp.js +369 -4
  40. package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
  41. package/lib/dist/extraction/languages/cfquery.d.ts +12 -0
  42. package/lib/dist/extraction/languages/cfquery.d.ts.map +1 -0
  43. package/lib/dist/extraction/languages/cfquery.js +28 -0
  44. package/lib/dist/extraction/languages/cfquery.js.map +1 -0
  45. package/lib/dist/extraction/languages/cfscript.d.ts +3 -0
  46. package/lib/dist/extraction/languages/cfscript.d.ts.map +1 -0
  47. package/lib/dist/extraction/languages/cfscript.js +73 -0
  48. package/lib/dist/extraction/languages/cfscript.js.map +1 -0
  49. package/lib/dist/extraction/languages/cobol.d.ts +33 -0
  50. package/lib/dist/extraction/languages/cobol.d.ts.map +1 -0
  51. package/lib/dist/extraction/languages/cobol.js +499 -0
  52. package/lib/dist/extraction/languages/cobol.js.map +1 -0
  53. package/lib/dist/extraction/languages/erlang.d.ts +3 -0
  54. package/lib/dist/extraction/languages/erlang.d.ts.map +1 -0
  55. package/lib/dist/extraction/languages/erlang.js +350 -0
  56. package/lib/dist/extraction/languages/erlang.js.map +1 -0
  57. package/lib/dist/extraction/languages/index.d.ts.map +1 -1
  58. package/lib/dist/extraction/languages/index.js +18 -0
  59. package/lib/dist/extraction/languages/index.js.map +1 -1
  60. package/lib/dist/extraction/languages/nix.d.ts +3 -0
  61. package/lib/dist/extraction/languages/nix.d.ts.map +1 -0
  62. package/lib/dist/extraction/languages/nix.js +294 -0
  63. package/lib/dist/extraction/languages/nix.js.map +1 -0
  64. package/lib/dist/extraction/languages/solidity.d.ts +3 -0
  65. package/lib/dist/extraction/languages/solidity.d.ts.map +1 -0
  66. package/lib/dist/extraction/languages/solidity.js +293 -0
  67. package/lib/dist/extraction/languages/solidity.js.map +1 -0
  68. package/lib/dist/extraction/languages/terraform.d.ts +3 -0
  69. package/lib/dist/extraction/languages/terraform.d.ts.map +1 -0
  70. package/lib/dist/extraction/languages/terraform.js +641 -0
  71. package/lib/dist/extraction/languages/terraform.js.map +1 -0
  72. package/lib/dist/extraction/languages/vbnet.d.ts +11 -0
  73. package/lib/dist/extraction/languages/vbnet.d.ts.map +1 -0
  74. package/lib/dist/extraction/languages/vbnet.js +141 -0
  75. package/lib/dist/extraction/languages/vbnet.js.map +1 -0
  76. package/lib/dist/extraction/mybatis-extractor.d.ts +30 -10
  77. package/lib/dist/extraction/mybatis-extractor.d.ts.map +1 -1
  78. package/lib/dist/extraction/mybatis-extractor.js +140 -38
  79. package/lib/dist/extraction/mybatis-extractor.js.map +1 -1
  80. package/lib/dist/extraction/tree-sitter-helpers.d.ts.map +1 -1
  81. package/lib/dist/extraction/tree-sitter-helpers.js +1 -0
  82. package/lib/dist/extraction/tree-sitter-helpers.js.map +1 -1
  83. package/lib/dist/extraction/tree-sitter-types.d.ts +3 -1
  84. package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
  85. package/lib/dist/extraction/tree-sitter.d.ts +38 -0
  86. package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
  87. package/lib/dist/extraction/tree-sitter.js +753 -10
  88. package/lib/dist/extraction/tree-sitter.js.map +1 -1
  89. package/lib/dist/extraction/wasm/tree-sitter-arkts.wasm +0 -0
  90. package/lib/dist/extraction/wasm/tree-sitter-cfml.wasm +0 -0
  91. package/lib/dist/extraction/wasm/tree-sitter-cfquery.wasm +0 -0
  92. package/lib/dist/extraction/wasm/tree-sitter-cfscript.wasm +0 -0
  93. package/lib/dist/extraction/wasm/tree-sitter-cobol.wasm +0 -0
  94. package/lib/dist/extraction/wasm/tree-sitter-erlang.wasm +0 -0
  95. package/lib/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  96. package/lib/dist/extraction/wasm/tree-sitter-terraform.wasm +0 -0
  97. package/lib/dist/extraction/wasm/tree-sitter-vbnet.wasm +0 -0
  98. package/lib/dist/index.d.ts +63 -1
  99. package/lib/dist/index.d.ts.map +1 -1
  100. package/lib/dist/index.js +306 -2
  101. package/lib/dist/index.js.map +1 -1
  102. package/lib/dist/installer/index.d.ts.map +1 -1
  103. package/lib/dist/installer/index.js +3 -1
  104. package/lib/dist/installer/index.js.map +1 -1
  105. package/lib/dist/mcp/daemon.d.ts +25 -3
  106. package/lib/dist/mcp/daemon.d.ts.map +1 -1
  107. package/lib/dist/mcp/daemon.js +39 -7
  108. package/lib/dist/mcp/daemon.js.map +1 -1
  109. package/lib/dist/mcp/dynamic-boundaries.d.ts.map +1 -1
  110. package/lib/dist/mcp/dynamic-boundaries.js +2 -1
  111. package/lib/dist/mcp/dynamic-boundaries.js.map +1 -1
  112. package/lib/dist/mcp/early-ppid.d.ts +26 -0
  113. package/lib/dist/mcp/early-ppid.d.ts.map +1 -0
  114. package/lib/dist/mcp/early-ppid.js +29 -0
  115. package/lib/dist/mcp/early-ppid.js.map +1 -0
  116. package/lib/dist/mcp/index.d.ts.map +1 -1
  117. package/lib/dist/mcp/index.js +21 -4
  118. package/lib/dist/mcp/index.js.map +1 -1
  119. package/lib/dist/mcp/proxy.d.ts.map +1 -1
  120. package/lib/dist/mcp/proxy.js +21 -3
  121. package/lib/dist/mcp/proxy.js.map +1 -1
  122. package/lib/dist/mcp/startup-handshake.d.ts +44 -0
  123. package/lib/dist/mcp/startup-handshake.d.ts.map +1 -0
  124. package/lib/dist/mcp/startup-handshake.js +73 -0
  125. package/lib/dist/mcp/startup-handshake.js.map +1 -0
  126. package/lib/dist/mcp/tools.d.ts +22 -0
  127. package/lib/dist/mcp/tools.d.ts.map +1 -1
  128. package/lib/dist/mcp/tools.js +74 -9
  129. package/lib/dist/mcp/tools.js.map +1 -1
  130. package/lib/dist/project-config.d.ts +38 -0
  131. package/lib/dist/project-config.d.ts.map +1 -1
  132. package/lib/dist/project-config.js +101 -2
  133. package/lib/dist/project-config.js.map +1 -1
  134. package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
  135. package/lib/dist/resolution/callback-synthesizer.js +672 -0
  136. package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
  137. package/lib/dist/resolution/frameworks/cics.d.ts +20 -0
  138. package/lib/dist/resolution/frameworks/cics.d.ts.map +1 -0
  139. package/lib/dist/resolution/frameworks/cics.js +90 -0
  140. package/lib/dist/resolution/frameworks/cics.js.map +1 -0
  141. package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
  142. package/lib/dist/resolution/frameworks/index.js +6 -0
  143. package/lib/dist/resolution/frameworks/index.js.map +1 -1
  144. package/lib/dist/resolution/frameworks/java.d.ts.map +1 -1
  145. package/lib/dist/resolution/frameworks/java.js +14 -6
  146. package/lib/dist/resolution/frameworks/java.js.map +1 -1
  147. package/lib/dist/resolution/frameworks/terraform.d.ts +38 -0
  148. package/lib/dist/resolution/frameworks/terraform.d.ts.map +1 -0
  149. package/lib/dist/resolution/frameworks/terraform.js +277 -0
  150. package/lib/dist/resolution/frameworks/terraform.js.map +1 -0
  151. package/lib/dist/resolution/import-resolver.d.ts +7 -0
  152. package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
  153. package/lib/dist/resolution/import-resolver.js +129 -4
  154. package/lib/dist/resolution/import-resolver.js.map +1 -1
  155. package/lib/dist/resolution/index.d.ts +39 -6
  156. package/lib/dist/resolution/index.d.ts.map +1 -1
  157. package/lib/dist/resolution/index.js +287 -50
  158. package/lib/dist/resolution/index.js.map +1 -1
  159. package/lib/dist/resolution/name-matcher.d.ts +0 -3
  160. package/lib/dist/resolution/name-matcher.d.ts.map +1 -1
  161. package/lib/dist/resolution/name-matcher.js +225 -33
  162. package/lib/dist/resolution/name-matcher.js.map +1 -1
  163. package/lib/dist/resolution/strip-comments.d.ts +1 -1
  164. package/lib/dist/resolution/strip-comments.d.ts.map +1 -1
  165. package/lib/dist/resolution/strip-comments.js +49 -0
  166. package/lib/dist/resolution/strip-comments.js.map +1 -1
  167. package/lib/dist/resolution/types.d.ts +20 -0
  168. package/lib/dist/resolution/types.d.ts.map +1 -1
  169. package/lib/dist/resolution/workspace-packages.d.ts +10 -0
  170. package/lib/dist/resolution/workspace-packages.d.ts.map +1 -1
  171. package/lib/dist/resolution/workspace-packages.js +142 -4
  172. package/lib/dist/resolution/workspace-packages.js.map +1 -1
  173. package/lib/dist/search/identifier-segments.d.ts +60 -0
  174. package/lib/dist/search/identifier-segments.d.ts.map +1 -0
  175. package/lib/dist/search/identifier-segments.js +176 -0
  176. package/lib/dist/search/identifier-segments.js.map +1 -0
  177. package/lib/dist/sync/git-hooks.d.ts.map +1 -1
  178. package/lib/dist/sync/git-hooks.js +2 -0
  179. package/lib/dist/sync/git-hooks.js.map +1 -1
  180. package/lib/dist/sync/watcher.d.ts +10 -5
  181. package/lib/dist/sync/watcher.d.ts.map +1 -1
  182. package/lib/dist/sync/watcher.js +51 -14
  183. package/lib/dist/sync/watcher.js.map +1 -1
  184. package/lib/dist/sync/worktree.d.ts.map +1 -1
  185. package/lib/dist/sync/worktree.js +5 -0
  186. package/lib/dist/sync/worktree.js.map +1 -1
  187. package/lib/dist/types.d.ts +19 -1
  188. package/lib/dist/types.d.ts.map +1 -1
  189. package/lib/dist/types.js +10 -0
  190. package/lib/dist/types.js.map +1 -1
  191. package/lib/node_modules/.package-lock.json +1 -1
  192. package/lib/package.json +1 -1
  193. package/package.json +1 -1
  194. package/lib/dist/reasoning/config.d.ts +0 -45
  195. package/lib/dist/reasoning/config.d.ts.map +0 -1
  196. package/lib/dist/reasoning/config.js +0 -171
  197. package/lib/dist/reasoning/config.js.map +0 -1
  198. package/lib/dist/reasoning/credentials.d.ts +0 -5
  199. package/lib/dist/reasoning/credentials.d.ts.map +0 -1
  200. package/lib/dist/reasoning/credentials.js +0 -83
  201. package/lib/dist/reasoning/credentials.js.map +0 -1
  202. package/lib/dist/reasoning/login.d.ts +0 -21
  203. package/lib/dist/reasoning/login.d.ts.map +0 -1
  204. package/lib/dist/reasoning/login.js +0 -85
  205. package/lib/dist/reasoning/login.js.map +0 -1
  206. package/lib/dist/reasoning/reasoner.d.ts +0 -43
  207. package/lib/dist/reasoning/reasoner.d.ts.map +0 -1
  208. package/lib/dist/reasoning/reasoner.js +0 -308
  209. package/lib/dist/reasoning/reasoner.js.map +0 -1
@@ -22,5 +22,5 @@
22
22
  * codegraph affected [files] Find test files affected by changes
23
23
  * codegraph upgrade [version] Update CodeGraph to the latest release
24
24
  */
25
- export {};
25
+ import '../mcp/early-ppid';
26
26
  //# sourceMappingURL=codegraph.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codegraph.d.ts","sourceRoot":"","sources":["../../src/bin/codegraph.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
1
+ {"version":3,"file":"codegraph.d.ts","sourceRoot":"","sources":["../../src/bin/codegraph.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,OAAO,mBAAmB,CAAC"}
@@ -57,10 +57,15 @@ var __importStar = (this && this.__importStar) || (function () {
57
57
  };
58
58
  })();
59
59
  Object.defineProperty(exports, "__esModule", { value: true });
60
+ // FIRST import, before anything else loads: capture process.ppid while our
61
+ // launcher is (almost certainly) still alive. A launcher killed mid-startup
62
+ // otherwise blinds the PPID watchdog forever (#1185) — see early-ppid.ts.
63
+ require("../mcp/early-ppid");
60
64
  const commander_1 = require("commander");
61
65
  const path = __importStar(require("path"));
62
66
  const fs = __importStar(require("fs"));
63
67
  const directory_1 = require("../directory");
68
+ const identifier_segments_1 = require("../search/identifier-segments");
64
69
  const worktree_1 = require("../sync/worktree");
65
70
  const shimmer_progress_1 = require("../ui/shimmer-progress");
66
71
  const glyphs_1 = require("../ui/glyphs");
@@ -343,6 +348,14 @@ function main() {
343
348
  clack.log.success(`Indexed ${formatNumber(result.filesIndexed)} files`);
344
349
  }
345
350
  clack.log.info(`${formatNumber(result.nodesCreated)} nodes, ${formatNumber(result.edgesCreated)} edges in ${formatDuration(result.durationMs)}`);
351
+ // A PARTIAL index (files silently dropped mid-pipeline) must not pass
352
+ // as a clean run — it's the difference between "indexed the repo" and
353
+ // "indexed most of the repo, quietly". Only the completeness
354
+ // reconciliation warning; per-file extractor warnings stay in the
355
+ // error-code summary below.
356
+ for (const w of result.errors.filter((e) => e.code === 'index_partial')) {
357
+ clack.log.warn(w.message);
358
+ }
346
359
  }
347
360
  else if (hasErrors) {
348
361
  clack.log.error(`Indexing failed ${(0, glyphs_1.getGlyphs)().dash} all ${formatNumber(result.filesErrored)} files had errors`);
@@ -385,6 +398,68 @@ function main() {
385
398
  }
386
399
  }
387
400
  }
401
+ /**
402
+ * When an `init`/`index` produced an EMPTY graph and the reason is that the
403
+ * project's own `.gitignore` excludes nested git repositories — the "super-repo
404
+ * gitignores its child repos" layout (#1156), where `init` at the parent
405
+ * correctly indexes ~nothing while `init` inside each child works — name those
406
+ * repos and offer to index them. An interactive terminal gets a yes/no prompt
407
+ * that writes `includeIgnored` to codegraph.json and re-indexes; a
408
+ * non-interactive run just prints the one-line opt-in snippet. The caller gates
409
+ * this on `nodesCreated === 0`, so a project that DID index real content is
410
+ * never nagged about the gitignored reference clones it deliberately keeps out
411
+ * (#970, #1065). Best-effort throughout: detection never breaks the command.
412
+ */
413
+ async function offerIndexIgnoredRepos(clack, projectPath, reindex, opts) {
414
+ let repos;
415
+ try {
416
+ const { findUnindexedIgnoredRepos } = await Promise.resolve().then(() => __importStar(require('../extraction')));
417
+ repos = findUnindexedIgnoredRepos(projectPath);
418
+ }
419
+ catch {
420
+ return; // detection is advisory — never let it break the command
421
+ }
422
+ if (repos.length === 0)
423
+ return;
424
+ const { PROJECT_CONFIG_FILENAME } = await Promise.resolve().then(() => __importStar(require('../project-config')));
425
+ const isOne = repos.length === 1;
426
+ const SHOWN = 6;
427
+ const names = repos.slice(0, SHOWN).map((r) => r.replace(/\/$/, ''));
428
+ const extra = repos.length > SHOWN ? ` (+${formatNumber(repos.length - SHOWN)} more)` : '';
429
+ const snippet = `{ "includeIgnored": [${repos.map((p) => JSON.stringify(p)).join(', ')}] }`;
430
+ clack.log.warn(`Your .gitignore excludes ${isOne ? 'a nested git repository' : `${formatNumber(repos.length)} nested git repositories`} here, ` +
431
+ `so ${isOne ? 'it was' : 'they were'} not indexed: ${names.join(', ')}${extra}.`);
432
+ const manualHint = () => {
433
+ clack.log.info(`If ${isOne ? "it's" : "they're"} your code, add ${isOne ? 'it' : 'them'} to ${PROJECT_CONFIG_FILENAME} and re-index:`);
434
+ clack.log.info(` ${snippet}`);
435
+ };
436
+ if (!opts.interactive || !process.stdin.isTTY) {
437
+ manualHint();
438
+ return;
439
+ }
440
+ const yes = await clack.confirm({
441
+ message: `Index ${isOne ? 'it' : `these ${formatNumber(repos.length)}`} now? Adds ${isOne ? 'it' : 'them'} to ${PROJECT_CONFIG_FILENAME}.`,
442
+ initialValue: true,
443
+ });
444
+ if (clack.isCancel(yes) || !yes) {
445
+ manualHint();
446
+ return;
447
+ }
448
+ let added;
449
+ try {
450
+ const { addIncludeIgnoredPatterns } = await Promise.resolve().then(() => __importStar(require('../project-config')));
451
+ added = addIncludeIgnoredPatterns(projectPath, repos);
452
+ }
453
+ catch (err) {
454
+ clack.log.error(`Could not update ${PROJECT_CONFIG_FILENAME}: ${err instanceof Error ? err.message : String(err)}`);
455
+ manualHint();
456
+ return;
457
+ }
458
+ clack.log.success(`Added ${formatNumber(added)} ${added === 1 ? 'entry' : 'entries'} to ${PROJECT_CONFIG_FILENAME} ${(0, glyphs_1.getGlyphs)().dash} re-indexing…`);
459
+ const result = await reindex();
460
+ printIndexResult(clack, result, projectPath);
461
+ return result;
462
+ }
388
463
  /**
389
464
  * Write detailed error log to .codegraph/errors.log
390
465
  */
@@ -481,29 +556,33 @@ function main() {
481
556
  // accepted (so existing muscle memory and scripts don't break) but is a
482
557
  // no-op — initializing always builds the initial index.
483
558
  // Supervise the index: self-terminate if orphaned or wedged (#999).
484
- const supervision = (0, command_supervision_1.installCommandSupervision)('init');
485
- let result;
486
- try {
487
- if (options.verbose) {
488
- result = await cg.indexAll({
489
- onProgress: createVerboseProgress(),
490
- verbose: true,
491
- });
492
- }
493
- else {
559
+ // A closure so we can re-run the exact same supervised, progress-rendered
560
+ // index if the user opts gitignored child repos in below (#1156).
561
+ const runIndex = async () => {
562
+ const supervision = (0, command_supervision_1.installCommandSupervision)('init');
563
+ try {
564
+ if (options.verbose) {
565
+ return await cg.indexAll({ onProgress: createVerboseProgress(), verbose: true });
566
+ }
494
567
  process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
495
568
  const progress = (0, shimmer_progress_1.createShimmerProgress)();
496
- result = await cg.indexAll({
497
- onProgress: progress.onProgress,
498
- });
569
+ const r = await cg.indexAll({ onProgress: progress.onProgress });
499
570
  await progress.stop();
571
+ return r;
500
572
  }
501
- }
502
- finally {
503
- supervision.stop();
504
- }
573
+ finally {
574
+ supervision.stop();
575
+ }
576
+ };
577
+ const result = await runIndex();
505
578
  printIndexResult(clack, result, projectPath);
506
579
  await recordIndexTelemetry(cg, result);
580
+ // An empty graph at a git super-repo usually means `.gitignore` excludes
581
+ // the child repos that hold the code — surface them and offer to opt in
582
+ // rather than leaving the user with a silent 0-node "Done". (#1156)
583
+ if (result.nodesCreated === 0) {
584
+ await offerIndexIgnoredRepos(clack, projectPath, runIndex, { interactive: true });
585
+ }
507
586
  try {
508
587
  const { offerWatchFallback } = await Promise.resolve().then(() => __importStar(require('../installer')));
509
588
  await offerWatchFallback(clack, projectPath);
@@ -619,24 +698,28 @@ function main() {
619
698
  }
620
699
  const clack = await importESM('@clack/prompts');
621
700
  clack.intro('Indexing project');
622
- let result;
623
- if (options.verbose) {
624
- result = await cg.indexAll({
625
- onProgress: createVerboseProgress(),
626
- verbose: true,
627
- });
628
- }
629
- else {
701
+ // A closure so a re-index (after opting gitignored child repos in, #1156)
702
+ // renders identically. Supervision already wraps the whole command.
703
+ const renderIndex = async () => {
704
+ if (options.verbose) {
705
+ return await cg.indexAll({ onProgress: createVerboseProgress(), verbose: true });
706
+ }
630
707
  process.stdout.write(`${colors.dim}${(0, glyphs_1.getGlyphs)().rail}${colors.reset}\n`);
631
708
  const progress = (0, shimmer_progress_1.createShimmerProgress)();
632
- result = await cg.indexAll({
633
- onProgress: progress.onProgress,
634
- });
709
+ const r = await cg.indexAll({ onProgress: progress.onProgress });
635
710
  await progress.stop();
636
- }
711
+ return r;
712
+ };
713
+ const result = await renderIndex();
637
714
  printIndexResult(clack, result, projectPath);
638
715
  await recordIndexTelemetry(cg, result);
639
- if (!result.success) {
716
+ // Empty graph at a git super-repo → likely `.gitignore`d child repos;
717
+ // name them and offer to opt in instead of a silent 0-node result (#1156).
718
+ let finalResult = result;
719
+ if (result.nodesCreated === 0) {
720
+ finalResult = (await offerIndexIgnoredRepos(clack, projectPath, renderIndex, { interactive: true })) ?? result;
721
+ }
722
+ if (!finalResult.success) {
640
723
  process.exit(1);
641
724
  }
642
725
  clack.outro('Done');
@@ -747,6 +830,10 @@ function main() {
747
830
  const journalMode = cg.getJournalMode();
748
831
  const buildInfo = cg.getIndexBuildInfo();
749
832
  const reindexRecommended = cg.isIndexStale();
833
+ const indexState = cg.getIndexState();
834
+ // Zero on a healthy index; non-zero at rest means a resolution pass was
835
+ // interrupted, so some files' call edges are missing (#1187).
836
+ const pendingRefs = cg.getPendingReferenceCount();
750
837
  // JSON output mode
751
838
  if (options.json) {
752
839
  const lastIndexedMs = cg.getLastIndexedAt();
@@ -777,6 +864,14 @@ function main() {
777
864
  builtWithExtractionVersion: buildInfo.extractionVersion,
778
865
  currentExtractionVersion: extraction_version_1.EXTRACTION_VERSION,
779
866
  reindexRecommended,
867
+ // 'complete' | 'partial' (files silently dropped) | 'indexing'
868
+ // (a run was killed mid-index — the index is truncated) |
869
+ // 'failed' | null (predates the marker).
870
+ state: indexState,
871
+ // References awaiting resolution. Non-zero at rest means an
872
+ // interrupted resolution pass left edges missing; the next
873
+ // sync sweeps them (#1187).
874
+ pendingRefs,
780
875
  },
781
876
  }));
782
877
  cg.destroy();
@@ -788,6 +883,18 @@ function main() {
788
883
  if (worktreeMismatch) {
789
884
  warn((0, worktree_1.worktreeMismatchWarning)(worktreeMismatch));
790
885
  }
886
+ if (indexState === 'indexing') {
887
+ warn('The last index run never finished (killed mid-index?) — the index is truncated. Re-run "codegraph index".');
888
+ }
889
+ else if (indexState === 'partial') {
890
+ warn('The last index run silently dropped files — the index is partial. Re-run "codegraph index".');
891
+ }
892
+ else if (indexState === 'failed') {
893
+ warn('The last index run failed — results may be incomplete. Re-run "codegraph index".');
894
+ }
895
+ if (pendingRefs > 0) {
896
+ warn(`${formatNumber(pendingRefs)} references from an interrupted run are awaiting resolution — some callers/impact edges are missing. Run "codegraph sync" to resolve them.`);
897
+ }
791
898
  console.log();
792
899
  // Index stats
793
900
  console.log(chalk.bold('Index Statistics:'));
@@ -1006,16 +1113,35 @@ function main() {
1006
1113
  return;
1007
1114
  }
1008
1115
  const prompt = String(input.prompt || '');
1009
- // Gate: only structural / flow / impact / where-how prompts get context, so
1010
- // every other prompt ("fix this typo") stays a zero-cost no-op. Language-aware
1011
- // (English + CJK keywords, plus code-shaped tokens) so it fires for non-English
1012
- // prompts too (issue #994). A keyword fires on its own; a code-token is only a
1013
- // CANDIDATE — verified against the graph below, so a tech brand ("JavaScript")
1014
- // that looks like a symbol but isn't one here doesn't inject spurious context.
1116
+ // Gate telemetry: how often each tier fires vs. no-ops counter names
1117
+ // only, NEVER prompt content (see TELEMETRY.md). This is the data that
1118
+ // turns "is the gate any good" from vibes into a measured recall rate.
1119
+ const gate = (outcome) => {
1120
+ try {
1121
+ (0, telemetry_1.getTelemetry)().recordUsage('cli_command', `prompt-hook-gate-${outcome}`, true);
1122
+ }
1123
+ catch { /* never break the hook */ }
1124
+ };
1125
+ // Gate, tiered by confidence (#994, #1126):
1126
+ // HIGH — a structural keyword (any covered language), or a code-shaped
1127
+ // token verified in the index → full explore injection.
1128
+ // MEDIUM — no keyword/token, but prose words match indexed symbol-name
1129
+ // SEGMENTS ("state machine" → OrderStateMachine, in any
1130
+ // language): inject a short list of the matching symbols and
1131
+ // let the AGENT write the explore query — the graph-derived
1132
+ // tier, no vocabulary involved.
1133
+ // silent — nothing verified. Every other prompt ("fix this typo")
1134
+ // stays a zero-cost no-op.
1135
+ // Keywords fire on their own; a token or prose word is only a CANDIDATE
1136
+ // verified against the graph below, so a tech brand ("JavaScript") that
1137
+ // merely looks like code doesn't inject spurious context.
1015
1138
  const keyworded = (0, directory_1.hasStructuralKeyword)(prompt);
1016
1139
  const codeTokens = keyworded ? [] : (0, directory_1.extractCodeTokens)(prompt);
1017
- if (!keyworded && codeTokens.length === 0)
1140
+ const proseWords = keyworded ? [] : (0, identifier_segments_1.extractProseCandidates)(prompt);
1141
+ if (!keyworded && codeTokens.length === 0 && proseWords.length === 0) {
1142
+ gate('noop-shape');
1018
1143
  return;
1144
+ }
1019
1145
  // Decide what to inject, shaped by WHERE the index(es) are: the nearest
1020
1146
  // indexed ancestor of cwd, or — when cwd is an un-indexed workspace root
1021
1147
  // whose indexed project(s) live in sub-dirs (the monorepo case, #964) —
@@ -1024,8 +1150,10 @@ function main() {
1024
1150
  // root (it only walked up), so the validated adoption lever never fired
1025
1151
  // exactly where the agent most needs it.
1026
1152
  const plan = (0, directory_1.planFrontload)(String(input.cwd || process.cwd()), prompt);
1027
- if (!plan.exploreRoot && plan.nudgeProjects.length === 0)
1028
- return; // nothing reachable — the agent's normal tools apply
1153
+ if (!plan.exploreRoot && plan.nudgeProjects.length === 0) {
1154
+ gate('noop-no-index');
1155
+ return;
1156
+ } // nothing reachable — the agent's normal tools apply
1029
1157
  // A "pass projectPath" line for indexed sub-projects we did NOT front-load.
1030
1158
  // Follow-up codegraph_explore calls against a sub-project (cwd isn't its
1031
1159
  // index root) need an explicit projectPath, so spell it out.
@@ -1034,30 +1162,72 @@ function main() {
1034
1162
  const { default: CodeGraph } = await loadCodeGraph();
1035
1163
  const cg = await CodeGraph.open(plan.exploreRoot);
1036
1164
  try {
1037
- // Code-token-only prompt: require that at least one token is a REAL symbol
1038
- // in THIS index before front-loading. Without it, a brand name or common
1039
- // word that merely looks like code ("JavaScript", "GitHub") would run
1040
- // explore and inject ~16KB of low-relevance context (issue #994 follow-up).
1041
- // A keyword-bearing prompt skips this the keyword is signal enough.
1042
- if (!keyworded && !codeTokens.some((t) => cg.getNodesByName(t).length > 0))
1165
+ const others = plan.nudgeProjects.length
1166
+ ? `\n${nudge(plan.nudgeProjects, 'Other indexed projects in this workspace pass projectPath to query them:')}`
1167
+ : '';
1168
+ // Tier decision against THIS index (issue #994 follow-up: candidates
1169
+ // must be real herea brand name or prose about another domain
1170
+ // must not inject). Keyword-bearing prompts skip verification — the
1171
+ // keyword is signal enough.
1172
+ const tokenVerified = !keyworded && codeTokens.some((t) => cg.getNodesByName(t).length > 0);
1173
+ if (keyworded || tokenVerified) {
1174
+ const { ToolHandler } = await Promise.resolve().then(() => __importStar(require('../mcp/tools')));
1175
+ const handler = new ToolHandler(cg);
1176
+ const result = await handler.execute('codegraph_explore', { query: prompt });
1177
+ const text = result.content[0]?.text ?? '';
1178
+ if (!result.isError && text.trim()) {
1179
+ // Cap the injection so a large-repo explore can't flood the prompt.
1180
+ const MAX = 16000;
1181
+ const body = text.length > MAX ? `${text.slice(0, MAX)}\n…(truncated; call codegraph_explore for the rest)` : text;
1182
+ // For a front-loaded SUB-project, a follow-up explore needs its path.
1183
+ const more = plan.viaSubScan
1184
+ ? `call codegraph_explore with projectPath: "${plan.exploreRoot}" for more`
1185
+ : 'call codegraph_explore for more';
1186
+ process.stdout.write(`<codegraph_context note="Structural context from CodeGraph for this prompt — treat returned source as already read; ${more}.">\n${body}${others}\n</codegraph_context>\n`);
1187
+ gate(keyworded ? 'high-keyword' : 'high-token');
1188
+ }
1189
+ else {
1190
+ // A high-* outcome must mean context was actually delivered —
1191
+ // the funnel's noop-vs-high split is how gate recall is
1192
+ // measured (#1143). An explore error or empty result is a
1193
+ // delivery failure, not a gate success.
1194
+ gate(keyworded ? 'noop-explore-keyword' : 'noop-explore-token');
1195
+ }
1196
+ return;
1197
+ }
1198
+ // MEDIUM: prose words → symbol-name segments, co-occurrence/rarity
1199
+ // scored, each hit re-verified to exist (see getSegmentMatches). The
1200
+ // payload names the symbols but does NOT run explore — the agent owns
1201
+ // the query where the hook's confidence is only "these are related".
1202
+ //
1203
+ // A database indexed before the vocab table existed starts with it
1204
+ // EMPTY, and only sync() backfills it — which this hook never runs
1205
+ // (#1142). Heal it here: on a populated vocab this is one SELECT;
1206
+ // the actual backfill is a one-time batched pass whose cost the MCP
1207
+ // server's own catch-up sync usually pays first (it runs at every
1208
+ // session start). A distinct noop outcome keeps a dormant vocab
1209
+ // from polluting the noop-unverified recall signal.
1210
+ const vocabReady = await cg.healSegmentVocabIfEmpty().catch(() => false);
1211
+ if (!vocabReady) {
1212
+ gate('noop-vocab-empty');
1213
+ return;
1214
+ }
1215
+ const related = cg.getSegmentMatches(proseWords);
1216
+ if (related.length === 0) {
1217
+ gate('noop-unverified');
1043
1218
  return;
1044
- const { ToolHandler } = await Promise.resolve().then(() => __importStar(require('../mcp/tools')));
1045
- const handler = new ToolHandler(cg);
1046
- const result = await handler.execute('codegraph_explore', { query: prompt });
1047
- const text = result.content[0]?.text ?? '';
1048
- if (!result.isError && text.trim()) {
1049
- // Cap the injection so a large-repo explore can't flood the prompt.
1050
- const MAX = 16000;
1051
- const body = text.length > MAX ? `${text.slice(0, MAX)}\n…(truncated; call codegraph_explore for the rest)` : text;
1052
- // For a front-loaded SUB-project, a follow-up explore needs its path.
1053
- const more = plan.viaSubScan
1054
- ? `call codegraph_explore with projectPath: "${plan.exploreRoot}" for more`
1055
- : 'call codegraph_explore for more';
1056
- const others = plan.nudgeProjects.length
1057
- ? `\n${nudge(plan.nudgeProjects, 'Other indexed projects in this workspace — pass projectPath to query them:')}`
1058
- : '';
1059
- process.stdout.write(`<codegraph_context note="Structural context from CodeGraph for this prompt — treat returned source as already read; ${more}.">\n${body}${others}\n</codegraph_context>\n`);
1060
1219
  }
1220
+ const lines = related
1221
+ .map((m) => ` - ${m.name} (${m.kind} — ${m.filePath}:${m.startLine})`)
1222
+ .join('\n');
1223
+ const exampleQuery = related.slice(0, 3).map((m) => m.name).join(' ');
1224
+ const projectHint = plan.viaSubScan ? ` with projectPath: "${plan.exploreRoot}"` : '';
1225
+ process.stdout.write(`<codegraph_context note="CodeGraph found indexed symbols matching this prompt — query the graph before searching files.">\n` +
1226
+ `This project's CodeGraph index contains symbols matching this request:\n${lines}\n` +
1227
+ `Call codegraph_explore ONCE${projectHint} with the relevant names in one query (e.g. "${exampleQuery}") ` +
1228
+ `to get their source, call paths, and blast radius — cheaper and more complete than Read/Grep.\n${others}` +
1229
+ `</codegraph_context>\n`);
1230
+ gate('medium-segment');
1061
1231
  }
1062
1232
  finally {
1063
1233
  cg.destroy();
@@ -1069,6 +1239,7 @@ function main() {
1069
1239
  process.stdout.write(`<codegraph_context note="CodeGraph is available for this workspace's indexed sub-projects — query one by passing projectPath to codegraph_explore.">\n` +
1070
1240
  nudge(plan.nudgeProjects, "This workspace's CodeGraph indexes live in sub-projects. To use CodeGraph, call codegraph_explore with the projectPath of the relevant one:") +
1071
1241
  `</codegraph_context>\n`);
1242
+ gate('nudge-projects');
1072
1243
  }
1073
1244
  }
1074
1245
  catch {