@mrclrchtr/supi-code-intelligence 1.6.0 → 1.7.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 (79) hide show
  1. package/README.md +42 -24
  2. package/node_modules/@mrclrchtr/supi-core/package.json +6 -2
  3. package/node_modules/@mrclrchtr/supi-core/src/api.ts +12 -1
  4. package/node_modules/@mrclrchtr/supi-core/src/config/config.ts +1 -1
  5. package/node_modules/@mrclrchtr/supi-core/src/index.ts +12 -1
  6. package/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +116 -0
  7. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/package.json +6 -2
  8. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/api.ts +12 -1
  9. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/config/config.ts +1 -1
  10. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/index.ts +12 -1
  11. package/node_modules/@mrclrchtr/supi-lsp/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +116 -0
  12. package/node_modules/@mrclrchtr/supi-lsp/package.json +9 -3
  13. package/node_modules/@mrclrchtr/supi-lsp/src/client/client.ts +8 -5
  14. package/node_modules/@mrclrchtr/supi-lsp/src/client/transport.ts +79 -190
  15. package/node_modules/@mrclrchtr/supi-lsp/src/config/server-config.ts +38 -0
  16. package/node_modules/@mrclrchtr/supi-lsp/src/config/types.ts +61 -387
  17. package/node_modules/@mrclrchtr/supi-lsp/src/format.ts +16 -8
  18. package/node_modules/@mrclrchtr/supi-lsp/src/lsp.ts +2 -2
  19. package/node_modules/@mrclrchtr/supi-lsp/src/manager/manager-project-info.ts +1 -1
  20. package/node_modules/@mrclrchtr/supi-lsp/src/session/lsp-state.ts +1 -1
  21. package/node_modules/@mrclrchtr/supi-lsp/src/tool/guidance.ts +1 -1
  22. package/node_modules/@mrclrchtr/supi-lsp/src/tool/tool-specs.ts +1 -1
  23. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/package.json +6 -2
  24. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/api.ts +12 -1
  25. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/config/config.ts +1 -1
  26. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/index.ts +12 -1
  27. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/@mrclrchtr/supi-core/src/tool-framework.ts +116 -0
  28. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/LICENSE +21 -0
  29. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/README.md +265 -0
  30. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs +4661 -0
  31. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.cjs.map +7 -0
  32. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js +4605 -0
  33. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.js.map +7 -0
  34. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm +0 -0
  35. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/debug/web-tree-sitter.wasm.map +57 -0
  36. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/package.json +100 -0
  37. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs +4063 -0
  38. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.cjs.map +7 -0
  39. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts +1025 -0
  40. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.cts.map +58 -0
  41. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts +1025 -0
  42. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.d.ts.map +58 -0
  43. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js +4007 -0
  44. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.js.map +7 -0
  45. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm +0 -0
  46. package/node_modules/@mrclrchtr/supi-tree-sitter/node_modules/web-tree-sitter/web-tree-sitter.wasm.map +55 -0
  47. package/node_modules/@mrclrchtr/supi-tree-sitter/package.json +2 -2
  48. package/package.json +4 -4
  49. package/src/actions/affected-action.ts +67 -54
  50. package/src/actions/brief-action.ts +142 -5
  51. package/src/actions/callees-action.ts +1 -1
  52. package/src/actions/callers-action.ts +38 -67
  53. package/src/actions/implementations-action.ts +27 -63
  54. package/src/actions/map-action.ts +206 -0
  55. package/src/actions/pattern-action.ts +1 -1
  56. package/src/api.ts +1 -0
  57. package/src/brief-focused.ts +5 -5
  58. package/src/brief.ts +3 -3
  59. package/src/code-intelligence.ts +6 -75
  60. package/src/index.ts +1 -0
  61. package/src/pattern-structured.ts +1 -1
  62. package/src/prioritization-signals.ts +13 -26
  63. package/src/query-params.ts +15 -0
  64. package/src/resolve-target.ts +2 -2
  65. package/src/search-helpers.ts +2 -2
  66. package/src/target-resolution.ts +27 -102
  67. package/src/tool/execute-affected.ts +25 -0
  68. package/src/tool/execute-brief.ts +25 -0
  69. package/src/tool/execute-map.ts +32 -0
  70. package/src/tool/execute-pattern.ts +26 -0
  71. package/src/tool/execute-relations.ts +48 -0
  72. package/src/tool/guidance.ts +24 -13
  73. package/src/tool/register-tools.ts +32 -0
  74. package/src/tool/tool-specs.ts +184 -0
  75. package/src/tool/validation.ts +43 -0
  76. package/src/types.ts +10 -0
  77. package/src/actions/index-action.ts +0 -187
  78. package/src/tool/action-specs.ts +0 -66
  79. package/src/tool-actions.ts +0 -100
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-tree-sitter",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "SuPi Tree-sitter extension — structural AST analysis for pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "dependencies": {
26
26
  "web-tree-sitter": "^0.26.8",
27
- "@mrclrchtr/supi-core": "1.6.0"
27
+ "@mrclrchtr/supi-core": "1.7.0"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@earendil-works/pi-ai": "*",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-code-intelligence",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "SuPi Code Intelligence extension — architecture briefs, caller/callee analysis, impact assessment, and pattern search for pi",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -19,9 +19,9 @@
19
19
  "src/**/*.ts"
20
20
  ],
21
21
  "dependencies": {
22
- "@mrclrchtr/supi-core": "1.6.0",
23
- "@mrclrchtr/supi-lsp": "1.6.0",
24
- "@mrclrchtr/supi-tree-sitter": "1.6.0"
22
+ "@mrclrchtr/supi-core": "1.7.0",
23
+ "@mrclrchtr/supi-tree-sitter": "1.7.0",
24
+ "@mrclrchtr/supi-lsp": "1.7.0"
25
25
  },
26
26
  "bundledDependencies": [
27
27
  "@mrclrchtr/supi-core",
@@ -8,22 +8,15 @@ import {
8
8
  summarizePrioritySignalsForFiles,
9
9
  } from "../prioritization-signals.ts";
10
10
  import { getSemanticService } from "../providers/semantic-provider.ts";
11
+ import type { CodeQueryParams as ActionParams } from "../query-params.ts";
11
12
  import { resolveTarget } from "../resolve-target.ts";
12
- import {
13
- escapeRegex,
14
- filterOutDeclaration,
15
- isInProjectPath,
16
- normalizePath,
17
- runRipgrep,
18
- uriToFile,
19
- } from "../search-helpers.ts";
13
+ import { filterOutDeclaration, isInProjectPath, uriToFile } from "../search-helpers.ts";
20
14
  import {
21
15
  dedupeFileLineRefs,
22
16
  highestConfidence,
23
17
  isResolvedTargetGroup,
24
18
  } from "../semantic-action-helpers.ts";
25
19
  import type { ResolvedTarget, ResolvedTargetGroup } from "../target-resolution.ts";
26
- import type { ActionParams } from "../tool-actions.ts";
27
20
  import type { AffectedDetails, CodeIntelResult, ConfidenceMode } from "../types.ts";
28
21
 
29
22
  export async function executeAffectedAction(
@@ -89,7 +82,15 @@ async function executeSingleAffected(
89
82
  cwd,
90
83
  analysis.affectedFiles.size > 0 ? [...analysis.affectedFiles] : [target.file],
91
84
  );
92
- const content = formatAffectedOutput(symbolName, refs, analysis, params, prioritySignals);
85
+ const content = formatAffectedOutput(
86
+ symbolName,
87
+ refs,
88
+ analysis,
89
+ params,
90
+ prioritySignals,
91
+ target,
92
+ cwd,
93
+ );
93
94
  const details: AffectedDetails = {
94
95
  confidence: analysis.confidence,
95
96
  directCount: refs.refs.length,
@@ -98,10 +99,7 @@ async function executeSingleAffected(
98
99
  checkNext: analysis.checkNext,
99
100
  likelyTests: analysis.likelyTests,
100
101
  omittedCount: computeOmittedCount(analysis.externalRefs, analysis.affectedFiles.size, params),
101
- nextQueries: [
102
- "`code_intel brief` on the most-affected module for deeper context",
103
- `\`code_intel callers\` with \`symbol: "${symbolName}"\` for grouped call-site detail`,
104
- ],
102
+ nextQueries: buildAffectedNextQueries(target, symbolName, cwd),
105
103
  prioritySignals,
106
104
  };
107
105
  return { content, details: { type: "affected" as const, data: details } };
@@ -160,7 +158,7 @@ async function executeFileLevelAffected(
160
158
  addCheckNextSection(lines, analysis.checkNext);
161
159
  addTestsSection(lines, analysis.likelyTests);
162
160
  lines.push("## Next");
163
- lines.push("- `code_intel brief` on the most-affected module for deeper context");
161
+ lines.push("- `code_brief` on the most-affected module for deeper context");
164
162
  lines.push("- Use `file` + coordinates to inspect one exported target precisely");
165
163
  lines.push("");
166
164
 
@@ -173,7 +171,7 @@ async function executeFileLevelAffected(
173
171
  likelyTests: analysis.likelyTests,
174
172
  omittedCount: computeOmittedCount(analysis.externalRefs, analysis.affectedFiles.size, params),
175
173
  nextQueries: [
176
- "`code_intel brief` on the most-affected module for deeper context",
174
+ "`code_brief` on the most-affected module for deeper context",
177
175
  "Use `file` + coordinates to inspect one exported target precisely",
178
176
  ],
179
177
  prioritySignals,
@@ -182,45 +180,40 @@ async function executeFileLevelAffected(
182
180
  return { content: lines.join("\n"), details: { type: "affected" as const, data: details } };
183
181
  }
184
182
 
185
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: multi-source reference gathering with fallback logic
186
183
  async function gatherReferences(
187
184
  target: ResolvedTarget,
188
- params: ActionParams,
185
+ _params: ActionParams,
189
186
  cwd: string,
190
187
  ): Promise<{ refs: GatheredRef[]; confidence: ConfidenceMode; externalCount: number }> {
191
188
  const lsp = await getSemanticService(cwd, { waitForReady: true });
189
+ if (!lsp) {
190
+ return { refs: [], confidence: "unavailable", externalCount: 0 };
191
+ }
192
+
193
+ const lspRefs = await lsp.references(target.file, target.position);
194
+ if (lspRefs === null) {
195
+ return { refs: [], confidence: "unavailable", externalCount: 0 };
196
+ }
197
+
192
198
  const refs: GatheredRef[] = [];
193
199
  let externalCount = 0;
200
+ const filtered = filterOutDeclaration(lspRefs, target.file, target.position);
194
201
 
195
- if (lsp) {
196
- const lspRefs = await lsp.references(target.file, target.position);
197
- if (lspRefs && lspRefs.length > 0) {
198
- const filtered = filterOutDeclaration(lspRefs, target.file, target.position);
199
- for (const ref of filtered) {
200
- const filePath = uriToFile(ref.uri);
201
- if (isInProjectPath(filePath, cwd)) {
202
- refs.push({ file: path.relative(cwd, filePath), line: ref.range.start.line + 1 });
203
- } else {
204
- externalCount++;
205
- }
206
- }
207
- return { refs, confidence: "semantic", externalCount };
202
+ for (const ref of lspRefs) {
203
+ const filePath = uriToFile(ref.uri);
204
+ if (!isInProjectPath(filePath, cwd)) {
205
+ externalCount++;
208
206
  }
209
207
  }
210
208
 
211
- if (target.name) {
212
- const scopePath = params.path ? normalizePath(params.path, cwd) : cwd;
213
- const pattern = `\\b${escapeRegex(target.name)}\\b`;
214
- const matches = runRipgrep(pattern, scopePath, cwd, { maxMatches: 30 });
215
- for (const m of matches) {
216
- if (!isDeclarationMatch(m.file, m.line, target, cwd)) {
217
- refs.push({ file: path.relative(cwd, path.resolve(cwd, m.file)), line: m.line });
218
- }
209
+ for (const ref of filtered) {
210
+ const filePath = uriToFile(ref.uri);
211
+ if (isInProjectPath(filePath, cwd)) {
212
+ refs.push({ file: path.relative(cwd, filePath), line: ref.range.start.line + 1 });
219
213
  }
220
- return { refs, confidence: "heuristic", externalCount: 0 };
221
214
  }
222
215
 
223
- return { refs, confidence: "unavailable", externalCount: 0 };
216
+ return { refs, confidence: "semantic", externalCount };
224
217
  }
225
218
 
226
219
  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: impact analysis with downstream module traversal
@@ -303,6 +296,8 @@ function formatAffectedOutput(
303
296
  analysis: ImpactAnalysis,
304
297
  params: ActionParams,
305
298
  prioritySignals: import("../prioritization-signals.ts").PrioritySignalsSummary | null,
299
+ target: ResolvedTarget,
300
+ cwd: string,
306
301
  ): string {
307
302
  const totalRefs = result.refs.length + analysis.externalRefs;
308
303
  const lines: string[] = [];
@@ -328,7 +323,12 @@ function formatAffectedOutput(
328
323
  appendPrioritySignalsSection(lines, prioritySignals);
329
324
  addCheckNextSection(lines, analysis.checkNext);
330
325
  addTestsSection(lines, analysis.likelyTests);
331
- addAffectedNextQueries(lines, symbolName, analysis);
326
+ addAffectedNextQueries(lines, {
327
+ target,
328
+ symbolName,
329
+ showBriefQuery: analysis.checkNext.length > 0,
330
+ cwd,
331
+ });
332
332
 
333
333
  return lines.join("\n");
334
334
  }
@@ -416,24 +416,37 @@ function formatFileLevelAffectedHeader(
416
416
 
417
417
  function addAffectedNextQueries(
418
418
  lines: string[],
419
- symbolName: string,
420
- analysis: ImpactAnalysis,
419
+ options: {
420
+ target: ResolvedTarget;
421
+ symbolName: string;
422
+ showBriefQuery: boolean;
423
+ cwd: string;
424
+ },
421
425
  ): void {
422
426
  lines.push("## Next");
423
- if (analysis.checkNext.length > 0) {
424
- lines.push("- `code_intel brief` on the most-affected module for deeper context");
427
+ const nextQueries = buildAffectedNextQueries(options.target, options.symbolName, options.cwd);
428
+ if (options.showBriefQuery) {
429
+ lines.push(`- ${nextQueries[0]}`);
425
430
  }
426
- lines.push(
427
- `- \`code_intel callers\` with \`symbol: "${symbolName}"\` for grouped call-site detail`,
428
- );
431
+ lines.push(`- ${nextQueries[1]}`);
429
432
  lines.push("");
430
433
  }
431
434
 
432
- function isDeclarationMatch(
433
- file: string,
434
- line: number,
435
+ function buildAffectedNextQueries(
435
436
  target: ResolvedTarget,
437
+ symbolName: string,
436
438
  cwd: string,
437
- ): boolean {
438
- return path.resolve(cwd, file) === target.file && line === target.displayLine;
439
+ ): [string, string] {
440
+ const briefQuery = "`code_brief` on the most-affected module for deeper context";
441
+ if (target.name) {
442
+ return [
443
+ briefQuery,
444
+ `\`code_relations\` with \`kind: "callers"\` and \`symbol: "${symbolName}"\` for grouped call-site detail`,
445
+ ];
446
+ }
447
+
448
+ return [
449
+ briefQuery,
450
+ `\`code_relations\` with \`kind: "callers"\`, \`file: "${path.relative(cwd, target.file)}"\`, \`line: ${target.displayLine}\`, and \`character: ${target.displayCharacter}\` for grouped call-site detail`,
451
+ ];
439
452
  }
@@ -6,8 +6,13 @@ import type { TreeSitterService } from "@mrclrchtr/supi-tree-sitter/api";
6
6
  import { buildArchitectureModel, findModuleForPath } from "../architecture.ts";
7
7
  import { generateFocusedBrief, generateProjectBrief } from "../brief.ts";
8
8
  import { withStructuralSession } from "../providers/structural-provider.ts";
9
+ import type { CodeQueryParams as ActionParams } from "../query-params.ts";
9
10
  import { normalizePath } from "../search-helpers.ts";
10
- import type { ActionParams } from "../tool-actions.ts";
11
+ import {
12
+ type ResolvedTarget,
13
+ resolveSymbolTarget,
14
+ type TargetResolutionResult,
15
+ } from "../target-resolution.ts";
11
16
  import type { CodeIntelResult } from "../types.ts";
12
17
 
13
18
  export async function executeBriefAction(
@@ -52,14 +57,18 @@ export async function executeBriefAction(
52
57
  dependencySummary: mod && model ? { moduleCount: 1, edgeCount: 0 } : null,
53
58
  omittedCount: 0,
54
59
  nextQueries: [
55
- `\`code_intel callers\` with \`file: "${relPath}", line: ${params.line}, character: ${params.character}\` for call sites`,
56
- `\`code_intel affected\` with \`file: "${relPath}", line: ${params.line}, character: ${params.character}\` for impact analysis`,
60
+ `\`code_relations\` with \`kind: "callers"\`, \`file: "${relPath}"\`, \`line: ${params.line}\`, and \`character: ${params.character}\` for call sites`,
61
+ `\`code_affected\` with \`file: "${relPath}"\`, \`line: ${params.line}\`, and \`character: ${params.character}\` for impact analysis`,
57
62
  ],
58
63
  },
59
64
  },
60
65
  };
61
66
  }
62
67
 
68
+ if (params.symbol) {
69
+ return executeSymbolBrief(params, cwd, model);
70
+ }
71
+
63
72
  if (params.path) {
64
73
  const result = generateFocusedBrief(model, normalizePath(params.path, cwd));
65
74
  return { content: result.content, details: { type: "brief" as const, data: result.details } };
@@ -74,6 +83,29 @@ export async function executeBriefAction(
74
83
  return { content: result.content, details: { type: "brief" as const, data: result.details } };
75
84
  }
76
85
 
86
+ async function executeSymbolBrief(
87
+ params: ActionParams,
88
+ cwd: string,
89
+ model: NonNullable<Awaited<ReturnType<typeof buildArchitectureModel>>>,
90
+ ): Promise<CodeIntelResult> {
91
+ const symbol = params.symbol ?? "";
92
+ const resolved = await resolveSymbolTarget(symbol, cwd, { path: params.path });
93
+
94
+ if (resolved.kind === "error") {
95
+ return createUnavailableSymbolBriefResult(symbol, resolved.message);
96
+ }
97
+
98
+ if (resolved.kind === "disambiguation") {
99
+ return createUnavailableSymbolBriefResult(
100
+ symbol,
101
+ formatBriefDisambiguation(symbol, resolved),
102
+ resolved.omittedCount,
103
+ );
104
+ }
105
+
106
+ return buildResolvedSymbolBriefResult(resolved.target, cwd, model);
107
+ }
108
+
77
109
  async function executeAnchoredBrief(
78
110
  params: ActionParams,
79
111
  cwd: string,
@@ -99,6 +131,63 @@ async function executeAnchoredBrief(
99
131
  return lines.join("\n");
100
132
  }
101
133
 
134
+ async function buildResolvedSymbolBriefResult(
135
+ target: ResolvedTarget,
136
+ cwd: string,
137
+ model: NonNullable<Awaited<ReturnType<typeof buildArchitectureModel>>>,
138
+ ): Promise<CodeIntelResult> {
139
+ const relPath = path.relative(cwd, target.file);
140
+ const content = await executeResolvedSymbolBrief(target, cwd, model);
141
+ const mod = findModuleForPath(model, target.file);
142
+
143
+ return {
144
+ content,
145
+ details: {
146
+ type: "brief" as const,
147
+ data: {
148
+ confidence: target.confidence,
149
+ focusTarget: `${target.name ?? relPath}:${target.displayLine}:${target.displayCharacter}`,
150
+ startHere: [],
151
+ publicSurfaces: [],
152
+ dependencySummary: mod ? { moduleCount: 1, edgeCount: 0 } : null,
153
+ omittedCount: 0,
154
+ nextQueries: [
155
+ `\`code_relations\` with \`kind: "callers"\`, \`file: "${relPath}"\`, \`line: ${target.displayLine}\`, and \`character: ${target.displayCharacter}\` for call sites`,
156
+ `\`code_affected\` with \`file: "${relPath}"\`, \`line: ${target.displayLine}\`, and \`character: ${target.displayCharacter}\` for impact analysis`,
157
+ ],
158
+ },
159
+ },
160
+ };
161
+ }
162
+
163
+ async function executeResolvedSymbolBrief(
164
+ target: ResolvedTarget,
165
+ cwd: string,
166
+ model: NonNullable<Awaited<ReturnType<typeof buildArchitectureModel>>>,
167
+ ): Promise<string> {
168
+ const relPath = path.relative(cwd, target.file);
169
+ const lines: string[] = [];
170
+
171
+ lines.push(`# Symbol Brief: ${target.name ?? relPath}`);
172
+ lines.push("");
173
+ lines.push(
174
+ `**Resolved to:** \`${relPath}:${target.displayLine}:${target.displayCharacter}\`${target.kind ? ` (${target.kind})` : ""}`,
175
+ );
176
+ lines.push("");
177
+
178
+ await addTreeSitterContext({
179
+ lines,
180
+ relPath,
181
+ line1: target.displayLine,
182
+ char1: target.displayCharacter,
183
+ cwd,
184
+ });
185
+ addModuleContext(lines, model, target.file);
186
+ addNextQueries(lines, relPath, target.displayLine, target.displayCharacter);
187
+
188
+ return lines.join("\n");
189
+ }
190
+
102
191
  interface TreeSitterContextInput {
103
192
  lines: string[];
104
193
  relPath: string;
@@ -232,10 +321,58 @@ function addModuleContext(
232
321
  function addNextQueries(lines: string[], relPath: string, line1: number, char1: number): void {
233
322
  lines.push("## Next");
234
323
  lines.push(
235
- `- \`code_intel callers\` with \`file: "${relPath}", line: ${line1}, character: ${char1}\` for call sites`,
324
+ `- \`code_relations\` with \`kind: "callers"\`, \`file: "${relPath}"\`, \`line: ${line1}\`, and \`character: ${char1}\` for call sites`,
325
+ );
326
+ lines.push(
327
+ `- \`code_affected\` with \`file: "${relPath}"\`, \`line: ${line1}\`, and \`character: ${char1}\` for impact analysis`,
236
328
  );
329
+ lines.push("");
330
+ }
331
+
332
+ function createUnavailableSymbolBriefResult(
333
+ symbol: string,
334
+ content: string,
335
+ omittedCount = 0,
336
+ ): CodeIntelResult {
337
+ return {
338
+ content,
339
+ details: {
340
+ type: "brief" as const,
341
+ data: {
342
+ confidence: "unavailable",
343
+ focusTarget: symbol,
344
+ startHere: [],
345
+ publicSurfaces: [],
346
+ dependencySummary: null,
347
+ omittedCount,
348
+ nextQueries: [
349
+ "Use `file` + coordinates for a precise symbol brief, or enable LSP and retry",
350
+ ],
351
+ },
352
+ },
353
+ };
354
+ }
355
+
356
+ function formatBriefDisambiguation(
357
+ symbol: string,
358
+ result: Extract<TargetResolutionResult, { kind: "disambiguation" }>,
359
+ ): string {
360
+ const lines: string[] = [];
361
+ lines.push(`# Disambiguation needed for \`${symbol}\``);
362
+ lines.push("");
363
+ const omitNote = result.omittedCount > 0 ? ` (+${result.omittedCount} more)` : "";
237
364
  lines.push(
238
- `- \`code_intel affected\` with \`file: "${relPath}", line: ${line1}, character: ${char1}\` for impact analysis`,
365
+ `Found ${result.candidates.length} candidates${omitNote}. Rerun with anchored coordinates:`,
239
366
  );
240
367
  lines.push("");
368
+
369
+ for (const candidate of result.candidates) {
370
+ const kind = candidate.kind ? ` (${candidate.kind})` : "";
371
+ const container = candidate.container ? ` in ${candidate.container}` : "";
372
+ lines.push(
373
+ `${candidate.rank}. **${candidate.name}**${kind}${container} — \`${candidate.file}\`:${candidate.line}:${candidate.character}`,
374
+ );
375
+ }
376
+
377
+ return lines.join("\n");
241
378
  }
@@ -4,9 +4,9 @@
4
4
 
5
5
  import * as path from "node:path";
6
6
  import { withStructuralSession } from "../providers/structural-provider.ts";
7
+ import type { CodeQueryParams as ActionParams } from "../query-params.ts";
7
8
  import { resolveTarget } from "../resolve-target.ts";
8
9
  import { isResolvedTargetGroup } from "../semantic-action-helpers.ts";
9
- import type { ActionParams } from "../tool-actions.ts";
10
10
  import type { CodeIntelResult, SearchDetails } from "../types.ts";
11
11
 
12
12
  export async function executeCalleesAction(
@@ -2,22 +2,15 @@
2
2
 
3
3
  import * as path from "node:path";
4
4
  import { getSemanticService } from "../providers/semantic-provider.ts";
5
+ import type { CodeQueryParams as ActionParams } from "../query-params.ts";
5
6
  import { resolveTarget } from "../resolve-target.ts";
6
- import {
7
- escapeRegex,
8
- filterOutDeclaration,
9
- isInProjectPath,
10
- normalizePath,
11
- runRipgrep,
12
- uriToFile,
13
- } from "../search-helpers.ts";
7
+ import { filterOutDeclaration, isInProjectPath, uriToFile } from "../search-helpers.ts";
14
8
  import {
15
9
  dedupeFileLineRefs,
16
10
  highestConfidence,
17
11
  isResolvedTargetGroup,
18
12
  } from "../semantic-action-helpers.ts";
19
13
  import type { ResolvedTarget, ResolvedTargetGroup } from "../target-resolution.ts";
20
- import type { ActionParams } from "../tool-actions.ts";
21
14
  import type { CodeIntelResult, ConfidenceMode, SearchDetails } from "../types.ts";
22
15
 
23
16
  export async function executeCallersAction(
@@ -59,8 +52,8 @@ export async function executeCallersAction(
59
52
  candidateCount: result.candidateCount,
60
53
  omittedCount: result.externalCount,
61
54
  nextQueries: [
62
- "`code_intel affected` for impact analysis",
63
- "`code_intel pattern` with broader scope for additional matches",
55
+ "`code_affected` for impact analysis",
56
+ "Use `code_pattern` only when you explicitly want text-search hints",
64
57
  ],
65
58
  };
66
59
  return { content, details: { type: "search" as const, data: details } };
@@ -76,7 +69,7 @@ export async function executeCallersAction(
76
69
  scope: params.path ?? null,
77
70
  candidateCount: 0,
78
71
  omittedCount: 0,
79
- nextQueries: ["Enable LSP for `semantic` caller accuracy"],
72
+ nextQueries: ["Use `code_affected` before editing a broadly referenced target"],
80
73
  },
81
74
  },
82
75
  };
@@ -84,7 +77,7 @@ export async function executeCallersAction(
84
77
 
85
78
  const relPath = path.relative(cwd, target.file);
86
79
  return {
87
- content: `No caller data available for ${relPath}:${target.displayLine}:${target.displayCharacter}. LSP may not be active.\n\nTry \`code_intel pattern\` with the symbol name for text-search matches.`,
80
+ content: `No caller data available for ${relPath}:${target.displayLine}:${target.displayCharacter}.`,
88
81
  details: {
89
82
  type: "search" as const,
90
83
  data: {
@@ -92,7 +85,7 @@ export async function executeCallersAction(
92
85
  scope: params.path ?? null,
93
86
  candidateCount: 0,
94
87
  omittedCount: 0,
95
- nextQueries: ["Enable LSP for semantic caller resolution, or try `code_intel pattern`"],
88
+ nextQueries: ["Enable LSP for semantic caller resolution or use `code_pattern` explicitly"],
96
89
  },
97
90
  },
98
91
  };
@@ -124,8 +117,8 @@ async function executeFileLevelCallers(
124
117
 
125
118
  const withRefs = perTarget.filter((entry) => entry.result.refs.length > 0);
126
119
  const uniqueRefs = dedupeFileLineRefs(withRefs.flatMap((entry) => entry.result.refs));
127
- const confidence = highestConfidence(withRefs.map((entry) => entry.result.confidence));
128
- const externalCount = withRefs.reduce((sum, entry) => sum + entry.result.externalCount, 0);
120
+ const confidence = highestConfidence(perTarget.map((entry) => entry.result.confidence));
121
+ const externalCount = perTarget.reduce((sum, entry) => sum + entry.result.externalCount, 0);
129
122
 
130
123
  const lines: string[] = [];
131
124
  lines.push(`# Callers in \`${targetGroup.displayName}\``);
@@ -155,7 +148,7 @@ async function executeFileLevelCallers(
155
148
  candidateCount: uniqueRefs.length,
156
149
  omittedCount: externalCount,
157
150
  nextQueries: [
158
- "`code_intel affected` for impact analysis",
151
+ "`code_affected` for impact analysis",
159
152
  "Use `file` + coordinates to drill into one symbol precisely",
160
153
  ],
161
154
  };
@@ -163,58 +156,45 @@ async function executeFileLevelCallers(
163
156
  return { content: lines.join("\n"), details: { type: "search" as const, data: details } };
164
157
  }
165
158
 
166
- // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: LSP-first caller collection with fallback and declaration filtering is clearest in one helper
167
159
  async function collectCallerRefs(
168
160
  target: ResolvedTarget,
169
- params: ActionParams,
161
+ _params: ActionParams,
170
162
  cwd: string,
171
163
  ): Promise<CallerCollection> {
172
164
  const lsp = await getSemanticService(cwd, { waitForReady: true });
173
-
174
- if (lsp) {
175
- const refs = await lsp.references(target.file, target.position);
176
- if (refs && refs.length > 0) {
177
- const filtered = filterOutDeclaration(refs, target.file, target.position);
178
- const projectRefs: CallerRef[] = [];
179
- let externalCount = 0;
180
- for (const ref of refs) {
181
- const filePath = uriToFile(ref.uri);
182
- if (!isInProjectPath(filePath, cwd)) {
183
- externalCount++;
184
- }
185
- }
186
- for (const ref of filtered) {
187
- const filePath = uriToFile(ref.uri);
188
- if (isInProjectPath(filePath, cwd)) {
189
- projectRefs.push({ file: path.relative(cwd, filePath), line: ref.range.start.line + 1 });
190
- }
191
- }
192
- if (projectRefs.length > 0) {
193
- return {
194
- refs: projectRefs,
195
- confidence: "semantic",
196
- externalCount,
197
- candidateCount: projectRefs.length,
198
- };
199
- }
200
- }
165
+ if (!lsp) {
166
+ return { refs: [], confidence: "unavailable", externalCount: 0, candidateCount: 0 };
201
167
  }
202
168
 
203
- if (!target.name) {
169
+ const refs = await lsp.references(target.file, target.position);
170
+ if (refs === null) {
204
171
  return { refs: [], confidence: "unavailable", externalCount: 0, candidateCount: 0 };
205
172
  }
206
173
 
207
- const scopePath = params.path ? normalizePath(params.path, cwd) : cwd;
208
- const pattern = `\\b${escapeRegex(target.name)}\\b`;
209
- const matches = runRipgrep(pattern, scopePath, cwd, { maxMatches: (params.maxResults ?? 8) * 3 });
210
- const refs = matches
211
- .filter((match) => !isDeclarationMatch(match.file, match.line, target, cwd))
212
- .map((match) => ({
213
- file: path.relative(cwd, path.resolve(cwd, match.file)),
214
- line: match.line,
215
- }));
174
+ const filtered = filterOutDeclaration(refs, target.file, target.position);
175
+ const projectRefs: CallerRef[] = [];
176
+ let externalCount = 0;
177
+
178
+ for (const ref of refs) {
179
+ const filePath = uriToFile(ref.uri);
180
+ if (!isInProjectPath(filePath, cwd)) {
181
+ externalCount++;
182
+ }
183
+ }
184
+
185
+ for (const ref of filtered) {
186
+ const filePath = uriToFile(ref.uri);
187
+ if (isInProjectPath(filePath, cwd)) {
188
+ projectRefs.push({ file: path.relative(cwd, filePath), line: ref.range.start.line + 1 });
189
+ }
190
+ }
216
191
 
217
- return { refs, confidence: "heuristic", externalCount: 0, candidateCount: refs.length };
192
+ return {
193
+ refs: projectRefs,
194
+ confidence: "semantic",
195
+ externalCount,
196
+ candidateCount: projectRefs.length,
197
+ };
218
198
  }
219
199
 
220
200
  function formatTargetCallers(
@@ -271,12 +251,3 @@ function groupRefsByFile(refs: CallerRef[], _cwd: string): Map<string, number[]>
271
251
  }
272
252
  return byFile;
273
253
  }
274
-
275
- function isDeclarationMatch(
276
- file: string,
277
- line: number,
278
- target: ResolvedTarget,
279
- cwd: string,
280
- ): boolean {
281
- return path.resolve(cwd, file) === target.file && line === target.displayLine;
282
- }