@shanepadgett/tau-agent 0.33.1 → 0.34.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 (190) hide show
  1. package/docs/context.md +29 -20
  2. package/docs/extending-tau-agent.md +63 -24
  3. package/extensions/appshot/index.ts +112 -111
  4. package/extensions/aside/README.md +7 -0
  5. package/extensions/aside/index.ts +168 -0
  6. package/extensions/aside/panel.ts +83 -0
  7. package/extensions/branch/index.ts +38 -21
  8. package/extensions/cache-diagnostics/index.ts +70 -58
  9. package/extensions/checkpoint/README.md +9 -0
  10. package/extensions/checkpoint/checkpoint-budget.ts +79 -0
  11. package/extensions/checkpoint/checkpoint.ts +277 -0
  12. package/extensions/checkpoint/index.ts +102 -0
  13. package/extensions/checkpoint/messages.ts +169 -0
  14. package/extensions/checkpoint/prompt.ts +24 -0
  15. package/extensions/checkpoint/settings.ts +27 -0
  16. package/extensions/commit/commit-effort.ts +3 -3
  17. package/extensions/context/README.md +12 -8
  18. package/extensions/context/definitions.ts +178 -55
  19. package/extensions/context/index.ts +192 -160
  20. package/extensions/context/panel.ts +57 -37
  21. package/extensions/context/sync.ts +139 -89
  22. package/extensions/context/validation.ts +37 -25
  23. package/extensions/effort/README.md +1 -1
  24. package/extensions/effort/index.ts +3 -3
  25. package/extensions/effort/state.ts +3 -18
  26. package/extensions/explore/guidance.ts +6 -47
  27. package/extensions/explore/index.ts +38 -53
  28. package/extensions/explore/{ast/read → read}/hook.ts +12 -7
  29. package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
  30. package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
  31. package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
  32. package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
  33. package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
  34. package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
  35. package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
  36. package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
  37. package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
  38. package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
  39. package/extensions/explore/tools/target-params.ts +9 -0
  40. package/extensions/footer/index.ts +75 -56
  41. package/extensions/handoff/index.ts +8 -30
  42. package/extensions/image-gen/index.ts +46 -40
  43. package/extensions/patch/executor.ts +190 -135
  44. package/extensions/patch/matcher.ts +82 -48
  45. package/extensions/patch/parser.ts +149 -105
  46. package/extensions/patch/render.ts +32 -39
  47. package/extensions/patch/summary.ts +30 -26
  48. package/extensions/ready/README.md +7 -0
  49. package/extensions/ready/index.ts +58 -0
  50. package/extensions/ready/model.ts +128 -0
  51. package/extensions/ready/packs.ts +272 -0
  52. package/extensions/ready/render.ts +445 -0
  53. package/extensions/ready/scan.ts +760 -0
  54. package/extensions/reference/panel.ts +28 -16
  55. package/extensions/review/index.ts +63 -51
  56. package/extensions/review/panel.ts +5 -34
  57. package/extensions/runtime-context/context.ts +30 -26
  58. package/extensions/script-runner/README.md +2 -2
  59. package/extensions/script-runner/index.ts +122 -82
  60. package/extensions/silent-command-runner/index.ts +38 -23
  61. package/extensions/subagent/agents/context-sync.md +185 -33
  62. package/extensions/subagent/agents/scout.md +2 -2
  63. package/extensions/subagent/agents.ts +137 -84
  64. package/extensions/subagent/cmux-dashboard.ts +39 -30
  65. package/extensions/subagent/index.ts +79 -59
  66. package/extensions/subagent/resume.ts +1 -1
  67. package/extensions/subagent/run.ts +304 -193
  68. package/extensions/subagent/runtime.ts +781 -343
  69. package/extensions/tau/index.ts +47 -38
  70. package/extensions/tau-help/help.md +14 -6
  71. package/extensions/tool-loader/README.md +4 -2
  72. package/extensions/tool-loader/index.ts +77 -52
  73. package/extensions/web/index.ts +6 -3
  74. package/extensions/web/webfetch.ts +114 -86
  75. package/package.json +3 -3
  76. package/schemas/tau.schema.json +20 -33
  77. package/shared/bounded-text-result.ts +1 -0
  78. package/shared/checkpoint-visibility.ts +9 -0
  79. package/shared/events.ts +28 -10
  80. package/shared/isolated-session.ts +71 -29
  81. package/shared/model-effort.ts +9 -19
  82. package/shared/model-fallback/index.ts +66 -41
  83. package/shared/settings/load.ts +45 -38
  84. package/shared/temporary-output-store.ts +16 -10
  85. package/{extensions/explore → src}/ast/adapter.ts +11 -2
  86. package/{extensions/explore → src}/ast/engine.ts +54 -38
  87. package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
  88. package/{extensions/explore → src}/ast/format/context.ts +3 -6
  89. package/src/ast/format/deps.ts +94 -0
  90. package/{extensions/explore → src}/ast/format/discover.ts +2 -2
  91. package/{extensions/explore → src}/ast/format/impact.ts +9 -11
  92. package/{extensions/explore → src}/ast/format/outline.ts +2 -2
  93. package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
  94. package/{extensions/explore → src}/ast/format/show.ts +1 -1
  95. package/src/ast/format/targeted-result.ts +20 -0
  96. package/src/ast/grammars/c_sharp.wasm +0 -0
  97. package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
  98. package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
  99. package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
  100. package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
  101. package/{extensions/explore → src}/ast/ir.ts +6 -0
  102. package/src/ast/languages/csharp-file-deps.ts +90 -0
  103. package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
  104. package/src/ast/languages/dotted-index.ts +131 -0
  105. package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
  106. package/src/ast/languages/fixtures/sample.cs +53 -0
  107. package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
  108. package/src/ast/languages/fixtures/sample.go +37 -0
  109. package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
  110. package/src/ast/languages/fixtures/sample.java +40 -0
  111. package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
  112. package/src/ast/languages/fixtures/sample.kt +31 -0
  113. package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
  114. package/src/ast/languages/fixtures/sample.md +23 -0
  115. package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
  116. package/src/ast/languages/fixtures/sample.rs +54 -0
  117. package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
  118. package/src/ast/languages/fixtures/sample.swift +45 -0
  119. package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
  120. package/src/ast/languages/fixtures/sample.ts +45 -0
  121. package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
  122. package/src/ast/languages/fixtures/sample.tsx +36 -0
  123. package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
  124. package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
  125. package/{extensions/explore → src}/ast/languages/go.ts +21 -3
  126. package/{extensions/explore → src}/ast/languages/java.ts +5 -38
  127. package/src/ast/languages/jvm-file-deps.ts +135 -0
  128. package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
  129. package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
  130. package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
  131. package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
  132. package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
  133. package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
  134. package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
  135. package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
  136. package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
  137. package/{extensions/explore → src}/ast/markdown.ts +72 -47
  138. package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
  139. package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
  140. package/{extensions/explore → src}/ast/queries/context.ts +116 -80
  141. package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
  142. package/src/ast/queries/impact.ts +291 -0
  143. package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
  144. package/{extensions/explore → src}/ast/queries/show.ts +46 -42
  145. package/{extensions/explore → src}/ast/query.ts +1 -1
  146. package/{extensions/explore → src}/ast/registry.ts +1 -2
  147. package/{extensions/explore → src}/ast/scan.ts +1 -1
  148. package/src/ast/session.ts +50 -0
  149. package/{extensions/explore → src}/ast/slice.ts +8 -0
  150. package/{extensions/explore → src/ast}/traverse.ts +32 -20
  151. package/src/file-injection/index.ts +547 -0
  152. package/src/image-generation/client.ts +50 -31
  153. package/src/image-generation/index.ts +177 -134
  154. package/src/index.ts +2 -0
  155. package/src/tool-loading/index.ts +58 -0
  156. package/extensions/context/evidence.ts +0 -517
  157. package/extensions/context/projection.ts +0 -141
  158. package/extensions/context/state.ts +0 -30
  159. package/extensions/context/write-scope.ts +0 -109
  160. package/extensions/explore/ast/format/deps.ts +0 -86
  161. package/extensions/explore/ast/grammars/odin.wasm +0 -0
  162. package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
  163. package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
  164. package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
  165. package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
  166. package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
  167. package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
  168. package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
  169. package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
  170. package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
  171. package/extensions/explore/ast/languages/odin.ts +0 -407
  172. package/extensions/explore/ast/queries/impact.ts +0 -250
  173. package/extensions/explore/outline-injection.ts +0 -151
  174. package/extensions/explore/read/autoread.ts +0 -118
  175. package/extensions/working-memory/README.md +0 -17
  176. package/extensions/working-memory/checkpoint.ts +0 -242
  177. package/extensions/working-memory/index.ts +0 -341
  178. package/extensions/working-memory/memory.ts +0 -235
  179. package/extensions/working-memory/render.ts +0 -185
  180. package/extensions/working-memory/settings.ts +0 -38
  181. package/extensions/working-memory/state.ts +0 -158
  182. package/shared/autoread.ts +0 -234
  183. package/shared/context-messages.ts +0 -19
  184. package/shared/outline-injection.ts +0 -56
  185. /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
  186. /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
  187. /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
  188. /package/{extensions/explore → src}/ast/identity.ts +0 -0
  189. /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
  190. /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
@@ -1,5 +1,5 @@
1
1
  import type { Tree } from "web-tree-sitter";
2
- import type { Decl, ImportRef } from "./ir.ts";
2
+ import type { CallSite, Decl, ImportRef } from "./ir.ts";
3
3
  import type { PackageSurfaceResolver } from "./package-surface.ts";
4
4
 
5
5
  export type LanguageCapabilities = {
@@ -8,6 +8,8 @@ export type LanguageCapabilities = {
8
8
  fileDeps: boolean;
9
9
  callEdges: boolean;
10
10
  packageSurface: boolean;
11
+ /** Interfaces are satisfied by method set, not by naming them (Go). */
12
+ structuralImplements: boolean;
11
13
  };
12
14
 
13
15
  /**
@@ -25,11 +27,18 @@ export type AstSearchPatternContext = {
25
27
  export type ExtractResult = {
26
28
  decls: Decl[];
27
29
  imports: ImportRef[];
30
+ /** Call sites in top-level statements — outside any declaration body. */
31
+ fileCalls: CallSite[];
28
32
  };
29
33
 
30
- /** Result of adapter-owned import specifier → file resolution. */
34
+ /**
35
+ * Result of adapter-owned import specifier → file resolution.
36
+ * `package` is an in-repo directory too large to list file by file — distinct
37
+ * from `external`, which means "not in this repository".
38
+ */
31
39
  export type FileDepResolution =
32
40
  | { kind: "internal"; paths: string[] }
41
+ | { kind: "package"; id: string; dir: string; fileCount: number }
33
42
  | { kind: "external"; id: string }
34
43
  | { kind: "unresolved" };
35
44
 
@@ -13,7 +13,7 @@ import type { AdapterRegistry } from "./registry.ts";
13
13
  import { createDefaultRegistry } from "./registry.ts";
14
14
  import type { FileIr } from "./ir.ts";
15
15
  import { grammarWasmPath, loadGrammarManifest, runtimeWasmPath, type GrammarPin } from "./grammars/manifest.ts";
16
- import { formatPathForDisplay, pathResolutionError, resolveExplorePath } from "../traverse.ts";
16
+ import { formatPathForDisplay, pathResolutionError, resolveExplorePath } from "./traverse.ts";
17
17
 
18
18
  export type FileSource = {
19
19
  ir: FileIr;
@@ -95,6 +95,40 @@ function pinById(id: string): GrammarPin {
95
95
  return pin;
96
96
  }
97
97
 
98
+ function isMetaVarStart(c: string): boolean {
99
+ return (c >= "A" && c <= "Z") || c === "_";
100
+ }
101
+
102
+ function isMetaVarContinue(c: string): boolean {
103
+ return isMetaVarStart(c) || (c >= "0" && c <= "9");
104
+ }
105
+
106
+ function pushUniqueName(list: string[], name: string): void {
107
+ if (!list.includes(name)) list.push(name);
108
+ }
109
+
110
+ /** Read `$NAME` / `$$$NAME` starting at `start` (must point at `$`). */
111
+ function readMetaVarAt(pattern: string, start: number): { dollars: number; name: string; next: number } {
112
+ let i = start;
113
+ let dollars = 0;
114
+ while (i < pattern.length && pattern[i] === "$") {
115
+ dollars += 1;
116
+ i += 1;
117
+ }
118
+ let name = "";
119
+ while (i < pattern.length) {
120
+ const c = pattern[i];
121
+ if (c === undefined) break;
122
+ if ((name.length === 0 && isMetaVarStart(c)) || (name.length > 0 && isMetaVarContinue(c))) {
123
+ name += c;
124
+ i += 1;
125
+ continue;
126
+ }
127
+ break;
128
+ }
129
+ return { dollars, name, next: i };
130
+ }
131
+
98
132
  /** ast-grep metavars: `$NAME` one node, `$$$NAME` sibling sequence. Skip `$_`. */
99
133
  function metaVarNames(pattern: string): { singles: string[]; multis: string[] } {
100
134
  const singles: string[] = [];
@@ -105,30 +139,11 @@ function metaVarNames(pattern: string): { singles: string[]; multis: string[] }
105
139
  i += 1;
106
140
  continue;
107
141
  }
108
- let dollars = 0;
109
- while (i < pattern.length && pattern[i] === "$") {
110
- dollars += 1;
111
- i += 1;
112
- }
113
- let name = "";
114
- while (i < pattern.length) {
115
- const c = pattern[i];
116
- if (c === undefined) break;
117
- const isAlpha = (c >= "A" && c <= "Z") || c === "_";
118
- const isAlnum = isAlpha || (c >= "0" && c <= "9");
119
- if ((name.length === 0 && isAlpha) || (name.length > 0 && isAlnum)) {
120
- name += c;
121
- i += 1;
122
- continue;
123
- }
124
- break;
125
- }
142
+ const { dollars, name, next } = readMetaVarAt(pattern, i);
143
+ i = next;
126
144
  if (name.length === 0 || name === "_") continue;
127
- if (dollars >= 3) {
128
- if (!multis.includes(name)) multis.push(name);
129
- } else if (dollars === 1) {
130
- if (!singles.includes(name)) singles.push(name);
131
- }
145
+ if (dollars >= 3) pushUniqueName(multis, name);
146
+ else if (dollars === 1) pushUniqueName(singles, name);
132
147
  }
133
148
  return { singles, multis };
134
149
  }
@@ -228,6 +243,17 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
228
243
  }
229
244
  };
230
245
 
246
+ const requireSearchableAdapter = (languageId: string) => {
247
+ const adapter = registry.adapterForId(languageId);
248
+ if (adapter === undefined) {
249
+ throw new Error(`Unregistered language: ${languageId}`);
250
+ }
251
+ if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
252
+ throw new Error(`Language does not support structural search: ${languageId}`);
253
+ }
254
+ return adapter;
255
+ };
256
+
231
257
  const ensureReady = async (): Promise<Parser> => {
232
258
  assertLive();
233
259
  if (parser !== undefined) return parser;
@@ -257,13 +283,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
257
283
  const ensureSearchLanguage = async (languageId: string): Promise<void> => {
258
284
  assertLive();
259
285
  if (searchLangReady.has(languageId)) return;
260
- const adapter = registry.adapterForId(languageId);
261
- if (adapter === undefined) {
262
- throw new Error(`Unregistered language: ${languageId}`);
263
- }
264
- if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
265
- throw new Error(`Language does not support structural search: ${languageId}`);
266
- }
286
+ requireSearchableAdapter(languageId);
267
287
  await ensureSearchReady();
268
288
  assertLive();
269
289
  await registerDynamicLanguage({
@@ -320,6 +340,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
320
340
  lineCount,
321
341
  decls: extracted.decls,
322
342
  imports: extracted.imports,
343
+ fileCalls: extracted.fileCalls,
323
344
  parseDegraded: false,
324
345
  };
325
346
  }
@@ -342,6 +363,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
342
363
  lineCount,
343
364
  decls: extracted.decls,
344
365
  imports: extracted.imports,
366
+ fileCalls: extracted.fileCalls,
345
367
  parseDegraded: tree.rootNode.hasError,
346
368
  };
347
369
  } finally {
@@ -386,13 +408,7 @@ export function createExploreEngine(options: ExploreEngineOptions): ExploreEngin
386
408
 
387
409
  async searchInSource(languageId: string, source: string, pattern: string): Promise<AstSearchHit[]> {
388
410
  assertLive();
389
- const adapter = registry.adapterForId(languageId);
390
- if (adapter === undefined) {
391
- throw new Error(`Unregistered language: ${languageId}`);
392
- }
393
- if (adapter.mode !== "grammar" || !adapter.capabilities.search) {
394
- throw new Error(`Language does not support structural search: ${languageId}`);
395
- }
411
+ const adapter = requireSearchableAdapter(languageId);
396
412
  await ensureSearchLanguage(languageId);
397
413
  assertLive();
398
414
 
@@ -1,27 +1,36 @@
1
1
  import type { AstSearchMatch, AstSearchResult } from "../queries/ast-search.ts";
2
2
  import type { ScanOutcome } from "../scan.ts";
3
- import type { TraversalLimit } from "../../traverse.ts";
4
- import { formatPathForDisplay } from "../../traverse.ts";
3
+ import type { TraversalLimit } from "../traverse.ts";
4
+ import { formatPathForDisplay } from "../traverse.ts";
5
5
 
6
6
  function lineRange(startLine: number, endLine: number): string {
7
7
  return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
8
8
  }
9
9
 
10
+ /** Head-retained line budget per match. resultLimit caps match count, not match size. */
11
+ const MATCH_MAX_LINES = 12;
12
+
10
13
  function formatMatchRows(match: AstSearchMatch): string[] {
11
14
  const lines: string[] = [];
12
15
  const preview = match.text.length > 0 ? match.text : "(empty)";
13
16
  const previewLines = preview.split("\n");
14
17
  const first = previewLines[0] ?? "(empty)";
15
18
  lines.push(`${lineRange(match.startLine, match.endLine)} ${first}`);
16
- for (let i = 1; i < previewLines.length; i += 1) {
19
+ const shown = Math.min(previewLines.length, MATCH_MAX_LINES);
20
+ for (let i = 1; i < shown; i += 1) {
17
21
  lines.push(` ${previewLines[i] ?? ""}`);
18
22
  }
23
+ if (previewLines.length > shown) {
24
+ lines.push(` ... +${previewLines.length - shown} lines`);
25
+ }
19
26
  for (const binding of match.bindings) {
20
27
  const bindLines = binding.text.split("\n");
21
- lines.push(` $${binding.name} = ${bindLines[0] ?? ""}`);
22
- for (let i = 1; i < bindLines.length; i += 1) {
23
- lines.push(` ${bindLines[i] ?? ""}`);
28
+ // A multi-line capture is a span, not a value — report its size.
29
+ if (bindLines.length > 1) {
30
+ lines.push(` $${binding.name} = <${bindLines.length} lines>`);
31
+ continue;
24
32
  }
33
+ lines.push(` $${binding.name} = ${bindLines[0] ?? ""}`);
25
34
  }
26
35
  if (match.enclosing !== undefined) {
27
36
  lines.push(` in ${match.enclosing.kind} ${match.enclosing.name} L${match.enclosing.startLine}`);
@@ -1,7 +1,7 @@
1
- import { formatPathForDisplay } from "../../traverse.ts";
1
+ import { formatPathForDisplay } from "../traverse.ts";
2
2
  import type { ContextEntry, ContextGroup, ContextResult, ContextTarget } from "../queries/context.ts";
3
3
  import { compositeSectionBlocks, type CompositeBlock } from "./composite.ts";
4
- import { formatCandidateList } from "./relationships.ts";
4
+ import { formatTargetedResult } from "./targeted-result.ts";
5
5
 
6
6
  function formatTargetHeader(target: ContextTarget, budget: number, used: number, cwd: string): string {
7
7
  const path = formatPathForDisplay(target.path, cwd);
@@ -43,10 +43,7 @@ function formatResolved(result: Extract<ContextResult, { kind: "resolved" }>, cw
43
43
  }
44
44
 
45
45
  export function formatContextResult(result: ContextResult, cwd: string): string {
46
- if (result.kind === "error") return result.message;
47
- if (result.kind === "notFound") return "No matching declaration.";
48
- if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
49
- return formatResolved(result, cwd);
46
+ return formatTargetedResult(result, cwd, formatResolved);
50
47
  }
51
48
 
52
49
  export function contextSectionBlocks(
@@ -0,0 +1,94 @@
1
+ import type { FileDepQueryResult } from "../graph/file-graph.ts";
2
+ import { formatPathForDisplay } from "../traverse.ts";
3
+
4
+ function depthPrefix(depth: number, showDepth: boolean): string {
5
+ return showDepth ? `d${depth} ` : "";
6
+ }
7
+
8
+ function commonDirPrefixLength(split: readonly string[][]): number {
9
+ const first = split[0];
10
+ if (first === undefined || split.length <= 1) return 0;
11
+ let common = 0;
12
+ while (common < first.length - 1) {
13
+ const part = first[common];
14
+ if (part === undefined) break;
15
+ if (!split.every((parts) => parts[common] === part)) break;
16
+ common += 1;
17
+ }
18
+ return common;
19
+ }
20
+
21
+ /** Factor shared directory prefixes into a small indent tree. */
22
+ function formatInternalTree(rows: readonly { depth: number; display: string }[], showDepth: boolean): string[] {
23
+ if (rows.length === 0) return [];
24
+
25
+ const split = rows.map((row) => row.display.split("/"));
26
+ const common = commonDirPrefixLength(split);
27
+ const first = split[0];
28
+ const lines: string[] = [];
29
+ if (common > 0 && first !== undefined) {
30
+ lines.push(first.slice(0, common).join("/"));
31
+ }
32
+
33
+ for (let i = 0; i < rows.length; i += 1) {
34
+ const row = rows[i];
35
+ const parts = split[i];
36
+ if (row === undefined || parts === undefined) continue;
37
+ const leaf = common > 0 ? parts.slice(common).join("/") : row.display;
38
+ const indent = common > 0 ? " " : "";
39
+ lines.push(`${indent}${depthPrefix(row.depth, showDepth)}${leaf}`);
40
+ }
41
+ return lines;
42
+ }
43
+
44
+ export function formatDepsResult(result: FileDepQueryResult, cwd: string, emptyLabel: string): string {
45
+ const showDepth = result.depth > 1;
46
+ const inRepo: { depth: number; display: string }[] = [];
47
+ const external: { depth: number; id: string }[] = [];
48
+ for (const hit of result.hits) {
49
+ if (hit.kind === "internal") {
50
+ inRepo.push({ depth: hit.depth, display: formatPathForDisplay(hit.path, cwd) });
51
+ continue;
52
+ }
53
+ if (hit.kind === "package") {
54
+ // In-repo directory, listed as a package because file-by-file would flood.
55
+ inRepo.push({
56
+ depth: hit.depth,
57
+ display: `${formatPathForDisplay(hit.dir, cwd)}/ (${hit.fileCount} files)`,
58
+ });
59
+ continue;
60
+ }
61
+ external.push({ depth: hit.depth, id: hit.id });
62
+ }
63
+
64
+ if (inRepo.length === 0 && external.length === 0) {
65
+ return emptyLabel;
66
+ }
67
+
68
+ const lines: string[] = [];
69
+ lines.push(...formatInternalTree(inRepo, showDepth));
70
+
71
+ if (external.length > 0) {
72
+ lines.push("external:");
73
+ for (const hit of external) {
74
+ lines.push(` ${depthPrefix(hit.depth, showDepth)}${hit.id}`);
75
+ }
76
+ }
77
+ if (result.externalOmitted > 0) {
78
+ lines.push(` +${result.externalOmitted} more external`);
79
+ }
80
+
81
+ if (result.resultLimitReached) {
82
+ lines.push(`omitted (result limit ${result.resultLimit})`);
83
+ }
84
+
85
+ return lines.join("\n");
86
+ }
87
+
88
+ export function formatDepsEmpty(): string {
89
+ return "No file dependencies";
90
+ }
91
+
92
+ export function formatReverseDepsEmpty(): string {
93
+ return "No reverse file dependencies";
94
+ }
@@ -1,7 +1,7 @@
1
1
  import type { DiscoverCandidate, DiscoverResult } from "../queries/discover.ts";
2
2
  import type { ScanOutcome } from "../scan.ts";
3
- import type { TraversalLimit } from "../../traverse.ts";
4
- import { formatPathForDisplay } from "../../traverse.ts";
3
+ import type { TraversalLimit } from "../traverse.ts";
4
+ import { formatPathForDisplay } from "../traverse.ts";
5
5
 
6
6
  function lineRange(startLine: number, endLine: number): string {
7
7
  return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
@@ -1,7 +1,7 @@
1
- import { formatPathForDisplay } from "../../traverse.ts";
1
+ import { formatPathForDisplay } from "../traverse.ts";
2
2
  import type { ImpactFileRow, ImpactResult, ImpactSection, ImpactSiteRow, ImpactTarget } from "../queries/impact.ts";
3
3
  import { compositeSectionBlocks, type CompositeBlock } from "./composite.ts";
4
- import { formatCandidateList } from "./relationships.ts";
4
+ import { formatTargetedResult } from "./targeted-result.ts";
5
5
 
6
6
  function formatTargetHeader(target: ImpactTarget, cwd: string): string {
7
7
  const path = formatPathForDisplay(target.path, cwd);
@@ -17,10 +17,11 @@ function formatSiteRow(row: ImpactSiteRow): string {
17
17
 
18
18
  function formatFileRow(row: ImpactFileRow, cwd: string, showDepth: boolean): string {
19
19
  const depth = showDepth ? `d${row.depth} ` : "";
20
- if (row.path !== undefined) {
21
- return ` ${depth}${formatPathForDisplay(row.path, cwd)}`;
20
+ if (row.target.kind === "internal") return ` ${depth}${formatPathForDisplay(row.target.path, cwd)}`;
21
+ if (row.target.kind === "package") {
22
+ return ` ${depth}${formatPathForDisplay(row.target.dir, cwd)}/ (${row.target.fileCount} files)`;
22
23
  }
23
- return ` ${depth}${row.externalId ?? "?"}`;
24
+ return ` ${depth}${row.target.id}`;
24
25
  }
25
26
 
26
27
  function formatSection(section: ImpactSection, cwd: string): string[] {
@@ -41,8 +42,8 @@ function formatSection(section: ImpactSection, cwd: string): string[] {
41
42
  }
42
43
 
43
44
  if (fileRows.length > 0) {
44
- const internal = fileRows.filter((row) => row.path !== undefined);
45
- const external = fileRows.filter((row) => row.externalId !== undefined);
45
+ const internal = fileRows.filter((row) => row.target.kind !== "external");
46
+ const external = fileRows.filter((row) => row.target.kind === "external");
46
47
  for (const row of internal) {
47
48
  lines.push(formatFileRow(row, cwd, showDepth));
48
49
  }
@@ -80,10 +81,7 @@ function formatResolved(result: Extract<ImpactResult, { kind: "resolved" }>, cwd
80
81
  }
81
82
 
82
83
  export function formatImpactResult(result: ImpactResult, cwd: string): string {
83
- if (result.kind === "error") return result.message;
84
- if (result.kind === "notFound") return "No matching declaration.";
85
- if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
86
- return formatResolved(result, cwd);
84
+ return formatTargetedResult(result, cwd, formatResolved);
87
85
  }
88
86
 
89
87
  export function impactSectionBlocks(
@@ -1,7 +1,7 @@
1
1
  import type { OutlineFileView, OutlineRow } from "../queries/outline.ts";
2
2
  import type { ScanOutcome } from "../scan.ts";
3
- import type { TraversalLimit } from "../../traverse.ts";
4
- import { formatPathForDisplay } from "../../traverse.ts";
3
+ import type { TraversalLimit } from "../traverse.ts";
4
+ import { formatPathForDisplay } from "../traverse.ts";
5
5
 
6
6
  function lineRange(startLine: number, endLine: number): string {
7
7
  return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
@@ -1,13 +1,19 @@
1
1
  import type { Candidate } from "../identity.ts";
2
2
  import type { RelationshipQueryResult, RelationshipSite, RelationshipTarget } from "../graph/relationships.ts";
3
- import { formatPathForDisplay } from "../../traverse.ts";
3
+ import { compactSignature } from "../slice.ts";
4
+ import { formatPathForDisplay } from "../traverse.ts";
5
+
6
+ function candidateParts(candidate: Candidate, cwd: string): { path: string; signature: string } {
7
+ return {
8
+ path: formatPathForDisplay(candidate.path, cwd),
9
+ signature: compactSignature(candidate.signature),
10
+ };
11
+ }
4
12
 
5
13
  function formatCompetitors(competitors: readonly Candidate[], cwd: string): string[] {
6
14
  const lines: string[] = [];
7
15
  for (const c of competitors) {
8
- const path = formatPathForDisplay(c.path, cwd);
9
- const sig = c.signature.replace(/\s+/gu, " ").trim();
10
- const short = sig.length > 80 ? `${sig.slice(0, 77)}...` : sig;
16
+ const { path, signature: short } = candidateParts(c, cwd);
11
17
  lines.push(` - ${path}:${c.startLine} ${c.kind} ${c.qualifiedName || c.name} ${short}`);
12
18
  }
13
19
  return lines;
@@ -57,9 +63,7 @@ function formatResolved(
57
63
  export function formatCandidateList(candidates: readonly Candidate[], cwd: string): string {
58
64
  const lines = ["Ambiguous target — disambiguate with targetPath or line:", ""];
59
65
  for (const c of candidates) {
60
- const path = formatPathForDisplay(c.path, cwd);
61
- const sig = c.signature.replace(/\s+/gu, " ").trim();
62
- const short = sig.length > 80 ? `${sig.slice(0, 77)}...` : sig;
66
+ const { path, signature: short } = candidateParts(c, cwd);
63
67
  lines.push(`${path}:${c.startLine} ${c.kind} ${c.qualifiedName || c.name}`);
64
68
  if (short.length > 0) lines.push(` ${short}`);
65
69
  }
@@ -1,5 +1,5 @@
1
1
  import type { ShowBatch, ShowBlock } from "../queries/show.ts";
2
- import { formatPathForDisplay } from "../../traverse.ts";
2
+ import { formatPathForDisplay } from "../traverse.ts";
3
3
 
4
4
  function lineRange(startLine: number, endLine: number): string {
5
5
  return startLine === endLine ? `L${startLine}` : `L${startLine}-${endLine}`;
@@ -0,0 +1,20 @@
1
+ import type { Candidate } from "../identity.ts";
2
+ import { formatCandidateList } from "./relationships.ts";
3
+
4
+ type TargetedResult<Resolved extends { kind: "resolved" }> =
5
+ | Resolved
6
+ | { kind: "candidates"; candidates: Candidate[] }
7
+ | { kind: "notFound" }
8
+ | { kind: "error"; message: string };
9
+
10
+ /** Shared dispatch for query results that resolve one declaration target. */
11
+ export function formatTargetedResult<Resolved extends { kind: "resolved" }>(
12
+ result: TargetedResult<Resolved>,
13
+ cwd: string,
14
+ formatResolved: (resolved: Resolved, cwd: string) => string,
15
+ ): string {
16
+ if (result.kind === "error") return result.message;
17
+ if (result.kind === "notFound") return "No matching declaration.";
18
+ if (result.kind === "candidates") return formatCandidateList(result.candidates, cwd);
19
+ return formatResolved(result, cwd);
20
+ }
Binary file
@@ -1,14 +1,20 @@
1
1
  {
2
2
  "webTreeSitter": "0.26.11",
3
3
  "vscodeTreeSitterWasm": "0.3.1",
4
- "treeSitterCli": "0.26.11",
5
- "wasiSdk": "wasi-sdk-29",
6
4
  "grammars": [
7
5
  { "id": "typescript", "source": "vscode", "file": "tree-sitter-typescript.wasm" },
8
6
  { "id": "tsx", "source": "vscode", "file": "tree-sitter-tsx.wasm" },
9
7
  { "id": "go", "source": "vscode", "file": "tree-sitter-go.wasm" },
10
8
  { "id": "rust", "source": "vscode", "file": "tree-sitter-rust.wasm" },
11
- { "id": "c_sharp", "source": "vscode", "file": "tree-sitter-c-sharp.wasm" },
9
+ {
10
+ "id": "c_sharp",
11
+ "source": "release",
12
+ "file": "c_sharp.wasm",
13
+ "repo": "https://github.com/tree-sitter/tree-sitter-c-sharp",
14
+ "tag": "v0.23.5",
15
+ "rev": "cac6d5fb595f5811a076336682d5d595ac1c9e85",
16
+ "url": "https://github.com/tree-sitter/tree-sitter-c-sharp/releases/download/v0.23.5/tree-sitter-c_sharp.wasm"
17
+ },
12
18
  { "id": "java", "source": "vscode", "file": "tree-sitter-java.wasm" },
13
19
  {
14
20
  "id": "kotlin",
@@ -27,15 +33,6 @@
27
33
  "tag": "0.7.3",
28
34
  "rev": "b8b22bffbb3441780e6471665bacfb263741c86a",
29
35
  "url": "https://github.com/alex-pinkus/tree-sitter-swift/releases/download/0.7.3/tree-sitter-swift.wasm"
30
- },
31
- {
32
- "id": "odin",
33
- "source": "built",
34
- "file": "odin.wasm",
35
- "repo": "https://github.com/tree-sitter-grammars/tree-sitter-odin",
36
- "tag": "v1.3.0",
37
- "rev": "e8adc739b78409a99f8c31313f0bb54cc538cf73",
38
- "subdir": "."
39
36
  }
40
37
  ]
41
38
  }
@@ -34,8 +34,6 @@ export type GrammarPin = VscodeGrammarPin | BuiltGrammarPin | ReleaseGrammarPin;
34
34
  export type GrammarManifest = {
35
35
  webTreeSitter: string;
36
36
  vscodeTreeSitterWasm: string;
37
- treeSitterCli: string;
38
- wasiSdk: string;
39
37
  grammars: GrammarPin[];
40
38
  };
41
39
 
@@ -92,8 +90,6 @@ export function loadGrammarManifest(): GrammarManifest {
92
90
  return {
93
91
  webTreeSitter: requireString(root, "webTreeSitter", "root"),
94
92
  vscodeTreeSitterWasm: requireString(root, "vscodeTreeSitterWasm", "root"),
95
- treeSitterCli: requireString(root, "treeSitterCli", "root"),
96
- wasiSdk: requireString(root, "wasiSdk", "root"),
97
93
  grammars: root.grammars.map(parseGrammarPin),
98
94
  };
99
95
  }