homegraph 1.1.2 → 1.1.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.
Files changed (175) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +243 -243
  3. package/dist/bin/homegraph.js +371 -9
  4. package/dist/bin/homegraph.js.map +1 -1
  5. package/dist/db/migrations.js +18 -18
  6. package/dist/db/queries.js +140 -140
  7. package/dist/db/schema.sql +152 -152
  8. package/dist/directory.js +5 -5
  9. package/dist/extraction/wasm/tree-sitter-c_sharp.wasm +0 -0
  10. package/dist/extraction/wasm/tree-sitter-pascal.wasm +0 -0
  11. package/dist/installer/instructions-template.js +9 -9
  12. package/dist/installer/targets/shared.d.ts +5 -6
  13. package/dist/installer/targets/shared.d.ts.map +1 -1
  14. package/dist/installer/targets/shared.js +5 -6
  15. package/dist/installer/targets/shared.js.map +1 -1
  16. package/dist/mcp/liveness-watchdog.js +16 -16
  17. package/dist/mcp/server-instructions.js +69 -69
  18. package/dist/mcp/tools.d.ts +17 -4
  19. package/dist/mcp/tools.d.ts.map +1 -1
  20. package/dist/mcp/tools.js +192 -22
  21. package/dist/mcp/tools.js.map +1 -1
  22. package/dist/reasoning/reasoner.js +32 -32
  23. package/dist/spec/config.d.ts +43 -0
  24. package/dist/spec/config.d.ts.map +1 -0
  25. package/dist/spec/config.js +275 -0
  26. package/dist/spec/config.js.map +1 -0
  27. package/dist/spec/db/commit-node.d.ts +23 -0
  28. package/dist/spec/db/commit-node.d.ts.map +1 -0
  29. package/dist/spec/db/commit-node.js +62 -0
  30. package/dist/spec/db/commit-node.js.map +1 -0
  31. package/dist/spec/db/fragment-node.d.ts +23 -0
  32. package/dist/spec/db/fragment-node.d.ts.map +1 -0
  33. package/dist/spec/db/fragment-node.js +120 -0
  34. package/dist/spec/db/fragment-node.js.map +1 -0
  35. package/dist/spec/db/fts.d.ts +60 -0
  36. package/dist/spec/db/fts.d.ts.map +1 -0
  37. package/dist/spec/db/fts.js +285 -0
  38. package/dist/spec/db/fts.js.map +1 -0
  39. package/dist/spec/db/index.d.ts +13 -0
  40. package/dist/spec/db/index.d.ts.map +1 -0
  41. package/dist/spec/db/index.js +50 -0
  42. package/dist/spec/db/index.js.map +1 -0
  43. package/dist/spec/db/relations.d.ts +55 -0
  44. package/dist/spec/db/relations.d.ts.map +1 -0
  45. package/dist/spec/db/relations.js +158 -0
  46. package/dist/spec/db/relations.js.map +1 -0
  47. package/dist/spec/db/schema.d.ts +30 -0
  48. package/dist/spec/db/schema.d.ts.map +1 -0
  49. package/dist/spec/db/schema.js +87 -0
  50. package/dist/spec/db/schema.js.map +1 -0
  51. package/dist/spec/db/schema.sql +107 -0
  52. package/dist/spec/db/spec-node.d.ts +41 -0
  53. package/dist/spec/db/spec-node.d.ts.map +1 -0
  54. package/dist/spec/db/spec-node.js +114 -0
  55. package/dist/spec/db/spec-node.js.map +1 -0
  56. package/dist/spec/evolve/impact-locator.d.ts +13 -0
  57. package/dist/spec/evolve/impact-locator.d.ts.map +1 -0
  58. package/dist/spec/evolve/impact-locator.js +25 -0
  59. package/dist/spec/evolve/impact-locator.js.map +1 -0
  60. package/dist/spec/evolve/llm-client.d.ts +50 -0
  61. package/dist/spec/evolve/llm-client.d.ts.map +1 -0
  62. package/dist/spec/evolve/llm-client.js +176 -0
  63. package/dist/spec/evolve/llm-client.js.map +1 -0
  64. package/dist/spec/evolve/logic-checker.d.ts +12 -0
  65. package/dist/spec/evolve/logic-checker.d.ts.map +1 -0
  66. package/dist/spec/evolve/logic-checker.js +48 -0
  67. package/dist/spec/evolve/logic-checker.js.map +1 -0
  68. package/dist/spec/evolve/pipeline.d.ts +40 -0
  69. package/dist/spec/evolve/pipeline.d.ts.map +1 -0
  70. package/dist/spec/evolve/pipeline.js +314 -0
  71. package/dist/spec/evolve/pipeline.js.map +1 -0
  72. package/dist/spec/evolve/spec-rewriter.d.ts +42 -0
  73. package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -0
  74. package/dist/spec/evolve/spec-rewriter.js +254 -0
  75. package/dist/spec/evolve/spec-rewriter.js.map +1 -0
  76. package/dist/spec/graph/queries.d.ts +58 -0
  77. package/dist/spec/graph/queries.d.ts.map +1 -0
  78. package/dist/spec/graph/queries.js +215 -0
  79. package/dist/spec/graph/queries.js.map +1 -0
  80. package/dist/spec/mining/diff-parser.d.ts +33 -0
  81. package/dist/spec/mining/diff-parser.d.ts.map +1 -0
  82. package/dist/spec/mining/diff-parser.js +166 -0
  83. package/dist/spec/mining/diff-parser.js.map +1 -0
  84. package/dist/spec/mining/git-scanner.d.ts +91 -0
  85. package/dist/spec/mining/git-scanner.d.ts.map +1 -0
  86. package/dist/spec/mining/git-scanner.js +266 -0
  87. package/dist/spec/mining/git-scanner.js.map +1 -0
  88. package/dist/spec/mining/pipeline.d.ts +53 -0
  89. package/dist/spec/mining/pipeline.d.ts.map +1 -0
  90. package/dist/spec/mining/pipeline.js +165 -0
  91. package/dist/spec/mining/pipeline.js.map +1 -0
  92. package/dist/spec/mining/scope-resolver.d.ts +45 -0
  93. package/dist/spec/mining/scope-resolver.d.ts.map +1 -0
  94. package/dist/spec/mining/scope-resolver.js +103 -0
  95. package/dist/spec/mining/scope-resolver.js.map +1 -0
  96. package/dist/spec/mining/spec-extractor.d.ts +69 -0
  97. package/dist/spec/mining/spec-extractor.d.ts.map +1 -0
  98. package/dist/spec/mining/spec-extractor.js +369 -0
  99. package/dist/spec/mining/spec-extractor.js.map +1 -0
  100. package/dist/spec/types.d.ts +149 -0
  101. package/dist/spec/types.d.ts.map +1 -0
  102. package/dist/spec/types.js +15 -0
  103. package/dist/spec/types.js.map +1 -0
  104. package/dist/spec/utils.d.ts +166 -0
  105. package/dist/spec/utils.d.ts.map +1 -0
  106. package/dist/spec/utils.js +461 -0
  107. package/dist/spec/utils.js.map +1 -0
  108. package/package.json +58 -57
  109. package/scripts/add-lang/bench.sh +60 -60
  110. package/scripts/add-lang/check-grammar.mjs +75 -75
  111. package/scripts/add-lang/dump-ast.mjs +103 -103
  112. package/scripts/add-lang/verify-extraction.mjs +70 -70
  113. package/scripts/agent-eval/ab-adoption.sh +91 -91
  114. package/scripts/agent-eval/ab-hook.sh +86 -86
  115. package/scripts/agent-eval/ab-impl.sh +78 -78
  116. package/scripts/agent-eval/ab-new-vs-baseline.sh +102 -102
  117. package/scripts/agent-eval/ab-sufficiency.sh +78 -78
  118. package/scripts/agent-eval/arms-F.sh +21 -21
  119. package/scripts/agent-eval/arms-matrix.sh +37 -37
  120. package/scripts/agent-eval/audit.sh +68 -68
  121. package/scripts/agent-eval/bench-readme.sh +28 -28
  122. package/scripts/agent-eval/bench-why-repo.sh +22 -22
  123. package/scripts/agent-eval/block-read-hook.sh +19 -19
  124. package/scripts/agent-eval/hook-settings.json +15 -15
  125. package/scripts/agent-eval/itrun.sh +120 -120
  126. package/scripts/agent-eval/offload-eval-3arm.sh +72 -72
  127. package/scripts/agent-eval/offload-eval-cost.mjs +133 -133
  128. package/scripts/agent-eval/offload-eval-effort.mjs +108 -108
  129. package/scripts/agent-eval/offload-eval-frontload-matrix.sh +25 -25
  130. package/scripts/agent-eval/offload-eval-frontload.sh +47 -47
  131. package/scripts/agent-eval/offload-eval-ground-truth.json +18 -18
  132. package/scripts/agent-eval/offload-eval-hook.mjs +84 -84
  133. package/scripts/agent-eval/offload-eval-judge.mjs +103 -103
  134. package/scripts/agent-eval/offload-eval-matrix.sh +20 -20
  135. package/scripts/agent-eval/offload-eval-metrics.mjs +94 -94
  136. package/scripts/agent-eval/offload-eval-refs1.sh +50 -50
  137. package/scripts/agent-eval/offload-eval-setup.sh +24 -24
  138. package/scripts/agent-eval/offload-eval-styles.sh +71 -71
  139. package/scripts/agent-eval/offload-eval-summarize.mjs +68 -68
  140. package/scripts/agent-eval/offload-eval.md +76 -76
  141. package/scripts/agent-eval/parse-arms.mjs +116 -116
  142. package/scripts/agent-eval/parse-bench-readme.mjs +84 -84
  143. package/scripts/agent-eval/parse-run.mjs +45 -45
  144. package/scripts/agent-eval/parse-session.mjs +93 -93
  145. package/scripts/agent-eval/probe-context.mjs +21 -21
  146. package/scripts/agent-eval/probe-explore.mjs +40 -40
  147. package/scripts/agent-eval/probe-node.mjs +20 -20
  148. package/scripts/agent-eval/probe-sweep.mjs +119 -119
  149. package/scripts/agent-eval/probe-trace.mjs +20 -20
  150. package/scripts/agent-eval/redirect-read-hook.sh +38 -38
  151. package/scripts/agent-eval/run-agent.sh +34 -34
  152. package/scripts/agent-eval/run-all.sh +69 -69
  153. package/scripts/agent-eval/run-arms.sh +56 -56
  154. package/scripts/agent-eval/seq-matrix.mjs +137 -137
  155. package/scripts/build-bundle.sh +118 -118
  156. package/scripts/extract-release-notes.mjs +130 -130
  157. package/scripts/local-install.sh +41 -41
  158. package/scripts/npm-sdk.js +75 -75
  159. package/scripts/npm-shim.js +246 -246
  160. package/scripts/pack-npm.sh +119 -119
  161. package/scripts/prepare-release.mjs +270 -270
  162. package/scripts/qa_eval/README.md +407 -404
  163. package/scripts/qa_eval/_test_deveco_probe.py +41 -41
  164. package/scripts/qa_eval/agent_runner.py +526 -526
  165. package/scripts/qa_eval/data/.gitignore +4 -4
  166. package/scripts/qa_eval/data/test-set.jsonl +2 -22
  167. package/scripts/qa_eval/eval_metrics.py +274 -233
  168. package/scripts/qa_eval/external_agent.py +976 -671
  169. package/scripts/qa_eval/llm_config.py +92 -92
  170. package/scripts/qa_eval/memory_monitor.py +132 -132
  171. package/scripts/qa_eval/my_answer_accuracy.py +187 -187
  172. package/scripts/qa_eval/requirements.txt +2 -2
  173. package/scripts/qa_eval/run_pipeline.py +804 -711
  174. package/scripts/qa_eval/stats_efficiency.py +279 -279
  175. package/scripts/qa_eval/stats_scores.py +207 -207
@@ -193,10 +193,11 @@ export declare class ToolHandler {
193
193
  hasDefaultHomeGraph(): boolean;
194
194
  /**
195
195
  * Optional allowlist of exposed tools, parsed from the HOMEGRAPH_MCP_TOOLS
196
- * env var (comma-separated short names, e.g. "trace,search,node,context").
197
- * Unset/empty → every tool is exposed. Lets an operator (or an A/B harness)
198
- * trim the tool surface without rebuilding the client config; the ablated
199
- * tool is then truly absent from ListTools rather than merely denied on call.
196
+ * env var (comma-separated short names, e.g. "explore,search,node").
197
+ * Unset/empty → every tool is exposed. Set only the listed tools are
198
+ * exposed. Lets an operator (or an A/B harness) trim the tool surface
199
+ * without rebuilding the client config; the ablated tool is then truly
200
+ * absent from ListTools rather than merely denied on call.
200
201
  * Matching is on the short form, so "node" and "homegraph_node" both work.
201
202
  */
202
203
  private toolAllowlist;
@@ -312,6 +313,8 @@ export declare class ToolHandler {
312
313
  * Handle homegraph_impact
313
314
  */
314
315
  private handleImpact;
316
+ /** Whether a graph edge may be traversed by homegraph_explore's main Flow BFS. */
317
+ private isExploreFlowEdge;
315
318
  /**
316
319
  * Describe a synthesized (dynamic-dispatch) edge for human output: how the
317
320
  * callback was wired up — the bridge static parsing can't see. Returns null
@@ -467,6 +470,16 @@ export declare class ToolHandler {
467
470
  * Format files as a tree structure
468
471
  */
469
472
  private formatFilesTree;
473
+ /**
474
+ * Match a spec/feature description against the Commit4Spec knowledge graph.
475
+ *
476
+ * Uses FTS5 full-text search to find the most similar historical specs,
477
+ * returning each with its linked commits and optional code fragments.
478
+ * The database lives at `.homegraph/commit4spec/commit4spec.db` by default and is
479
+ * separate from the HomeGraph code-symbol index — this tool works whether
480
+ * or not the code index is present.
481
+ */
482
+ private handleSpecMatch;
470
483
  /**
471
484
  * Find a symbol by name, handling disambiguation when multiple matches exist.
472
485
  * Returns the best match and a note about alternatives if any.
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"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"}
package/dist/mcp/tools.js CHANGED
@@ -25,6 +25,14 @@ const fs_1 = require("fs");
25
25
  const utils_1 = require("../utils");
26
26
  const generated_detection_1 = require("../extraction/generated-detection");
27
27
  const dynamic_boundaries_1 = require("./dynamic-boundaries");
28
+ /** ViewTree structural `references` vias — not UI event bindings. */
29
+ const VIEWTREE_STRUCTURE_VIAS = new Set([
30
+ 'child-component',
31
+ 'state-binding',
32
+ 'prop-transfer',
33
+ 'builder',
34
+ 'builder-param',
35
+ ]);
28
36
  /**
29
37
  * An expected, recoverable "homegraph can't serve this" condition — most
30
38
  * importantly a project with no index. The dispatch catch converts these to
@@ -551,6 +559,40 @@ exports.tools = [
551
559
  },
552
560
  },
553
561
  },
562
+ {
563
+ name: 'homegraph_spec_match',
564
+ description: 'Match a new spec/feature description against the Commit4Spec knowledge graph using FTS5 full-text search. ' +
565
+ 'Returns the most similar historical specs with their associated commits and code fragments. ' +
566
+ 'The database defaults to .homegraph/commit4spec/commit4spec.db under the repo path.',
567
+ inputSchema: {
568
+ type: 'object',
569
+ properties: {
570
+ query: {
571
+ type: 'string',
572
+ description: 'Spec text (title + description) to match against historical specs.',
573
+ },
574
+ repoPath: {
575
+ type: 'string',
576
+ description: 'Path to the repository root. Defaults to the current working directory.',
577
+ },
578
+ topK: {
579
+ type: 'number',
580
+ description: 'Maximum number of similar specs to return (default: 5).',
581
+ default: 5,
582
+ },
583
+ includeFragments: {
584
+ type: 'boolean',
585
+ description: 'Whether to include full code diffs per commit (default: true).',
586
+ default: true,
587
+ },
588
+ dbPath: {
589
+ type: 'string',
590
+ description: 'Explicit path to the Commit4Spec database. Overrides repoPath-based resolution.',
591
+ },
592
+ },
593
+ required: ['query'],
594
+ },
595
+ },
554
596
  ];
555
597
  /**
556
598
  * Allowlist-filtered tool definitions WITHOUT an engine — the static surface the
@@ -561,23 +603,11 @@ exports.tools = [
561
603
  function getStaticTools() {
562
604
  const raw = process.env.HOMEGRAPH_MCP_TOOLS ?? process.env.HOMEGRAPH_MCP_TOOLS;
563
605
  if (!raw || !raw.trim()) {
564
- return exports.tools.filter(t => DEFAULT_MCP_TOOLS.has(t.name.replace(/^homegraph_/, '')));
606
+ return exports.tools;
565
607
  }
566
608
  const allow = new Set(raw.split(',').map(s => s.trim().replace(/^homegraph_/, '').replace(/^homegraph_/, '')).filter(Boolean));
567
609
  return allow.size ? exports.tools.filter(t => allow.has(t.name.replace(/^homegraph_/, ''))) : exports.tools;
568
610
  }
569
- /**
570
- * The MCP tools served by DEFAULT (short names). Pared to ONLY `homegraph_explore`
571
- * — the single tool that reliably earns its place: one capped call returns the
572
- * verbatim source of the relevant symbols grouped by file. Every other tool is a
573
- * narrower slice of what explore already does, and presence itself steers
574
- * mis-picks, so they are no longer LISTED to agents.
575
- *
576
- * The other defined tools (`node`, `search`, `callers`, plus callees/impact/files/
577
- * status) remain fully functional — handlers stay, the library API and CLI are
578
- * untouched, and `HOMEGRAPH_MCP_TOOLS=explore,node,...` re-enables any of them.
579
- */
580
- const DEFAULT_MCP_TOOLS = new Set(['explore']);
581
611
  /**
582
612
  * Tool handler that executes tools against a HomeGraph instance
583
613
  *
@@ -680,10 +710,11 @@ class ToolHandler {
680
710
  }
681
711
  /**
682
712
  * Optional allowlist of exposed tools, parsed from the HOMEGRAPH_MCP_TOOLS
683
- * env var (comma-separated short names, e.g. "trace,search,node,context").
684
- * Unset/empty → every tool is exposed. Lets an operator (or an A/B harness)
685
- * trim the tool surface without rebuilding the client config; the ablated
686
- * tool is then truly absent from ListTools rather than merely denied on call.
713
+ * env var (comma-separated short names, e.g. "explore,search,node").
714
+ * Unset/empty → every tool is exposed. Set only the listed tools are
715
+ * exposed. Lets an operator (or an A/B harness) trim the tool surface
716
+ * without rebuilding the client config; the ablated tool is then truly
717
+ * absent from ListTools rather than merely denied on call.
687
718
  * Matching is on the short form, so "node" and "homegraph_node" both work.
688
719
  */
689
720
  toolAllowlist() {
@@ -707,12 +738,11 @@ class ToolHandler {
707
738
  */
708
739
  getTools() {
709
740
  const allow = this.toolAllowlist();
710
- // No explicit allowlist → the default 4-tool surface (see
711
- // DEFAULT_MCP_TOOLS for the evidence). An allowlist replaces the
712
- // default entirely, so any defined tool can be re-enabled.
741
+ // No explicit allowlist → expose every defined tool. An allowlist trims
742
+ // the surface to only the listed short names.
713
743
  let visible = allow
714
744
  ? exports.tools.filter(t => allow.has(t.name.replace(/^homegraph_/, '')))
715
- : exports.tools.filter(t => DEFAULT_MCP_TOOLS.has(t.name.replace(/^homegraph_/, '')));
745
+ : exports.tools;
716
746
  if (!this.cg)
717
747
  return visible;
718
748
  try {
@@ -1147,6 +1177,9 @@ class ToolHandler {
1147
1177
  case 'homegraph_files':
1148
1178
  result = await this.handleFiles(args);
1149
1179
  break;
1180
+ case 'homegraph_spec_match':
1181
+ result = await this.handleSpecMatch(args);
1182
+ break;
1150
1183
  default:
1151
1184
  return this.errorResult(`Unknown tool: ${toolName}`);
1152
1185
  }
@@ -1427,6 +1460,18 @@ class ToolHandler {
1427
1460
  }
1428
1461
  return this.textResult(this.truncateOutput(sections.join('\n') + filterNote));
1429
1462
  }
1463
+ /** Whether a graph edge may be traversed by homegraph_explore's main Flow BFS. */
1464
+ isExploreFlowEdge(edge) {
1465
+ if (edge.kind === 'calls')
1466
+ return true;
1467
+ if (edge.kind !== 'references' || edge.provenance !== 'heuristic')
1468
+ return false;
1469
+ const m = edge.metadata;
1470
+ if (m?.synthesizedBy !== 'viewtree')
1471
+ return false;
1472
+ const via = typeof m.via === 'string' ? m.via : '';
1473
+ return via.length > 0 && !VIEWTREE_STRUCTURE_VIAS.has(via);
1474
+ }
1430
1475
  /**
1431
1476
  * Describe a synthesized (dynamic-dispatch) edge for human output: how the
1432
1477
  * callback was wired up — the bridge static parsing can't see. Returns null
@@ -1479,6 +1524,16 @@ class ToolHandler {
1479
1524
  registeredAt,
1480
1525
  };
1481
1526
  }
1527
+ if (m?.synthesizedBy === 'viewtree') {
1528
+ const via = typeof m.via === 'string' ? m.via : '';
1529
+ if (via && !VIEWTREE_STRUCTURE_VIAS.has(via)) {
1530
+ return {
1531
+ label: `ArkUI event \`.${via}\` — bound handler (dynamic dispatch)`,
1532
+ compact: `dynamic: ArkUI .${via}${at}`,
1533
+ registeredAt,
1534
+ };
1535
+ }
1536
+ }
1482
1537
  if (m?.synthesizedBy === 'interface-impl') {
1483
1538
  return {
1484
1539
  label: `interface/abstract dispatch — runs the implementation override (dynamic dispatch)`,
@@ -1687,7 +1742,7 @@ class ToolHandler {
1687
1742
  if (depth >= MAX_HOPS - 1)
1688
1743
  continue;
1689
1744
  for (const c of cg.getCallees(id)) {
1690
- if (c.edge.kind !== 'calls' || parent.has(c.node.id))
1745
+ if (!this.isExploreFlowEdge(c.edge) || parent.has(c.node.id))
1691
1746
  continue;
1692
1747
  const newStreak = named.has(c.node.id) ? 0 : streak + 1;
1693
1748
  if (newStreak > MAX_BRIDGE)
@@ -3814,6 +3869,121 @@ class ToolHandler {
3814
3869
  return lines.join('\n');
3815
3870
  }
3816
3871
  // =========================================================================
3872
+ // handleSpecMatch — Commit4Spec knowledge-graph search
3873
+ // =========================================================================
3874
+ /**
3875
+ * Match a spec/feature description against the Commit4Spec knowledge graph.
3876
+ *
3877
+ * Uses FTS5 full-text search to find the most similar historical specs,
3878
+ * returning each with its linked commits and optional code fragments.
3879
+ * The database lives at `.homegraph/commit4spec/commit4spec.db` by default and is
3880
+ * separate from the HomeGraph code-symbol index — this tool works whether
3881
+ * or not the code index is present.
3882
+ */
3883
+ async handleSpecMatch(args) {
3884
+ const query = this.validateString(args.query, 'query');
3885
+ if (typeof query !== 'string')
3886
+ return query;
3887
+ const repoPath = args.repoPath;
3888
+ const explicitDbPath = args.dbPath;
3889
+ const topK = Math.max(1, Math.min(Number(args.topK) || 5, 50));
3890
+ const includeFragments = args.includeFragments !== false;
3891
+ // Lazily require spec modules so the MCP startup path stays lean.
3892
+ const { resolveDbPath } = require('../spec/utils');
3893
+ const { createDatabase } = require('../db/sqlite-adapter');
3894
+ const { initSpecSchema } = require('../spec/db/schema');
3895
+ const { searchAndGetContext } = require('../spec/graph/queries');
3896
+ const { truncateCodeDiff, truncateSubtitles, computeBudgetProfile, } = require('../spec/utils');
3897
+ // Resolve the database path.
3898
+ const dbPath = resolveDbPath(repoPath || process.cwd(), explicitDbPath);
3899
+ // Open the database.
3900
+ let db;
3901
+ try {
3902
+ db = createDatabase(dbPath).db;
3903
+ }
3904
+ catch (err) {
3905
+ return this.errorResult(`Failed to open Commit4Spec database at "${dbPath}": ` +
3906
+ `${err instanceof Error ? err.message : String(err)}`);
3907
+ }
3908
+ try {
3909
+ // Ensure the schema exists (idempotent).
3910
+ initSpecSchema(db);
3911
+ // Search and traverse.
3912
+ const contexts = searchAndGetContext(db, query, topK, includeFragments);
3913
+ if (contexts.length === 0) {
3914
+ return this.textResult(JSON.stringify({
3915
+ query: query.slice(0, 200),
3916
+ matched_count: 0,
3917
+ results: [],
3918
+ }, null, 2));
3919
+ }
3920
+ // Build budget profile for truncation.
3921
+ const profile = computeBudgetProfile(contexts.length);
3922
+ // Serialize to JSON (matching Python's spec_contexts_to_results format).
3923
+ const results = contexts.map((ctx) => {
3924
+ const subtitles = profile.tier === 'vlarge'
3925
+ ? [] // vlarge disables subtitles entirely
3926
+ : truncateSubtitles(ctx.spec.subtitles, 200, profile.maxContents);
3927
+ const commits = ctx.commits.slice(0, profile.maxContents || 5).map((c) => {
3928
+ const cd = {
3929
+ hash: c.commit.hash,
3930
+ message: c.commit.message,
3931
+ relation_type: c.relationType,
3932
+ };
3933
+ if (includeFragments) {
3934
+ const maxFrags = profile.maxFragments || 3;
3935
+ cd.fragments = c.fragments.slice(0, maxFrags).map((f) => ({
3936
+ file_path: f.filePath,
3937
+ change_type: f.changeType,
3938
+ start_line: f.startLine,
3939
+ end_line: f.endLine,
3940
+ code_diff: truncateCodeDiff(f.codeDiff),
3941
+ }));
3942
+ }
3943
+ return cd;
3944
+ });
3945
+ return {
3946
+ spec_id: ctx.spec.id,
3947
+ title: ctx.spec.title,
3948
+ subtitles,
3949
+ file_path: ctx.spec.filePath,
3950
+ commits,
3951
+ };
3952
+ });
3953
+ const response = {
3954
+ query: query.slice(0, 200),
3955
+ matched_count: results.length,
3956
+ results,
3957
+ };
3958
+ const json = JSON.stringify(response, null, 2);
3959
+ // Hard cap to MAX_OUTPUT_LENGTH to prevent context bloat.
3960
+ if (json.length <= MAX_OUTPUT_LENGTH) {
3961
+ return this.textResult(json);
3962
+ }
3963
+ // When the full payload exceeds the cap, drop fragments first,
3964
+ // then trim commits, then trim the whole thing.
3965
+ if (includeFragments) {
3966
+ const slimResults = results.map((r) => ({
3967
+ ...r,
3968
+ commits: r.commits.map((c) => {
3969
+ const { fragments: _, ...rest } = c;
3970
+ return rest;
3971
+ }),
3972
+ }));
3973
+ const slim = JSON.stringify({ ...response, results: slimResults }, null, 2);
3974
+ if (slim.length <= MAX_OUTPUT_LENGTH) {
3975
+ return this.textResult(`(Fragments elided — output exceeded ${MAX_OUTPUT_LENGTH} chars)\n\n` + slim);
3976
+ }
3977
+ }
3978
+ // Fallback: hard-truncate the JSON.
3979
+ const truncated = json.slice(0, MAX_OUTPUT_LENGTH - 3) + '...';
3980
+ return this.textResult(truncated);
3981
+ }
3982
+ finally {
3983
+ db.close();
3984
+ }
3985
+ }
3986
+ // =========================================================================
3817
3987
  // Symbol resolution helpers
3818
3988
  // =========================================================================
3819
3989
  /**