@shanepadgett/tau-agent 0.27.0 → 0.28.1

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 (113) hide show
  1. package/extensions/context/sync.ts +1 -9
  2. package/extensions/context-pruning/prune.ts +2 -2
  3. package/extensions/explore/README.md +13 -21
  4. package/extensions/explore/ast/adapter.ts +97 -0
  5. package/extensions/explore/ast/engine.ts +470 -0
  6. package/extensions/explore/ast/format/ast-search.ts +97 -0
  7. package/extensions/explore/ast/format/composite.ts +26 -0
  8. package/extensions/explore/ast/format/context.ts +66 -0
  9. package/extensions/explore/ast/format/deps.ts +86 -0
  10. package/extensions/explore/ast/format/discover.ts +85 -0
  11. package/extensions/explore/ast/format/impact.ts +105 -0
  12. package/extensions/explore/ast/format/outline.ts +66 -0
  13. package/extensions/explore/ast/format/relationships.ts +81 -0
  14. package/extensions/explore/ast/format/show.ts +38 -0
  15. package/extensions/explore/ast/grammars/kotlin.wasm +0 -0
  16. package/extensions/explore/ast/grammars/manifest.json +41 -0
  17. package/extensions/explore/ast/grammars/manifest.ts +99 -0
  18. package/extensions/explore/ast/grammars/odin.wasm +0 -0
  19. package/extensions/explore/ast/grammars/swift.wasm +0 -0
  20. package/extensions/explore/ast/graph/file-graph.ts +360 -0
  21. package/extensions/explore/ast/graph/relationships.ts +597 -0
  22. package/extensions/explore/ast/identity.ts +119 -0
  23. package/extensions/explore/ast/ir.ts +136 -0
  24. package/extensions/explore/ast/languages/csharp-file-deps.ts +189 -0
  25. package/extensions/explore/ast/languages/csharp.ts +493 -0
  26. package/extensions/explore/ast/languages/file-dep-util.ts +120 -0
  27. package/extensions/explore/ast/languages/fixtures/sample.cs +17 -0
  28. package/extensions/explore/ast/languages/fixtures/sample.java +21 -0
  29. package/extensions/explore/ast/languages/fixtures/sample.kt +15 -0
  30. package/extensions/explore/ast/languages/fixtures/sample.odin +28 -0
  31. package/extensions/explore/ast/languages/fixtures/sample.rs +31 -0
  32. package/extensions/explore/ast/languages/fixtures/sample.swift +25 -0
  33. package/extensions/explore/ast/languages/go-file-deps.ts +139 -0
  34. package/extensions/explore/ast/languages/go.ts +545 -0
  35. package/extensions/explore/ast/languages/java.ts +412 -0
  36. package/extensions/explore/ast/languages/jvm-file-deps.ts +217 -0
  37. package/extensions/explore/ast/languages/kotlin.ts +611 -0
  38. package/extensions/explore/ast/languages/odin-file-deps.ts +175 -0
  39. package/extensions/explore/ast/languages/odin.ts +407 -0
  40. package/extensions/explore/ast/languages/rust-file-deps.ts +159 -0
  41. package/extensions/explore/ast/languages/rust.ts +506 -0
  42. package/extensions/explore/ast/languages/swift-file-deps.ts +59 -0
  43. package/extensions/explore/ast/languages/swift.ts +466 -0
  44. package/extensions/explore/ast/languages/tree.ts +220 -0
  45. package/extensions/explore/ast/languages/typescript-file-deps.ts +259 -0
  46. package/extensions/explore/ast/languages/typescript-package-surface.ts +440 -0
  47. package/extensions/explore/ast/languages/typescript.ts +751 -0
  48. package/extensions/explore/ast/markdown.ts +145 -0
  49. package/extensions/explore/ast/package-surface.ts +42 -0
  50. package/extensions/explore/ast/queries/ast-search.ts +306 -0
  51. package/extensions/explore/ast/queries/composite-target.ts +77 -0
  52. package/extensions/explore/ast/queries/context.ts +406 -0
  53. package/extensions/explore/ast/queries/discover.ts +427 -0
  54. package/extensions/explore/ast/queries/impact.ts +250 -0
  55. package/extensions/explore/ast/queries/outline.ts +203 -0
  56. package/extensions/explore/ast/queries/show.ts +262 -0
  57. package/extensions/explore/ast/query.ts +48 -0
  58. package/extensions/explore/ast/read/hook.ts +125 -0
  59. package/extensions/explore/ast/read/policy.ts +55 -0
  60. package/extensions/explore/ast/registry.ts +120 -0
  61. package/extensions/explore/ast/scan.ts +76 -0
  62. package/extensions/explore/ast/slice.ts +44 -0
  63. package/extensions/explore/ast/tools/ast-search.ts +138 -0
  64. package/extensions/explore/ast/tools/context.ts +126 -0
  65. package/extensions/explore/ast/tools/deps.ts +72 -0
  66. package/extensions/explore/ast/tools/discover.ts +208 -0
  67. package/extensions/explore/ast/tools/impact.ts +135 -0
  68. package/extensions/explore/ast/tools/outline.ts +200 -0
  69. package/extensions/explore/ast/tools/relationships.ts +160 -0
  70. package/extensions/explore/ast/tools/render.ts +121 -0
  71. package/extensions/explore/ast/tools/reverse-deps.ts +72 -0
  72. package/extensions/explore/ast/tools/show.ts +116 -0
  73. package/extensions/explore/guidance.ts +52 -0
  74. package/extensions/explore/index.ts +82 -92
  75. package/extensions/explore/read/autoread.ts +118 -0
  76. package/extensions/explore/settings.ts +49 -31
  77. package/extensions/explore/traverse.ts +254 -91
  78. package/extensions/handoff/index.ts +1 -1
  79. package/extensions/publish/index.ts +18 -85
  80. package/extensions/publish/publish-ui.ts +0 -4
  81. package/extensions/soul/README.md +7 -4
  82. package/extensions/soul/index.ts +11 -5
  83. package/extensions/soul/prompt.ts +31 -13
  84. package/extensions/soul/settings.ts +7 -2
  85. package/extensions/subagent/agents/context-sync.md +6 -10
  86. package/extensions/subagent/agents/review.md +24 -55
  87. package/extensions/subagent/agents/scout.md +38 -115
  88. package/extensions/subagent/run.ts +1 -1
  89. package/extensions/tau-help/help.md +2 -4
  90. package/package.json +6 -4
  91. package/schemas/tau.schema.json +35 -30
  92. package/{extensions/explore → shared}/autoread.ts +21 -7
  93. package/shared/events.ts +1 -1
  94. package/shared/full-file-knowledge.ts +49 -0
  95. package/extensions/explore/ast-guidance.ts +0 -67
  96. package/extensions/explore/ast-languages.ts +0 -61
  97. package/extensions/explore/ast-tools.ts +0 -1994
  98. package/extensions/explore/ast-worker.ts +0 -1025
  99. package/extensions/explore/find.ts +0 -147
  100. package/extensions/explore/full-file-knowledge.ts +0 -234
  101. package/extensions/explore/grep.ts +0 -749
  102. package/extensions/explore/limits.ts +0 -22
  103. package/extensions/explore/ls.ts +0 -113
  104. package/extensions/explore/orientation-state.ts +0 -280
  105. package/extensions/explore/path-display.ts +0 -41
  106. package/extensions/explore/path-tree.ts +0 -150
  107. package/extensions/explore/read-cache.ts +0 -273
  108. package/extensions/explore/read-snapshots.ts +0 -57
  109. package/extensions/explore/read-stats-panel.ts +0 -176
  110. package/extensions/explore/read-stats.ts +0 -138
  111. package/extensions/explore/read.ts +0 -372
  112. package/extensions/explore/result.ts +0 -29
  113. package/native-bin/darwin-arm64/tau-ast +0 -0
@@ -0,0 +1,406 @@
1
+ import type { ExploreEngine } from "../engine.ts";
2
+ import type { Candidate } from "../identity.ts";
3
+ import { resolveTarget } from "../identity.ts";
4
+ import { isCallableLike, isTypeLike, type Decl, type DeclKind, type FileIr } from "../ir.ts";
5
+ import { walkDecls } from "../query.ts";
6
+ import type { ExploreFileGraph } from "../graph/file-graph.ts";
7
+ import { queryRelationships, type RelationshipSite } from "../graph/relationships.ts";
8
+ import { resolveCompositeTarget, type CompositeTarget } from "./composite-target.ts";
9
+ import { extractShowView } from "./show.ts";
10
+
11
+ const CONTEXT_REL_LIMIT = 20;
12
+ const CONTEXT_FOLLOWUP_N = 8;
13
+ const CONTEXT_METHOD_CAP = 12;
14
+
15
+ export type ContextFlag = "truncated" | "target_omitted" | "body_unavailable";
16
+
17
+ export type ContextEntry = {
18
+ path: string;
19
+ name: string;
20
+ qualifiedName: string;
21
+ kind: DeclKind;
22
+ startLine: number;
23
+ text: string;
24
+ tokens: number;
25
+ view: "body" | "signature";
26
+ flags: ContextFlag[];
27
+ };
28
+
29
+ export type ContextGroupId =
30
+ | "target"
31
+ | "callees"
32
+ | "callers"
33
+ | "calleesDepth2"
34
+ | "callersDepth2"
35
+ | "implementors"
36
+ | "methods"
37
+ | "dependents";
38
+
39
+ export type ContextGroup = {
40
+ id: ContextGroupId;
41
+ label: string;
42
+ entries: ContextEntry[];
43
+ };
44
+
45
+ export type ContextTarget = CompositeTarget;
46
+
47
+ export type ContextResult =
48
+ | {
49
+ kind: "resolved";
50
+ target: ContextTarget;
51
+ budget: number;
52
+ used: number;
53
+ groups: ContextGroup[];
54
+ truncated: boolean;
55
+ }
56
+ | { kind: "candidates"; candidates: Candidate[] }
57
+ | { kind: "notFound" }
58
+ | { kind: "error"; message: string };
59
+
60
+ export type ContextQueryArgs = {
61
+ engine: ExploreEngine;
62
+ graph: ExploreFileGraph;
63
+ scopePath: string;
64
+ targetPath: string | undefined;
65
+ name: string;
66
+ line: number | undefined;
67
+ budget: number;
68
+ signal: AbortSignal;
69
+ };
70
+
71
+ type DeclSnap = {
72
+ path: string;
73
+ decl: Decl;
74
+ ir: FileIr;
75
+ source: string;
76
+ };
77
+
78
+ function tokenEstimate(text: string): number {
79
+ return Math.ceil(text.length / 4);
80
+ }
81
+
82
+ function snapKey(snap: DeclSnap): string {
83
+ return `${snap.path}\0${snap.decl.qualifiedName || snap.decl.name}\0${snap.decl.startLine}`;
84
+ }
85
+
86
+ function entryFrom(snap: DeclSnap, view: "body" | "signature", flags: ContextFlag[]): ContextEntry {
87
+ const showView = view === "body" ? "declaration" : "signature";
88
+ const block = extractShowView(snap.decl, snap.path, snap.ir, snap.source, showView);
89
+ return {
90
+ path: snap.path,
91
+ name: snap.decl.name,
92
+ qualifiedName: snap.decl.qualifiedName,
93
+ kind: snap.decl.kind,
94
+ startLine: snap.decl.startLine,
95
+ text: block.text,
96
+ tokens: tokenEstimate(block.text),
97
+ view,
98
+ flags,
99
+ };
100
+ }
101
+
102
+ function bodyUnavailable(snap: DeclSnap): boolean {
103
+ if (snap.decl.bodyStartOffset === undefined) {
104
+ if (isTypeLike(snap.decl.kind)) {
105
+ return snap.decl.endOffset <= snap.decl.signatureEndOffset;
106
+ }
107
+ return true;
108
+ }
109
+ return snap.decl.bodyEndOffset !== undefined && snap.decl.bodyEndOffset <= snap.decl.bodyStartOffset;
110
+ }
111
+
112
+ function tryPackEntry(
113
+ snap: DeclSnap,
114
+ budgetLeft: number,
115
+ preferBody: boolean,
116
+ ): { entry: ContextEntry | undefined; truncated: boolean } {
117
+ if (preferBody && !bodyUnavailable(snap)) {
118
+ const body = entryFrom(snap, "body", []);
119
+ if (body.tokens <= budgetLeft && body.text.length > 0) {
120
+ return { entry: body, truncated: false };
121
+ }
122
+ }
123
+
124
+ const flags: ContextFlag[] = [];
125
+ if (preferBody && bodyUnavailable(snap)) flags.push("body_unavailable");
126
+ const signature = entryFrom(snap, "signature", flags);
127
+ if (signature.tokens <= budgetLeft && signature.text.length > 0) {
128
+ return { entry: signature, truncated: false };
129
+ }
130
+ return { entry: undefined, truncated: true };
131
+ }
132
+
133
+ function declCoveringLine(
134
+ ir: FileIr,
135
+ source: string,
136
+ path: string,
137
+ line: number,
138
+ pred: (decl: Decl) => boolean,
139
+ ): DeclSnap | undefined {
140
+ let best: Decl | undefined;
141
+ walkDecls(ir.decls, (decl) => {
142
+ if (!pred(decl)) return;
143
+ if (line < decl.startLine || line > decl.endLine) return;
144
+ if (best === undefined) {
145
+ best = decl;
146
+ return;
147
+ }
148
+ const bestSpan = best.endLine - best.startLine;
149
+ const span = decl.endLine - decl.startLine;
150
+ if (span < bestSpan) best = decl;
151
+ });
152
+ if (best === undefined) return undefined;
153
+ return { path, decl: best, ir, source };
154
+ }
155
+
156
+ async function snapsFromSites(
157
+ engine: ExploreEngine,
158
+ sites: readonly RelationshipSite[],
159
+ signal: AbortSignal,
160
+ pred: (decl: Decl) => boolean,
161
+ ): Promise<DeclSnap[]> {
162
+ const out: DeclSnap[] = [];
163
+ const seen = new Set<string>();
164
+ for (const site of sites) {
165
+ signal.throwIfAborted();
166
+ const file = await engine.sourceForFile(site.path);
167
+ const snap = declCoveringLine(file.ir, file.source, site.path, site.line, pred);
168
+ if (snap === undefined) continue;
169
+ const key = snapKey(snap);
170
+ if (seen.has(key)) continue;
171
+ seen.add(key);
172
+ out.push(snap);
173
+ }
174
+ return out;
175
+ }
176
+
177
+ async function snapsFromCalleeSites(
178
+ engine: ExploreEngine,
179
+ scopeDir: string,
180
+ sites: readonly RelationshipSite[],
181
+ signal: AbortSignal,
182
+ ): Promise<DeclSnap[]> {
183
+ const out: DeclSnap[] = [];
184
+ const seen = new Set<string>();
185
+ const seenNames = new Set<string>();
186
+ for (const site of sites) {
187
+ signal.throwIfAborted();
188
+ if (site.name.length === 0 || seenNames.has(site.name)) continue;
189
+ seenNames.add(site.name);
190
+ const resolution = await resolveTarget(engine, scopeDir, { name: site.name }, signal);
191
+ if (resolution.kind !== "resolved") continue;
192
+ const item: DeclSnap = {
193
+ path: resolution.path,
194
+ decl: resolution.decl,
195
+ ir: resolution.ir,
196
+ source: resolution.source,
197
+ };
198
+ const key = snapKey(item);
199
+ if (seen.has(key)) continue;
200
+ seen.add(key);
201
+ out.push(item);
202
+ }
203
+ return out;
204
+ }
205
+
206
+ async function relSites(
207
+ args: ContextQueryArgs,
208
+ op: "callees" | "callers" | "implementations",
209
+ target: ContextTarget,
210
+ ): Promise<RelationshipSite[]> {
211
+ const result = await queryRelationships({
212
+ engine: args.engine,
213
+ graph: args.graph,
214
+ scopePath: args.scopePath,
215
+ op,
216
+ targetPath: target.path,
217
+ name: target.name,
218
+ line: target.startLine,
219
+ resultLimit: CONTEXT_REL_LIMIT,
220
+ signal: args.signal,
221
+ });
222
+ if (result.kind !== "resolved") return [];
223
+ return result.sites;
224
+ }
225
+
226
+ type PackState = {
227
+ budget: number;
228
+ used: number;
229
+ truncated: boolean;
230
+ seen: Set<string>;
231
+ groups: ContextGroup[];
232
+ };
233
+
234
+ function packInto(
235
+ state: PackState,
236
+ id: ContextGroupId,
237
+ label: string,
238
+ snaps: readonly DeclSnap[],
239
+ preferBody: boolean,
240
+ ): void {
241
+ const entries: ContextEntry[] = [];
242
+ for (const snap of snaps) {
243
+ const key = snapKey(snap);
244
+ if (state.seen.has(key)) continue;
245
+ const left = state.budget - state.used;
246
+ if (left <= 0) {
247
+ state.truncated = true;
248
+ break;
249
+ }
250
+ const packed = tryPackEntry(snap, left, preferBody);
251
+ if (packed.entry === undefined) {
252
+ state.truncated = true;
253
+ continue;
254
+ }
255
+ state.seen.add(key);
256
+ state.used += packed.entry.tokens;
257
+ entries.push(packed.entry);
258
+ }
259
+ if (entries.length > 0) {
260
+ state.groups.push({ id, label, entries });
261
+ }
262
+ }
263
+
264
+ function packTarget(state: PackState, snap: DeclSnap): void {
265
+ const left = state.budget - state.used;
266
+ const preferBody = !bodyUnavailable(snap);
267
+ if (preferBody) {
268
+ const body = entryFrom(snap, "body", []);
269
+ if (body.tokens <= left && body.text.length > 0) {
270
+ state.seen.add(snapKey(snap));
271
+ state.used += body.tokens;
272
+ state.groups.push({ id: "target", label: "target", entries: [body] });
273
+ return;
274
+ }
275
+ }
276
+ const flags: ContextFlag[] = ["target_omitted"];
277
+ if (bodyUnavailable(snap)) flags.push("body_unavailable");
278
+ const signature = entryFrom(snap, "signature", flags);
279
+ if (signature.tokens <= left && signature.text.length > 0) {
280
+ state.seen.add(snapKey(snap));
281
+ state.used += signature.tokens;
282
+ state.groups.push({ id: "target", label: "target", entries: [signature] });
283
+ return;
284
+ }
285
+ state.truncated = true;
286
+ }
287
+
288
+ /**
289
+ * Budgeted symbol pack. Bodies/signatures via show view extraction.
290
+ * Depth-2 is a capped second resolve+query pass — no relationship depth param.
291
+ */
292
+ export async function queryContext(args: ContextQueryArgs): Promise<ContextResult> {
293
+ const { engine, signal } = args;
294
+ if (args.budget < 1) {
295
+ return { kind: "error", message: "budget must be >= 1" };
296
+ }
297
+
298
+ const resolved = await resolveCompositeTarget(
299
+ engine,
300
+ args.scopePath,
301
+ args.targetPath,
302
+ args.name,
303
+ args.line,
304
+ "context",
305
+ signal,
306
+ );
307
+ if (resolved.kind !== "resolved") return resolved;
308
+
309
+ const { scopeDir, target, decl, ir, source } = resolved.value;
310
+ const targetSnap: DeclSnap = { path: target.path, decl, ir, source };
311
+ const kind = target.kind;
312
+ const state: PackState = {
313
+ budget: args.budget,
314
+ used: 0,
315
+ truncated: false,
316
+ seen: new Set<string>(),
317
+ groups: [],
318
+ };
319
+
320
+ packTarget(state, targetSnap);
321
+
322
+ if (isCallableLike(kind)) {
323
+ const calleeSites = await relSites(args, "callees", target);
324
+ const calleeSnaps = await snapsFromCalleeSites(engine, scopeDir, calleeSites, signal);
325
+ packInto(state, "callees", "direct callees", calleeSnaps, true);
326
+
327
+ const callerSites = await relSites(args, "callers", target);
328
+ const callerSnaps = await snapsFromSites(engine, callerSites, signal, (d) => isCallableLike(d.kind));
329
+ packInto(state, "callers", "direct callers", callerSnaps, false);
330
+
331
+ let followUps = 0;
332
+ const depth2Callees: DeclSnap[] = [];
333
+ for (const snap of calleeSnaps) {
334
+ if (followUps >= CONTEXT_FOLLOWUP_N || state.used >= state.budget) break;
335
+ signal.throwIfAborted();
336
+ followUps += 1;
337
+ const sites = await relSites(args, "callees", {
338
+ path: snap.path,
339
+ name: snap.decl.name,
340
+ qualifiedName: snap.decl.qualifiedName,
341
+ kind: snap.decl.kind,
342
+ startLine: snap.decl.startLine,
343
+ });
344
+ for (const item of await snapsFromCalleeSites(engine, scopeDir, sites, signal)) {
345
+ if (!state.seen.has(snapKey(item))) depth2Callees.push(item);
346
+ }
347
+ }
348
+ packInto(state, "calleesDepth2", "depth-2 callees", depth2Callees, false);
349
+
350
+ const depth2Callers: DeclSnap[] = [];
351
+ for (const snap of callerSnaps) {
352
+ if (followUps >= CONTEXT_FOLLOWUP_N || state.used >= state.budget) break;
353
+ signal.throwIfAborted();
354
+ followUps += 1;
355
+ const sites = await relSites(args, "callers", {
356
+ path: snap.path,
357
+ name: snap.decl.name,
358
+ qualifiedName: snap.decl.qualifiedName,
359
+ kind: snap.decl.kind,
360
+ startLine: snap.decl.startLine,
361
+ });
362
+ for (const item of await snapsFromSites(engine, sites, signal, (d) => isCallableLike(d.kind))) {
363
+ if (!state.seen.has(snapKey(item))) depth2Callers.push(item);
364
+ }
365
+ }
366
+ packInto(state, "callersDepth2", "depth-2 callers", depth2Callers, false);
367
+ } else {
368
+ const implSites = await relSites(args, "implementations", target);
369
+ const implSnaps = await snapsFromSites(engine, implSites, signal, (d) => isTypeLike(d.kind));
370
+ packInto(state, "implementors", "implementors", implSnaps, true);
371
+
372
+ const methods: DeclSnap[] = [];
373
+ for (const child of decl.children) {
374
+ if (!isCallableLike(child.kind)) continue;
375
+ if (methods.length >= CONTEXT_METHOD_CAP) break;
376
+ methods.push({ path: target.path, decl: child, ir, source });
377
+ }
378
+ packInto(state, "methods", "methods", methods, true);
379
+
380
+ const dependents: DeclSnap[] = [];
381
+ for (const method of methods) {
382
+ if (state.used >= state.budget) break;
383
+ signal.throwIfAborted();
384
+ const sites = await relSites(args, "callers", {
385
+ path: method.path,
386
+ name: method.decl.name,
387
+ qualifiedName: method.decl.qualifiedName,
388
+ kind: method.decl.kind,
389
+ startLine: method.decl.startLine,
390
+ });
391
+ for (const item of await snapsFromSites(engine, sites, signal, (d) => isCallableLike(d.kind))) {
392
+ if (!state.seen.has(snapKey(item))) dependents.push(item);
393
+ }
394
+ }
395
+ packInto(state, "dependents", "dependents", dependents, false);
396
+ }
397
+
398
+ return {
399
+ kind: "resolved",
400
+ target,
401
+ budget: state.budget,
402
+ used: state.used,
403
+ groups: state.groups,
404
+ truncated: state.truncated,
405
+ };
406
+ }