@shanepadgett/tau-agent 0.26.0 → 0.28.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 (121) hide show
  1. package/docs/subagents.md +1 -1
  2. package/extensions/appshot/README.md +1 -1
  3. package/extensions/appshot/index.ts +5 -11
  4. package/extensions/context/sync.ts +1 -9
  5. package/extensions/context-pruning/README.md +2 -2
  6. package/extensions/context-pruning/index.ts +58 -57
  7. package/extensions/context-pruning/prune.ts +2 -2
  8. package/extensions/context-pruning/render.ts +51 -39
  9. package/extensions/context-pruning/settings.ts +4 -5
  10. package/extensions/explore/README.md +13 -14
  11. package/extensions/explore/ast/adapter.ts +97 -0
  12. package/extensions/explore/ast/engine.ts +470 -0
  13. package/extensions/explore/ast/format/ast-search.ts +97 -0
  14. package/extensions/explore/ast/format/composite.ts +26 -0
  15. package/extensions/explore/ast/format/context.ts +66 -0
  16. package/extensions/explore/ast/format/deps.ts +86 -0
  17. package/extensions/explore/ast/format/discover.ts +85 -0
  18. package/extensions/explore/ast/format/impact.ts +105 -0
  19. package/extensions/explore/ast/format/outline.ts +66 -0
  20. package/extensions/explore/ast/format/relationships.ts +81 -0
  21. package/extensions/explore/ast/format/show.ts +38 -0
  22. package/extensions/explore/ast/grammars/kotlin.wasm +0 -0
  23. package/extensions/explore/ast/grammars/manifest.json +41 -0
  24. package/extensions/explore/ast/grammars/manifest.ts +99 -0
  25. package/extensions/explore/ast/grammars/odin.wasm +0 -0
  26. package/extensions/explore/ast/grammars/swift.wasm +0 -0
  27. package/extensions/explore/ast/graph/file-graph.ts +360 -0
  28. package/extensions/explore/ast/graph/relationships.ts +597 -0
  29. package/extensions/explore/ast/identity.ts +119 -0
  30. package/extensions/explore/ast/ir.ts +130 -0
  31. package/extensions/explore/ast/languages/csharp-file-deps.ts +189 -0
  32. package/extensions/explore/ast/languages/csharp.ts +493 -0
  33. package/extensions/explore/ast/languages/file-dep-util.ts +120 -0
  34. package/extensions/explore/ast/languages/fixtures/sample.cs +17 -0
  35. package/extensions/explore/ast/languages/fixtures/sample.java +21 -0
  36. package/extensions/explore/ast/languages/fixtures/sample.kt +15 -0
  37. package/extensions/explore/ast/languages/fixtures/sample.odin +28 -0
  38. package/extensions/explore/ast/languages/fixtures/sample.rs +31 -0
  39. package/extensions/explore/ast/languages/fixtures/sample.swift +25 -0
  40. package/extensions/explore/ast/languages/go-file-deps.ts +139 -0
  41. package/extensions/explore/ast/languages/go.ts +545 -0
  42. package/extensions/explore/ast/languages/java.ts +412 -0
  43. package/extensions/explore/ast/languages/jvm-file-deps.ts +217 -0
  44. package/extensions/explore/ast/languages/kotlin.ts +611 -0
  45. package/extensions/explore/ast/languages/odin-file-deps.ts +175 -0
  46. package/extensions/explore/ast/languages/odin.ts +407 -0
  47. package/extensions/explore/ast/languages/rust-file-deps.ts +159 -0
  48. package/extensions/explore/ast/languages/rust.ts +506 -0
  49. package/extensions/explore/ast/languages/swift-file-deps.ts +59 -0
  50. package/extensions/explore/ast/languages/swift.ts +466 -0
  51. package/extensions/explore/ast/languages/tree.ts +220 -0
  52. package/extensions/explore/ast/languages/typescript-file-deps.ts +259 -0
  53. package/extensions/explore/ast/languages/typescript-package-surface.ts +440 -0
  54. package/extensions/explore/ast/languages/typescript.ts +716 -0
  55. package/extensions/explore/ast/markdown.ts +145 -0
  56. package/extensions/explore/ast/package-surface.ts +42 -0
  57. package/extensions/explore/ast/queries/ast-search.ts +306 -0
  58. package/extensions/explore/ast/queries/composite-target.ts +77 -0
  59. package/extensions/explore/ast/queries/context.ts +406 -0
  60. package/extensions/explore/ast/queries/discover.ts +427 -0
  61. package/extensions/explore/ast/queries/impact.ts +250 -0
  62. package/extensions/explore/ast/queries/outline.ts +203 -0
  63. package/extensions/explore/ast/queries/show.ts +262 -0
  64. package/extensions/explore/ast/query.ts +48 -0
  65. package/extensions/explore/ast/read/hook.ts +125 -0
  66. package/extensions/explore/ast/read/policy.ts +55 -0
  67. package/extensions/explore/ast/registry.ts +120 -0
  68. package/extensions/explore/ast/scan.ts +76 -0
  69. package/extensions/explore/ast/slice.ts +31 -0
  70. package/extensions/explore/ast/tools/ast-search.ts +138 -0
  71. package/extensions/explore/ast/tools/context.ts +126 -0
  72. package/extensions/explore/ast/tools/deps.ts +72 -0
  73. package/extensions/explore/ast/tools/discover.ts +208 -0
  74. package/extensions/explore/ast/tools/impact.ts +135 -0
  75. package/extensions/explore/ast/tools/outline.ts +200 -0
  76. package/extensions/explore/ast/tools/relationships.ts +160 -0
  77. package/extensions/explore/ast/tools/render.ts +121 -0
  78. package/extensions/explore/ast/tools/reverse-deps.ts +72 -0
  79. package/extensions/explore/ast/tools/show.ts +116 -0
  80. package/extensions/explore/guidance.ts +52 -0
  81. package/extensions/explore/index.ts +91 -45
  82. package/extensions/explore/read/autoread.ts +118 -0
  83. package/extensions/explore/settings.ts +64 -0
  84. package/extensions/explore/traverse.ts +260 -86
  85. package/extensions/handoff/index.ts +1 -1
  86. package/extensions/patch/executor.ts +95 -1
  87. package/extensions/patch/index.ts +1 -0
  88. package/extensions/publish/index.ts +18 -85
  89. package/extensions/publish/publish-ui.ts +0 -4
  90. package/extensions/soul/README.md +7 -4
  91. package/extensions/soul/index.ts +11 -5
  92. package/extensions/soul/prompt.ts +30 -14
  93. package/extensions/soul/settings.ts +7 -2
  94. package/extensions/subagent/agents/context-sync.md +6 -10
  95. package/extensions/subagent/agents/review.md +44 -24
  96. package/extensions/subagent/agents/scout.md +53 -34
  97. package/extensions/subagent/run.ts +1 -1
  98. package/extensions/tau-help/help.md +2 -2
  99. package/package.json +6 -5
  100. package/schemas/tau.schema.json +51 -6
  101. package/{extensions/explore → shared}/autoread.ts +21 -7
  102. package/shared/bounded-text-result.ts +304 -0
  103. package/shared/events.ts +1 -0
  104. package/shared/full-file-knowledge.ts +49 -0
  105. package/shared/temporary-output-store.ts +275 -0
  106. package/extensions/explore/ast-tools.ts +0 -828
  107. package/extensions/explore/ast-worker.ts +0 -356
  108. package/extensions/explore/find.ts +0 -147
  109. package/extensions/explore/full-file-knowledge.ts +0 -234
  110. package/extensions/explore/grep.ts +0 -749
  111. package/extensions/explore/limits.ts +0 -22
  112. package/extensions/explore/ls.ts +0 -113
  113. package/extensions/explore/path-display.ts +0 -41
  114. package/extensions/explore/path-tree.ts +0 -150
  115. package/extensions/explore/read-cache.ts +0 -273
  116. package/extensions/explore/read-snapshots.ts +0 -57
  117. package/extensions/explore/read-stats-panel.ts +0 -154
  118. package/extensions/explore/read-stats.ts +0 -120
  119. package/extensions/explore/read.ts +0 -335
  120. package/extensions/explore/result.ts +0 -29
  121. package/native-bin/darwin-arm64/tau-ast +0 -0
@@ -0,0 +1,545 @@
1
+ import type { Node, Tree } from "web-tree-sitter";
2
+ import type { ExtractResult, GrammarAdapter, LanguageCapabilities } from "../adapter.ts";
3
+ import { resolveGoFileDep } from "./go-file-deps.ts";
4
+ import type { CallSite, Decl, ImportRef, Visibility } from "../ir.ts";
5
+ import {
6
+ applyDoc,
7
+ callSite,
8
+ docSpanBefore,
9
+ endLine,
10
+ field,
11
+ finishDecl,
12
+ nameText,
13
+ qualify,
14
+ startLine,
15
+ unquote,
16
+ walkBodyNodes,
17
+ type DocSpan,
18
+ } from "./tree.ts";
19
+
20
+ const CAPABILITIES: LanguageCapabilities = {
21
+ shape: true,
22
+ search: true,
23
+ fileDeps: true,
24
+ callEdges: true,
25
+ packageSurface: false,
26
+ };
27
+
28
+ const IMPORT_NOISE = new Set([
29
+ "break",
30
+ "case",
31
+ "chan",
32
+ "const",
33
+ "continue",
34
+ "default",
35
+ "defer",
36
+ "else",
37
+ "fallthrough",
38
+ "for",
39
+ "func",
40
+ "go",
41
+ "goto",
42
+ "if",
43
+ "import",
44
+ "interface",
45
+ "map",
46
+ "package",
47
+ "range",
48
+ "return",
49
+ "select",
50
+ "struct",
51
+ "switch",
52
+ "type",
53
+ "var",
54
+ "iota",
55
+ "true",
56
+ "false",
57
+ "nil",
58
+ "error",
59
+ "int",
60
+ "int32",
61
+ "int64",
62
+ "uint",
63
+ "byte",
64
+ "rune",
65
+ "string",
66
+ "bool",
67
+ "float64",
68
+ "any",
69
+ ]);
70
+
71
+ const EXTENSIONS = [".go"] as const;
72
+
73
+ // Node-type constants — owned by this adapter.
74
+ const FUNCTION_DECLARATION = "function_declaration";
75
+ const METHOD_DECLARATION = "method_declaration";
76
+ const TYPE_DECLARATION = "type_declaration";
77
+ const TYPE_SPEC = "type_spec";
78
+ const TYPE_ALIAS = "type_alias";
79
+ const CONST_DECLARATION = "const_declaration";
80
+ const CONST_SPEC = "const_spec";
81
+ const VAR_DECLARATION = "var_declaration";
82
+ const VAR_SPEC = "var_spec";
83
+ const VAR_SPEC_LIST = "var_spec_list";
84
+ const IMPORT_DECLARATION = "import_declaration";
85
+ const IMPORT_SPEC = "import_spec";
86
+ const IMPORT_SPEC_LIST = "import_spec_list";
87
+ const STRUCT_TYPE = "struct_type";
88
+ const INTERFACE_TYPE = "interface_type";
89
+ const FIELD_DECLARATION_LIST = "field_declaration_list";
90
+ const FIELD_DECLARATION = "field_declaration";
91
+ const METHOD_ELEM = "method_elem";
92
+ const CALL_EXPRESSION = "call_expression";
93
+ const COMPOSITE_LITERAL = "composite_literal";
94
+ const SELECTOR_EXPRESSION = "selector_expression";
95
+ const IDENTIFIER = "identifier";
96
+ const TYPE_IDENTIFIER = "type_identifier";
97
+ const BLOCK = "block";
98
+
99
+ const NESTED_SCOPE = new Set([FUNCTION_DECLARATION, METHOD_DECLARATION]);
100
+
101
+ function extractCalls(body: Node | null): CallSite[] {
102
+ if (body === null) return [];
103
+ const out: CallSite[] = [];
104
+ walkBodyNodes(
105
+ body,
106
+ (node) => NESTED_SCOPE.has(node.type),
107
+ (node) => {
108
+ if (node.type === CALL_EXPRESSION) {
109
+ const fn = field(node, "function");
110
+ if (fn === null) return;
111
+ let name = "";
112
+ let receiver = "";
113
+ let leaf: Node | null = null;
114
+ if (fn.type === IDENTIFIER) {
115
+ name = fn.text;
116
+ leaf = fn;
117
+ } else if (fn.type === SELECTOR_EXPRESSION) {
118
+ const fld = field(fn, "field");
119
+ const op = field(fn, "operand");
120
+ if (fld !== null) {
121
+ name = fld.text;
122
+ leaf = fld;
123
+ }
124
+ receiver = op === null ? "" : op.text;
125
+ }
126
+ if (leaf === null || name.length === 0) return;
127
+ const site = callSite(name, startLine(leaf), leaf.startIndex, leaf.endIndex, "call", receiver);
128
+ if (site !== undefined) out.push(site);
129
+ return;
130
+ }
131
+ if (node.type === COMPOSITE_LITERAL) {
132
+ const typeNode = field(node, "type");
133
+ if (typeNode === null) return;
134
+ const leaf =
135
+ typeNode.type === TYPE_IDENTIFIER || typeNode.type === IDENTIFIER
136
+ ? typeNode
137
+ : typeNode.namedChildren.find((c) => c.type === TYPE_IDENTIFIER || c.type === IDENTIFIER);
138
+ if (leaf === undefined || leaf === null) return;
139
+ const site = callSite(leaf.text, startLine(leaf), leaf.startIndex, leaf.endIndex, "construct");
140
+ if (site !== undefined) out.push(site);
141
+ }
142
+ },
143
+ );
144
+ return out;
145
+ }
146
+
147
+ function embeddedBases(list: Node | null): string[] {
148
+ if (list === null) return [];
149
+ const bases: string[] = [];
150
+ for (const node of list.namedChildren) {
151
+ if (node.type !== FIELD_DECLARATION) continue;
152
+ if (node.childrenForFieldName("name").length > 0) continue;
153
+ const typeNode = field(node, "type");
154
+ if (typeNode === null) continue;
155
+ const text = typeNode.text.replace(/^\*/, "");
156
+ const bare = text.includes(".") ? (text.split(".").pop() ?? text) : text;
157
+ if (bare.length > 0) bases.push(bare);
158
+ }
159
+ return bases;
160
+ }
161
+ const POINTER_TYPE = "pointer_type";
162
+ const PARAMETER_DECLARATION = "parameter_declaration";
163
+
164
+ /** Go exported = first rune uppercase (unicode letter). */
165
+ function goExported(name: string): boolean {
166
+ if (name.length === 0) return false;
167
+ const cp = name.codePointAt(0);
168
+ if (cp === undefined) return false;
169
+ const ch = String.fromCodePoint(cp);
170
+ return ch.toUpperCase() === ch && ch.toLowerCase() !== ch;
171
+ }
172
+
173
+ function visibilityFor(name: string): Visibility {
174
+ return goExported(name) ? "public" : "private";
175
+ }
176
+
177
+ function receiverTypeName(receiver: Node): string {
178
+ for (const param of receiver.namedChildren) {
179
+ if (param.type !== PARAMETER_DECLARATION) continue;
180
+ const typeNode = field(param, "type");
181
+ if (typeNode === null) continue;
182
+ if (typeNode.type === POINTER_TYPE) {
183
+ const inner = typeNode.namedChildren[0];
184
+ if (inner !== undefined) return inner.text;
185
+ }
186
+ return typeNode.text;
187
+ }
188
+ return "";
189
+ }
190
+
191
+ function braceOpen(node: Node): Node | undefined {
192
+ for (const child of node.children) {
193
+ if (child.type === "{") return child;
194
+ }
195
+ return undefined;
196
+ }
197
+
198
+ function typeSpecKind(typeNode: Node): Decl["kind"] {
199
+ if (typeNode.type === STRUCT_TYPE) return "struct";
200
+ if (typeNode.type === INTERFACE_TYPE) return "interface";
201
+ return "type";
202
+ }
203
+
204
+ function leafMember(
205
+ node: Node,
206
+ owner: string,
207
+ kind: Decl["kind"],
208
+ name: string,
209
+ endNode: Node = node,
210
+ ): Decl | undefined {
211
+ if (name.length === 0) return undefined;
212
+ return {
213
+ kind,
214
+ name,
215
+ qualifiedName: qualify(owner, name),
216
+ startLine: startLine(node),
217
+ endLine: endLine(endNode),
218
+ startOffset: node.startIndex,
219
+ endOffset: endNode.endIndex,
220
+ signatureEndOffset: endNode.endIndex,
221
+ visibility: visibilityFor(name),
222
+ exported: goExported(name),
223
+ children: [],
224
+ calls: [],
225
+ bases: [],
226
+ };
227
+ }
228
+
229
+ function structFields(list: Node, owner: string): Decl[] {
230
+ const out: Decl[] = [];
231
+ for (const node of list.namedChildren) {
232
+ if (node.type !== FIELD_DECLARATION) continue;
233
+ const nameNodes = node.childrenForFieldName("name");
234
+ if (nameNodes.length === 0) {
235
+ // Embedded field — name is the type identifier text.
236
+ const typeNode = field(node, "type");
237
+ const name = typeNode === null ? "" : typeNode.text.replace(/^\*/, "");
238
+ const decl = leafMember(node, owner, "field", name);
239
+ if (decl !== undefined) out.push(decl);
240
+ continue;
241
+ }
242
+ for (const nameNode of nameNodes) {
243
+ const decl = leafMember(nameNode, owner, "field", nameNode.text, node);
244
+ if (decl !== undefined) out.push(decl);
245
+ }
246
+ }
247
+ return out;
248
+ }
249
+
250
+ function interfaceMethods(iface: Node, owner: string): Decl[] {
251
+ const out: Decl[] = [];
252
+ for (const node of iface.namedChildren) {
253
+ if (node.type !== METHOD_ELEM) continue;
254
+ const decl = leafMember(node, owner, "method", nameText(field(node, "name")));
255
+ if (decl !== undefined) out.push(decl);
256
+ }
257
+ return out;
258
+ }
259
+
260
+ function declsFromTypeSpec(spec: Node, span: Node, doc: DocSpan | undefined): Decl[] {
261
+ const name = nameText(field(spec, "name"));
262
+ if (name.length === 0) return [];
263
+ const typeNode = field(spec, "type");
264
+ if (typeNode === null) return [];
265
+
266
+ const kind = typeSpecKind(typeNode);
267
+ let children: Decl[] = [];
268
+ let body: Node | null = null;
269
+
270
+ if (typeNode.type === STRUCT_TYPE) {
271
+ const list = typeNode.namedChildren.find((child) => child.type === FIELD_DECLARATION_LIST);
272
+ if (list !== undefined) {
273
+ body = list;
274
+ children = structFields(list, name);
275
+ }
276
+ } else if (typeNode.type === INTERFACE_TYPE) {
277
+ const open = braceOpen(typeNode);
278
+ if (open !== undefined) {
279
+ const decl = applyDoc(
280
+ {
281
+ kind,
282
+ name,
283
+ qualifiedName: name,
284
+ startLine: startLine(span),
285
+ endLine: endLine(span),
286
+ startOffset: span.startIndex,
287
+ endOffset: span.endIndex,
288
+ signatureEndOffset: open.startIndex,
289
+ bodyStartOffset: open.startIndex,
290
+ bodyEndOffset: typeNode.endIndex,
291
+ visibility: visibilityFor(name),
292
+ exported: goExported(name),
293
+ children: interfaceMethods(typeNode, name),
294
+ calls: [],
295
+ bases: [],
296
+ },
297
+ doc,
298
+ );
299
+ return [decl];
300
+ }
301
+ }
302
+
303
+ const decl = finishDecl(
304
+ {
305
+ kind,
306
+ name,
307
+ qualifiedName: name,
308
+ startLine: startLine(span),
309
+ endLine: endLine(span),
310
+ startOffset: span.startIndex,
311
+ endOffset: span.endIndex,
312
+ visibility: visibilityFor(name),
313
+ exported: goExported(name),
314
+ children,
315
+ bases: typeNode.type === STRUCT_TYPE ? embeddedBases(body) : [],
316
+ },
317
+ body,
318
+ );
319
+ return [applyDoc(decl, doc)];
320
+ }
321
+
322
+ function declsFromTypeAlias(alias: Node, span: Node, doc: DocSpan | undefined): Decl[] {
323
+ const name = nameText(field(alias, "name"));
324
+ if (name.length === 0) return [];
325
+ const decl = finishDecl(
326
+ {
327
+ kind: "typeAlias",
328
+ name,
329
+ qualifiedName: name,
330
+ startLine: startLine(span),
331
+ endLine: endLine(span),
332
+ startOffset: span.startIndex,
333
+ endOffset: span.endIndex,
334
+ visibility: visibilityFor(name),
335
+ exported: goExported(name),
336
+ },
337
+ null,
338
+ );
339
+ return [applyDoc(decl, doc)];
340
+ }
341
+
342
+ function declsFromTypeDeclaration(node: Node, source: string): Decl[] {
343
+ const doc = docSpanBefore(node, source);
344
+ const entries: Node[] = [];
345
+ for (const child of node.namedChildren) {
346
+ if (child.type === TYPE_SPEC || child.type === TYPE_ALIAS) entries.push(child);
347
+ }
348
+ const single = entries.length === 1;
349
+ const out: Decl[] = [];
350
+ let first = true;
351
+ for (const child of entries) {
352
+ const span = single ? node : child;
353
+ const attached = first ? doc : undefined;
354
+ first = false;
355
+ if (child.type === TYPE_SPEC) out.push(...declsFromTypeSpec(child, span, attached));
356
+ else out.push(...declsFromTypeAlias(child, span, attached));
357
+ }
358
+ return out;
359
+ }
360
+
361
+ function specNames(spec: Node): Node[] {
362
+ return spec.childrenForFieldName("name");
363
+ }
364
+
365
+ function declsFromConstOrVar(node: Node, kind: "constant" | "variable", source: string): Decl[] {
366
+ const doc = docSpanBefore(node, source);
367
+ const specs: Node[] = [];
368
+ for (const child of node.namedChildren) {
369
+ if (child.type === CONST_SPEC || child.type === VAR_SPEC) specs.push(child);
370
+ if (child.type === VAR_SPEC_LIST) {
371
+ for (const inner of child.namedChildren) {
372
+ if (inner.type === VAR_SPEC) specs.push(inner);
373
+ }
374
+ }
375
+ }
376
+
377
+ const totalNames = specs.reduce((n, spec) => n + specNames(spec).length, 0);
378
+ const single = totalNames === 1;
379
+ const out: Decl[] = [];
380
+ let docUsed = false;
381
+ for (const spec of specs) {
382
+ for (const nameNode of specNames(spec)) {
383
+ const name = nameNode.text;
384
+ const spanStart = single ? node : nameNode;
385
+ const spanEnd = single ? node : spec;
386
+ const decl = finishDecl(
387
+ {
388
+ kind,
389
+ name,
390
+ qualifiedName: name,
391
+ startLine: startLine(spanStart),
392
+ endLine: endLine(spanEnd),
393
+ startOffset: spanStart.startIndex,
394
+ endOffset: spanEnd.endIndex,
395
+ visibility: visibilityFor(name),
396
+ exported: goExported(name),
397
+ },
398
+ null,
399
+ );
400
+ if (!docUsed) {
401
+ out.push(applyDoc(decl, doc));
402
+ docUsed = true;
403
+ } else {
404
+ out.push(decl);
405
+ }
406
+ }
407
+ }
408
+ return out;
409
+ }
410
+
411
+ function declsFromFunction(node: Node, source: string): Decl[] {
412
+ const doc = docSpanBefore(node, source);
413
+ const name = nameText(field(node, "name"));
414
+ if (name.length === 0) return [];
415
+ const body = field(node, "body");
416
+ const bodyNode = body !== null && body.type === BLOCK ? body : null;
417
+ const decl = finishDecl(
418
+ {
419
+ kind: "function",
420
+ name,
421
+ qualifiedName: name,
422
+ startLine: startLine(node),
423
+ endLine: endLine(node),
424
+ startOffset: node.startIndex,
425
+ endOffset: node.endIndex,
426
+ visibility: visibilityFor(name),
427
+ exported: goExported(name),
428
+ calls: extractCalls(bodyNode),
429
+ },
430
+ bodyNode,
431
+ );
432
+ return [applyDoc(decl, doc)];
433
+ }
434
+
435
+ function declsFromMethod(node: Node, source: string): Decl[] {
436
+ const doc = docSpanBefore(node, source);
437
+ const name = nameText(field(node, "name"));
438
+ if (name.length === 0) return [];
439
+ const receiver = field(node, "receiver");
440
+ const recvName = receiver === null ? "" : receiverTypeName(receiver);
441
+ const qualifiedName = recvName.length === 0 ? name : `${recvName}.${name}`;
442
+ const body = field(node, "body");
443
+ const bodyNode = body !== null && body.type === BLOCK ? body : null;
444
+ const decl = finishDecl(
445
+ {
446
+ kind: "method",
447
+ name,
448
+ qualifiedName,
449
+ startLine: startLine(node),
450
+ endLine: endLine(node),
451
+ startOffset: node.startIndex,
452
+ endOffset: node.endIndex,
453
+ visibility: visibilityFor(name),
454
+ exported: goExported(name),
455
+ calls: extractCalls(bodyNode),
456
+ },
457
+ bodyNode,
458
+ );
459
+ return [applyDoc(decl, doc)];
460
+ }
461
+
462
+ function collectImports(root: Node): ImportRef[] {
463
+ const imports: ImportRef[] = [];
464
+ for (const node of root.namedChildren) {
465
+ if (node.type !== IMPORT_DECLARATION) continue;
466
+ // Per-spec specifier for file-graph; statement bytes cover the whole declaration.
467
+ const specs: Node[] = [];
468
+ for (const child of node.namedChildren) {
469
+ if (child.type === IMPORT_SPEC) specs.push(child);
470
+ if (child.type === IMPORT_SPEC_LIST) {
471
+ for (const inner of child.namedChildren) {
472
+ if (inner.type === IMPORT_SPEC) specs.push(inner);
473
+ }
474
+ }
475
+ }
476
+ for (const spec of specs) {
477
+ const pathNode = field(spec, "path");
478
+ if (pathNode === null) continue;
479
+ imports.push({
480
+ specifier: unquote(pathNode.text),
481
+ startLine: startLine(spec),
482
+ startOffset: node.startIndex,
483
+ endOffset: node.endIndex,
484
+ bindings: [],
485
+ });
486
+ }
487
+ }
488
+ return imports;
489
+ }
490
+
491
+ function extractFromNode(node: Node, source: string, decls: Decl[]): void {
492
+ if (node.isError || node.type === "ERROR") {
493
+ for (const child of node.children) {
494
+ if (child.isNamed || child.isError) extractFromNode(child, source, decls);
495
+ }
496
+ return;
497
+ }
498
+ switch (node.type) {
499
+ case FUNCTION_DECLARATION:
500
+ decls.push(...declsFromFunction(node, source));
501
+ break;
502
+ case METHOD_DECLARATION:
503
+ decls.push(...declsFromMethod(node, source));
504
+ break;
505
+ case TYPE_DECLARATION:
506
+ decls.push(...declsFromTypeDeclaration(node, source));
507
+ break;
508
+ case CONST_DECLARATION:
509
+ decls.push(...declsFromConstOrVar(node, "constant", source));
510
+ break;
511
+ case VAR_DECLARATION:
512
+ decls.push(...declsFromConstOrVar(node, "variable", source));
513
+ break;
514
+ default:
515
+ break;
516
+ }
517
+ }
518
+
519
+ function extractGo(tree: Tree, source: string): ExtractResult {
520
+ const root = tree.rootNode;
521
+ const decls: Decl[] = [];
522
+ for (const node of root.children) {
523
+ if (node.isNamed || node.isError) extractFromNode(node, source, decls);
524
+ }
525
+ return { decls, imports: collectImports(root) };
526
+ }
527
+
528
+ /** Bare `pkg.Call($A)` parses as type_conversion in Go; wrap as a statement call. */
529
+ const PATTERN_CONTEXTS = [
530
+ { context: "func f() {\n$PATTERN\n}", selector: "call_expression" },
531
+ { context: "_ = $PATTERN", selector: "call_expression" },
532
+ ] as const;
533
+
534
+ export function goAdapter(): GrammarAdapter {
535
+ return {
536
+ mode: "grammar",
537
+ id: "go",
538
+ extensions: EXTENSIONS,
539
+ capabilities: CAPABILITIES,
540
+ importNoiseIdentifiers: IMPORT_NOISE,
541
+ extract: extractGo,
542
+ resolveFileDep: resolveGoFileDep,
543
+ patternContexts: PATTERN_CONTEXTS,
544
+ };
545
+ }