@shanepadgett/tau-agent 0.33.0 → 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.
- package/docs/context.md +29 -20
- package/docs/extending-tau-agent.md +63 -24
- package/extensions/appshot/index.ts +112 -111
- package/extensions/aside/README.md +7 -0
- package/extensions/aside/index.ts +168 -0
- package/extensions/aside/panel.ts +83 -0
- package/extensions/branch/index.ts +38 -21
- package/extensions/cache-diagnostics/index.ts +70 -58
- package/extensions/checkpoint/README.md +9 -0
- package/extensions/checkpoint/checkpoint-budget.ts +79 -0
- package/extensions/checkpoint/checkpoint.ts +277 -0
- package/extensions/checkpoint/index.ts +102 -0
- package/extensions/checkpoint/messages.ts +169 -0
- package/extensions/checkpoint/prompt.ts +24 -0
- package/extensions/checkpoint/settings.ts +27 -0
- package/extensions/commit/commit-effort.ts +3 -3
- package/extensions/context/README.md +12 -8
- package/extensions/context/definitions.ts +178 -55
- package/extensions/context/index.ts +192 -160
- package/extensions/context/panel.ts +57 -37
- package/extensions/context/sync.ts +139 -89
- package/extensions/context/validation.ts +37 -25
- package/extensions/effort/README.md +1 -1
- package/extensions/effort/index.ts +3 -3
- package/extensions/effort/state.ts +3 -18
- package/extensions/explore/guidance.ts +6 -47
- package/extensions/explore/index.ts +38 -53
- package/extensions/explore/{ast/read → read}/hook.ts +12 -7
- package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
- package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
- package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
- package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
- package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
- package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
- package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
- package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
- package/extensions/explore/tools/target-params.ts +9 -0
- package/extensions/footer/index.ts +75 -56
- package/extensions/handoff/index.ts +8 -30
- package/extensions/image-gen/index.ts +46 -40
- package/extensions/patch/executor.ts +190 -135
- package/extensions/patch/matcher.ts +82 -48
- package/extensions/patch/parser.ts +149 -105
- package/extensions/patch/render.ts +32 -39
- package/extensions/patch/summary.ts +30 -26
- package/extensions/ready/README.md +7 -0
- package/extensions/ready/index.ts +58 -0
- package/extensions/ready/model.ts +128 -0
- package/extensions/ready/packs.ts +272 -0
- package/extensions/ready/render.ts +445 -0
- package/extensions/ready/scan.ts +760 -0
- package/extensions/reference/panel.ts +28 -16
- package/extensions/review/index.ts +63 -51
- package/extensions/review/panel.ts +5 -34
- package/extensions/runtime-context/context.ts +30 -26
- package/extensions/script-runner/README.md +2 -2
- package/extensions/script-runner/index.ts +130 -93
- package/extensions/silent-command-runner/index.ts +38 -23
- package/extensions/subagent/agents/context-sync.md +185 -33
- package/extensions/subagent/agents/scout.md +2 -2
- package/extensions/subagent/agents.ts +137 -84
- package/extensions/subagent/cmux-dashboard.ts +39 -30
- package/extensions/subagent/index.ts +79 -59
- package/extensions/subagent/resume.ts +1 -1
- package/extensions/subagent/run.ts +304 -193
- package/extensions/subagent/runtime.ts +781 -343
- package/extensions/tau/index.ts +47 -38
- package/extensions/tau-help/help.md +14 -6
- package/extensions/tool-loader/README.md +4 -2
- package/extensions/tool-loader/index.ts +77 -52
- package/extensions/web/index.ts +6 -3
- package/extensions/web/webfetch.ts +114 -86
- package/package.json +3 -3
- package/schemas/tau.schema.json +20 -33
- package/shared/bounded-text-result.ts +1 -0
- package/shared/checkpoint-visibility.ts +9 -0
- package/shared/events.ts +28 -10
- package/shared/isolated-session.ts +71 -29
- package/shared/model-effort.ts +9 -19
- package/shared/model-fallback/index.ts +66 -41
- package/shared/settings/load.ts +45 -38
- package/shared/temporary-output-store.ts +16 -10
- package/{extensions/explore → src}/ast/adapter.ts +11 -2
- package/{extensions/explore → src}/ast/engine.ts +54 -38
- package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
- package/{extensions/explore → src}/ast/format/context.ts +3 -6
- package/src/ast/format/deps.ts +94 -0
- package/{extensions/explore → src}/ast/format/discover.ts +2 -2
- package/{extensions/explore → src}/ast/format/impact.ts +9 -11
- package/{extensions/explore → src}/ast/format/outline.ts +2 -2
- package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
- package/{extensions/explore → src}/ast/format/show.ts +1 -1
- package/src/ast/format/targeted-result.ts +20 -0
- package/src/ast/grammars/c_sharp.wasm +0 -0
- package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
- package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
- package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
- package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
- package/{extensions/explore → src}/ast/ir.ts +6 -0
- package/src/ast/languages/csharp-file-deps.ts +90 -0
- package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
- package/src/ast/languages/dotted-index.ts +131 -0
- package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
- package/src/ast/languages/fixtures/sample.cs +53 -0
- package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
- package/src/ast/languages/fixtures/sample.go +37 -0
- package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
- package/src/ast/languages/fixtures/sample.java +40 -0
- package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
- package/src/ast/languages/fixtures/sample.kt +31 -0
- package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
- package/src/ast/languages/fixtures/sample.md +23 -0
- package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
- package/src/ast/languages/fixtures/sample.rs +54 -0
- package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
- package/src/ast/languages/fixtures/sample.swift +45 -0
- package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
- package/src/ast/languages/fixtures/sample.ts +45 -0
- package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
- package/src/ast/languages/fixtures/sample.tsx +36 -0
- package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
- package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
- package/{extensions/explore → src}/ast/languages/go.ts +21 -3
- package/{extensions/explore → src}/ast/languages/java.ts +5 -38
- package/src/ast/languages/jvm-file-deps.ts +135 -0
- package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
- package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
- package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
- package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
- package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
- package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
- package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
- package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
- package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
- package/{extensions/explore → src}/ast/markdown.ts +72 -47
- package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
- package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
- package/{extensions/explore → src}/ast/queries/context.ts +116 -80
- package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
- package/src/ast/queries/impact.ts +291 -0
- package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
- package/{extensions/explore → src}/ast/queries/show.ts +46 -42
- package/{extensions/explore → src}/ast/query.ts +1 -1
- package/{extensions/explore → src}/ast/registry.ts +1 -2
- package/{extensions/explore → src}/ast/scan.ts +1 -1
- package/src/ast/session.ts +50 -0
- package/{extensions/explore → src}/ast/slice.ts +8 -0
- package/{extensions/explore → src/ast}/traverse.ts +32 -20
- package/src/file-injection/index.ts +547 -0
- package/src/image-generation/client.ts +50 -31
- package/src/image-generation/index.ts +177 -134
- package/src/index.ts +2 -0
- package/src/tool-loading/index.ts +58 -0
- package/extensions/context/evidence.ts +0 -517
- package/extensions/context/projection.ts +0 -141
- package/extensions/context/state.ts +0 -30
- package/extensions/context/write-scope.ts +0 -109
- package/extensions/explore/ast/format/deps.ts +0 -86
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
- package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
- package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
- package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
- package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
- package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
- package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
- package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
- package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
- package/extensions/explore/ast/languages/odin.ts +0 -407
- package/extensions/explore/ast/queries/impact.ts +0 -250
- package/extensions/explore/outline-injection.ts +0 -151
- package/extensions/explore/read/autoread.ts +0 -118
- package/extensions/working-memory/README.md +0 -17
- package/extensions/working-memory/checkpoint.ts +0 -242
- package/extensions/working-memory/index.ts +0 -341
- package/extensions/working-memory/memory.ts +0 -235
- package/extensions/working-memory/render.ts +0 -185
- package/extensions/working-memory/settings.ts +0 -38
- package/extensions/working-memory/state.ts +0 -158
- package/shared/autoread.ts +0 -234
- package/shared/context-messages.ts +0 -19
- package/shared/outline-injection.ts +0 -56
- /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
- /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
- /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
- /package/{extensions/explore → src}/ast/identity.ts +0 -0
- /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
- /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import type { Node, Tree } from "web-tree-sitter";
|
|
2
|
-
import type { ExtractResult, GrammarAdapter, LanguageCapabilities } from "../adapter.ts";
|
|
3
|
-
import { resolveOdinFileDep } from "./odin-file-deps.ts";
|
|
4
|
-
import type { CallSite, Decl, ImportRef, Visibility } from "../ir.ts";
|
|
5
|
-
import {
|
|
6
|
-
applyDoc,
|
|
7
|
-
callSite,
|
|
8
|
-
docSpanBefore,
|
|
9
|
-
endLine,
|
|
10
|
-
finishDecl,
|
|
11
|
-
qualify,
|
|
12
|
-
startLine,
|
|
13
|
-
unquote,
|
|
14
|
-
walkBodyNodes,
|
|
15
|
-
type DocSpan,
|
|
16
|
-
} from "./tree.ts";
|
|
17
|
-
|
|
18
|
-
const CAPABILITIES: LanguageCapabilities = {
|
|
19
|
-
shape: true,
|
|
20
|
-
search: true,
|
|
21
|
-
fileDeps: true,
|
|
22
|
-
callEdges: true,
|
|
23
|
-
packageSurface: false,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const IMPORT_NOISE = new Set([
|
|
27
|
-
"package",
|
|
28
|
-
"import",
|
|
29
|
-
"foreign",
|
|
30
|
-
"proc",
|
|
31
|
-
"where",
|
|
32
|
-
"when",
|
|
33
|
-
"if",
|
|
34
|
-
"else",
|
|
35
|
-
"for",
|
|
36
|
-
"in",
|
|
37
|
-
"switch",
|
|
38
|
-
"case",
|
|
39
|
-
"break",
|
|
40
|
-
"continue",
|
|
41
|
-
"fallthrough",
|
|
42
|
-
"return",
|
|
43
|
-
"defer",
|
|
44
|
-
"using",
|
|
45
|
-
"struct",
|
|
46
|
-
"union",
|
|
47
|
-
"enum",
|
|
48
|
-
"bit_set",
|
|
49
|
-
"map",
|
|
50
|
-
"dynamic",
|
|
51
|
-
"cast",
|
|
52
|
-
"transmute",
|
|
53
|
-
"auto_cast",
|
|
54
|
-
"true",
|
|
55
|
-
"false",
|
|
56
|
-
"nil",
|
|
57
|
-
"context",
|
|
58
|
-
]);
|
|
59
|
-
|
|
60
|
-
const EXTENSIONS = [".odin"] as const;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Node kinds from tree-sitter-odin v1.3.0 node-types + locals.scm definitions:
|
|
64
|
-
* procedure_declaration, overloaded_procedure_declaration → function
|
|
65
|
-
* struct_declaration / union_declaration / bit_field_declaration → struct (union/bit_field closest kind)
|
|
66
|
-
* enum_declaration → enum
|
|
67
|
-
* const_declaration / const_type_declaration → constant
|
|
68
|
-
* variable_declaration (`:=`) → variable, or function when value is `procedure`
|
|
69
|
-
* var_declaration (`:`) → variable
|
|
70
|
-
* field → struct field
|
|
71
|
-
* foreign_block → walk nested package-level decls
|
|
72
|
-
* Package-level only (plan). Nested procs inside function bodies stay out.
|
|
73
|
-
*/
|
|
74
|
-
const PROCEDURE_DECLARATION = "procedure_declaration";
|
|
75
|
-
const OVERLOADED_PROCEDURE_DECLARATION = "overloaded_procedure_declaration";
|
|
76
|
-
const STRUCT_DECLARATION = "struct_declaration";
|
|
77
|
-
const ENUM_DECLARATION = "enum_declaration";
|
|
78
|
-
const UNION_DECLARATION = "union_declaration";
|
|
79
|
-
const BIT_FIELD_DECLARATION = "bit_field_declaration";
|
|
80
|
-
const CONST_DECLARATION = "const_declaration";
|
|
81
|
-
const CONST_TYPE_DECLARATION = "const_type_declaration";
|
|
82
|
-
const VAR_DECLARATION = "var_declaration";
|
|
83
|
-
const VARIABLE_DECLARATION = "variable_declaration";
|
|
84
|
-
const FOREIGN_BLOCK = "foreign_block";
|
|
85
|
-
const IMPORT_DECLARATION = "import_declaration";
|
|
86
|
-
const ATTRIBUTES = "attributes";
|
|
87
|
-
const ATTRIBUTE = "attribute";
|
|
88
|
-
const IDENTIFIER = "identifier";
|
|
89
|
-
const PROCEDURE = "procedure";
|
|
90
|
-
const FIELD = "field";
|
|
91
|
-
const BLOCK = "block";
|
|
92
|
-
|
|
93
|
-
const NESTED_SCOPE = new Set([
|
|
94
|
-
"procedure_declaration",
|
|
95
|
-
"overloaded_procedure_declaration",
|
|
96
|
-
"struct_declaration",
|
|
97
|
-
"enum_declaration",
|
|
98
|
-
]);
|
|
99
|
-
|
|
100
|
-
function extractCalls(body: Node | null): CallSite[] {
|
|
101
|
-
if (body === null) return [];
|
|
102
|
-
const out: CallSite[] = [];
|
|
103
|
-
walkBodyNodes(
|
|
104
|
-
body,
|
|
105
|
-
(n) => NESTED_SCOPE.has(n.type),
|
|
106
|
-
(node) => {
|
|
107
|
-
if (node.type !== "call_expression" && node.type !== "selector_call_expression") return;
|
|
108
|
-
const fn = node.childForFieldName("function") ?? node.namedChildren[0];
|
|
109
|
-
if (fn === null || fn === undefined) return;
|
|
110
|
-
let leafNode = fn;
|
|
111
|
-
let receiver = "";
|
|
112
|
-
if (fn.type === "member_expression" || fn.type === "selector_expression") {
|
|
113
|
-
const fieldNode = fn.childForFieldName("field") ?? fn.namedChildren[fn.namedChildren.length - 1];
|
|
114
|
-
const obj = fn.childForFieldName("argument") ?? fn.childForFieldName("operand") ?? fn.namedChildren[0];
|
|
115
|
-
if (fieldNode !== null && fieldNode !== undefined) leafNode = fieldNode;
|
|
116
|
-
if (obj !== null && obj !== undefined) receiver = obj.text;
|
|
117
|
-
}
|
|
118
|
-
const site = callSite(
|
|
119
|
-
leafNode.text,
|
|
120
|
-
startLine(leafNode),
|
|
121
|
-
leafNode.startIndex,
|
|
122
|
-
leafNode.endIndex,
|
|
123
|
-
"call",
|
|
124
|
-
receiver,
|
|
125
|
-
);
|
|
126
|
-
if (site !== undefined) out.push(site);
|
|
127
|
-
},
|
|
128
|
-
);
|
|
129
|
-
return out;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function odinDoc(node: Node, source: string): DocSpan | undefined {
|
|
133
|
-
return docSpanBefore(node, source);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
function hasPrivateAttribute(node: Node): boolean {
|
|
137
|
-
const attrs = node.namedChildren.find((child) => child.type === ATTRIBUTES);
|
|
138
|
-
if (attrs === undefined) return false;
|
|
139
|
-
for (const attr of attrs.namedChildren) {
|
|
140
|
-
if (attr.type !== ATTRIBUTE) continue;
|
|
141
|
-
for (const child of attr.namedChildren) {
|
|
142
|
-
if (child.type === IDENTIFIER && child.text === "private") return true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function visibilityOf(node: Node): Visibility {
|
|
149
|
-
return hasPrivateAttribute(node) ? "private" : "public";
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** First non-attribute identifier child — name position for all odin decls in this grammar. */
|
|
153
|
-
function firstIdentifier(node: Node): string {
|
|
154
|
-
for (const child of node.namedChildren) {
|
|
155
|
-
if (child.type === ATTRIBUTES) continue;
|
|
156
|
-
if (child.type === IDENTIFIER) return child.text;
|
|
157
|
-
}
|
|
158
|
-
return "";
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function procedureBody(node: Node): Node | null {
|
|
162
|
-
const proc = node.namedChildren.find((child) => child.type === PROCEDURE);
|
|
163
|
-
if (proc === undefined) return null;
|
|
164
|
-
// `---` foreign stubs use uninitialized, not block.
|
|
165
|
-
return proc.namedChildren.find((child) => child.type === BLOCK) ?? null;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
function leaf(
|
|
169
|
-
node: Node,
|
|
170
|
-
owner: string,
|
|
171
|
-
kind: Decl["kind"],
|
|
172
|
-
name: string,
|
|
173
|
-
visibility: Visibility,
|
|
174
|
-
body: Node | null,
|
|
175
|
-
children: Decl[],
|
|
176
|
-
doc: DocSpan | undefined,
|
|
177
|
-
): Decl | undefined {
|
|
178
|
-
if (name.length === 0) return undefined;
|
|
179
|
-
const callable = kind === "function" || kind === "method" || kind === "constructor";
|
|
180
|
-
const decl = finishDecl(
|
|
181
|
-
{
|
|
182
|
-
kind,
|
|
183
|
-
name,
|
|
184
|
-
qualifiedName: qualify(owner, name),
|
|
185
|
-
startLine: startLine(node),
|
|
186
|
-
endLine: endLine(node),
|
|
187
|
-
startOffset: node.startIndex,
|
|
188
|
-
endOffset: node.endIndex,
|
|
189
|
-
visibility,
|
|
190
|
-
exported: visibility === "public",
|
|
191
|
-
children,
|
|
192
|
-
calls: callable ? extractCalls(body) : [],
|
|
193
|
-
bases: [],
|
|
194
|
-
},
|
|
195
|
-
body,
|
|
196
|
-
);
|
|
197
|
-
if (body === null) decl.signatureEndOffset = node.endIndex;
|
|
198
|
-
return applyDoc(decl, doc);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/** struct_declaration children of type `field` (not `struct_field` — that is composite-literal elements). */
|
|
202
|
-
function structFields(node: Node, owner: string): Decl[] {
|
|
203
|
-
const out: Decl[] = [];
|
|
204
|
-
for (const child of node.namedChildren) {
|
|
205
|
-
if (child.type !== FIELD) continue;
|
|
206
|
-
const names: string[] = [];
|
|
207
|
-
for (const part of child.namedChildren) {
|
|
208
|
-
if (part.type === IDENTIFIER) names.push(part.text);
|
|
209
|
-
if (part.type === "type") break;
|
|
210
|
-
}
|
|
211
|
-
for (const name of names) {
|
|
212
|
-
// `using _: T` embedding — skip blank identifier.
|
|
213
|
-
if (name === "_") continue;
|
|
214
|
-
const decl = leaf(child, owner, "field", name, "public", null, [], undefined);
|
|
215
|
-
if (decl !== undefined) out.push(decl);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
return out;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function enumMembers(node: Node, owner: string): Decl[] {
|
|
222
|
-
const out: Decl[] = [];
|
|
223
|
-
let seenName = false;
|
|
224
|
-
for (const child of node.namedChildren) {
|
|
225
|
-
if (child.type !== IDENTIFIER) continue;
|
|
226
|
-
if (!seenName) {
|
|
227
|
-
seenName = true;
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
const decl = leaf(child, owner, "enumMember", child.text, "public", null, [], undefined);
|
|
231
|
-
if (decl !== undefined) out.push(decl);
|
|
232
|
-
}
|
|
233
|
-
return out;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* bit_field_declaration flattens members as identifier/type/number triples after the backing type.
|
|
238
|
-
* Shape: Name :: bit_field Backing { field: T | bits, ... }
|
|
239
|
-
*/
|
|
240
|
-
function bitFieldMembers(node: Node, owner: string): Decl[] {
|
|
241
|
-
const out: Decl[] = [];
|
|
242
|
-
let seenName = false;
|
|
243
|
-
let seenBackingType = false;
|
|
244
|
-
for (const child of node.namedChildren) {
|
|
245
|
-
if (child.type === ATTRIBUTES) continue;
|
|
246
|
-
if (!seenName && child.type === IDENTIFIER) {
|
|
247
|
-
seenName = true;
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
if (seenName && !seenBackingType && child.type === "type") {
|
|
251
|
-
seenBackingType = true;
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
if (!seenBackingType) continue;
|
|
255
|
-
if (child.type === IDENTIFIER) {
|
|
256
|
-
const decl = leaf(child, owner, "field", child.text, "public", null, [], undefined);
|
|
257
|
-
if (decl !== undefined) out.push(decl);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return out;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
function cutSignatureBefore(node: Node, firstChild: Node | undefined, decl: Decl): void {
|
|
264
|
-
if (firstChild === undefined) return;
|
|
265
|
-
decl.signatureEndOffset = firstChild.startIndex;
|
|
266
|
-
decl.bodyStartOffset = firstChild.startIndex;
|
|
267
|
-
decl.bodyEndOffset = node.endIndex;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
function declsFromNode(node: Node, owner: string, source: string): Decl[] {
|
|
271
|
-
if (node.isError || node.type === "ERROR") {
|
|
272
|
-
const out: Decl[] = [];
|
|
273
|
-
for (const child of node.children) {
|
|
274
|
-
if (child.isNamed || child.isError) out.push(...declsFromNode(child, owner, source));
|
|
275
|
-
}
|
|
276
|
-
return out;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const doc = odinDoc(node, source);
|
|
280
|
-
const visibility = visibilityOf(node);
|
|
281
|
-
|
|
282
|
-
switch (node.type) {
|
|
283
|
-
case PROCEDURE_DECLARATION:
|
|
284
|
-
case OVERLOADED_PROCEDURE_DECLARATION: {
|
|
285
|
-
const name = firstIdentifier(node);
|
|
286
|
-
const body = node.type === PROCEDURE_DECLARATION ? procedureBody(node) : null;
|
|
287
|
-
const decl = leaf(node, owner, "function", name, visibility, body, [], doc);
|
|
288
|
-
return decl === undefined ? [] : [decl];
|
|
289
|
-
}
|
|
290
|
-
case STRUCT_DECLARATION: {
|
|
291
|
-
const name = firstIdentifier(node);
|
|
292
|
-
const qn = qualify(owner, name);
|
|
293
|
-
const children = structFields(node, qn);
|
|
294
|
-
const firstField = node.namedChildren.find((child) => child.type === FIELD);
|
|
295
|
-
const decl = leaf(node, owner, "struct", name, visibility, null, children, doc);
|
|
296
|
-
if (decl !== undefined) cutSignatureBefore(node, firstField, decl);
|
|
297
|
-
return decl === undefined ? [] : [decl];
|
|
298
|
-
}
|
|
299
|
-
case UNION_DECLARATION: {
|
|
300
|
-
// locals.scm: union → type; shared IR uses struct as closest kind.
|
|
301
|
-
const name = firstIdentifier(node);
|
|
302
|
-
const decl = leaf(node, owner, "struct", name, visibility, null, [], doc);
|
|
303
|
-
return decl === undefined ? [] : [decl];
|
|
304
|
-
}
|
|
305
|
-
case BIT_FIELD_DECLARATION: {
|
|
306
|
-
// locals.scm: bit_field → type; shared IR uses struct.
|
|
307
|
-
const name = firstIdentifier(node);
|
|
308
|
-
const qn = qualify(owner, name);
|
|
309
|
-
const children = bitFieldMembers(node, qn);
|
|
310
|
-
const decl = leaf(node, owner, "struct", name, visibility, null, children, doc);
|
|
311
|
-
// Signature through backing type: first member identifier after backing `type`.
|
|
312
|
-
const firstMember = children[0];
|
|
313
|
-
if (decl !== undefined && firstMember !== undefined) {
|
|
314
|
-
decl.signatureEndOffset = firstMember.startOffset;
|
|
315
|
-
decl.bodyStartOffset = firstMember.startOffset;
|
|
316
|
-
decl.bodyEndOffset = node.endIndex;
|
|
317
|
-
}
|
|
318
|
-
return decl === undefined ? [] : [decl];
|
|
319
|
-
}
|
|
320
|
-
case ENUM_DECLARATION: {
|
|
321
|
-
const name = firstIdentifier(node);
|
|
322
|
-
const qn = qualify(owner, name);
|
|
323
|
-
const children = enumMembers(node, qn);
|
|
324
|
-
const decl = leaf(node, owner, "enum", name, visibility, null, children, doc);
|
|
325
|
-
return decl === undefined ? [] : [decl];
|
|
326
|
-
}
|
|
327
|
-
case CONST_DECLARATION:
|
|
328
|
-
case CONST_TYPE_DECLARATION: {
|
|
329
|
-
// locals.scm: const_declaration → constant; const_type_declaration → type (value const with explicit type).
|
|
330
|
-
const name = firstIdentifier(node);
|
|
331
|
-
// `_ :: runtime` package aliases are not outline decls.
|
|
332
|
-
if (name === "_") return [];
|
|
333
|
-
const decl = leaf(node, owner, "constant", name, visibility, null, [], doc);
|
|
334
|
-
return decl === undefined ? [] : [decl];
|
|
335
|
-
}
|
|
336
|
-
case VAR_DECLARATION: {
|
|
337
|
-
// `name: Type` / `name: Type = value`
|
|
338
|
-
const name = firstIdentifier(node);
|
|
339
|
-
if (name === "_") return [];
|
|
340
|
-
const decl = leaf(node, owner, "variable", name, visibility, null, [], doc);
|
|
341
|
-
return decl === undefined ? [] : [decl];
|
|
342
|
-
}
|
|
343
|
-
case VARIABLE_DECLARATION: {
|
|
344
|
-
// `name := value` — function when value is a procedure literal (locals.scm still marks var).
|
|
345
|
-
const name = firstIdentifier(node);
|
|
346
|
-
if (name === "_") return [];
|
|
347
|
-
const proc = node.namedChildren.find((child) => child.type === PROCEDURE);
|
|
348
|
-
if (proc !== undefined) {
|
|
349
|
-
const body = proc.namedChildren.find((child) => child.type === BLOCK) ?? null;
|
|
350
|
-
const decl = leaf(node, owner, "function", name, visibility, body, [], doc);
|
|
351
|
-
return decl === undefined ? [] : [decl];
|
|
352
|
-
}
|
|
353
|
-
const decl = leaf(node, owner, "variable", name, visibility, null, [], doc);
|
|
354
|
-
return decl === undefined ? [] : [decl];
|
|
355
|
-
}
|
|
356
|
-
case FOREIGN_BLOCK: {
|
|
357
|
-
// Package-level foreign { ... } — extract nested decls at same owner.
|
|
358
|
-
const block = node.namedChildren.find((child) => child.type === BLOCK);
|
|
359
|
-
if (block === undefined) return [];
|
|
360
|
-
const out: Decl[] = [];
|
|
361
|
-
for (const child of block.namedChildren) {
|
|
362
|
-
out.push(...declsFromNode(child, owner, source));
|
|
363
|
-
}
|
|
364
|
-
return out;
|
|
365
|
-
}
|
|
366
|
-
default:
|
|
367
|
-
return [];
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function collectImports(root: Node): ImportRef[] {
|
|
372
|
-
const imports: ImportRef[] = [];
|
|
373
|
-
for (const node of root.namedChildren) {
|
|
374
|
-
if (node.type !== IMPORT_DECLARATION) continue;
|
|
375
|
-
const str = node.namedChildren.find((child) => child.type === "string");
|
|
376
|
-
const specifier = str === undefined ? node.text : unquote(str.text);
|
|
377
|
-
imports.push({
|
|
378
|
-
specifier,
|
|
379
|
-
startLine: startLine(node),
|
|
380
|
-
startOffset: node.startIndex,
|
|
381
|
-
endOffset: node.endIndex,
|
|
382
|
-
bindings: [],
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
return imports;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function extractOdin(tree: Tree, source: string): ExtractResult {
|
|
389
|
-
const root = tree.rootNode;
|
|
390
|
-
const decls: Decl[] = [];
|
|
391
|
-
for (const node of root.children) {
|
|
392
|
-
if (node.isNamed || node.isError) decls.push(...declsFromNode(node, "", source));
|
|
393
|
-
}
|
|
394
|
-
return { decls, imports: collectImports(root) };
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
export function odinAdapter(): GrammarAdapter {
|
|
398
|
-
return {
|
|
399
|
-
mode: "grammar",
|
|
400
|
-
id: "odin",
|
|
401
|
-
extensions: EXTENSIONS,
|
|
402
|
-
capabilities: CAPABILITIES,
|
|
403
|
-
importNoiseIdentifiers: IMPORT_NOISE,
|
|
404
|
-
extract: extractOdin,
|
|
405
|
-
resolveFileDep: resolveOdinFileDep,
|
|
406
|
-
};
|
|
407
|
-
}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import type { ExploreEngine } from "../engine.ts";
|
|
2
|
-
import type { Candidate } from "../identity.ts";
|
|
3
|
-
import type { ExploreFileGraph, FileGraphEdge } from "../graph/file-graph.ts";
|
|
4
|
-
import {
|
|
5
|
-
queryRelationships,
|
|
6
|
-
type RelationshipCertainty,
|
|
7
|
-
type RelationshipSite,
|
|
8
|
-
type RelationshipSiteKind,
|
|
9
|
-
} from "../graph/relationships.ts";
|
|
10
|
-
import { resolveCompositeTarget, type CompositeTarget } from "./composite-target.ts";
|
|
11
|
-
|
|
12
|
-
const IMPACT_SECTION_LIMIT = 50;
|
|
13
|
-
export const IMPACT_DEPTH_DEFAULT = 2;
|
|
14
|
-
export const IMPACT_DEPTH_MAX = 5;
|
|
15
|
-
|
|
16
|
-
export type ImpactMode = "all" | "deps" | "dependents";
|
|
17
|
-
|
|
18
|
-
export type ImpactSectionId = "callees" | "fileImports" | "callers" | "fileImporters" | "transitiveDependents";
|
|
19
|
-
|
|
20
|
-
export type ImpactSiteRow = {
|
|
21
|
-
kind: "site";
|
|
22
|
-
path: string;
|
|
23
|
-
line: number;
|
|
24
|
-
siteKind: RelationshipSiteKind;
|
|
25
|
-
name: string;
|
|
26
|
-
preview: string;
|
|
27
|
-
certainty: RelationshipCertainty;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export type ImpactFileRow = {
|
|
31
|
-
kind: "file";
|
|
32
|
-
path: string | undefined;
|
|
33
|
-
externalId: string | undefined;
|
|
34
|
-
depth: number;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export type ImpactRow = ImpactSiteRow | ImpactFileRow;
|
|
38
|
-
|
|
39
|
-
export type ImpactSection = {
|
|
40
|
-
id: ImpactSectionId;
|
|
41
|
-
label: string;
|
|
42
|
-
rows: ImpactRow[];
|
|
43
|
-
limit: number;
|
|
44
|
-
omitted: boolean;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export type ImpactTarget = CompositeTarget;
|
|
48
|
-
|
|
49
|
-
export type ImpactResult =
|
|
50
|
-
| {
|
|
51
|
-
kind: "resolved";
|
|
52
|
-
target: ImpactTarget;
|
|
53
|
-
sections: ImpactSection[];
|
|
54
|
-
parseDegraded: boolean;
|
|
55
|
-
notes: string[];
|
|
56
|
-
}
|
|
57
|
-
| { kind: "candidates"; candidates: Candidate[] }
|
|
58
|
-
| { kind: "notFound" }
|
|
59
|
-
| { kind: "error"; message: string };
|
|
60
|
-
|
|
61
|
-
export type ImpactQueryArgs = {
|
|
62
|
-
engine: ExploreEngine;
|
|
63
|
-
graph: ExploreFileGraph;
|
|
64
|
-
scopePath: string;
|
|
65
|
-
targetPath: string | undefined;
|
|
66
|
-
name: string;
|
|
67
|
-
line: number | undefined;
|
|
68
|
-
depth: number;
|
|
69
|
-
mode: ImpactMode;
|
|
70
|
-
signal: AbortSignal;
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
function siteRows(sites: readonly RelationshipSite[]): ImpactSiteRow[] {
|
|
74
|
-
return sites.slice(0, IMPACT_SECTION_LIMIT).map((site) => ({
|
|
75
|
-
kind: "site" as const,
|
|
76
|
-
path: site.path,
|
|
77
|
-
line: site.line,
|
|
78
|
-
siteKind: site.kind,
|
|
79
|
-
name: site.name,
|
|
80
|
-
preview: site.preview,
|
|
81
|
-
certainty: site.certainty,
|
|
82
|
-
}));
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function fileRowsFromEdges(edges: readonly FileGraphEdge[]): ImpactFileRow[] {
|
|
86
|
-
const rows: ImpactFileRow[] = [];
|
|
87
|
-
for (const edge of edges) {
|
|
88
|
-
if (rows.length >= IMPACT_SECTION_LIMIT) break;
|
|
89
|
-
if (edge.kind === "internal") {
|
|
90
|
-
rows.push({ kind: "file", path: edge.to, externalId: undefined, depth: 1 });
|
|
91
|
-
} else {
|
|
92
|
-
rows.push({ kind: "file", path: undefined, externalId: edge.id, depth: 1 });
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return rows;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async function relationshipSection(
|
|
99
|
-
args: ImpactQueryArgs,
|
|
100
|
-
op: "callees" | "callers",
|
|
101
|
-
id: ImpactSectionId,
|
|
102
|
-
label: string,
|
|
103
|
-
target: ImpactTarget,
|
|
104
|
-
): Promise<{ section: ImpactSection | undefined; parseDegraded: boolean; note: string | undefined }> {
|
|
105
|
-
const result = await queryRelationships({
|
|
106
|
-
engine: args.engine,
|
|
107
|
-
graph: args.graph,
|
|
108
|
-
scopePath: args.scopePath,
|
|
109
|
-
op,
|
|
110
|
-
targetPath: target.path,
|
|
111
|
-
name: target.name,
|
|
112
|
-
line: target.startLine,
|
|
113
|
-
resultLimit: IMPACT_SECTION_LIMIT,
|
|
114
|
-
signal: args.signal,
|
|
115
|
-
});
|
|
116
|
-
if (result.kind === "resolved") {
|
|
117
|
-
const rows = siteRows(result.sites);
|
|
118
|
-
if (rows.length === 0) return { section: undefined, parseDegraded: result.parseDegraded, note: undefined };
|
|
119
|
-
return {
|
|
120
|
-
section: {
|
|
121
|
-
id,
|
|
122
|
-
label,
|
|
123
|
-
rows,
|
|
124
|
-
limit: IMPACT_SECTION_LIMIT,
|
|
125
|
-
omitted: result.resultLimitReached || result.sites.length > IMPACT_SECTION_LIMIT,
|
|
126
|
-
},
|
|
127
|
-
parseDegraded: result.parseDegraded,
|
|
128
|
-
note: undefined,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
if (result.kind === "error") {
|
|
132
|
-
return { section: undefined, parseDegraded: false, note: result.message };
|
|
133
|
-
}
|
|
134
|
-
return { section: undefined, parseDegraded: false, note: undefined };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Blast radius composite: symbol callees/callers + file imports/importers + transitive file dependents.
|
|
139
|
-
* Symbol hops are depth 1 only; `depth` applies to reverse file BFS only.
|
|
140
|
-
*/
|
|
141
|
-
export async function queryImpact(args: ImpactQueryArgs): Promise<ImpactResult> {
|
|
142
|
-
const { graph, signal } = args;
|
|
143
|
-
if (args.depth < 1) {
|
|
144
|
-
return { kind: "error", message: "depth must be >= 1" };
|
|
145
|
-
}
|
|
146
|
-
const depth = Math.min(args.depth, IMPACT_DEPTH_MAX);
|
|
147
|
-
|
|
148
|
-
const resolved = await resolveCompositeTarget(
|
|
149
|
-
args.engine,
|
|
150
|
-
args.scopePath,
|
|
151
|
-
args.targetPath,
|
|
152
|
-
args.name,
|
|
153
|
-
args.line,
|
|
154
|
-
"impact",
|
|
155
|
-
signal,
|
|
156
|
-
);
|
|
157
|
-
if (resolved.kind !== "resolved") return resolved;
|
|
158
|
-
|
|
159
|
-
const target = resolved.value.target;
|
|
160
|
-
const mode = args.mode;
|
|
161
|
-
const wantDeps = mode === "all" || mode === "deps";
|
|
162
|
-
const wantDependents = mode === "all" || mode === "dependents";
|
|
163
|
-
const sections: ImpactSection[] = [];
|
|
164
|
-
const notes: string[] = [];
|
|
165
|
-
let parseDegraded = resolved.value.parseDegraded;
|
|
166
|
-
|
|
167
|
-
if (wantDeps) {
|
|
168
|
-
const callees = await relationshipSection(args, "callees", "callees", "callees", target);
|
|
169
|
-
if (callees.section !== undefined) sections.push(callees.section);
|
|
170
|
-
if (callees.parseDegraded) parseDegraded = true;
|
|
171
|
-
if (callees.note !== undefined) notes.push(callees.note);
|
|
172
|
-
|
|
173
|
-
try {
|
|
174
|
-
const edges = await graph.forwardEdges(target.path, signal);
|
|
175
|
-
const rows = fileRowsFromEdges(edges);
|
|
176
|
-
if (rows.length > 0) {
|
|
177
|
-
sections.push({
|
|
178
|
-
id: "fileImports",
|
|
179
|
-
label: "file imports",
|
|
180
|
-
rows,
|
|
181
|
-
limit: IMPACT_SECTION_LIMIT,
|
|
182
|
-
omitted: edges.length > IMPACT_SECTION_LIMIT,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
} catch (error) {
|
|
186
|
-
notes.push(error instanceof Error ? error.message : String(error));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (wantDependents) {
|
|
191
|
-
const callers = await relationshipSection(args, "callers", "callers", "callers", target);
|
|
192
|
-
if (callers.section !== undefined) sections.push(callers.section);
|
|
193
|
-
if (callers.parseDegraded) parseDegraded = true;
|
|
194
|
-
if (callers.note !== undefined) notes.push(callers.note);
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
const reverseLimit = IMPACT_SECTION_LIMIT * Math.max(depth, 1);
|
|
198
|
-
const reverse = await graph.reverseDeps(target.path, depth, reverseLimit, signal);
|
|
199
|
-
const importerHits = reverse.hits.filter((hit) => hit.depth === 1);
|
|
200
|
-
const importers = importerHits.slice(0, IMPACT_SECTION_LIMIT).map(
|
|
201
|
-
(hit): ImpactFileRow => ({
|
|
202
|
-
kind: "file",
|
|
203
|
-
path: hit.path,
|
|
204
|
-
externalId: hit.externalId,
|
|
205
|
-
depth: hit.depth,
|
|
206
|
-
}),
|
|
207
|
-
);
|
|
208
|
-
if (importers.length > 0) {
|
|
209
|
-
sections.push({
|
|
210
|
-
id: "fileImporters",
|
|
211
|
-
label: "file importers",
|
|
212
|
-
rows: importers,
|
|
213
|
-
limit: IMPACT_SECTION_LIMIT,
|
|
214
|
-
omitted: importerHits.length > IMPACT_SECTION_LIMIT,
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (depth >= 2) {
|
|
219
|
-
const transitiveHits = reverse.hits.filter((hit) => hit.depth >= 2 && hit.depth <= depth);
|
|
220
|
-
const transitive = transitiveHits.slice(0, IMPACT_SECTION_LIMIT).map(
|
|
221
|
-
(hit): ImpactFileRow => ({
|
|
222
|
-
kind: "file",
|
|
223
|
-
path: hit.path,
|
|
224
|
-
externalId: hit.externalId,
|
|
225
|
-
depth: hit.depth,
|
|
226
|
-
}),
|
|
227
|
-
);
|
|
228
|
-
if (transitive.length > 0) {
|
|
229
|
-
sections.push({
|
|
230
|
-
id: "transitiveDependents",
|
|
231
|
-
label: "transitive dependents",
|
|
232
|
-
rows: transitive,
|
|
233
|
-
limit: IMPACT_SECTION_LIMIT,
|
|
234
|
-
omitted: transitiveHits.length > IMPACT_SECTION_LIMIT || reverse.resultLimitReached,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
} catch (error) {
|
|
239
|
-
notes.push(error instanceof Error ? error.message : String(error));
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
kind: "resolved",
|
|
245
|
-
target,
|
|
246
|
-
sections,
|
|
247
|
-
parseDegraded,
|
|
248
|
-
notes: [...new Set(notes)],
|
|
249
|
-
};
|
|
250
|
-
}
|