@moda-ai/cli 1.55.60 → 1.55.62
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/dist/{agent-ds0qdtxz.js → agent-rc62qxke.js} +18 -17
- package/dist/{cli-94r5x9bg.js → cli-27kkk5z4.js} +1 -1
- package/dist/{cli-bt564t50.js → cli-3t4ft30h.js} +5 -5
- package/dist/{cli-9g8kp42c.js → cli-9rmx2zzy.js} +2 -2
- package/dist/{cli-hawwf30b.js → cli-bpnt0z0y.js} +1 -1
- package/dist/{cli-2jwxdhh5.js → cli-c7mj168q.js} +1 -1
- package/dist/cli-fsgh8mq5.js +1522 -0
- package/dist/{cli-y5d33a1y.js → cli-gmvbapx7.js} +2 -1517
- package/dist/{cli-rtkjjf0a.js → cli-kmq9pgef.js} +68 -1241
- package/dist/{cli-v2h21cgf.js → cli-m702wdtv.js} +1 -1
- package/dist/cli-mfvwvh84.js +1178 -0
- package/dist/{cli-b918vs2m.js → cli-p2tfx93b.js} +4 -4
- package/dist/{cli-m25c0rke.js → cli-rdwy3y4f.js} +3 -3
- package/dist/{cli-hxy54rx3.js → cli-thy08dak.js} +11 -11
- package/dist/{cli-wbd3hzqh.js → cli-tn9dg758.js} +680 -153
- package/dist/{cli-31ybq5f2.js → cli-wcax07xh.js} +2 -2
- package/dist/cli.js +27 -20
- package/dist/{doctor-s9t8e808.js → doctor-ehqrzq5e.js} +8 -8
- package/dist/{harness-bxcetthw.js → harness-e1yawk87.js} +13 -11
- package/dist/{harness-github-actions-acxh0dbf.js → harness-github-actions-bgfnh4tw.js} +11 -9
- package/dist/{harness-report-gz5d3y48.js → harness-report-dc6yf2qv.js} +2 -1
- package/dist/index-gtqxj0fp.js +2956 -0
- package/dist/{index-d8hc0er0.js → index-ma1gt133.js} +31 -29
- package/dist/{production-intelligence-fqvhzq6s.js → production-intelligence-40teyxyv.js} +4 -4
- package/dist/{profile-commands-yvpe4d8y.js → profile-commands-fa2858ez.js} +5 -5
- package/dist/{prompt-attribution-6xc7h59r.js → prompt-attribution-htyrwdjj.js} +13 -11
- package/dist/prompt-source-mcp.js +11 -9
- package/dist/{prompt-sources-1hycgx6r.js → prompt-sources-r2xbxr0r.js} +2 -1
- package/dist/{prompts-e8rhawyc.js → prompts-s5q70jge.js} +6 -6
- package/dist/{provision-aqhfbnez.js → provision-2bb73ywd.js} +6 -6
- package/dist/{registry-wv1zzyce.js → registry-ztn727mn.js} +4 -4
- package/dist/{skills-etzcqhp8.js → skills-c25dmy28.js} +6 -6
- package/dist/{sync-m9htrc8t.js → sync-t1d50rpv.js} +16 -14
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/dist/{cli-pnarsb96.js → cli-15pzedv3.js} +3 -3
|
@@ -0,0 +1,2956 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildImportGraphReachability
|
|
3
|
+
} from "./cli-mfvwvh84.js";
|
|
4
|
+
import {
|
|
5
|
+
require_typescript
|
|
6
|
+
} from "./cli-gmvbapx7.js";
|
|
7
|
+
import {
|
|
8
|
+
__toESM
|
|
9
|
+
} from "./cli-0v6na3yp.js";
|
|
10
|
+
|
|
11
|
+
// src/harness-extract/index.ts
|
|
12
|
+
var import_typescript6 = __toESM(require_typescript(), 1);
|
|
13
|
+
import { resolve as resolve2 } from "node:path";
|
|
14
|
+
|
|
15
|
+
// src/harness-extract/ast.ts
|
|
16
|
+
var import_typescript = __toESM(require_typescript(), 1);
|
|
17
|
+
import { relative } from "node:path";
|
|
18
|
+
var SVELTE_VIRTUAL_SUFFIX = ".moda-script.ts";
|
|
19
|
+
function svelteVirtualName(svelteFile) {
|
|
20
|
+
return `${svelteFile}${SVELTE_VIRTUAL_SUFFIX}`;
|
|
21
|
+
}
|
|
22
|
+
function relPath(rootDir, fileName) {
|
|
23
|
+
const real = fileName.endsWith(SVELTE_VIRTUAL_SUFFIX) ? fileName.slice(0, -SVELTE_VIRTUAL_SUFFIX.length) : fileName;
|
|
24
|
+
return relative(rootDir, real).split("\\").join("/");
|
|
25
|
+
}
|
|
26
|
+
function lineOf(node) {
|
|
27
|
+
const source = node.getSourceFile();
|
|
28
|
+
return source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1;
|
|
29
|
+
}
|
|
30
|
+
function colOf(node) {
|
|
31
|
+
const source = node.getSourceFile();
|
|
32
|
+
return source.getLineAndCharacterOfPosition(node.getStart(source)).character + 1;
|
|
33
|
+
}
|
|
34
|
+
function unwrap(node) {
|
|
35
|
+
let current = node;
|
|
36
|
+
for (;; ) {
|
|
37
|
+
if (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isSatisfiesExpression(current) || import_typescript.default.isTypeAssertionExpression(current) || import_typescript.default.isNonNullExpression(current) || import_typescript.default.isAwaitExpression(current)) {
|
|
38
|
+
current = current.expression;
|
|
39
|
+
} else {
|
|
40
|
+
return current;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function propertyNameText(name) {
|
|
45
|
+
if (!name)
|
|
46
|
+
return;
|
|
47
|
+
if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isPrivateIdentifier(name) || import_typescript.default.isNumericLiteral(name) || import_typescript.default.isNoSubstitutionTemplateLiteral(name))
|
|
48
|
+
return name.text;
|
|
49
|
+
if (import_typescript.default.isComputedPropertyName(name)) {
|
|
50
|
+
const inner = unwrap(name.expression);
|
|
51
|
+
if (import_typescript.default.isStringLiteral(inner) || import_typescript.default.isNoSubstitutionTemplateLiteral(inner))
|
|
52
|
+
return inner.text;
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
function calleeChain(expression) {
|
|
57
|
+
const parts = [];
|
|
58
|
+
let current = expression;
|
|
59
|
+
for (;; ) {
|
|
60
|
+
current = unwrap(current);
|
|
61
|
+
if (import_typescript.default.isPropertyAccessExpression(current)) {
|
|
62
|
+
parts.unshift(current.name.text);
|
|
63
|
+
current = current.expression;
|
|
64
|
+
} else if (import_typescript.default.isIdentifier(current)) {
|
|
65
|
+
parts.unshift(current.text);
|
|
66
|
+
return parts;
|
|
67
|
+
} else if (current.kind === import_typescript.default.SyntaxKind.ThisKeyword) {
|
|
68
|
+
parts.unshift("this");
|
|
69
|
+
return parts;
|
|
70
|
+
} else if (import_typescript.default.isCallExpression(current) || import_typescript.default.isNewExpression(current) || import_typescript.default.isElementAccessExpression(current)) {
|
|
71
|
+
parts.unshift("()");
|
|
72
|
+
return parts;
|
|
73
|
+
} else {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function isFunctionLike(node) {
|
|
79
|
+
return import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isMethodDeclaration(node) || import_typescript.default.isArrowFunction(node) || import_typescript.default.isFunctionExpression(node) || import_typescript.default.isConstructorDeclaration(node) || import_typescript.default.isGetAccessorDeclaration(node);
|
|
80
|
+
}
|
|
81
|
+
function enclosingFunction(node) {
|
|
82
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
83
|
+
if (isFunctionLike(current))
|
|
84
|
+
return current;
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
function functionName(fn) {
|
|
89
|
+
if (import_typescript.default.isConstructorDeclaration(fn))
|
|
90
|
+
return "constructor";
|
|
91
|
+
if (fn.name)
|
|
92
|
+
return propertyNameText(fn.name);
|
|
93
|
+
const holder = fn.parent;
|
|
94
|
+
if (holder && import_typescript.default.isVariableDeclaration(holder) && import_typescript.default.isIdentifier(holder.name))
|
|
95
|
+
return holder.name.text;
|
|
96
|
+
if (holder && (import_typescript.default.isPropertyAssignment(holder) || import_typescript.default.isPropertyDeclaration(holder)))
|
|
97
|
+
return propertyNameText(holder.name);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
function enclosingClass(node) {
|
|
101
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
102
|
+
if (import_typescript.default.isClassDeclaration(current) || import_typescript.default.isClassExpression(current))
|
|
103
|
+
return current;
|
|
104
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
function className(cls) {
|
|
108
|
+
if (cls.name)
|
|
109
|
+
return cls.name.text;
|
|
110
|
+
const holder = cls.parent;
|
|
111
|
+
if (holder && import_typescript.default.isVariableDeclaration(holder) && import_typescript.default.isIdentifier(holder.name))
|
|
112
|
+
return holder.name.text;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
function returnExpressions(fn) {
|
|
116
|
+
const body = fn.body;
|
|
117
|
+
if (!body)
|
|
118
|
+
return [];
|
|
119
|
+
if (!import_typescript.default.isBlock(body))
|
|
120
|
+
return [body];
|
|
121
|
+
const out = [];
|
|
122
|
+
const visit = (node) => {
|
|
123
|
+
if (isFunctionLike(node) || import_typescript.default.isClassLike(node))
|
|
124
|
+
return;
|
|
125
|
+
if (import_typescript.default.isReturnStatement(node) && node.expression)
|
|
126
|
+
out.push(node.expression);
|
|
127
|
+
import_typescript.default.forEachChild(node, visit);
|
|
128
|
+
};
|
|
129
|
+
import_typescript.default.forEachChild(body, visit);
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
function moduleSpecifierOf(declaration) {
|
|
133
|
+
let specifier;
|
|
134
|
+
let imported = "";
|
|
135
|
+
if (import_typescript.default.isImportSpecifier(declaration)) {
|
|
136
|
+
specifier = declaration.parent.parent.parent.moduleSpecifier;
|
|
137
|
+
imported = (declaration.propertyName ?? declaration.name).text;
|
|
138
|
+
} else if (import_typescript.default.isImportClause(declaration)) {
|
|
139
|
+
specifier = declaration.parent.moduleSpecifier;
|
|
140
|
+
imported = "default";
|
|
141
|
+
} else if (import_typescript.default.isNamespaceImport(declaration)) {
|
|
142
|
+
specifier = declaration.parent.parent.moduleSpecifier;
|
|
143
|
+
imported = "*";
|
|
144
|
+
} else if (import_typescript.default.isExportSpecifier(declaration)) {
|
|
145
|
+
specifier = declaration.parent.parent.moduleSpecifier;
|
|
146
|
+
imported = (declaration.propertyName ?? declaration.name).text;
|
|
147
|
+
} else if (import_typescript.default.isImportEqualsDeclaration(declaration) && import_typescript.default.isExternalModuleReference(declaration.moduleReference)) {
|
|
148
|
+
specifier = declaration.moduleReference.expression;
|
|
149
|
+
imported = "*";
|
|
150
|
+
} else if (import_typescript.default.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
151
|
+
const init = unwrap(declaration.initializer);
|
|
152
|
+
if (import_typescript.default.isCallExpression(init) && import_typescript.default.isIdentifier(init.expression) && init.expression.text === "require" && init.arguments[0] && import_typescript.default.isStringLiteral(init.arguments[0])) {
|
|
153
|
+
specifier = init.arguments[0];
|
|
154
|
+
imported = "*";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (!specifier || !import_typescript.default.isStringLiteral(specifier))
|
|
158
|
+
return;
|
|
159
|
+
return { module: specifier.text, imported };
|
|
160
|
+
}
|
|
161
|
+
function isBareModule(module) {
|
|
162
|
+
return !module.startsWith(".") && !module.startsWith("/");
|
|
163
|
+
}
|
|
164
|
+
function importOrigin(identifier, checker) {
|
|
165
|
+
let symbol;
|
|
166
|
+
try {
|
|
167
|
+
symbol = checker.getSymbolAtLocation(identifier);
|
|
168
|
+
} catch {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
for (let hop = 0;symbol && hop < 6; hop += 1) {
|
|
172
|
+
if (!(symbol.flags & import_typescript.default.SymbolFlags.Alias))
|
|
173
|
+
return;
|
|
174
|
+
const declaration = symbol.declarations?.[0];
|
|
175
|
+
if (!declaration)
|
|
176
|
+
return;
|
|
177
|
+
const origin = moduleSpecifierOf(declaration);
|
|
178
|
+
if (origin && isBareModule(origin.module))
|
|
179
|
+
return origin;
|
|
180
|
+
let next;
|
|
181
|
+
try {
|
|
182
|
+
next = checker.getImmediateAliasedSymbol(symbol);
|
|
183
|
+
} catch {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!next || next === symbol)
|
|
187
|
+
return;
|
|
188
|
+
symbol = next;
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
function resolvedSymbol(node, checker) {
|
|
193
|
+
let symbol;
|
|
194
|
+
try {
|
|
195
|
+
symbol = node.parent && import_typescript.default.isShorthandPropertyAssignment(node.parent) && node.parent.name === node ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
|
|
196
|
+
if (symbol && symbol.flags & import_typescript.default.SymbolFlags.Alias) {
|
|
197
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
198
|
+
if (aliased && aliased.declarations && aliased.declarations.length > 0)
|
|
199
|
+
symbol = aliased;
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
return symbol;
|
|
205
|
+
}
|
|
206
|
+
function valueDeclaration(symbol) {
|
|
207
|
+
if (!symbol)
|
|
208
|
+
return;
|
|
209
|
+
return symbol.valueDeclaration ?? symbol.declarations?.[0];
|
|
210
|
+
}
|
|
211
|
+
function rootIdentifier(expression) {
|
|
212
|
+
let current = unwrap(expression);
|
|
213
|
+
while (import_typescript.default.isPropertyAccessExpression(current) || import_typescript.default.isElementAccessExpression(current))
|
|
214
|
+
current = unwrap(current.expression);
|
|
215
|
+
return import_typescript.default.isIdentifier(current) ? current : undefined;
|
|
216
|
+
}
|
|
217
|
+
function objectLiteralOf(node, checker, depth = 0) {
|
|
218
|
+
if (!node || depth > 3)
|
|
219
|
+
return;
|
|
220
|
+
const value = unwrap(node);
|
|
221
|
+
if (import_typescript.default.isObjectLiteralExpression(value))
|
|
222
|
+
return value;
|
|
223
|
+
if (import_typescript.default.isIdentifier(value)) {
|
|
224
|
+
const declaration = valueDeclaration(resolvedSymbol(value, checker));
|
|
225
|
+
if (declaration && import_typescript.default.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
226
|
+
return objectLiteralOf(declaration.initializer, checker, depth + 1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
function propertyValue(object, key) {
|
|
232
|
+
let found;
|
|
233
|
+
for (const property of object.properties) {
|
|
234
|
+
if (import_typescript.default.isPropertyAssignment(property) && propertyNameText(property.name) === key)
|
|
235
|
+
found = property.initializer;
|
|
236
|
+
else if (import_typescript.default.isShorthandPropertyAssignment(property) && property.name.text === key)
|
|
237
|
+
found = property.name;
|
|
238
|
+
else if (import_typescript.default.isMethodDeclaration(property) && propertyNameText(property.name) === key)
|
|
239
|
+
found = undefined;
|
|
240
|
+
}
|
|
241
|
+
return found;
|
|
242
|
+
}
|
|
243
|
+
function hasProperty(object, key) {
|
|
244
|
+
return object.properties.some((property) => propertyNameText(property.name) === key);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// src/harness-extract/calls.ts
|
|
248
|
+
var import_typescript3 = __toESM(require_typescript(), 1);
|
|
249
|
+
|
|
250
|
+
// src/harness-extract/trace.ts
|
|
251
|
+
var import_typescript2 = __toESM(require_typescript(), 1);
|
|
252
|
+
var DEFAULT_TRACE_DEPTH = 8;
|
|
253
|
+
var DEFAULT_MAX_CALLERS = 10;
|
|
254
|
+
var DEFAULT_MAX_NODES = 4000;
|
|
255
|
+
var MAX_TEXT = 4000;
|
|
256
|
+
var MAX_RETURNS = 12;
|
|
257
|
+
var MAX_MEMBERS = 400;
|
|
258
|
+
var MAX_MUTATIONS = 64;
|
|
259
|
+
var DEFAULT_CALLER_DEPTH = 3;
|
|
260
|
+
var TEXT_HELPERS = new Set(["dedent", "outdent", "stripIndent", "stripIndents", "oneLine", "oneLineTrim", "String"]);
|
|
261
|
+
var TRIM_METHODS = new Set(["trim", "trimStart", "trimEnd"]);
|
|
262
|
+
var CASE_METHODS = new Set(["toLowerCase", "toUpperCase"]);
|
|
263
|
+
var EMPTY_ENV = new Map;
|
|
264
|
+
function envFrom(bindings) {
|
|
265
|
+
const env = new Map;
|
|
266
|
+
for (const binding of bindings)
|
|
267
|
+
env.set(binding.param, { expr: binding.expr, env: envFrom(binding.outer ?? []) });
|
|
268
|
+
return env;
|
|
269
|
+
}
|
|
270
|
+
function valueChildren(tree) {
|
|
271
|
+
if (tree.kind === "call" && tree.callee)
|
|
272
|
+
return [tree.callee];
|
|
273
|
+
if (tree.kind === "param")
|
|
274
|
+
return [...tree.bindings ?? [], ...tree.children ?? []];
|
|
275
|
+
return tree.children ?? [];
|
|
276
|
+
}
|
|
277
|
+
function mapFlow(tree, map) {
|
|
278
|
+
if (tree.kind === "call" && tree.callee) {
|
|
279
|
+
const callee = map(tree.callee);
|
|
280
|
+
return { ...tree, callee, resolution: callee.resolution, ...reasonOf(callee.resolution, [callee]) };
|
|
281
|
+
}
|
|
282
|
+
const out = { ...tree };
|
|
283
|
+
if (tree.bindings)
|
|
284
|
+
out.bindings = tree.bindings.map(map);
|
|
285
|
+
if (tree.children)
|
|
286
|
+
out.children = tree.children.map(map);
|
|
287
|
+
const all = valueChildren(out);
|
|
288
|
+
out.resolution = rollup(all);
|
|
289
|
+
delete out.unresolvedReason;
|
|
290
|
+
Object.assign(out, reasonOf(out.resolution, all));
|
|
291
|
+
return out;
|
|
292
|
+
}
|
|
293
|
+
function reasonOf(resolution, children) {
|
|
294
|
+
if (resolution !== "unresolved")
|
|
295
|
+
return {};
|
|
296
|
+
const reason = children.find((child) => child.unresolvedReason)?.unresolvedReason;
|
|
297
|
+
return reason ? { unresolvedReason: reason } : {};
|
|
298
|
+
}
|
|
299
|
+
function rollup(children) {
|
|
300
|
+
if (children.length === 0)
|
|
301
|
+
return "unresolved";
|
|
302
|
+
if (children.every((child) => child.resolution === "resolved"))
|
|
303
|
+
return "resolved";
|
|
304
|
+
if (children.every((child) => child.resolution === "unresolved"))
|
|
305
|
+
return "unresolved";
|
|
306
|
+
return "partial";
|
|
307
|
+
}
|
|
308
|
+
function truncate(text) {
|
|
309
|
+
return text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT)}...` : text;
|
|
310
|
+
}
|
|
311
|
+
function makeNode(rootDir, kind, at, extra) {
|
|
312
|
+
const source = at.getSourceFile();
|
|
313
|
+
const start = at.getStart(source);
|
|
314
|
+
const end = at.getEnd();
|
|
315
|
+
const begin = source.getLineAndCharacterOfPosition(start);
|
|
316
|
+
const path = relPath(rootDir, source.fileName);
|
|
317
|
+
const out = {
|
|
318
|
+
id: `${path}:${begin.line + 1}:${begin.character + 1}`,
|
|
319
|
+
kind,
|
|
320
|
+
path,
|
|
321
|
+
line: begin.line + 1,
|
|
322
|
+
endLine: source.getLineAndCharacterOfPosition(end).line + 1,
|
|
323
|
+
start,
|
|
324
|
+
end,
|
|
325
|
+
resolution: extra.resolution
|
|
326
|
+
};
|
|
327
|
+
for (const [field, value] of Object.entries(extra)) {
|
|
328
|
+
if (value !== undefined && field !== "resolution")
|
|
329
|
+
out[field] = value;
|
|
330
|
+
}
|
|
331
|
+
if (out.resolution === "unresolved" && !out.unresolvedReason)
|
|
332
|
+
Object.assign(out, reasonOf("unresolved", valueChildren(out)));
|
|
333
|
+
return out;
|
|
334
|
+
}
|
|
335
|
+
function shallow(tree) {
|
|
336
|
+
const { children: _children, bindings: _bindings, callee: _callee, args: _args, object: _object, keyNode: _keyNode, parts: _parts, ...rest } = tree;
|
|
337
|
+
return rest;
|
|
338
|
+
}
|
|
339
|
+
var IO_METHOD = /^(?:fetch|readFile|readFileSync|readdir|query|prepare|first|all|exec|execute|getItem|json|text|blob|arrayBuffer|findMany|findFirst|findUnique|findOne|find|select|download|getObject|scan|batch|sql|raw)$/;
|
|
340
|
+
var IO_MODULE = /^(?:node:)?(?:fs|fs\/promises|http|https|net|child_process)$|^(?:@supabase\/|@prisma\/|drizzle-orm|pg$|postgres$|mysql2?|mongodb|mongoose|redis|ioredis|@upstash\/|@aws-sdk\/|@google-cloud\/|kysely|knex|better-sqlite3|@libsql\/|@planetscale\/|@neondatabase\/|axios|got|node-fetch|undici|ky)/;
|
|
341
|
+
var MESSAGE_CLASS = /^(?:System|Human|AI|Ai|Tool|Function|Chat|Assistant|User)Message(?:Chunk)?$/;
|
|
342
|
+
var PROMPT_FACTORY = /(?:PromptTemplate|MessagePromptTemplate)\.(?:fromTemplate|fromMessages|fromPromptMessages)$/;
|
|
343
|
+
var ARRAY_METHODS = new Set(["push", "unshift", "splice"]);
|
|
344
|
+
var mutationIndex = new WeakMap;
|
|
345
|
+
function mutationsIn(scope) {
|
|
346
|
+
const cached = mutationIndex.get(scope);
|
|
347
|
+
if (cached)
|
|
348
|
+
return cached;
|
|
349
|
+
const byName = new Map;
|
|
350
|
+
const add = (mutation) => {
|
|
351
|
+
const list = byName.get(mutation.target.text);
|
|
352
|
+
if (list)
|
|
353
|
+
list.push(mutation);
|
|
354
|
+
else
|
|
355
|
+
byName.set(mutation.target.text, [mutation]);
|
|
356
|
+
};
|
|
357
|
+
const visit = (node) => {
|
|
358
|
+
if (import_typescript2.default.isBinaryExpression(node) && import_typescript2.default.isIdentifier(node.left)) {
|
|
359
|
+
const kind = node.operatorToken.kind;
|
|
360
|
+
if (kind === import_typescript2.default.SyntaxKind.PlusEqualsToken)
|
|
361
|
+
add({ op: "+=", at: node, target: node.left, values: [node.right] });
|
|
362
|
+
else if (kind === import_typescript2.default.SyntaxKind.EqualsToken)
|
|
363
|
+
add(selfAssignment(node.left, node.right, node));
|
|
364
|
+
} else if (import_typescript2.default.isCallExpression(node) && import_typescript2.default.isPropertyAccessExpression(node.expression) && import_typescript2.default.isIdentifier(node.expression.expression) && ARRAY_METHODS.has(node.expression.name.text)) {
|
|
365
|
+
const op = node.expression.name.text;
|
|
366
|
+
const target = node.expression.expression;
|
|
367
|
+
if (op === "splice") {
|
|
368
|
+
const first = node.arguments[0] ? unwrap(node.arguments[0]) : undefined;
|
|
369
|
+
add({ op, at: node, target, values: [...node.arguments.slice(2)], index: first && import_typescript2.default.isNumericLiteral(first) ? Number(first.text) : undefined });
|
|
370
|
+
} else {
|
|
371
|
+
add({ op, at: node, target, values: [...node.arguments] });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
375
|
+
};
|
|
376
|
+
import_typescript2.default.forEachChild(scope, visit);
|
|
377
|
+
mutationIndex.set(scope, byName);
|
|
378
|
+
return byName;
|
|
379
|
+
}
|
|
380
|
+
function selfAssignment(target, right, at) {
|
|
381
|
+
const value = unwrap(right);
|
|
382
|
+
const isSelf = (expression) => {
|
|
383
|
+
const inner = unwrap(expression);
|
|
384
|
+
return import_typescript2.default.isIdentifier(inner) && inner.text === target.text;
|
|
385
|
+
};
|
|
386
|
+
if (import_typescript2.default.isCallExpression(value) && import_typescript2.default.isPropertyAccessExpression(value.expression) && value.expression.name.text === "concat" && isSelf(value.expression.expression)) {
|
|
387
|
+
return { op: "concat", at, target, values: [...value.arguments] };
|
|
388
|
+
}
|
|
389
|
+
if (import_typescript2.default.isBinaryExpression(value) && value.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
390
|
+
const parts = [];
|
|
391
|
+
const flatten = (node) => {
|
|
392
|
+
const inner = unwrap(node);
|
|
393
|
+
if (import_typescript2.default.isBinaryExpression(inner) && inner.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
394
|
+
flatten(inner.left);
|
|
395
|
+
flatten(inner.right);
|
|
396
|
+
} else
|
|
397
|
+
parts.push(node);
|
|
398
|
+
};
|
|
399
|
+
flatten(value);
|
|
400
|
+
if (parts.length > 1 && isSelf(parts[0]))
|
|
401
|
+
return { op: "+=", at, target, values: parts.slice(1) };
|
|
402
|
+
}
|
|
403
|
+
if (import_typescript2.default.isArrayLiteralExpression(value)) {
|
|
404
|
+
const elements = [...value.elements];
|
|
405
|
+
const first = elements[0];
|
|
406
|
+
const last = elements[elements.length - 1];
|
|
407
|
+
if (first && import_typescript2.default.isSpreadElement(first) && isSelf(first.expression))
|
|
408
|
+
return { op: "push", at, target, values: elements.slice(1) };
|
|
409
|
+
if (last && import_typescript2.default.isSpreadElement(last) && isSelf(last.expression))
|
|
410
|
+
return { op: "unshift", at, target, values: elements.slice(0, -1) };
|
|
411
|
+
}
|
|
412
|
+
return { op: "=", at, target, values: [right] };
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
class ValueTracer {
|
|
416
|
+
rootDir;
|
|
417
|
+
checker;
|
|
418
|
+
calls;
|
|
419
|
+
modelArgOf;
|
|
420
|
+
maxDepth;
|
|
421
|
+
maxCallers;
|
|
422
|
+
maxNodes;
|
|
423
|
+
maxCallerDepth;
|
|
424
|
+
count = 0;
|
|
425
|
+
callerLevel = 0;
|
|
426
|
+
stack = new Set;
|
|
427
|
+
reassigning = new Set;
|
|
428
|
+
constructor(rootDir, checker, calls, options = {}, modelArgOf) {
|
|
429
|
+
this.rootDir = rootDir;
|
|
430
|
+
this.checker = checker;
|
|
431
|
+
this.calls = calls;
|
|
432
|
+
this.modelArgOf = modelArgOf;
|
|
433
|
+
this.maxDepth = options.maxDepth ?? DEFAULT_TRACE_DEPTH;
|
|
434
|
+
this.maxCallers = options.maxCallers ?? DEFAULT_MAX_CALLERS;
|
|
435
|
+
this.maxNodes = options.maxNodes ?? DEFAULT_MAX_NODES;
|
|
436
|
+
this.maxCallerDepth = options.maxCallerDepth ?? DEFAULT_CALLER_DEPTH;
|
|
437
|
+
}
|
|
438
|
+
trace(expression, bindings = []) {
|
|
439
|
+
this.count = 0;
|
|
440
|
+
this.callerLevel = 0;
|
|
441
|
+
this.stack.clear();
|
|
442
|
+
this.reassigning.clear();
|
|
443
|
+
return this.value(expression, 0, envFrom(bindings));
|
|
444
|
+
}
|
|
445
|
+
traceAll(expressions, at) {
|
|
446
|
+
if (expressions.length === 1)
|
|
447
|
+
return this.trace(expressions[0]);
|
|
448
|
+
const children = expressions.map((expression) => this.trace(expression));
|
|
449
|
+
return this.node("oneOf", at, { children, resolution: rollup(children) });
|
|
450
|
+
}
|
|
451
|
+
missing(at, note, reason = "external") {
|
|
452
|
+
return this.node("external", at, { resolution: "unresolved", note, unresolvedReason: reason });
|
|
453
|
+
}
|
|
454
|
+
node(kind, at, extra) {
|
|
455
|
+
return makeNode(this.rootDir, kind, at, extra);
|
|
456
|
+
}
|
|
457
|
+
external(at, note, name, reason = "external") {
|
|
458
|
+
return this.node("external", at, { resolution: "unresolved", note, name, text: truncate(at.getText().replace(/\s+/g, " ")), unresolvedReason: reason });
|
|
459
|
+
}
|
|
460
|
+
depthLimit(at, name) {
|
|
461
|
+
return this.external(at, "depth limit reached", name, "depth-limit");
|
|
462
|
+
}
|
|
463
|
+
value(expression, depth, env) {
|
|
464
|
+
this.count += 1;
|
|
465
|
+
if (this.count > this.maxNodes)
|
|
466
|
+
return this.external(expression, "node budget reached", undefined, "depth-limit");
|
|
467
|
+
const expr = unwrap(expression);
|
|
468
|
+
if (this.stack.has(expr))
|
|
469
|
+
return this.external(expr, "cycle", undefined, "depth-limit");
|
|
470
|
+
this.stack.add(expr);
|
|
471
|
+
try {
|
|
472
|
+
return this.dispatch(expr, depth, env);
|
|
473
|
+
} finally {
|
|
474
|
+
this.stack.delete(expr);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
hop(expression, depth, env) {
|
|
478
|
+
if (depth + 1 > this.maxDepth)
|
|
479
|
+
return this.depthLimit(expression);
|
|
480
|
+
return this.value(expression, depth + 1, env);
|
|
481
|
+
}
|
|
482
|
+
element(element, depth, env) {
|
|
483
|
+
return import_typescript2.default.isSpreadElement(element) ? { ...this.value(element.expression, depth, env), key: "..." } : this.value(element, depth, env);
|
|
484
|
+
}
|
|
485
|
+
dispatch(expr, depth, env) {
|
|
486
|
+
if (import_typescript2.default.isStringLiteral(expr) || import_typescript2.default.isNoSubstitutionTemplateLiteral(expr)) {
|
|
487
|
+
return this.node("literal", expr, { text: expr.text, resolution: "resolved" });
|
|
488
|
+
}
|
|
489
|
+
if (import_typescript2.default.isNumericLiteral(expr) || import_typescript2.default.isBigIntLiteral(expr))
|
|
490
|
+
return this.node("literal", expr, { text: expr.text, resolution: "resolved" });
|
|
491
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.TrueKeyword || expr.kind === import_typescript2.default.SyntaxKind.FalseKeyword) {
|
|
492
|
+
return this.node("literal", expr, { text: expr.getText(), resolution: "resolved" });
|
|
493
|
+
}
|
|
494
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.NullKeyword || import_typescript2.default.isVoidExpression(expr) || import_typescript2.default.isIdentifier(expr) && expr.text === "undefined") {
|
|
495
|
+
return this.node("external", expr, { resolution: "unresolved", note: "nullish", name: "undefined", unresolvedReason: "external" });
|
|
496
|
+
}
|
|
497
|
+
if (import_typescript2.default.isTemplateExpression(expr))
|
|
498
|
+
return this.template(expr, depth, env);
|
|
499
|
+
if (import_typescript2.default.isTaggedTemplateExpression(expr)) {
|
|
500
|
+
const tag = import_typescript2.default.isIdentifier(expr.tag) ? expr.tag.text : undefined;
|
|
501
|
+
if (tag && TEXT_HELPERS.has(tag))
|
|
502
|
+
return this.value(expr.template, depth, env);
|
|
503
|
+
return this.external(expr, `tagged template ${expr.tag.getText()}`);
|
|
504
|
+
}
|
|
505
|
+
if (import_typescript2.default.isBinaryExpression(expr))
|
|
506
|
+
return this.binary(expr, depth, env);
|
|
507
|
+
if (import_typescript2.default.isConditionalExpression(expr)) {
|
|
508
|
+
const children = [this.value(expr.whenTrue, depth, env), this.value(expr.whenFalse, depth, env)];
|
|
509
|
+
return this.node("oneOf", expr, { children, resolution: rollup(children), note: "conditional" });
|
|
510
|
+
}
|
|
511
|
+
if (import_typescript2.default.isArrayLiteralExpression(expr)) {
|
|
512
|
+
const children = expr.elements.slice(0, MAX_MEMBERS).map((element) => this.element(element, depth, env));
|
|
513
|
+
return this.node("array", expr, { children, resolution: children.length === 0 ? "resolved" : rollup(children) });
|
|
514
|
+
}
|
|
515
|
+
if (import_typescript2.default.isObjectLiteralExpression(expr))
|
|
516
|
+
return this.object(expr, depth, env);
|
|
517
|
+
if (import_typescript2.default.isIdentifier(expr))
|
|
518
|
+
return this.identifier(expr, depth, env);
|
|
519
|
+
if (import_typescript2.default.isPropertyAccessExpression(expr))
|
|
520
|
+
return this.propertyAccess(expr, depth, env);
|
|
521
|
+
if (import_typescript2.default.isElementAccessExpression(expr))
|
|
522
|
+
return this.elementAccess(expr, depth, env);
|
|
523
|
+
if (import_typescript2.default.isCallExpression(expr))
|
|
524
|
+
return this.call(expr, depth, env);
|
|
525
|
+
if (import_typescript2.default.isNewExpression(expr)) {
|
|
526
|
+
const name = expr.expression.getText();
|
|
527
|
+
const last = import_typescript2.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name.text : name;
|
|
528
|
+
if (MESSAGE_CLASS.test(last) && !resolvedFunction(expr.expression, this.checker)) {
|
|
529
|
+
const children = (expr.arguments ?? []).map((argument) => this.element(argument, depth, env));
|
|
530
|
+
return this.node("call", expr, { name, children, resolution: children.length === 0 ? "unresolved" : rollup(children), note: "constructor" });
|
|
531
|
+
}
|
|
532
|
+
return this.external(expr, `new ${name}`, name);
|
|
533
|
+
}
|
|
534
|
+
if (import_typescript2.default.isArrowFunction(expr) || import_typescript2.default.isFunctionExpression(expr))
|
|
535
|
+
return this.external(expr, "function value");
|
|
536
|
+
if (expr.kind === import_typescript2.default.SyntaxKind.ThisKeyword)
|
|
537
|
+
return this.external(expr, "this");
|
|
538
|
+
return this.external(expr, import_typescript2.default.SyntaxKind[expr.kind]);
|
|
539
|
+
}
|
|
540
|
+
template(expr, depth, env) {
|
|
541
|
+
const children = expr.templateSpans.map((span) => ({ ...this.value(span.expression, depth, env), hole: truncate(span.expression.getText().replace(/\s+/g, " ")) }));
|
|
542
|
+
const literalText = expr.head.text + expr.templateSpans.map((span) => span.literal.text).join("");
|
|
543
|
+
const resolution = children.every((child) => child.resolution === "resolved") ? "resolved" : literalText.trim() !== "" ? "partial" : rollup(children);
|
|
544
|
+
const parts = [expr.head.text, ...expr.templateSpans.map((span) => span.literal.text)];
|
|
545
|
+
return this.node("template", expr, { text: truncate(expr.getText()), children, parts, resolution });
|
|
546
|
+
}
|
|
547
|
+
binary(expr, depth, env) {
|
|
548
|
+
const operator = expr.operatorToken.kind;
|
|
549
|
+
if (operator === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
550
|
+
const parts = [];
|
|
551
|
+
const flatten = (node) => {
|
|
552
|
+
const inner = unwrap(node);
|
|
553
|
+
if (import_typescript2.default.isBinaryExpression(inner) && inner.operatorToken.kind === import_typescript2.default.SyntaxKind.PlusToken) {
|
|
554
|
+
flatten(inner.left);
|
|
555
|
+
flatten(inner.right);
|
|
556
|
+
} else {
|
|
557
|
+
parts.push(node);
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
flatten(expr);
|
|
561
|
+
const children = parts.map((part) => this.value(part, depth, env));
|
|
562
|
+
return this.node("concat", expr, { children, resolution: rollup(children) });
|
|
563
|
+
}
|
|
564
|
+
if (operator === import_typescript2.default.SyntaxKind.QuestionQuestionToken || operator === import_typescript2.default.SyntaxKind.BarBarToken) {
|
|
565
|
+
const left = this.value(expr.left, depth, env);
|
|
566
|
+
if (left.resolution === "resolved" && leaves(left).every((leaf) => leaf.kind === "literal" && (operator === import_typescript2.default.SyntaxKind.QuestionQuestionToken || leaf.text !== "" && leaf.text !== "false" && leaf.text !== "0"))) {
|
|
567
|
+
return left;
|
|
568
|
+
}
|
|
569
|
+
const children = [left, this.value(expr.right, depth, env)];
|
|
570
|
+
return this.node("oneOf", expr, { children, resolution: rollup(children), note: operator === import_typescript2.default.SyntaxKind.BarBarToken ? "||" : "??" });
|
|
571
|
+
}
|
|
572
|
+
if (operator === import_typescript2.default.SyntaxKind.AmpersandAmpersandToken || operator === import_typescript2.default.SyntaxKind.CommaToken) {
|
|
573
|
+
const child = this.value(expr.right, depth, env);
|
|
574
|
+
return this.node("oneOf", expr, { children: [child], resolution: child.resolution, note: operator === import_typescript2.default.SyntaxKind.CommaToken ? "," : "&&" });
|
|
575
|
+
}
|
|
576
|
+
return this.external(expr, `binary ${import_typescript2.default.tokenToString(operator) ?? import_typescript2.default.SyntaxKind[operator]}`);
|
|
577
|
+
}
|
|
578
|
+
object(expr, depth, env) {
|
|
579
|
+
const children = [];
|
|
580
|
+
for (const property of expr.properties.slice(0, MAX_MEMBERS)) {
|
|
581
|
+
if (import_typescript2.default.isPropertyAssignment(property)) {
|
|
582
|
+
const key = propertyNameText(property.name) ?? property.name.getText();
|
|
583
|
+
children.push({ ...this.value(property.initializer, depth, env), key });
|
|
584
|
+
} else if (import_typescript2.default.isShorthandPropertyAssignment(property)) {
|
|
585
|
+
children.push({ ...this.value(property.name, depth, env), key: property.name.text });
|
|
586
|
+
} else if (import_typescript2.default.isSpreadAssignment(property)) {
|
|
587
|
+
children.push({ ...this.value(property.expression, depth, env), key: "..." });
|
|
588
|
+
} else if (import_typescript2.default.isMethodDeclaration(property) || import_typescript2.default.isGetAccessorDeclaration(property)) {
|
|
589
|
+
const key = propertyNameText(property.name) ?? property.name.getText();
|
|
590
|
+
children.push({ ...this.node("external", property, { resolution: "unresolved", note: "method", unresolvedReason: "external" }), key });
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return this.node("object", expr, { children, resolution: children.length === 0 ? "resolved" : rollup(children) });
|
|
594
|
+
}
|
|
595
|
+
identifier(id, depth, env) {
|
|
596
|
+
const symbol = resolvedSymbol(id, this.checker);
|
|
597
|
+
const declaration = valueDeclaration(symbol);
|
|
598
|
+
if (!symbol || !declaration) {
|
|
599
|
+
const origin = importOrigin(id, this.checker);
|
|
600
|
+
if (origin)
|
|
601
|
+
return this.external(id, `import ${origin.imported} from ${origin.module}`, id.text);
|
|
602
|
+
return this.external(id, "unresolved identifier", id.text);
|
|
603
|
+
}
|
|
604
|
+
if (this.reassigning.has(declaration))
|
|
605
|
+
return this.external(id, "previous value", id.text);
|
|
606
|
+
if (import_typescript2.default.isParameter(declaration))
|
|
607
|
+
return this.parameter(declaration, id, depth, env);
|
|
608
|
+
if (import_typescript2.default.isBindingElement(declaration))
|
|
609
|
+
return this.bindingElement(declaration, id, depth, env);
|
|
610
|
+
if (import_typescript2.default.isVariableDeclaration(declaration) && import_typescript2.default.isVariableDeclarationList(declaration.parent) && import_typescript2.default.isForOfStatement(declaration.parent.parent)) {
|
|
611
|
+
if (depth + 1 > this.maxDepth)
|
|
612
|
+
return this.depthLimit(id, id.text);
|
|
613
|
+
const iterable = this.value(declaration.parent.parent.expression, depth + 1, env);
|
|
614
|
+
const values = allValues(iterable);
|
|
615
|
+
if (values.length === 0)
|
|
616
|
+
return this.external(id, "element of an unresolved iterable", id.text);
|
|
617
|
+
return this.node("oneOf", id, { name: id.text, children: values, resolution: rollup(values), note: "for-of element" });
|
|
618
|
+
}
|
|
619
|
+
if (import_typescript2.default.isVariableDeclaration(declaration)) {
|
|
620
|
+
const mutations = this.mutations(symbol, declaration);
|
|
621
|
+
if (mutations.some((mutation) => mutation.op !== "="))
|
|
622
|
+
return this.assembled(id, declaration, mutations, depth, env);
|
|
623
|
+
const sources = [];
|
|
624
|
+
if (declaration.initializer)
|
|
625
|
+
sources.push(this.hop(declaration.initializer, depth, env));
|
|
626
|
+
sources.push(...this.reassignments(declaration, mutations, depth, env));
|
|
627
|
+
if (sources.length === 0)
|
|
628
|
+
return this.external(id, "declared without a value", id.text);
|
|
629
|
+
return this.node("ref", id, { name: id.text, children: sources, resolution: rollup(sources), note: sources.length > 1 ? "reassigned" : undefined });
|
|
630
|
+
}
|
|
631
|
+
if (import_typescript2.default.isEnumMember(declaration) || import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration)) {
|
|
632
|
+
if (!declaration.initializer)
|
|
633
|
+
return this.external(id, "declared without a value", id.text);
|
|
634
|
+
const child = this.hop(declaration.initializer, depth, env);
|
|
635
|
+
return this.node("ref", id, { name: id.text, children: [child], resolution: child.resolution });
|
|
636
|
+
}
|
|
637
|
+
if (import_typescript2.default.isShorthandPropertyAssignment(declaration))
|
|
638
|
+
return this.hop(declaration.name, depth, env);
|
|
639
|
+
if (import_typescript2.default.isFunctionDeclaration(declaration) || import_typescript2.default.isMethodDeclaration(declaration))
|
|
640
|
+
return this.external(id, "function", id.text);
|
|
641
|
+
if (import_typescript2.default.isClassDeclaration(declaration))
|
|
642
|
+
return this.external(id, "class", id.text);
|
|
643
|
+
return this.external(id, `declaration ${import_typescript2.default.SyntaxKind[declaration.kind]}`, id.text);
|
|
644
|
+
}
|
|
645
|
+
mutations(symbol, declaration) {
|
|
646
|
+
const scope = import_typescript2.default.isParameter(declaration) && isFunctionLike(declaration.parent) ? declaration.parent : enclosingScope(declaration);
|
|
647
|
+
const candidates = mutationsIn(scope).get(symbol.name) ?? [];
|
|
648
|
+
return candidates.filter((mutation) => resolvedSymbol(mutation.target, this.checker) === symbol).slice(0, MAX_MUTATIONS);
|
|
649
|
+
}
|
|
650
|
+
reassignments(declaration, mutations, depth, env) {
|
|
651
|
+
if (mutations.length === 0)
|
|
652
|
+
return [];
|
|
653
|
+
this.reassigning.add(declaration);
|
|
654
|
+
try {
|
|
655
|
+
return mutations.slice(0, MAX_RETURNS).map((mutation) => {
|
|
656
|
+
const values = mutation.values.map((value) => this.hop(value, depth, env));
|
|
657
|
+
if (mutation.op === "=")
|
|
658
|
+
return values[0];
|
|
659
|
+
const previous = this.node("external", mutation.target, { resolution: "unresolved", note: "previous value", name: mutation.target.text, unresolvedReason: "external" });
|
|
660
|
+
return this.node("concat", mutation.at, { children: [previous, ...values], resolution: values.every((value) => value.resolution === "unresolved") ? "unresolved" : "partial", note: "compound assignment" });
|
|
661
|
+
});
|
|
662
|
+
} finally {
|
|
663
|
+
this.reassigning.delete(declaration);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
assembled(id, declaration, mutations, depth, env) {
|
|
667
|
+
if (depth + 1 > this.maxDepth)
|
|
668
|
+
return this.depthLimit(id, id.text);
|
|
669
|
+
const items = [];
|
|
670
|
+
let order = 0;
|
|
671
|
+
const tag = (value, note) => ({ ...value, order: order++, note });
|
|
672
|
+
const init = declaration.initializer ? unwrap(declaration.initializer) : undefined;
|
|
673
|
+
const arrayOps = mutations.some((mutation) => mutation.op === "push" || mutation.op === "unshift" || mutation.op === "splice" || mutation.op === "concat");
|
|
674
|
+
if (init && import_typescript2.default.isArrayLiteralExpression(init)) {
|
|
675
|
+
for (const element of init.elements.slice(0, MAX_MEMBERS))
|
|
676
|
+
items.push(tag(this.element(element, depth + 1, env), "init"));
|
|
677
|
+
} else if (init) {
|
|
678
|
+
items.push(tag(this.value(init, depth + 1, env), "init"));
|
|
679
|
+
}
|
|
680
|
+
this.reassigning.add(declaration);
|
|
681
|
+
try {
|
|
682
|
+
for (const mutation of mutations) {
|
|
683
|
+
const values = mutation.values.slice(0, MAX_MEMBERS).map((value) => tag(this.element(value, depth + 1, env), mutation.op));
|
|
684
|
+
if (mutation.op === "=") {
|
|
685
|
+
items.length = 0;
|
|
686
|
+
items.push(...values);
|
|
687
|
+
} else if (mutation.op === "unshift") {
|
|
688
|
+
items.unshift(...values);
|
|
689
|
+
} else if (mutation.op === "splice" && mutation.index !== undefined) {
|
|
690
|
+
items.splice(Math.min(mutation.index, items.length), 0, ...values);
|
|
691
|
+
} else {
|
|
692
|
+
items.push(...values);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
} finally {
|
|
696
|
+
this.reassigning.delete(declaration);
|
|
697
|
+
}
|
|
698
|
+
const isString = !arrayOps && (!init || !import_typescript2.default.isArrayLiteralExpression(init));
|
|
699
|
+
return this.node("assembled", id, {
|
|
700
|
+
name: id.text,
|
|
701
|
+
children: items,
|
|
702
|
+
resolution: items.length === 0 ? arrayOps ? "resolved" : "unresolved" : rollup(items),
|
|
703
|
+
text: arrayOps || init && import_typescript2.default.isArrayLiteralExpression(init) ? "array" : isString ? "string" : undefined
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
parameter(declaration, at, depth, env) {
|
|
707
|
+
const name = import_typescript2.default.isIdentifier(declaration.name) ? declaration.name.text : declaration.name.getText();
|
|
708
|
+
const fn = declaration.parent;
|
|
709
|
+
const bindings = [];
|
|
710
|
+
const children = [];
|
|
711
|
+
let note;
|
|
712
|
+
let reason;
|
|
713
|
+
const bound = env.get(declaration);
|
|
714
|
+
if (bound) {
|
|
715
|
+
const argument = bound.expr && !isUndefinedLiteral(bound.expr) ? bound.expr : undefined;
|
|
716
|
+
if (argument)
|
|
717
|
+
bindings.push(bound.traced ?? this.value(argument, depth, bound.env));
|
|
718
|
+
else if (declaration.initializer)
|
|
719
|
+
children.push(this.value(declaration.initializer, depth, env));
|
|
720
|
+
else {
|
|
721
|
+
note = "argument omitted";
|
|
722
|
+
reason = "param-unbound";
|
|
723
|
+
}
|
|
724
|
+
} else if (declaration.dotDotDotToken) {
|
|
725
|
+
note = "rest parameter";
|
|
726
|
+
reason = "param-unbound";
|
|
727
|
+
} else if (isFunctionLike(fn)) {
|
|
728
|
+
const fnName = functionName(fn);
|
|
729
|
+
if (this.callerLevel >= this.maxCallerDepth) {
|
|
730
|
+
note = `caller depth limit (${this.maxCallerDepth})`;
|
|
731
|
+
reason = "depth-limit";
|
|
732
|
+
} else {
|
|
733
|
+
const index = fn.parameters.indexOf(declaration);
|
|
734
|
+
const found = fnName ? this.calls.callersOf(fn, fnName, this.maxCallers + 1) : [];
|
|
735
|
+
const callers = found.slice(0, this.maxCallers);
|
|
736
|
+
this.callerLevel += 1;
|
|
737
|
+
try {
|
|
738
|
+
if (found.length > callers.length)
|
|
739
|
+
bindings.push(this.node("external", declaration, { resolution: "unresolved", note: `more than ${this.maxCallers} call sites of ${fnName}; the rest not followed`, unresolvedReason: "depth-limit" }));
|
|
740
|
+
let usedDefault = false;
|
|
741
|
+
for (const call of callers) {
|
|
742
|
+
const spreadBefore = call.arguments.slice(0, index + 1).some((argument2) => import_typescript2.default.isSpreadElement(argument2));
|
|
743
|
+
const argument = call.arguments[index];
|
|
744
|
+
if (spreadBefore) {
|
|
745
|
+
bindings.push(this.external(call, "spread arguments"));
|
|
746
|
+
} else if (argument && !isUndefinedLiteral(argument)) {
|
|
747
|
+
bindings.push(this.hop(argument, depth, EMPTY_ENV));
|
|
748
|
+
} else if (declaration.initializer && !usedDefault) {
|
|
749
|
+
usedDefault = true;
|
|
750
|
+
children.push(this.hop(declaration.initializer, depth, env));
|
|
751
|
+
} else if (!declaration.initializer) {
|
|
752
|
+
bindings.push(this.node("external", call, { resolution: "unresolved", note: "argument omitted", unresolvedReason: "param-unbound" }));
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
} finally {
|
|
756
|
+
this.callerLevel -= 1;
|
|
757
|
+
}
|
|
758
|
+
if (callers.length === 0) {
|
|
759
|
+
if (declaration.initializer)
|
|
760
|
+
children.push(this.hop(declaration.initializer, depth, env));
|
|
761
|
+
note = fnName ? `no call sites of ${fnName} found` : "callback parameter";
|
|
762
|
+
reason = "param-unbound";
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
if (!this.reassigning.has(declaration) && isFunctionLike(fn) && fn.body) {
|
|
767
|
+
const symbol = import_typescript2.default.isIdentifier(declaration.name) ? this.checker.getSymbolAtLocation(declaration.name) : undefined;
|
|
768
|
+
if (symbol) {
|
|
769
|
+
const mutations = this.mutations(symbol, declaration).filter((mutation) => mutation.op === "=" || mutation.op === "+=");
|
|
770
|
+
children.push(...this.reassignments(declaration, mutations, depth, env));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
const all = [...bindings, ...children];
|
|
774
|
+
const resolution = rollup(all);
|
|
775
|
+
return this.node("param", at, {
|
|
776
|
+
name,
|
|
777
|
+
bindings: bindings.length > 0 ? bindings : undefined,
|
|
778
|
+
children: children.length > 0 ? children : undefined,
|
|
779
|
+
resolution,
|
|
780
|
+
note,
|
|
781
|
+
unresolvedReason: resolution === "unresolved" ? reasonOf("unresolved", all).unresolvedReason ?? reason ?? "param-unbound" : undefined
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
bindingElement(element, at, depth, env) {
|
|
785
|
+
const pattern = element.parent;
|
|
786
|
+
const name = import_typescript2.default.isIdentifier(element.name) ? element.name.text : element.name.getText();
|
|
787
|
+
if (!import_typescript2.default.isObjectBindingPattern(pattern) || element.dotDotDotToken)
|
|
788
|
+
return this.external(at, "array or rest destructuring", name);
|
|
789
|
+
const key = propertyNameText(element.propertyName ?? element.name);
|
|
790
|
+
if (!key)
|
|
791
|
+
return this.external(at, "computed destructuring key", name);
|
|
792
|
+
const holder = pattern.parent;
|
|
793
|
+
let whole;
|
|
794
|
+
if (import_typescript2.default.isVariableDeclaration(holder) && holder.initializer)
|
|
795
|
+
whole = this.hop(holder.initializer, depth, env);
|
|
796
|
+
else if (import_typescript2.default.isParameter(holder))
|
|
797
|
+
whole = this.parameter(holder, holder, depth + 1, env);
|
|
798
|
+
else if (import_typescript2.default.isBindingElement(holder))
|
|
799
|
+
whole = this.bindingElement(holder, holder, depth + 1, env);
|
|
800
|
+
if (!whole)
|
|
801
|
+
return this.external(at, "destructured from an unknown value", name);
|
|
802
|
+
const missing = this.missing(at, `no property ${key}`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external");
|
|
803
|
+
let selected = selectKey(whole, key, missing);
|
|
804
|
+
const extra = { name, key, object: shallow(whole), keyNode: this.keyLiteral(element.propertyName ?? element.name, key) };
|
|
805
|
+
if (element.initializer && hasNode(selected, missing)) {
|
|
806
|
+
const fallback = this.hop(element.initializer, depth, env);
|
|
807
|
+
selected = substitute(selected, missing, fallback);
|
|
808
|
+
return this.node("lookup", at, { ...extra, children: [selected], resolution: selected.resolution, note: "with default" });
|
|
809
|
+
}
|
|
810
|
+
return this.node("lookup", at, { ...extra, children: [selected], resolution: selected.resolution });
|
|
811
|
+
}
|
|
812
|
+
keyLiteral(at, key) {
|
|
813
|
+
return this.node("literal", at, { text: key, resolution: "resolved" });
|
|
814
|
+
}
|
|
815
|
+
tableRef(receiver, resolution) {
|
|
816
|
+
return this.node("ref", receiver, { name: truncate(receiver.getText().replace(/\s+/g, " ")), resolution, note: "table (member resolved by declaration)" });
|
|
817
|
+
}
|
|
818
|
+
propertyAccess(expr, depth, env) {
|
|
819
|
+
const key = expr.name.text;
|
|
820
|
+
const receiver = unwrap(expr.expression);
|
|
821
|
+
const receiverName = import_typescript2.default.isPropertyAccessExpression(receiver) ? receiver.name.text : import_typescript2.default.isIdentifier(receiver) ? receiver.text : undefined;
|
|
822
|
+
if (receiverName === "env")
|
|
823
|
+
return this.node("env", expr, { name: key, resolution: "unresolved", note: "environment variable", unresolvedReason: "env" });
|
|
824
|
+
const keyNode = this.keyLiteral(expr.name, key);
|
|
825
|
+
const symbol = resolvedSymbol(expr.name, this.checker);
|
|
826
|
+
const declaration = symbol?.declarations?.find((candidate) => (import_typescript2.default.isPropertyAssignment(candidate) || import_typescript2.default.isPropertyDeclaration(candidate) || import_typescript2.default.isEnumMember(candidate) || import_typescript2.default.isVariableDeclaration(candidate)) && candidate.initializer) ?? symbol?.declarations?.find((candidate) => import_typescript2.default.isShorthandPropertyAssignment(candidate) || import_typescript2.default.isGetAccessorDeclaration(candidate));
|
|
827
|
+
const lookup = (children, note) => {
|
|
828
|
+
const resolution = rollup(children);
|
|
829
|
+
return this.node("lookup", expr, { name: expr.getText(), key, keyNode, object: this.tableRef(expr.expression, resolution), children, resolution, note });
|
|
830
|
+
};
|
|
831
|
+
if (declaration && (import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration) || import_typescript2.default.isEnumMember(declaration) || import_typescript2.default.isVariableDeclaration(declaration))) {
|
|
832
|
+
const children = [this.hop(declaration.initializer, depth, env)];
|
|
833
|
+
if (import_typescript2.default.isPropertyDeclaration(declaration) && symbol)
|
|
834
|
+
children.push(...this.memberAssignments(declaration, key, depth, env));
|
|
835
|
+
return lookup(children);
|
|
836
|
+
}
|
|
837
|
+
if (declaration && import_typescript2.default.isShorthandPropertyAssignment(declaration))
|
|
838
|
+
return lookup([this.hop(declaration.name, depth, env)]);
|
|
839
|
+
if (declaration && import_typescript2.default.isGetAccessorDeclaration(declaration)) {
|
|
840
|
+
return lookup(returnExpressions(declaration).slice(0, MAX_RETURNS).map((ret) => this.hop(ret, depth, env)), "getter");
|
|
841
|
+
}
|
|
842
|
+
const field = symbol?.declarations?.find((candidate) => import_typescript2.default.isPropertyDeclaration(candidate));
|
|
843
|
+
if (field && import_typescript2.default.isPropertyDeclaration(field)) {
|
|
844
|
+
const children = this.memberAssignments(field, key, depth, env);
|
|
845
|
+
if (children.length > 0)
|
|
846
|
+
return lookup(children);
|
|
847
|
+
}
|
|
848
|
+
if (depth + 1 > this.maxDepth)
|
|
849
|
+
return this.depthLimit(expr);
|
|
850
|
+
const whole = this.value(expr.expression, depth + 1, env);
|
|
851
|
+
const selected = selectKey(whole, key, this.missing(expr, `property ${key} not found`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external"));
|
|
852
|
+
return this.node("lookup", expr, { name: expr.getText(), key, keyNode, object: shallow(whole), children: [selected], resolution: selected.resolution });
|
|
853
|
+
}
|
|
854
|
+
memberAssignments(field, key, depth, env) {
|
|
855
|
+
const cls = field.parent;
|
|
856
|
+
const out = [];
|
|
857
|
+
const visit = (node) => {
|
|
858
|
+
if (out.length >= MAX_RETURNS)
|
|
859
|
+
return;
|
|
860
|
+
if (import_typescript2.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript2.default.SyntaxKind.EqualsToken && import_typescript2.default.isPropertyAccessExpression(node.left) && node.left.expression.kind === import_typescript2.default.SyntaxKind.ThisKeyword && node.left.name.text === key && enclosingClass(node) === cls) {
|
|
861
|
+
out.push(this.hop(node.right, depth, env));
|
|
862
|
+
}
|
|
863
|
+
import_typescript2.default.forEachChild(node, visit);
|
|
864
|
+
};
|
|
865
|
+
import_typescript2.default.forEachChild(cls, visit);
|
|
866
|
+
return out;
|
|
867
|
+
}
|
|
868
|
+
elementAccess(expr, depth, env) {
|
|
869
|
+
const argument = unwrap(expr.argumentExpression);
|
|
870
|
+
if (depth + 1 > this.maxDepth)
|
|
871
|
+
return this.depthLimit(expr);
|
|
872
|
+
const whole = this.value(expr.expression, depth + 1, env);
|
|
873
|
+
const object = shallow(whole);
|
|
874
|
+
const name = expr.getText();
|
|
875
|
+
if (import_typescript2.default.isStringLiteral(argument) || import_typescript2.default.isNoSubstitutionTemplateLiteral(argument) || import_typescript2.default.isNumericLiteral(argument)) {
|
|
876
|
+
const selected = selectKey(whole, argument.text, this.missing(expr, `property ${argument.text} not found`, whole.resolution === "unresolved" ? whole.unresolvedReason : "external"));
|
|
877
|
+
return this.node("lookup", expr, { name, key: argument.text, keyNode: this.keyLiteral(argument, argument.text), object, children: [selected], resolution: selected.resolution });
|
|
878
|
+
}
|
|
879
|
+
const keyNode = this.value(argument, depth + 1, env);
|
|
880
|
+
const keys = keyNode.resolution === "resolved" ? renderings(keyNode) : [];
|
|
881
|
+
if (keys.length > 0 && !keys.some((key) => key.includes("${...}"))) {
|
|
882
|
+
const children = [...new Set(keys)].map((key) => {
|
|
883
|
+
const missing = this.node("external", expr, { resolution: "unresolved", note: `no entry for key ${JSON.stringify(key)}`, name: "undefined", unresolvedReason: "external" });
|
|
884
|
+
const selected = selectKey(whole, key, missing);
|
|
885
|
+
return selected === missing ? missing : { ...selected, key };
|
|
886
|
+
});
|
|
887
|
+
return this.node("lookup", expr, { name, keyNode, object, children, resolution: rollup(children), note: "computed key" });
|
|
888
|
+
}
|
|
889
|
+
const values = allValues(whole);
|
|
890
|
+
if (values.length === 0) {
|
|
891
|
+
return this.node("lookup", expr, { name, keyNode, object, resolution: "unresolved", note: `dynamic key ${truncate(argument.getText())} on a value with no known entries`, unresolvedReason: "dynamic-key" });
|
|
892
|
+
}
|
|
893
|
+
const literal = values.some((value) => value.resolution !== "unresolved");
|
|
894
|
+
return this.node("lookup", expr, {
|
|
895
|
+
name,
|
|
896
|
+
keyNode,
|
|
897
|
+
object,
|
|
898
|
+
children: values,
|
|
899
|
+
resolution: literal ? "partial" : "unresolved",
|
|
900
|
+
unresolvedReason: literal ? undefined : "dynamic-key",
|
|
901
|
+
note: `dynamic key ${truncate(argument.getText())}`
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
call(expr, depth, env) {
|
|
905
|
+
const callee = unwrap(expr.expression);
|
|
906
|
+
const factoryModel = this.modelArgOf?.(expr);
|
|
907
|
+
if (factoryModel) {
|
|
908
|
+
const child = this.hop(factoryModel, depth, env);
|
|
909
|
+
return this.node("call", expr, { name: callee.getText(), children: [child], resolution: child.resolution, note: "model factory" });
|
|
910
|
+
}
|
|
911
|
+
if (import_typescript2.default.isPropertyAccessExpression(callee)) {
|
|
912
|
+
const method = callee.name.text;
|
|
913
|
+
if (method === "join")
|
|
914
|
+
return this.arrayJoin(expr, callee, depth, env);
|
|
915
|
+
if (TRIM_METHODS.has(method) && expr.arguments.length === 0)
|
|
916
|
+
return this.value(callee.expression, depth, env);
|
|
917
|
+
if (CASE_METHODS.has(method) && expr.arguments.length === 0) {
|
|
918
|
+
const receiver = this.value(callee.expression, depth, env);
|
|
919
|
+
const texts = receiver.resolution === "resolved" ? renderings(receiver) : [];
|
|
920
|
+
if (texts.length > 0 && !texts.some((text) => text.includes("${...}"))) {
|
|
921
|
+
const children = [...new Set(texts)].map((text) => this.node("literal", expr, { text: method === "toLowerCase" ? text.toLowerCase() : text.toUpperCase(), resolution: "resolved" }));
|
|
922
|
+
return children.length === 1 ? children[0] : this.node("oneOf", expr, { children, resolution: "resolved", note: method });
|
|
923
|
+
}
|
|
924
|
+
return this.node("call", expr, { name: method, children: [receiver], resolution: receiver.resolution === "resolved" ? "partial" : receiver.resolution });
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (import_typescript2.default.isPropertyAccessExpression(callee) && import_typescript2.default.isIdentifier(callee.expression) && callee.expression.text === "JSON" && callee.name.text === "stringify" && expr.arguments[0]) {
|
|
928
|
+
const child = this.value(expr.arguments[0], depth, env);
|
|
929
|
+
return this.node("call", expr, { name: "JSON.stringify", children: [child], resolution: child.resolution });
|
|
930
|
+
}
|
|
931
|
+
if (import_typescript2.default.isIdentifier(callee) && TEXT_HELPERS.has(callee.text) && expr.arguments.length === 1 && !resolvedFunction(callee, this.checker)) {
|
|
932
|
+
return this.value(expr.arguments[0], depth, env);
|
|
933
|
+
}
|
|
934
|
+
const fn = resolvedFunction(callee, this.checker);
|
|
935
|
+
const name = callee.getText().replace(/\s+/g, "");
|
|
936
|
+
if (!fn) {
|
|
937
|
+
const root = rootOf(callee);
|
|
938
|
+
const origin = root ? importOrigin(root, this.checker) : undefined;
|
|
939
|
+
if (PROMPT_FACTORY.test(name) || import_typescript2.default.isIdentifier(callee) && MESSAGE_CLASS.test(callee.text)) {
|
|
940
|
+
const children = expr.arguments.map((argument) => this.element(argument, depth, env));
|
|
941
|
+
return this.node("call", expr, { name, children, resolution: children.length === 0 ? "unresolved" : rollup(children), note: origin ? `call into ${origin.module}` : "prompt template" });
|
|
942
|
+
}
|
|
943
|
+
const last = import_typescript2.default.isPropertyAccessExpression(callee) ? callee.name.text : import_typescript2.default.isIdentifier(callee) ? callee.text : "";
|
|
944
|
+
const io = origin && IO_MODULE.test(origin.module) || IO_METHOD.test(last);
|
|
945
|
+
return this.external(expr, origin ? `call into ${origin.module}` : "call to an unresolved function", name, io ? "io" : "external");
|
|
946
|
+
}
|
|
947
|
+
if (depth + 1 > this.maxDepth)
|
|
948
|
+
return this.depthLimit(expr, name);
|
|
949
|
+
const returns = returnExpressions(fn).slice(0, MAX_RETURNS);
|
|
950
|
+
const anchor = { anchorPath: relPath(this.rootDir, fn.getSourceFile().fileName), anchorLine: lineOf(fn) };
|
|
951
|
+
const args = expr.arguments.slice(0, MAX_MEMBERS).map((argument) => this.element(argument, depth, env));
|
|
952
|
+
if (returns.length === 0) {
|
|
953
|
+
return this.node("call", expr, { name, args, ...anchor, resolution: "unresolved", note: "function returns no value", unresolvedReason: "external" });
|
|
954
|
+
}
|
|
955
|
+
const inner = new Map(env);
|
|
956
|
+
fn.parameters.forEach((parameter, index) => {
|
|
957
|
+
if (expr.arguments.slice(0, index + 1).some((argument) => import_typescript2.default.isSpreadElement(argument)))
|
|
958
|
+
return;
|
|
959
|
+
inner.set(parameter, { expr: expr.arguments[index], env, traced: args[index] });
|
|
960
|
+
});
|
|
961
|
+
const live = returns.filter((ret) => this.reachableReturn(ret, fn, depth + 1, inner));
|
|
962
|
+
const values = (live.length > 0 ? live : returns).map((ret) => this.value(ret, depth + 1, inner));
|
|
963
|
+
const calleeTree = values.length === 1 ? values[0] : this.node("oneOf", fn, { children: values, resolution: rollup(values), note: "returns" });
|
|
964
|
+
return this.node("call", expr, { name, callee: calleeTree, args, ...anchor, resolution: calleeTree.resolution });
|
|
965
|
+
}
|
|
966
|
+
reachableReturn(ret, fn, depth, env) {
|
|
967
|
+
let node = ret;
|
|
968
|
+
while (node.parent && node !== fn) {
|
|
969
|
+
const parent = node.parent;
|
|
970
|
+
if (import_typescript2.default.isIfStatement(parent) && node !== parent.expression) {
|
|
971
|
+
const value = this.condition(parent.expression, depth, env);
|
|
972
|
+
if (value === false && node === parent.thenStatement)
|
|
973
|
+
return false;
|
|
974
|
+
if (value === true && node === parent.elseStatement)
|
|
975
|
+
return false;
|
|
976
|
+
}
|
|
977
|
+
if (import_typescript2.default.isBlock(parent) || import_typescript2.default.isSourceFile(parent)) {
|
|
978
|
+
for (const statement of parent.statements) {
|
|
979
|
+
if (statement === node)
|
|
980
|
+
break;
|
|
981
|
+
if (import_typescript2.default.isIfStatement(statement) && !statement.elseStatement && alwaysReturns(statement.thenStatement) && this.condition(statement.expression, depth, env) === true)
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
node = parent;
|
|
986
|
+
}
|
|
987
|
+
return true;
|
|
988
|
+
}
|
|
989
|
+
condition(expression, depth, env) {
|
|
990
|
+
const expr = unwrap(expression);
|
|
991
|
+
if (!import_typescript2.default.isBinaryExpression(expr))
|
|
992
|
+
return;
|
|
993
|
+
const operator = expr.operatorToken.kind;
|
|
994
|
+
const equal = operator === import_typescript2.default.SyntaxKind.EqualsEqualsEqualsToken || operator === import_typescript2.default.SyntaxKind.EqualsEqualsToken;
|
|
995
|
+
const notEqual = operator === import_typescript2.default.SyntaxKind.ExclamationEqualsEqualsToken || operator === import_typescript2.default.SyntaxKind.ExclamationEqualsToken;
|
|
996
|
+
if (!equal && !notEqual)
|
|
997
|
+
return;
|
|
998
|
+
const left = unwrap(expr.left);
|
|
999
|
+
const right = unwrap(expr.right);
|
|
1000
|
+
const literal = import_typescript2.default.isStringLiteral(right) || import_typescript2.default.isNoSubstitutionTemplateLiteral(right) ? right : import_typescript2.default.isStringLiteral(left) || import_typescript2.default.isNoSubstitutionTemplateLiteral(left) ? left : undefined;
|
|
1001
|
+
if (!literal)
|
|
1002
|
+
return;
|
|
1003
|
+
const operand = literal === right ? expr.left : expr.right;
|
|
1004
|
+
const traced = this.value(operand, depth, env);
|
|
1005
|
+
if (traced.resolution !== "resolved")
|
|
1006
|
+
return;
|
|
1007
|
+
const values = renderings(traced);
|
|
1008
|
+
if (values.length === 0 || values.some((value) => value.includes("${...}")))
|
|
1009
|
+
return;
|
|
1010
|
+
const matches = values.map((value) => value === literal.text);
|
|
1011
|
+
if (matches.every(Boolean))
|
|
1012
|
+
return equal;
|
|
1013
|
+
if (!matches.some(Boolean))
|
|
1014
|
+
return notEqual;
|
|
1015
|
+
return;
|
|
1016
|
+
}
|
|
1017
|
+
arrayJoin(expr, callee, depth, env) {
|
|
1018
|
+
let receiver = unwrap(callee.expression);
|
|
1019
|
+
while (import_typescript2.default.isCallExpression(receiver) && import_typescript2.default.isPropertyAccessExpression(receiver.expression) && receiver.expression.name.text === "filter" && receiver.arguments.length === 1 && import_typescript2.default.isIdentifier(receiver.arguments[0]) && receiver.arguments[0].text === "Boolean") {
|
|
1020
|
+
receiver = unwrap(receiver.expression.expression);
|
|
1021
|
+
}
|
|
1022
|
+
const separatorArg = expr.arguments[0];
|
|
1023
|
+
const separator = separatorArg === undefined ? "," : import_typescript2.default.isStringLiteral(separatorArg) || import_typescript2.default.isNoSubstitutionTemplateLiteral(separatorArg) ? separatorArg.text : undefined;
|
|
1024
|
+
const children = import_typescript2.default.isArrayLiteralExpression(receiver) ? receiver.elements.slice(0, MAX_MEMBERS).map((element) => this.element(element, depth, env)) : [this.value(receiver, depth, env)];
|
|
1025
|
+
const resolution = separator === undefined && rollup(children) === "resolved" ? "partial" : rollup(children);
|
|
1026
|
+
return this.node("arrayJoin", expr, { text: separator, children, resolution, note: separator === undefined ? "computed separator" : undefined });
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
function alwaysReturns(statement) {
|
|
1030
|
+
if (import_typescript2.default.isReturnStatement(statement) || import_typescript2.default.isThrowStatement(statement))
|
|
1031
|
+
return true;
|
|
1032
|
+
if (import_typescript2.default.isBlock(statement)) {
|
|
1033
|
+
const last = statement.statements[statement.statements.length - 1];
|
|
1034
|
+
return Boolean(last && alwaysReturns(last));
|
|
1035
|
+
}
|
|
1036
|
+
return false;
|
|
1037
|
+
}
|
|
1038
|
+
function isUndefinedLiteral(node) {
|
|
1039
|
+
const inner = unwrap(node);
|
|
1040
|
+
return import_typescript2.default.isIdentifier(inner) && inner.text === "undefined" || import_typescript2.default.isVoidExpression(inner);
|
|
1041
|
+
}
|
|
1042
|
+
function enclosingScope(node) {
|
|
1043
|
+
for (let current = node.parent;current; current = current.parent) {
|
|
1044
|
+
if (isFunctionLike(current) || import_typescript2.default.isSourceFile(current))
|
|
1045
|
+
return current;
|
|
1046
|
+
}
|
|
1047
|
+
return node.getSourceFile();
|
|
1048
|
+
}
|
|
1049
|
+
function rootOf(expression) {
|
|
1050
|
+
let current = unwrap(expression);
|
|
1051
|
+
while (import_typescript2.default.isPropertyAccessExpression(current) || import_typescript2.default.isElementAccessExpression(current) || import_typescript2.default.isCallExpression(current))
|
|
1052
|
+
current = unwrap(current.expression);
|
|
1053
|
+
return import_typescript2.default.isIdentifier(current) ? current : undefined;
|
|
1054
|
+
}
|
|
1055
|
+
function resolvedFunction(callee, checker) {
|
|
1056
|
+
const inner = unwrap(callee);
|
|
1057
|
+
if (import_typescript2.default.isArrowFunction(inner) || import_typescript2.default.isFunctionExpression(inner))
|
|
1058
|
+
return inner;
|
|
1059
|
+
const nameNode = import_typescript2.default.isPropertyAccessExpression(inner) ? inner.name : import_typescript2.default.isIdentifier(inner) ? inner : undefined;
|
|
1060
|
+
if (!nameNode)
|
|
1061
|
+
return;
|
|
1062
|
+
const symbol = resolvedSymbol(nameNode, checker);
|
|
1063
|
+
for (const declaration of symbol?.declarations ?? []) {
|
|
1064
|
+
if (isFunctionLike(declaration) && declaration.body)
|
|
1065
|
+
return declaration;
|
|
1066
|
+
if ((import_typescript2.default.isVariableDeclaration(declaration) || import_typescript2.default.isPropertyAssignment(declaration) || import_typescript2.default.isPropertyDeclaration(declaration)) && declaration.initializer) {
|
|
1067
|
+
const value = unwrap(declaration.initializer);
|
|
1068
|
+
if ((import_typescript2.default.isArrowFunction(value) || import_typescript2.default.isFunctionExpression(value)) && value.body)
|
|
1069
|
+
return value;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
return;
|
|
1073
|
+
}
|
|
1074
|
+
function selectKey(tree, key, missing) {
|
|
1075
|
+
if (tree.kind === "object") {
|
|
1076
|
+
const members = tree.children ?? [];
|
|
1077
|
+
for (let index = members.length - 1;index >= 0; index -= 1) {
|
|
1078
|
+
const member = members[index];
|
|
1079
|
+
if (member.key === key)
|
|
1080
|
+
return { ...member, key };
|
|
1081
|
+
if (member.key === "...") {
|
|
1082
|
+
const fromSpread = selectKey(member, key, missing);
|
|
1083
|
+
if (fromSpread !== missing)
|
|
1084
|
+
return fromSpread;
|
|
1085
|
+
if (member.kind !== "object")
|
|
1086
|
+
return { ...missing, note: `property ${key} may come from an unresolved spread` };
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
return missing;
|
|
1090
|
+
}
|
|
1091
|
+
if (FLOW_KINDS.has(tree.kind)) {
|
|
1092
|
+
const flow = valueChildren(tree);
|
|
1093
|
+
if (flow.length === 0)
|
|
1094
|
+
return { ...missing, note: `property ${key} of ${tree.kind}${tree.name ? ` ${tree.name}` : ""}` };
|
|
1095
|
+
const selected = new Map(flow.map((child) => [child, selectKey(child, key, missing)]));
|
|
1096
|
+
if ([...selected.values()].every((child) => child === missing))
|
|
1097
|
+
return missing;
|
|
1098
|
+
return mapFlow(tree, (child) => selected.get(child) ?? child);
|
|
1099
|
+
}
|
|
1100
|
+
return { ...missing, note: `property ${key} of ${tree.kind}${tree.name ? ` ${tree.name}` : ""}` };
|
|
1101
|
+
}
|
|
1102
|
+
var FLOW_KINDS = new Set(["ref", "call", "param", "oneOf", "lookup"]);
|
|
1103
|
+
function leaves(tree) {
|
|
1104
|
+
const flow = valueChildren(tree);
|
|
1105
|
+
return flow.length > 0 && tree.kind !== "template" ? flow.flatMap(leaves) : [tree];
|
|
1106
|
+
}
|
|
1107
|
+
function hasNode(tree, target) {
|
|
1108
|
+
return tree === target || valueChildren(tree).some((child) => hasNode(child, target));
|
|
1109
|
+
}
|
|
1110
|
+
function substitute(tree, target, replacement) {
|
|
1111
|
+
if (tree === target)
|
|
1112
|
+
return replacement;
|
|
1113
|
+
if (!hasNode(tree, target))
|
|
1114
|
+
return tree;
|
|
1115
|
+
if (FLOW_KINDS.has(tree.kind))
|
|
1116
|
+
return mapFlow(tree, (child) => substitute(child, target, replacement));
|
|
1117
|
+
return { ...tree, children: (tree.children ?? []).map((child) => substitute(child, target, replacement)) };
|
|
1118
|
+
}
|
|
1119
|
+
function allValues(tree) {
|
|
1120
|
+
if (tree.kind === "object" || tree.kind === "array" || tree.kind === "assembled" && tree.text === "array") {
|
|
1121
|
+
return (tree.children ?? []).flatMap((child) => child.key === "..." ? allValues(child) : [child]);
|
|
1122
|
+
}
|
|
1123
|
+
if (FLOW_KINDS.has(tree.kind))
|
|
1124
|
+
return valueChildren(tree).flatMap((child) => allValues(child));
|
|
1125
|
+
return [];
|
|
1126
|
+
}
|
|
1127
|
+
function renderings(tree, limit = 16) {
|
|
1128
|
+
const combine = (pieces) => {
|
|
1129
|
+
let out = [""];
|
|
1130
|
+
for (const options of pieces) {
|
|
1131
|
+
const next = [];
|
|
1132
|
+
for (const prefix of out)
|
|
1133
|
+
for (const option of options)
|
|
1134
|
+
if (next.length < limit)
|
|
1135
|
+
next.push(prefix + option);
|
|
1136
|
+
out = next;
|
|
1137
|
+
}
|
|
1138
|
+
return out;
|
|
1139
|
+
};
|
|
1140
|
+
switch (tree.kind) {
|
|
1141
|
+
case "literal":
|
|
1142
|
+
return [tree.text ?? ""];
|
|
1143
|
+
case "template": {
|
|
1144
|
+
const parts = tree.parts ?? [];
|
|
1145
|
+
const pieces = [];
|
|
1146
|
+
parts.forEach((part, index) => {
|
|
1147
|
+
pieces.push([part]);
|
|
1148
|
+
const child = tree.children?.[index];
|
|
1149
|
+
if (child)
|
|
1150
|
+
pieces.push(renderings(child, limit));
|
|
1151
|
+
});
|
|
1152
|
+
return combine(pieces);
|
|
1153
|
+
}
|
|
1154
|
+
case "concat":
|
|
1155
|
+
return combine((tree.children ?? []).map((child) => renderings(child, limit)));
|
|
1156
|
+
case "assembled":
|
|
1157
|
+
return tree.text === "string" ? combine((tree.children ?? []).map((child) => renderings(child, limit))) : ["${...}"];
|
|
1158
|
+
case "ref":
|
|
1159
|
+
case "lookup":
|
|
1160
|
+
case "param":
|
|
1161
|
+
case "call":
|
|
1162
|
+
case "oneOf": {
|
|
1163
|
+
const out = valueChildren(tree).flatMap((child) => renderings(child, limit)).slice(0, limit);
|
|
1164
|
+
return out.length > 0 ? out : ["${...}"];
|
|
1165
|
+
}
|
|
1166
|
+
default:
|
|
1167
|
+
return ["${...}"];
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/harness-extract/calls.ts
|
|
1172
|
+
class CallIndex {
|
|
1173
|
+
program;
|
|
1174
|
+
checker;
|
|
1175
|
+
byName;
|
|
1176
|
+
aliases = new Map;
|
|
1177
|
+
members = new Map;
|
|
1178
|
+
constructor(program, checker) {
|
|
1179
|
+
this.program = program;
|
|
1180
|
+
this.checker = checker;
|
|
1181
|
+
}
|
|
1182
|
+
build() {
|
|
1183
|
+
const byName = new Map;
|
|
1184
|
+
for (const source of this.program.getSourceFiles()) {
|
|
1185
|
+
if (source.isDeclarationFile || /[\\/]node_modules[\\/]/.test(source.fileName))
|
|
1186
|
+
continue;
|
|
1187
|
+
const visit = (node) => {
|
|
1188
|
+
if ((import_typescript3.default.isParameter(node) || import_typescript3.default.isVariableDeclaration(node)) && node.initializer && import_typescript3.default.isIdentifier(node.name)) {
|
|
1189
|
+
let init = unwrap(node.initializer);
|
|
1190
|
+
if (import_typescript3.default.isBinaryExpression(init) && (init.operatorToken.kind === import_typescript3.default.SyntaxKind.QuestionQuestionToken || init.operatorToken.kind === import_typescript3.default.SyntaxKind.BarBarToken))
|
|
1191
|
+
init = unwrap(init.right);
|
|
1192
|
+
if (import_typescript3.default.isIdentifier(init)) {
|
|
1193
|
+
const entry = { declaration: node, target: init };
|
|
1194
|
+
const list = this.aliases.get(init.text);
|
|
1195
|
+
if (list)
|
|
1196
|
+
list.push(entry);
|
|
1197
|
+
else
|
|
1198
|
+
this.aliases.set(init.text, [entry]);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
if ((import_typescript3.default.isPropertyAssignment(node) || import_typescript3.default.isShorthandPropertyAssignment(node)) && import_typescript3.default.isObjectLiteralExpression(node.parent)) {
|
|
1202
|
+
const value = import_typescript3.default.isShorthandPropertyAssignment(node) ? node.name : unwrap(node.initializer);
|
|
1203
|
+
const property = import_typescript3.default.isIdentifier(node.name) || import_typescript3.default.isStringLiteral(node.name) ? node.name.text : undefined;
|
|
1204
|
+
if (property && import_typescript3.default.isIdentifier(value)) {
|
|
1205
|
+
const entry = { property, literal: node.parent, target: value };
|
|
1206
|
+
const list = this.members.get(value.text);
|
|
1207
|
+
if (list)
|
|
1208
|
+
list.push(entry);
|
|
1209
|
+
else
|
|
1210
|
+
this.members.set(value.text, [entry]);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (import_typescript3.default.isCallExpression(node)) {
|
|
1214
|
+
const callee = unwrap(node.expression);
|
|
1215
|
+
const name = import_typescript3.default.isIdentifier(callee) ? callee.text : import_typescript3.default.isPropertyAccessExpression(callee) ? callee.name.text : undefined;
|
|
1216
|
+
if (name) {
|
|
1217
|
+
const list = byName.get(name);
|
|
1218
|
+
if (list)
|
|
1219
|
+
list.push(node);
|
|
1220
|
+
else
|
|
1221
|
+
byName.set(name, [node]);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
import_typescript3.default.forEachChild(node, visit);
|
|
1225
|
+
};
|
|
1226
|
+
visit(source);
|
|
1227
|
+
}
|
|
1228
|
+
return byName;
|
|
1229
|
+
}
|
|
1230
|
+
callersOf(fn, name, limit) {
|
|
1231
|
+
this.byName ??= this.build();
|
|
1232
|
+
const out = this.direct(name, limit, (declaration) => declares(declaration, fn));
|
|
1233
|
+
for (const alias of this.aliases.get(name) ?? []) {
|
|
1234
|
+
if (out.length >= limit)
|
|
1235
|
+
break;
|
|
1236
|
+
const symbol = resolvedSymbol(alias.target, this.checker);
|
|
1237
|
+
if (!symbol?.declarations?.some((declaration) => declares(declaration, fn)))
|
|
1238
|
+
continue;
|
|
1239
|
+
const aliasName = alias.declaration.name.text;
|
|
1240
|
+
out.push(...this.direct(aliasName, limit - out.length, (declaration) => declaration === alias.declaration));
|
|
1241
|
+
}
|
|
1242
|
+
for (const member of this.members.get(name) ?? []) {
|
|
1243
|
+
if (out.length >= limit)
|
|
1244
|
+
break;
|
|
1245
|
+
const symbol = resolvedSymbol(member.target, this.checker);
|
|
1246
|
+
if (!symbol?.declarations?.some((declaration) => declares(declaration, fn)))
|
|
1247
|
+
continue;
|
|
1248
|
+
for (const param of this.holders(member.literal)) {
|
|
1249
|
+
out.push(...this.memberCalls(param, member.property, limit - out.length));
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
1252
|
+
return out;
|
|
1253
|
+
}
|
|
1254
|
+
holders(literal) {
|
|
1255
|
+
let node = literal;
|
|
1256
|
+
while (node.parent && (import_typescript3.default.isParenthesizedExpression(node.parent) || import_typescript3.default.isAsExpression(node.parent) || import_typescript3.default.isSatisfiesExpression(node.parent)))
|
|
1257
|
+
node = node.parent;
|
|
1258
|
+
const parent = node.parent;
|
|
1259
|
+
const out = [];
|
|
1260
|
+
if (parent && import_typescript3.default.isCallExpression(parent)) {
|
|
1261
|
+
const index = parent.arguments.indexOf(node);
|
|
1262
|
+
const fn = index >= 0 ? resolvedFunction(parent.expression, this.checker) : undefined;
|
|
1263
|
+
if (fn && fn.parameters[index])
|
|
1264
|
+
out.push(fn.parameters[index]);
|
|
1265
|
+
} else if (parent && import_typescript3.default.isParameter(parent) && parent.initializer === node) {
|
|
1266
|
+
out.push(parent);
|
|
1267
|
+
} else if (parent && import_typescript3.default.isVariableDeclaration(parent) && parent.initializer === node && import_typescript3.default.isIdentifier(parent.name)) {
|
|
1268
|
+
for (const alias of this.aliases.get(parent.name.text) ?? []) {
|
|
1269
|
+
if (import_typescript3.default.isParameter(alias.declaration) && valueDeclaration(resolvedSymbol(alias.target, this.checker)) === parent)
|
|
1270
|
+
out.push(alias.declaration);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
return out;
|
|
1274
|
+
}
|
|
1275
|
+
memberCalls(param, property, limit) {
|
|
1276
|
+
const out = [];
|
|
1277
|
+
for (const call of this.byName.get(property) ?? []) {
|
|
1278
|
+
if (out.length >= limit)
|
|
1279
|
+
break;
|
|
1280
|
+
const callee = unwrap(call.expression);
|
|
1281
|
+
if (import_typescript3.default.isPropertyAccessExpression(callee)) {
|
|
1282
|
+
const receiver = unwrap(callee.expression);
|
|
1283
|
+
if (import_typescript3.default.isIdentifier(receiver) && valueDeclaration(resolvedSymbol(receiver, this.checker)) === param)
|
|
1284
|
+
out.push(call);
|
|
1285
|
+
} else if (import_typescript3.default.isIdentifier(callee)) {
|
|
1286
|
+
const declaration = valueDeclaration(resolvedSymbol(callee, this.checker));
|
|
1287
|
+
if (!declaration || !import_typescript3.default.isBindingElement(declaration))
|
|
1288
|
+
continue;
|
|
1289
|
+
const holder = declaration.parent.parent;
|
|
1290
|
+
const init = import_typescript3.default.isVariableDeclaration(holder) && holder.initializer ? unwrap(holder.initializer) : undefined;
|
|
1291
|
+
if (holder === param || init && import_typescript3.default.isIdentifier(init) && valueDeclaration(resolvedSymbol(init, this.checker)) === param)
|
|
1292
|
+
out.push(call);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
return out;
|
|
1296
|
+
}
|
|
1297
|
+
direct(name, limit, matches) {
|
|
1298
|
+
const candidates = this.byName.get(name) ?? [];
|
|
1299
|
+
const out = [];
|
|
1300
|
+
let checked = 0;
|
|
1301
|
+
for (const call of candidates) {
|
|
1302
|
+
if (out.length >= limit || checked >= limit * 20)
|
|
1303
|
+
break;
|
|
1304
|
+
checked += 1;
|
|
1305
|
+
const callee = unwrap(call.expression);
|
|
1306
|
+
const nameNode = import_typescript3.default.isPropertyAccessExpression(callee) ? callee.name : callee;
|
|
1307
|
+
const symbol = resolvedSymbol(nameNode, this.checker);
|
|
1308
|
+
if (symbol?.declarations?.some(matches))
|
|
1309
|
+
out.push(call);
|
|
1310
|
+
}
|
|
1311
|
+
return out;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
function declares(declaration, fn) {
|
|
1315
|
+
if (declaration === fn)
|
|
1316
|
+
return true;
|
|
1317
|
+
if ((import_typescript3.default.isVariableDeclaration(declaration) || import_typescript3.default.isPropertyAssignment(declaration) || import_typescript3.default.isPropertyDeclaration(declaration)) && declaration.initializer && unwrap(declaration.initializer) === fn)
|
|
1318
|
+
return true;
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// src/harness-extract/messages.ts
|
|
1323
|
+
var ROLE_LITERALS = {
|
|
1324
|
+
system: "system",
|
|
1325
|
+
developer: "system",
|
|
1326
|
+
user: "user",
|
|
1327
|
+
human: "user",
|
|
1328
|
+
assistant: "assistant",
|
|
1329
|
+
ai: "assistant",
|
|
1330
|
+
model: "assistant",
|
|
1331
|
+
tool: "tool",
|
|
1332
|
+
function: "tool"
|
|
1333
|
+
};
|
|
1334
|
+
var CONSTRUCTOR_ROLE = [
|
|
1335
|
+
[/(?:^|\.)System(?:Message|MessagePromptTemplate)\b/, "system"],
|
|
1336
|
+
[/(?:^|\.)(?:Human|User)(?:Message|MessagePromptTemplate)\b/, "user"],
|
|
1337
|
+
[/(?:^|\.)(?:AI|Ai|Assistant)(?:Message|MessagePromptTemplate)\b/, "assistant"],
|
|
1338
|
+
[/(?:^|\.)(?:Tool|Function)Message\b/, "tool"]
|
|
1339
|
+
];
|
|
1340
|
+
var PASS_THROUGH = new Set(["ref", "lookup", "param", "call", "oneOf"]);
|
|
1341
|
+
var STRINGY = new Set(["literal", "template", "concat", "arrayJoin"]);
|
|
1342
|
+
var MAX_CONTAINERS = 16;
|
|
1343
|
+
function singleLiteral(tree) {
|
|
1344
|
+
if (!tree)
|
|
1345
|
+
return;
|
|
1346
|
+
if (tree.kind === "literal")
|
|
1347
|
+
return tree.text;
|
|
1348
|
+
if (PASS_THROUGH.has(tree.kind)) {
|
|
1349
|
+
const flow = valueChildren(tree);
|
|
1350
|
+
if (flow.length === 1)
|
|
1351
|
+
return singleLiteral(flow[0]);
|
|
1352
|
+
}
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
function elementRole(element, depth = 0) {
|
|
1356
|
+
if (depth > 6 || element.key === "...")
|
|
1357
|
+
return "unknown";
|
|
1358
|
+
if (element.kind === "object") {
|
|
1359
|
+
const members = element.children ?? [];
|
|
1360
|
+
for (let index = members.length - 1;index >= 0; index -= 1) {
|
|
1361
|
+
if (members[index].key === "role") {
|
|
1362
|
+
const text = singleLiteral(members[index]);
|
|
1363
|
+
return text && ROLE_LITERALS[text.toLowerCase()] || "unknown";
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
return "unknown";
|
|
1367
|
+
}
|
|
1368
|
+
if (element.kind === "array") {
|
|
1369
|
+
const text = singleLiteral(element.children?.[0]);
|
|
1370
|
+
return text && ROLE_LITERALS[text.toLowerCase()] || "unknown";
|
|
1371
|
+
}
|
|
1372
|
+
if ((element.kind === "call" || element.kind === "external") && element.name) {
|
|
1373
|
+
for (const [pattern, role] of CONSTRUCTOR_ROLE)
|
|
1374
|
+
if (pattern.test(element.name))
|
|
1375
|
+
return role;
|
|
1376
|
+
}
|
|
1377
|
+
if (PASS_THROUGH.has(element.kind)) {
|
|
1378
|
+
const roles = new Set(valueChildren(element).map((child) => elementRole(child, depth + 1)));
|
|
1379
|
+
return roles.size === 1 ? [...roles][0] : "unknown";
|
|
1380
|
+
}
|
|
1381
|
+
return "unknown";
|
|
1382
|
+
}
|
|
1383
|
+
function containersOf(tree, containers, others, depth = 0) {
|
|
1384
|
+
if (containers.length >= MAX_CONTAINERS)
|
|
1385
|
+
return;
|
|
1386
|
+
if (tree.kind === "array" || tree.kind === "assembled" && tree.text !== "string") {
|
|
1387
|
+
containers.push(tree);
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
const flow = PASS_THROUGH.has(tree.kind) ? valueChildren(tree) : [];
|
|
1391
|
+
if (flow.length > 0 && depth < 12) {
|
|
1392
|
+
for (const child of flow)
|
|
1393
|
+
containersOf(child, containers, others, depth + 1);
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
others.push(tree);
|
|
1397
|
+
}
|
|
1398
|
+
function splitMessages(tree) {
|
|
1399
|
+
const containers = [];
|
|
1400
|
+
const others = [];
|
|
1401
|
+
containersOf(tree, containers, others);
|
|
1402
|
+
if (containers.length === 0) {
|
|
1403
|
+
return [{ role: STRINGY.has(tree.kind) || others.length > 0 && others.every((other) => STRINGY.has(other.kind)) ? "user" : "unknown", tree }];
|
|
1404
|
+
}
|
|
1405
|
+
const out = [];
|
|
1406
|
+
for (const container of containers) {
|
|
1407
|
+
(container.children ?? []).forEach((element, index) => {
|
|
1408
|
+
out.push({ role: elementRole(element), tree: element, message: { arrayId: container.id, index } });
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
for (const other of others)
|
|
1412
|
+
out.push({ role: STRINGY.has(other.kind) ? "user" : "unknown", tree: other });
|
|
1413
|
+
return out;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/harness-extract/program.ts
|
|
1417
|
+
var import_typescript4 = __toESM(require_typescript(), 1);
|
|
1418
|
+
import { readdirSync, statSync } from "node:fs";
|
|
1419
|
+
import { dirname, join, relative as relative2, resolve } from "node:path";
|
|
1420
|
+
var SKIPPED_DIRS = new Set(["node_modules", "dist", "build", "out", "vendor", "coverage", "graphify-out", "__pycache__"]);
|
|
1421
|
+
var CODE_FILE = /\.(?:[cm]?[jt]sx?)$/i;
|
|
1422
|
+
var SVELTE_FILE = /\.svelte$/i;
|
|
1423
|
+
var SCRIPT_BLOCK = /(<script\b[^>]*>)([\s\S]*?)<\/script\s*>/gi;
|
|
1424
|
+
function svelteScriptText(text) {
|
|
1425
|
+
const out = text.replace(/[^\n]/g, " ").split("");
|
|
1426
|
+
for (const match of text.matchAll(SCRIPT_BLOCK)) {
|
|
1427
|
+
const start = (match.index ?? 0) + match[1].length;
|
|
1428
|
+
for (let index = 0;index < match[2].length; index += 1)
|
|
1429
|
+
out[start + index] = match[2][index];
|
|
1430
|
+
}
|
|
1431
|
+
return out.join("");
|
|
1432
|
+
}
|
|
1433
|
+
var DECLARATION_FILE = /\.d\.[cm]?ts$/i;
|
|
1434
|
+
var TEST_RUNNER_FILE = /(?:^|\/)__tests__\/|\.(?:test|spec)\.[cm]?[jt]sx?$/i;
|
|
1435
|
+
var TEST_PATH = /(?:^|\/)(?:test|tests|__tests__|test-fixtures|fixtures?|__fixtures__|__mocks__|e2e)\/|\.(?:test|spec)\.[cm]?[jt]sx?$/i;
|
|
1436
|
+
var EVAL_PATH = /(?:^|\/)evals?\/|\.evals?\.[cm]?[jt]sx?$/i;
|
|
1437
|
+
var MAX_FILE_BYTES = 1024 * 1024;
|
|
1438
|
+
var DEFAULT_MAX_FILES = 20000;
|
|
1439
|
+
function isTestPath(rel) {
|
|
1440
|
+
return TEST_PATH.test(rel);
|
|
1441
|
+
}
|
|
1442
|
+
function isEvalPath(rel) {
|
|
1443
|
+
return EVAL_PATH.test(rel);
|
|
1444
|
+
}
|
|
1445
|
+
function walkRepository(rootDir, maxFiles, includeTestRunnerFiles) {
|
|
1446
|
+
const files = [];
|
|
1447
|
+
const configs = [];
|
|
1448
|
+
let truncated = false;
|
|
1449
|
+
const walk = (abs, rel) => {
|
|
1450
|
+
let entries;
|
|
1451
|
+
try {
|
|
1452
|
+
entries = readdirSync(abs, { withFileTypes: true });
|
|
1453
|
+
} catch {
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1457
|
+
for (const entry of entries) {
|
|
1458
|
+
if (files.length >= maxFiles) {
|
|
1459
|
+
truncated = true;
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
const childRel = rel ? `${rel}/${entry.name}` : entry.name;
|
|
1463
|
+
const childAbs = join(abs, entry.name);
|
|
1464
|
+
if (entry.isDirectory()) {
|
|
1465
|
+
if (!entry.name.startsWith(".") && !SKIPPED_DIRS.has(entry.name))
|
|
1466
|
+
walk(childAbs, childRel);
|
|
1467
|
+
} else if (entry.isFile()) {
|
|
1468
|
+
if (entry.name === "tsconfig.json")
|
|
1469
|
+
configs.push(childAbs);
|
|
1470
|
+
else if (SVELTE_FILE.test(entry.name)) {
|
|
1471
|
+
try {
|
|
1472
|
+
if (statSync(childAbs).size <= MAX_FILE_BYTES)
|
|
1473
|
+
files.push(svelteVirtualName(childAbs));
|
|
1474
|
+
} catch {
|
|
1475
|
+
continue;
|
|
1476
|
+
}
|
|
1477
|
+
} else if (CODE_FILE.test(entry.name) && !DECLARATION_FILE.test(entry.name) && !/\.min\.[cm]?js$/i.test(entry.name) && (includeTestRunnerFiles || !TEST_RUNNER_FILE.test(childRel))) {
|
|
1478
|
+
try {
|
|
1479
|
+
if (statSync(childAbs).size > MAX_FILE_BYTES)
|
|
1480
|
+
continue;
|
|
1481
|
+
} catch {
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
files.push(childAbs);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
walk(rootDir, "");
|
|
1490
|
+
return { files, configs, truncated };
|
|
1491
|
+
}
|
|
1492
|
+
function extractorOptions(base) {
|
|
1493
|
+
const options = {
|
|
1494
|
+
...base,
|
|
1495
|
+
noEmit: true,
|
|
1496
|
+
skipLibCheck: true,
|
|
1497
|
+
noLib: true,
|
|
1498
|
+
types: [],
|
|
1499
|
+
noResolve: false,
|
|
1500
|
+
allowJs: true,
|
|
1501
|
+
checkJs: false,
|
|
1502
|
+
resolveJsonModule: false,
|
|
1503
|
+
declaration: false,
|
|
1504
|
+
composite: false,
|
|
1505
|
+
incremental: false,
|
|
1506
|
+
tsBuildInfoFile: undefined,
|
|
1507
|
+
plugins: undefined
|
|
1508
|
+
};
|
|
1509
|
+
if (options.moduleResolution === undefined) {
|
|
1510
|
+
options.module = import_typescript4.default.ModuleKind.ESNext;
|
|
1511
|
+
options.moduleResolution = import_typescript4.default.ModuleResolutionKind.Bundler;
|
|
1512
|
+
}
|
|
1513
|
+
options.allowImportingTsExtensions = true;
|
|
1514
|
+
return options;
|
|
1515
|
+
}
|
|
1516
|
+
var FALLBACK_OPTIONS = extractorOptions({
|
|
1517
|
+
target: import_typescript4.default.ScriptTarget.ES2022,
|
|
1518
|
+
jsx: import_typescript4.default.JsxEmit.Preserve,
|
|
1519
|
+
esModuleInterop: true
|
|
1520
|
+
});
|
|
1521
|
+
function sharedHost(options, cache) {
|
|
1522
|
+
const host = import_typescript4.default.createCompilerHost(options, true);
|
|
1523
|
+
const moduleCache = import_typescript4.default.createModuleResolutionCache(host.getCurrentDirectory(), (name) => name, options);
|
|
1524
|
+
host.getSourceFile = (fileName, languageVersionOrOptions) => {
|
|
1525
|
+
const version = typeof languageVersionOrOptions === "object" ? languageVersionOrOptions.languageVersion : languageVersionOrOptions;
|
|
1526
|
+
const key = `${version}:${fileName}`;
|
|
1527
|
+
if (cache.has(key))
|
|
1528
|
+
return cache.get(key);
|
|
1529
|
+
let source;
|
|
1530
|
+
const svelte = fileName.endsWith(SVELTE_VIRTUAL_SUFFIX);
|
|
1531
|
+
const raw = import_typescript4.default.sys.readFile(svelte ? fileName.slice(0, -SVELTE_VIRTUAL_SUFFIX.length) : fileName);
|
|
1532
|
+
const text = svelte && raw !== undefined ? svelteScriptText(raw) : raw;
|
|
1533
|
+
if (text !== undefined && text.length <= MAX_FILE_BYTES) {
|
|
1534
|
+
source = import_typescript4.default.createSourceFile(fileName, text, languageVersionOrOptions, true, svelte ? import_typescript4.default.ScriptKind.TS : undefined);
|
|
1535
|
+
}
|
|
1536
|
+
cache.set(key, source);
|
|
1537
|
+
return source;
|
|
1538
|
+
};
|
|
1539
|
+
host.resolveModuleNameLiterals = (literals, containingFile, redirected, compilerOptions) => literals.map((literal) => {
|
|
1540
|
+
const resolved = import_typescript4.default.resolveModuleName(literal.text, containingFile, compilerOptions, host, moduleCache, redirected).resolvedModule;
|
|
1541
|
+
if (!resolved || resolved.isExternalLibraryImport || /[\\/]node_modules[\\/]/.test(resolved.resolvedFileName) || DECLARATION_FILE.test(resolved.resolvedFileName) || !CODE_FILE.test(resolved.resolvedFileName)) {
|
|
1542
|
+
return { resolvedModule: undefined };
|
|
1543
|
+
}
|
|
1544
|
+
return { resolvedModule: resolved };
|
|
1545
|
+
});
|
|
1546
|
+
const fileExists = host.fileExists.bind(host);
|
|
1547
|
+
host.fileExists = (fileName) => fileName.endsWith(SVELTE_VIRTUAL_SUFFIX) ? fileExists(fileName.slice(0, -SVELTE_VIRTUAL_SUFFIX.length)) : fileExists(fileName);
|
|
1548
|
+
host.writeFile = () => {};
|
|
1549
|
+
return host;
|
|
1550
|
+
}
|
|
1551
|
+
function parseConfig(configPath, warnings, rootDir) {
|
|
1552
|
+
const rel = relative2(rootDir, configPath).split("\\").join("/");
|
|
1553
|
+
const read = import_typescript4.default.readConfigFile(configPath, import_typescript4.default.sys.readFile);
|
|
1554
|
+
if (read.error || !read.config || typeof read.config !== "object") {
|
|
1555
|
+
warnings.push(`tsconfig ${rel}: unreadable, its files fall back to the default program`);
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
const raw = read.config;
|
|
1559
|
+
const parsed = import_typescript4.default.parseJsonConfigFileContent(read.config, import_typescript4.default.sys, dirname(configPath), undefined, configPath);
|
|
1560
|
+
const explicit = raw.include !== undefined || raw.files !== undefined || parsed.raw && (parsed.raw.include !== undefined || parsed.raw.files !== undefined);
|
|
1561
|
+
return { options: parsed.options, fileNames: explicit ? parsed.fileNames.map((name) => resolve(name)) : undefined };
|
|
1562
|
+
}
|
|
1563
|
+
function isUnder(file, dir) {
|
|
1564
|
+
const rel = relative2(dir, file);
|
|
1565
|
+
return rel !== "" && !rel.startsWith("..") && !rel.startsWith("/");
|
|
1566
|
+
}
|
|
1567
|
+
function buildPrograms(rootDir, options = {}) {
|
|
1568
|
+
const root = resolve(rootDir);
|
|
1569
|
+
const maxFiles = options.maxFiles ?? DEFAULT_MAX_FILES;
|
|
1570
|
+
const warnings = [];
|
|
1571
|
+
const walked = walkRepository(root, maxFiles, options.includeTestRunnerFiles ?? false);
|
|
1572
|
+
if (walked.truncated)
|
|
1573
|
+
warnings.push(`file cap reached: only the first ${maxFiles} code files are scanned`);
|
|
1574
|
+
const known = new Set(walked.files);
|
|
1575
|
+
const configDirs = walked.configs.map((path) => dirname(path));
|
|
1576
|
+
const assigned = new Set;
|
|
1577
|
+
const cache = new Map;
|
|
1578
|
+
const entries = [];
|
|
1579
|
+
const owner = new Map;
|
|
1580
|
+
const create = (rootNames, owned, compilerOptions, configPath) => {
|
|
1581
|
+
const host = sharedHost(compilerOptions, cache);
|
|
1582
|
+
let program;
|
|
1583
|
+
try {
|
|
1584
|
+
program = import_typescript4.default.createProgram({ rootNames, options: compilerOptions, host });
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
warnings.push(`program ${configPath ?? "(fallback)"}: ${error.message}`);
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
let checker;
|
|
1590
|
+
const entry = {
|
|
1591
|
+
program,
|
|
1592
|
+
configPath,
|
|
1593
|
+
owned,
|
|
1594
|
+
checker: () => checker ??= program.getTypeChecker()
|
|
1595
|
+
};
|
|
1596
|
+
entries.push(entry);
|
|
1597
|
+
for (const file of owned)
|
|
1598
|
+
owner.set(file, entry);
|
|
1599
|
+
};
|
|
1600
|
+
const configs = [...walked.configs].sort((a, b) => b.split(/[\\/]/).length - a.split(/[\\/]/).length || a.localeCompare(b));
|
|
1601
|
+
for (const configPath of configs) {
|
|
1602
|
+
const parsed = parseConfig(configPath, warnings, root);
|
|
1603
|
+
if (!parsed)
|
|
1604
|
+
continue;
|
|
1605
|
+
const dir = dirname(configPath);
|
|
1606
|
+
const nested = configDirs.filter((other) => other !== dir && isUnder(other, dir));
|
|
1607
|
+
const included = parsed.fileNames ? parsed.fileNames.filter((file) => known.has(file)) : walked.files.filter((file) => isUnder(file, dir) && !nested.some((other) => isUnder(file, other)));
|
|
1608
|
+
const owned = included.filter((file) => !assigned.has(file));
|
|
1609
|
+
if (owned.length === 0)
|
|
1610
|
+
continue;
|
|
1611
|
+
for (const file of owned)
|
|
1612
|
+
assigned.add(file);
|
|
1613
|
+
create(included, owned, extractorOptions(parsed.options), relative2(root, configPath).split("\\").join("/"));
|
|
1614
|
+
}
|
|
1615
|
+
const rest = walked.files.filter((file) => !assigned.has(file));
|
|
1616
|
+
if (rest.length > 0)
|
|
1617
|
+
create(rest, rest, FALLBACK_OPTIONS);
|
|
1618
|
+
return { rootDir: root, entries, owner, files: assigned.size + rest.length, warnings };
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// src/harness-extract/sinks.ts
|
|
1622
|
+
var import_typescript5 = __toESM(require_typescript(), 1);
|
|
1623
|
+
var ANTHROPIC_MODULE = /^@anthropic-ai\//;
|
|
1624
|
+
var OPENAI_MODULE = /^openai(?:\/|$)/;
|
|
1625
|
+
var OPENAI_COMPATIBLE_MODULE = /^(?:groq-sdk|together-ai|@cerebras\/cerebras_cloud_sdk|fireworks-ai|portkey-ai|@portkey-ai\/|@azure\/openai|deepseek|@helicone\/|cohere-ai)/;
|
|
1626
|
+
var AI_SDK_CALLS = new Set(["generateText", "streamText", "generateObject", "streamObject"]);
|
|
1627
|
+
var AI_SDK_DECIDE = new Set(["experimental_decide", "decide", "experimental_evaluate", "evaluate"]);
|
|
1628
|
+
var AI_SDK_AGENTS = new Set(["Agent", "Experimental_Agent", "ToolLoopAgent"]);
|
|
1629
|
+
var PROVIDER_MODULE = /^(?:@ai-sdk\/(?!react$|ui-utils$|rsc$|provider$|provider-utils$|svelte$|vue$|solid$|angular$|valibot$)[\w-]+|@openrouter\/ai-sdk-provider|workers-ai-provider|ollama-ai-provider(?:-v2)?|@requesty\/ai-sdk|@portkey-ai\/vercel-provider|@mistralai\/ai-sdk)$/;
|
|
1630
|
+
var MODEL_HOST = /^https?:\/\/(?:openrouter\.ai|api\.openai\.com|api\.anthropic\.com|generativelanguage\.googleapis\.com|api\.groq\.com|api\.together\.(?:xyz|ai)|api\.mistral\.ai|api\.deepseek\.com|api\.fireworks\.ai|api\.x\.ai|api\.perplexity\.ai|gateway\.ai\.cloudflare\.com)\//;
|
|
1631
|
+
var MODEL_PATH = /\/chat\/completions\b|\/v1\/messages\b|\/v1\/responses\b|:generateContent\b|:streamGenerateContent\b/;
|
|
1632
|
+
var FRAMEWORK_MODULE = /^(?:agents(?:\/.*)?|@cloudflare\/think|@cloudflare\/ai-chat|@cloudflare\/agents|cloudflare:workers|cloudflare:workflows)$/;
|
|
1633
|
+
var FRAMEWORK_BASES = new Set(["Think", "Agent", "AIChatAgent", "McpAgent", "DurableObject", "WorkflowEntrypoint", "AgentWorkflow"]);
|
|
1634
|
+
var HOOK_BASES = new Set(["Think", "Agent", "AIChatAgent", "McpAgent"]);
|
|
1635
|
+
var HOOK_METHODS = { getModel: "model", getSystemPrompt: "system", getTools: "tools" };
|
|
1636
|
+
var HOOK_PROPERTIES = { model: "model", systemPrompt: "system" };
|
|
1637
|
+
var TURN_HOOKS = new Set(["beforeTurn"]);
|
|
1638
|
+
var TURN_CONFIG_KEYS = { model: "model", system: "system", tools: "tools" };
|
|
1639
|
+
function providerName(module) {
|
|
1640
|
+
if (module === "ai" || module === "@ai-sdk/gateway")
|
|
1641
|
+
return "ai-gateway";
|
|
1642
|
+
if (module === "@openrouter/ai-sdk-provider")
|
|
1643
|
+
return "openrouter";
|
|
1644
|
+
if (module === "workers-ai-provider")
|
|
1645
|
+
return "workers-ai";
|
|
1646
|
+
if (module.startsWith("ollama-ai-provider"))
|
|
1647
|
+
return "ollama";
|
|
1648
|
+
const scoped = /^@[\w-]+\/(?:ai-sdk-)?([\w-]+)$/.exec(module);
|
|
1649
|
+
return scoped ? scoped[1] : module;
|
|
1650
|
+
}
|
|
1651
|
+
function requestRoles(argument, keys, ctx) {
|
|
1652
|
+
if (!argument)
|
|
1653
|
+
return [];
|
|
1654
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
1655
|
+
const roles = [];
|
|
1656
|
+
if (object && unwrap(argument) === object) {
|
|
1657
|
+
for (const [key, role] of Object.entries(keys)) {
|
|
1658
|
+
const value = propertyValue(object, key);
|
|
1659
|
+
if (value)
|
|
1660
|
+
roles.push({ role, node: value });
|
|
1661
|
+
else if (!hasProperty(object, key) && object.properties.some((property) => import_typescript5.default.isSpreadAssignment(property))) {
|
|
1662
|
+
roles.push({ role, node: argument, key });
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return dedupeRoles(roles);
|
|
1666
|
+
}
|
|
1667
|
+
for (const [key, role] of Object.entries(keys)) {
|
|
1668
|
+
if (!object || hasProperty(object, key) || object.properties.some((property) => import_typescript5.default.isSpreadAssignment(property))) {
|
|
1669
|
+
roles.push({ role, node: argument, key });
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
return dedupeRoles(roles);
|
|
1673
|
+
}
|
|
1674
|
+
function dedupeRoles(roles) {
|
|
1675
|
+
const seen = new Set;
|
|
1676
|
+
return roles.filter((role) => {
|
|
1677
|
+
if (seen.has(role.role))
|
|
1678
|
+
return false;
|
|
1679
|
+
seen.add(role.role);
|
|
1680
|
+
return true;
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
function typeOrigin(type, checker) {
|
|
1684
|
+
if (!type)
|
|
1685
|
+
return;
|
|
1686
|
+
if (import_typescript5.default.isUnionTypeNode(type) || import_typescript5.default.isIntersectionTypeNode(type)) {
|
|
1687
|
+
for (const member of type.types) {
|
|
1688
|
+
const origin = typeOrigin(member, checker);
|
|
1689
|
+
if (origin)
|
|
1690
|
+
return origin;
|
|
1691
|
+
}
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
if (import_typescript5.default.isTypeReferenceNode(type)) {
|
|
1695
|
+
let name = type.typeName;
|
|
1696
|
+
while (import_typescript5.default.isQualifiedName(name))
|
|
1697
|
+
name = name.left;
|
|
1698
|
+
return importOrigin(name, checker);
|
|
1699
|
+
}
|
|
1700
|
+
return;
|
|
1701
|
+
}
|
|
1702
|
+
function valueOrigin(expression, checker, depth = 0, seen = new Set) {
|
|
1703
|
+
const expr = unwrap(expression);
|
|
1704
|
+
if (depth > 6 || seen.has(expr))
|
|
1705
|
+
return;
|
|
1706
|
+
seen.add(expr);
|
|
1707
|
+
if (import_typescript5.default.isNewExpression(expr) || import_typescript5.default.isCallExpression(expr)) {
|
|
1708
|
+
const root = rootIdentifier(expr.expression);
|
|
1709
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
1710
|
+
if (origin)
|
|
1711
|
+
return origin;
|
|
1712
|
+
const fn = resolvedFunction(expr.expression, checker);
|
|
1713
|
+
if (fn) {
|
|
1714
|
+
const declared = typeOrigin(fn.type, checker);
|
|
1715
|
+
if (declared)
|
|
1716
|
+
return declared;
|
|
1717
|
+
for (const ret of returnExpressions(fn)) {
|
|
1718
|
+
const found = valueOrigin(ret, checker, depth + 1, seen);
|
|
1719
|
+
if (found)
|
|
1720
|
+
return found;
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return;
|
|
1724
|
+
}
|
|
1725
|
+
let declaration;
|
|
1726
|
+
if (import_typescript5.default.isIdentifier(expr)) {
|
|
1727
|
+
const origin = importOrigin(expr, checker);
|
|
1728
|
+
if (origin)
|
|
1729
|
+
return origin;
|
|
1730
|
+
declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1731
|
+
} else if (import_typescript5.default.isPropertyAccessExpression(expr)) {
|
|
1732
|
+
declaration = valueDeclaration(resolvedSymbol(expr.name, checker));
|
|
1733
|
+
}
|
|
1734
|
+
if (!declaration)
|
|
1735
|
+
return;
|
|
1736
|
+
if (import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isPropertyDeclaration(declaration) || import_typescript5.default.isParameter(declaration) || import_typescript5.default.isPropertySignature(declaration) || import_typescript5.default.isPropertyAssignment(declaration)) {
|
|
1737
|
+
const declared = "type" in declaration ? typeOrigin(declaration.type, checker) : undefined;
|
|
1738
|
+
if (declared)
|
|
1739
|
+
return declared;
|
|
1740
|
+
const initializer = "initializer" in declaration ? declaration.initializer : undefined;
|
|
1741
|
+
if (initializer)
|
|
1742
|
+
return valueOrigin(initializer, checker, depth + 1, seen);
|
|
1743
|
+
if (import_typescript5.default.isPropertyDeclaration(declaration)) {
|
|
1744
|
+
const key = propertyNameText(declaration.name);
|
|
1745
|
+
let found;
|
|
1746
|
+
const visit = (node) => {
|
|
1747
|
+
if (found)
|
|
1748
|
+
return;
|
|
1749
|
+
if (import_typescript5.default.isBinaryExpression(node) && node.operatorToken.kind === import_typescript5.default.SyntaxKind.EqualsToken && import_typescript5.default.isPropertyAccessExpression(node.left) && node.left.expression.kind === import_typescript5.default.SyntaxKind.ThisKeyword && node.left.name.text === key) {
|
|
1750
|
+
found = valueOrigin(node.right, checker, depth + 1, seen);
|
|
1751
|
+
}
|
|
1752
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
1753
|
+
};
|
|
1754
|
+
import_typescript5.default.forEachChild(declaration.parent, visit);
|
|
1755
|
+
return found;
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
function providerInstance(expression, checker, depth = 0) {
|
|
1761
|
+
const expr = unwrap(expression);
|
|
1762
|
+
if (depth > 6)
|
|
1763
|
+
return;
|
|
1764
|
+
if (import_typescript5.default.isIdentifier(expr)) {
|
|
1765
|
+
const origin = importOrigin(expr, checker);
|
|
1766
|
+
if (origin) {
|
|
1767
|
+
if (origin.module === "ai" && origin.imported === "gateway")
|
|
1768
|
+
return "ai";
|
|
1769
|
+
return PROVIDER_MODULE.test(origin.module) && !/^create/.test(origin.imported) && origin.imported !== "*" ? origin.module : undefined;
|
|
1770
|
+
}
|
|
1771
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1772
|
+
if (declaration && (import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isPropertyDeclaration(declaration)) && declaration.initializer) {
|
|
1773
|
+
const initializer = declaration.initializer;
|
|
1774
|
+
return memoized(declaration, () => providerInstance(initializer, checker, depth + 1));
|
|
1775
|
+
}
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
if (import_typescript5.default.isPropertyAccessExpression(expr)) {
|
|
1779
|
+
const declaration = valueDeclaration(resolvedSymbol(expr.name, checker));
|
|
1780
|
+
if (declaration && (import_typescript5.default.isPropertyDeclaration(declaration) || import_typescript5.default.isPropertyAssignment(declaration) || import_typescript5.default.isVariableDeclaration(declaration)) && declaration.initializer) {
|
|
1781
|
+
const initializer = declaration.initializer;
|
|
1782
|
+
return memoized(declaration, () => providerInstance(initializer, checker, depth + 1));
|
|
1783
|
+
}
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
if (import_typescript5.default.isCallExpression(expr)) {
|
|
1787
|
+
const root = rootIdentifier(expr.expression);
|
|
1788
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
1789
|
+
if (origin) {
|
|
1790
|
+
if (PROVIDER_MODULE.test(origin.module) && /^create/.test(origin.imported))
|
|
1791
|
+
return origin.module;
|
|
1792
|
+
if (origin.module === "ai" && (origin.imported === "customProvider" || origin.imported === "createGateway"))
|
|
1793
|
+
return "ai";
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
const fn = resolvedFunction(expr.expression, checker);
|
|
1797
|
+
if (fn) {
|
|
1798
|
+
return memoized(fn, () => {
|
|
1799
|
+
for (const ret of returnExpressions(fn)) {
|
|
1800
|
+
const found = providerInstance(ret, checker, depth + 1);
|
|
1801
|
+
if (found)
|
|
1802
|
+
return found;
|
|
1803
|
+
}
|
|
1804
|
+
return;
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
var providerMemo = new WeakMap;
|
|
1811
|
+
function memoized(node, compute) {
|
|
1812
|
+
if (providerMemo.has(node))
|
|
1813
|
+
return providerMemo.get(node) ?? undefined;
|
|
1814
|
+
providerMemo.set(node, null);
|
|
1815
|
+
const value = compute();
|
|
1816
|
+
providerMemo.set(node, value ?? null);
|
|
1817
|
+
return value;
|
|
1818
|
+
}
|
|
1819
|
+
var MODEL_METHOD = /model|chat|completion|responses|messages|image|embedding|speech|transcription/i;
|
|
1820
|
+
function providerModelCall(call, checker) {
|
|
1821
|
+
const model = call.arguments[0];
|
|
1822
|
+
if (!model || import_typescript5.default.isSpreadElement(model) || import_typescript5.default.isObjectLiteralExpression(unwrap(model)))
|
|
1823
|
+
return;
|
|
1824
|
+
const callee = unwrap(call.expression);
|
|
1825
|
+
if (import_typescript5.default.isIdentifier(callee)) {
|
|
1826
|
+
const module = providerInstance(callee, checker);
|
|
1827
|
+
return module ? { module, model } : undefined;
|
|
1828
|
+
}
|
|
1829
|
+
if (import_typescript5.default.isPropertyAccessExpression(callee) && MODEL_METHOD.test(callee.name.text)) {
|
|
1830
|
+
const module = providerInstance(callee.expression, checker);
|
|
1831
|
+
return module ? { module, method: callee.name.text, model } : undefined;
|
|
1832
|
+
}
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
function chainEndsWith(chain, tail) {
|
|
1836
|
+
if (!chain || chain.length <= tail.length)
|
|
1837
|
+
return false;
|
|
1838
|
+
return tail.every((part, index) => chain[chain.length - tail.length + index] === part);
|
|
1839
|
+
}
|
|
1840
|
+
function receiverOf(callee, tailLength) {
|
|
1841
|
+
let current = unwrap(callee);
|
|
1842
|
+
for (let index = 0;index < tailLength && import_typescript5.default.isPropertyAccessExpression(current); index += 1)
|
|
1843
|
+
current = unwrap(current.expression);
|
|
1844
|
+
return current;
|
|
1845
|
+
}
|
|
1846
|
+
var anthropicSink = {
|
|
1847
|
+
id: "anthropic",
|
|
1848
|
+
sdk: "anthropic",
|
|
1849
|
+
match(call, ctx) {
|
|
1850
|
+
if (!import_typescript5.default.isCallExpression(call))
|
|
1851
|
+
return;
|
|
1852
|
+
const chain = calleeChain(call.expression);
|
|
1853
|
+
const tails = [["beta", "messages", "create"], ["beta", "messages", "stream"], ["messages", "create"], ["messages", "stream"]];
|
|
1854
|
+
const tail = tails.find((candidate) => chainEndsWith(chain, candidate));
|
|
1855
|
+
if (!tail || chain.includes("threads"))
|
|
1856
|
+
return;
|
|
1857
|
+
const receiver = receiverOf(call.expression, tail.length);
|
|
1858
|
+
const origin = valueOrigin(receiver, ctx.checker);
|
|
1859
|
+
const request = call.arguments[0];
|
|
1860
|
+
if (origin && !ANTHROPIC_MODULE.test(origin.module))
|
|
1861
|
+
return;
|
|
1862
|
+
if (!origin) {
|
|
1863
|
+
const object = objectLiteralOf(request, ctx.checker);
|
|
1864
|
+
const receiverName = receiver.getText();
|
|
1865
|
+
if (!object || !hasProperty(object, "model") || !hasProperty(object, "messages"))
|
|
1866
|
+
return;
|
|
1867
|
+
if (!/anthropic|claude|client|llm|openrouter/i.test(receiverName) && !hasProperty(object, "max_tokens"))
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
return {
|
|
1871
|
+
api: `anthropic.${tail.join(".")}`,
|
|
1872
|
+
provider: "anthropic",
|
|
1873
|
+
roles: requestRoles(request, { model: "model", system: "system", messages: "messages", tools: "tools" }, ctx)
|
|
1874
|
+
};
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
var openaiSink = {
|
|
1878
|
+
id: "openai",
|
|
1879
|
+
sdk: "openai",
|
|
1880
|
+
match(call, ctx) {
|
|
1881
|
+
if (!import_typescript5.default.isCallExpression(call))
|
|
1882
|
+
return;
|
|
1883
|
+
const chain = calleeChain(call.expression);
|
|
1884
|
+
const tails = [["chat", "completions", "create"], ["chat", "completions", "parse"], ["chat", "completions", "stream"], ["responses", "create"], ["responses", "stream"], ["responses", "parse"]];
|
|
1885
|
+
const tail = tails.find((candidate) => chainEndsWith(chain, candidate));
|
|
1886
|
+
if (!tail)
|
|
1887
|
+
return;
|
|
1888
|
+
const receiver = receiverOf(call.expression, tail.length);
|
|
1889
|
+
const origin = valueOrigin(receiver, ctx.checker);
|
|
1890
|
+
if (origin && !OPENAI_MODULE.test(origin.module) && !(tail[0] === "chat" && !ANTHROPIC_MODULE.test(origin.module)))
|
|
1891
|
+
return;
|
|
1892
|
+
const request = call.arguments[0];
|
|
1893
|
+
if (!origin && tail[0] === "responses") {
|
|
1894
|
+
const object = objectLiteralOf(request, ctx.checker);
|
|
1895
|
+
if (!object || !hasProperty(object, "model") || !(hasProperty(object, "input") || hasProperty(object, "instructions")))
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1898
|
+
return {
|
|
1899
|
+
api: `openai.${tail.join(".")}`,
|
|
1900
|
+
provider: !origin || OPENAI_MODULE.test(origin.module) ? "openai" : OPENAI_COMPATIBLE_MODULE.test(origin.module) ? providerName(origin.module).replace(/-sdk$|_cloud_sdk$|-ai$/, "") : providerName(origin.module),
|
|
1901
|
+
roles: requestRoles(request, { model: "model", messages: "messages", input: "messages", instructions: "instructions", tools: "tools", functions: "tools" }, ctx)
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
var aiSdkSink = {
|
|
1906
|
+
id: "ai-sdk",
|
|
1907
|
+
sdk: "ai-sdk",
|
|
1908
|
+
match(call, ctx) {
|
|
1909
|
+
const callee = unwrap(call.expression);
|
|
1910
|
+
const nameNode = import_typescript5.default.isPropertyAccessExpression(callee) ? callee.name : import_typescript5.default.isIdentifier(callee) ? callee : undefined;
|
|
1911
|
+
const root = rootIdentifier(callee);
|
|
1912
|
+
if (!nameNode || !root)
|
|
1913
|
+
return;
|
|
1914
|
+
const origin = importOrigin(root, ctx.checker);
|
|
1915
|
+
if (!origin || origin.module !== "ai")
|
|
1916
|
+
return;
|
|
1917
|
+
const name = origin.imported === "*" ? nameNode.text : origin.imported;
|
|
1918
|
+
if (!import_typescript5.default.isNewExpression(call) && AI_SDK_DECIDE.has(name)) {
|
|
1919
|
+
return { api: `ai.${name}`, roles: requestRoles(call.arguments[0], { model: "model", questions: "questions", criteria: "questions" }, ctx) };
|
|
1920
|
+
}
|
|
1921
|
+
const known = import_typescript5.default.isNewExpression(call) ? AI_SDK_AGENTS.has(name) : AI_SDK_CALLS.has(name);
|
|
1922
|
+
if (!known)
|
|
1923
|
+
return;
|
|
1924
|
+
return {
|
|
1925
|
+
api: `ai.${name}`,
|
|
1926
|
+
roles: requestRoles(call.arguments?.[0], { model: "model", system: "system", instructions: "instructions", prompt: "prompt", messages: "messages", tools: "tools" }, ctx)
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
};
|
|
1930
|
+
var providerFactorySink = {
|
|
1931
|
+
id: "provider-factory",
|
|
1932
|
+
sdk: "provider-factory",
|
|
1933
|
+
match(call, ctx) {
|
|
1934
|
+
if (!import_typescript5.default.isCallExpression(call))
|
|
1935
|
+
return;
|
|
1936
|
+
const found = providerModelCall(call, ctx.checker);
|
|
1937
|
+
if (!found)
|
|
1938
|
+
return;
|
|
1939
|
+
const provider = providerName(found.module);
|
|
1940
|
+
return { api: `${provider}${found.method ? `.${found.method}` : ""}(model)`, provider, roles: [{ role: "model", node: found.model }] };
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
var workersAiSink = {
|
|
1944
|
+
id: "workers-ai",
|
|
1945
|
+
sdk: "workers-ai",
|
|
1946
|
+
match(call, ctx) {
|
|
1947
|
+
if (!import_typescript5.default.isCallExpression(call))
|
|
1948
|
+
return;
|
|
1949
|
+
const chain = calleeChain(call.expression);
|
|
1950
|
+
if (!chainEndsWith(chain, ["AI", "run"]) || call.arguments.length === 0)
|
|
1951
|
+
return;
|
|
1952
|
+
const [model, input] = call.arguments;
|
|
1953
|
+
return {
|
|
1954
|
+
api: "workers-ai.AI.run",
|
|
1955
|
+
provider: "workers-ai",
|
|
1956
|
+
roles: [{ role: "model", node: model }, ...requestRoles(input, { messages: "messages", prompt: "prompt", tools: "tools" }, ctx)]
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
var REQUEST_KEYS = { model: "model", system: "system", messages: "messages", input: "messages", instructions: "instructions", prompt: "prompt", tools: "tools" };
|
|
1961
|
+
var OPAQUE_BODY_KEYS = { model: "model", system: "system", messages: "messages", tools: "tools" };
|
|
1962
|
+
var FETCH_LIKE = /fetch|request|post/i;
|
|
1963
|
+
var NON_MODEL_PATH = /\/models\/?(?:\?|$|`)|\/generation\b|\/credits\b|\/auth\/|\/keys?\b|\/embeddings\b|\/files\b/;
|
|
1964
|
+
function bodyHasModel(init, checker) {
|
|
1965
|
+
const body = init ? propertyValue(init, "body") : undefined;
|
|
1966
|
+
let payload = body ? unwrap(body) : undefined;
|
|
1967
|
+
if (payload && import_typescript5.default.isCallExpression(payload) && payload.arguments[0])
|
|
1968
|
+
payload = payload.arguments[0];
|
|
1969
|
+
const object = objectLiteralOf(payload, checker);
|
|
1970
|
+
return Boolean(object && hasProperty(object, "model"));
|
|
1971
|
+
}
|
|
1972
|
+
function urlTemplate(expression, checker, depth = 0) {
|
|
1973
|
+
const expr = unwrap(expression);
|
|
1974
|
+
if (import_typescript5.default.isTemplateExpression(expr))
|
|
1975
|
+
return expr;
|
|
1976
|
+
if (depth < 3 && import_typescript5.default.isIdentifier(expr)) {
|
|
1977
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
1978
|
+
if (declaration && import_typescript5.default.isVariableDeclaration(declaration) && declaration.initializer)
|
|
1979
|
+
return urlTemplate(declaration.initializer, checker, depth + 1);
|
|
1980
|
+
}
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
function urlModel(url, checker) {
|
|
1984
|
+
const template = urlTemplate(url, checker);
|
|
1985
|
+
if (!template)
|
|
1986
|
+
return;
|
|
1987
|
+
let before = template.head.text;
|
|
1988
|
+
for (const span of template.templateSpans) {
|
|
1989
|
+
if (/\/models\/$|[?&]model=$/.test(before))
|
|
1990
|
+
return span.expression;
|
|
1991
|
+
before = span.literal.text;
|
|
1992
|
+
}
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
var fetchSink = {
|
|
1996
|
+
id: "fetch",
|
|
1997
|
+
sdk: "fetch",
|
|
1998
|
+
match(call, ctx) {
|
|
1999
|
+
if (!import_typescript5.default.isCallExpression(call) || call.arguments.length < 2)
|
|
2000
|
+
return;
|
|
2001
|
+
const callee = unwrap(call.expression);
|
|
2002
|
+
const calleeText = import_typescript5.default.isCallExpression(callee) ? callee.expression.getText() : callee.getText();
|
|
2003
|
+
if (!FETCH_LIKE.test(calleeText))
|
|
2004
|
+
return;
|
|
2005
|
+
if (import_typescript5.default.isIdentifier(callee) && callee.text === "fetch" && resolvedFunction(callee, ctx.checker))
|
|
2006
|
+
return;
|
|
2007
|
+
const second = unwrap(call.arguments[1]);
|
|
2008
|
+
if (import_typescript5.default.isArrowFunction(second) || import_typescript5.default.isFunctionExpression(second))
|
|
2009
|
+
return;
|
|
2010
|
+
const first = unwrap(call.arguments[0]);
|
|
2011
|
+
if ((import_typescript5.default.isStringLiteral(first) || import_typescript5.default.isNoSubstitutionTemplateLiteral(first)) && !MODEL_HOST.test(first.text) && !MODEL_PATH.test(first.text))
|
|
2012
|
+
return;
|
|
2013
|
+
const urls = ctx.urlTexts(call.arguments[0]);
|
|
2014
|
+
const initArg = call.arguments[1];
|
|
2015
|
+
const init = objectLiteralOf(initArg, ctx.checker);
|
|
2016
|
+
const url = urls.find((candidate) => !NON_MODEL_PATH.test(candidate) && (MODEL_HOST.test(candidate) || MODEL_PATH.test(candidate) && (/^https?:\/\//.test(candidate) || bodyHasModel(init, ctx.checker))));
|
|
2017
|
+
if (!url)
|
|
2018
|
+
return;
|
|
2019
|
+
const roles = [];
|
|
2020
|
+
if (init) {
|
|
2021
|
+
const body = propertyValue(init, "body");
|
|
2022
|
+
let payload = body ? unwrap(body) : undefined;
|
|
2023
|
+
if (payload && import_typescript5.default.isCallExpression(payload) && calleeChain(payload.expression)?.join(".") === "JSON.stringify")
|
|
2024
|
+
payload = payload.arguments[0];
|
|
2025
|
+
if (payload)
|
|
2026
|
+
roles.push(...requestRoles(payload, REQUEST_KEYS, ctx));
|
|
2027
|
+
} else {
|
|
2028
|
+
for (const [key, role] of Object.entries(OPAQUE_BODY_KEYS))
|
|
2029
|
+
roles.push({ role, node: initArg, key: `body.${key}` });
|
|
2030
|
+
}
|
|
2031
|
+
const modelInUrl = urlModel(call.arguments[0], ctx.checker);
|
|
2032
|
+
if (modelInUrl && !roles.some((role) => role.role === "model"))
|
|
2033
|
+
roles.unshift({ role: "model", node: modelInUrl });
|
|
2034
|
+
if (modelInUrl) {
|
|
2035
|
+
const index = roles.findIndex((role) => role.role === "model" && role.key?.startsWith("body."));
|
|
2036
|
+
if (index >= 0)
|
|
2037
|
+
roles[index] = { role: "model", node: modelInUrl };
|
|
2038
|
+
}
|
|
2039
|
+
return {
|
|
2040
|
+
api: "fetch",
|
|
2041
|
+
provider: /anthropic/.test(url) ? "anthropic" : /openrouter/.test(url) ? "openrouter" : /openai/.test(url) ? "openai" : /generativelanguage/.test(url) ? "google" : undefined,
|
|
2042
|
+
roles
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
var AGENT_ENTRY_METHODS = new Set(["run", "chat", "saveMessages", "sendMessage", "submitMessage", "prompt"]);
|
|
2047
|
+
var AGENT_BASES = new Set(["Think", "Agent", "AIChatAgent"]);
|
|
2048
|
+
var ENTRY_FIELDS = ["message", "context", "brief"];
|
|
2049
|
+
var STUB_GETTERS = new Set(["get", "getByName", "getAgentByName", "getServerByName", "routeAgentRequest", "getStub"]);
|
|
2050
|
+
function classOfDeclaration(declaration) {
|
|
2051
|
+
if (!declaration)
|
|
2052
|
+
return;
|
|
2053
|
+
if (import_typescript5.default.isClassDeclaration(declaration) || import_typescript5.default.isClassExpression(declaration))
|
|
2054
|
+
return declaration;
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
function classesInType(type, checker, out = []) {
|
|
2058
|
+
if (!type || out.length > 4)
|
|
2059
|
+
return out;
|
|
2060
|
+
if (import_typescript5.default.isTypeReferenceNode(type)) {
|
|
2061
|
+
const name = import_typescript5.default.isQualifiedName(type.typeName) ? type.typeName.right : type.typeName;
|
|
2062
|
+
const cls = classOfDeclaration(valueDeclaration(resolvedSymbol(name, checker)));
|
|
2063
|
+
if (cls)
|
|
2064
|
+
out.push(cls);
|
|
2065
|
+
for (const argument of type.typeArguments ?? [])
|
|
2066
|
+
classesInType(argument, checker, out);
|
|
2067
|
+
} else if (import_typescript5.default.isUnionTypeNode(type) || import_typescript5.default.isIntersectionTypeNode(type)) {
|
|
2068
|
+
for (const member of type.types)
|
|
2069
|
+
classesInType(member, checker, out);
|
|
2070
|
+
}
|
|
2071
|
+
return out;
|
|
2072
|
+
}
|
|
2073
|
+
function receiverClasses(expression, checker, depth = 0) {
|
|
2074
|
+
const expr = unwrap(expression);
|
|
2075
|
+
if (depth > 4)
|
|
2076
|
+
return [];
|
|
2077
|
+
if (expr.kind === import_typescript5.default.SyntaxKind.ThisKeyword) {
|
|
2078
|
+
for (let current = expr.parent;current; current = current.parent) {
|
|
2079
|
+
if (import_typescript5.default.isClassDeclaration(current) || import_typescript5.default.isClassExpression(current))
|
|
2080
|
+
return [current];
|
|
2081
|
+
}
|
|
2082
|
+
return [];
|
|
2083
|
+
}
|
|
2084
|
+
if (import_typescript5.default.isNewExpression(expr)) {
|
|
2085
|
+
const cls = classOfDeclaration(valueDeclaration(resolvedSymbol(import_typescript5.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name : expr.expression, checker)));
|
|
2086
|
+
return cls ? [cls] : [];
|
|
2087
|
+
}
|
|
2088
|
+
if (import_typescript5.default.isCallExpression(expr)) {
|
|
2089
|
+
const callee = unwrap(expr.expression);
|
|
2090
|
+
const name = import_typescript5.default.isPropertyAccessExpression(callee) ? callee.name.text : import_typescript5.default.isIdentifier(callee) ? callee.text : "";
|
|
2091
|
+
if (!STUB_GETTERS.has(name))
|
|
2092
|
+
return [];
|
|
2093
|
+
const fromTypeArgs = (expr.typeArguments ?? []).flatMap((argument) => classesInType(argument, checker));
|
|
2094
|
+
if (fromTypeArgs.length > 0)
|
|
2095
|
+
return fromTypeArgs;
|
|
2096
|
+
const namespace = import_typescript5.default.isPropertyAccessExpression(callee) && name !== "getAgentByName" && name !== "getServerByName" ? callee.expression : expr.arguments[0];
|
|
2097
|
+
return namespace ? receiverClasses(namespace, checker, depth + 1) : [];
|
|
2098
|
+
}
|
|
2099
|
+
const nameNode = import_typescript5.default.isPropertyAccessExpression(expr) ? expr.name : import_typescript5.default.isIdentifier(expr) ? expr : undefined;
|
|
2100
|
+
if (!nameNode)
|
|
2101
|
+
return [];
|
|
2102
|
+
const declaration = valueDeclaration(resolvedSymbol(nameNode, checker));
|
|
2103
|
+
if (!declaration)
|
|
2104
|
+
return [];
|
|
2105
|
+
if (import_typescript5.default.isVariableDeclaration(declaration) || import_typescript5.default.isParameter(declaration) || import_typescript5.default.isPropertyDeclaration(declaration) || import_typescript5.default.isPropertySignature(declaration)) {
|
|
2106
|
+
const declared = classesInType(declaration.type, checker);
|
|
2107
|
+
if (declared.length > 0)
|
|
2108
|
+
return declared;
|
|
2109
|
+
if ("initializer" in declaration && declaration.initializer)
|
|
2110
|
+
return receiverClasses(declaration.initializer, checker, depth + 1);
|
|
2111
|
+
}
|
|
2112
|
+
return [];
|
|
2113
|
+
}
|
|
2114
|
+
function firstParamType(declaration) {
|
|
2115
|
+
if (!declaration)
|
|
2116
|
+
return;
|
|
2117
|
+
let parameters;
|
|
2118
|
+
if (import_typescript5.default.isMethodSignature(declaration) || import_typescript5.default.isMethodDeclaration(declaration))
|
|
2119
|
+
parameters = declaration.parameters;
|
|
2120
|
+
else if ((import_typescript5.default.isPropertySignature(declaration) || import_typescript5.default.isPropertyDeclaration(declaration)) && declaration.type && import_typescript5.default.isFunctionTypeNode(declaration.type))
|
|
2121
|
+
parameters = declaration.type.parameters;
|
|
2122
|
+
const type = parameters?.[0]?.type;
|
|
2123
|
+
return type && import_typescript5.default.isTypeReferenceNode(type) ? type.typeName.getText() : undefined;
|
|
2124
|
+
}
|
|
2125
|
+
function structuralAgent(receiver, method, ctx) {
|
|
2126
|
+
let declaration;
|
|
2127
|
+
try {
|
|
2128
|
+
declaration = ctx.checker.getTypeAtLocation(receiver).getProperty(method)?.declarations?.[0];
|
|
2129
|
+
} catch {
|
|
2130
|
+
return;
|
|
2131
|
+
}
|
|
2132
|
+
if (!declaration)
|
|
2133
|
+
return;
|
|
2134
|
+
const owner = declaration.parent;
|
|
2135
|
+
if (owner && (import_typescript5.default.isClassDeclaration(owner) || import_typescript5.default.isClassExpression(owner))) {
|
|
2136
|
+
const base = ctx.frameworkBase(owner).base;
|
|
2137
|
+
return base && AGENT_BASES.has(base) ? owner : undefined;
|
|
2138
|
+
}
|
|
2139
|
+
const wanted = firstParamType(declaration);
|
|
2140
|
+
if (!wanted)
|
|
2141
|
+
return;
|
|
2142
|
+
return ctx.agentClasses().find((cls) => cls.members.some((member) => import_typescript5.default.isMethodDeclaration(member) && propertyNameText(member.name) === method && firstParamType(member) === wanted));
|
|
2143
|
+
}
|
|
2144
|
+
var agentEntrySink = {
|
|
2145
|
+
id: "agent-entry",
|
|
2146
|
+
sdk: "agent-entry",
|
|
2147
|
+
match(call, ctx) {
|
|
2148
|
+
if (!import_typescript5.default.isCallExpression(call) || call.arguments.length === 0)
|
|
2149
|
+
return;
|
|
2150
|
+
const callee = unwrap(call.expression);
|
|
2151
|
+
if (!import_typescript5.default.isPropertyAccessExpression(callee) || !AGENT_ENTRY_METHODS.has(callee.name.text))
|
|
2152
|
+
return;
|
|
2153
|
+
const method = callee.name.text;
|
|
2154
|
+
const cls = receiverClasses(callee.expression, ctx.checker).find((candidate) => {
|
|
2155
|
+
const base = ctx.frameworkBase(candidate).base;
|
|
2156
|
+
return base !== undefined && AGENT_BASES.has(base);
|
|
2157
|
+
});
|
|
2158
|
+
const target = cls ?? structuralAgent(callee.expression, method, ctx);
|
|
2159
|
+
if (!target)
|
|
2160
|
+
return;
|
|
2161
|
+
const argument = call.arguments[0];
|
|
2162
|
+
if (import_typescript5.default.isSpreadElement(argument))
|
|
2163
|
+
return;
|
|
2164
|
+
const roles = [];
|
|
2165
|
+
if (method === "saveMessages") {
|
|
2166
|
+
roles.push({ role: "messages", node: argument });
|
|
2167
|
+
} else {
|
|
2168
|
+
const object = objectLiteralOf(argument, ctx.checker);
|
|
2169
|
+
const fields = object ? ENTRY_FIELDS.filter((field) => propertyValue(object, field)) : [];
|
|
2170
|
+
if (object && unwrap(argument) === object && fields.length > 0) {
|
|
2171
|
+
for (const field of fields)
|
|
2172
|
+
roles.push({ role: "user", node: propertyValue(object, field) });
|
|
2173
|
+
} else {
|
|
2174
|
+
roles.push({ role: "user", node: argument });
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
return { api: `${className(target) ?? "agent"}.${method}`, roles };
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
var CHAT_HOOK_MODULE = /^(?:@ai-sdk\/(?:react|svelte|vue|angular|solid)|ai\/(?:react|svelte|vue)|agents\/(?:ai-)?react|@cloudflare\/(?:think|ai-chat|agents)\/react)$/;
|
|
2181
|
+
var CHAT_HOOKS = new Set(["useChat", "useAgentChat", "Chat", "useCompletion"]);
|
|
2182
|
+
var CHAT_SEND = new Set(["sendMessage", "append", "submitMessage", "complete"]);
|
|
2183
|
+
function fromChatHook(expression, checker, depth = 0) {
|
|
2184
|
+
if (!expression || depth > 3)
|
|
2185
|
+
return false;
|
|
2186
|
+
const expr = unwrap(expression);
|
|
2187
|
+
if (import_typescript5.default.isCallExpression(expr) || import_typescript5.default.isNewExpression(expr)) {
|
|
2188
|
+
const root = rootIdentifier(expr.expression);
|
|
2189
|
+
const origin = root ? importOrigin(root, checker) : undefined;
|
|
2190
|
+
return Boolean(origin && CHAT_HOOK_MODULE.test(origin.module) && CHAT_HOOKS.has(origin.imported === "*" || origin.imported === "default" ? import_typescript5.default.isPropertyAccessExpression(expr.expression) ? expr.expression.name.text : "" : origin.imported));
|
|
2191
|
+
}
|
|
2192
|
+
const nameNode = import_typescript5.default.isIdentifier(expr) ? expr : import_typescript5.default.isPropertyAccessExpression(expr) ? expr.name : undefined;
|
|
2193
|
+
const declaration = nameNode ? valueDeclaration(resolvedSymbol(nameNode, checker)) : undefined;
|
|
2194
|
+
if (!declaration)
|
|
2195
|
+
return false;
|
|
2196
|
+
if (import_typescript5.default.isBindingElement(declaration)) {
|
|
2197
|
+
const holder = declaration.parent.parent;
|
|
2198
|
+
return import_typescript5.default.isVariableDeclaration(holder) && fromChatHook(holder.initializer, checker, depth + 1);
|
|
2199
|
+
}
|
|
2200
|
+
if (import_typescript5.default.isVariableDeclaration(declaration))
|
|
2201
|
+
return fromChatHook(declaration.initializer, checker, depth + 1);
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
function looksLikeUiMessage(argument) {
|
|
2205
|
+
const object = unwrap(argument);
|
|
2206
|
+
if (!import_typescript5.default.isObjectLiteralExpression(object))
|
|
2207
|
+
return false;
|
|
2208
|
+
const parts = propertyValue(object, "parts");
|
|
2209
|
+
if (parts) {
|
|
2210
|
+
const array = unwrap(parts);
|
|
2211
|
+
return import_typescript5.default.isArrayLiteralExpression(array) && array.elements.some((element) => {
|
|
2212
|
+
const part = unwrap(element);
|
|
2213
|
+
if (!import_typescript5.default.isObjectLiteralExpression(part))
|
|
2214
|
+
return false;
|
|
2215
|
+
const type = propertyValue(part, "type");
|
|
2216
|
+
return Boolean(type && import_typescript5.default.isStringLiteralLike(unwrap(type)) && unwrap(type).text === "text");
|
|
2217
|
+
});
|
|
2218
|
+
}
|
|
2219
|
+
if (propertyValue(object, "text") && object.properties.length <= 3)
|
|
2220
|
+
return true;
|
|
2221
|
+
const role = propertyValue(object, "role");
|
|
2222
|
+
return Boolean(role && import_typescript5.default.isStringLiteralLike(unwrap(role)) && unwrap(role).text === "user" && (propertyValue(object, "content") || propertyValue(object, "parts")));
|
|
2223
|
+
}
|
|
2224
|
+
var clientChatSink = {
|
|
2225
|
+
id: "client-chat",
|
|
2226
|
+
sdk: "client-chat",
|
|
2227
|
+
match(call, ctx) {
|
|
2228
|
+
if (!import_typescript5.default.isCallExpression(call) || call.arguments.length === 0)
|
|
2229
|
+
return;
|
|
2230
|
+
const callee = unwrap(call.expression);
|
|
2231
|
+
const name = import_typescript5.default.isIdentifier(callee) ? callee.text : import_typescript5.default.isPropertyAccessExpression(callee) ? callee.name.text : undefined;
|
|
2232
|
+
if (!name || !CHAT_SEND.has(name))
|
|
2233
|
+
return;
|
|
2234
|
+
const argument = call.arguments[0];
|
|
2235
|
+
if (import_typescript5.default.isSpreadElement(argument))
|
|
2236
|
+
return;
|
|
2237
|
+
const hooked = import_typescript5.default.isIdentifier(callee) ? fromChatHook(callee, ctx.checker) : fromChatHook(callee.expression, ctx.checker);
|
|
2238
|
+
if (!hooked && !((name === "sendMessage" || name === "append") && looksLikeUiMessage(argument)))
|
|
2239
|
+
return;
|
|
2240
|
+
return { api: `chat.${name}`, roles: [{ role: "user", node: argument }] };
|
|
2241
|
+
}
|
|
2242
|
+
};
|
|
2243
|
+
function frameworkName(identifier, checker, member) {
|
|
2244
|
+
if (!identifier)
|
|
2245
|
+
return;
|
|
2246
|
+
const origin = importOrigin(identifier, checker);
|
|
2247
|
+
if (origin) {
|
|
2248
|
+
const name = origin.imported === "*" || origin.imported === "default" ? member ?? identifier.text : origin.imported;
|
|
2249
|
+
return FRAMEWORK_MODULE.test(origin.module) && FRAMEWORK_BASES.has(name) ? { base: name, module: origin.module } : undefined;
|
|
2250
|
+
}
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
2253
|
+
function frameworkBaseOf(cls, checker, memo, depth = 0) {
|
|
2254
|
+
const cached = memo.get(cls);
|
|
2255
|
+
if (cached)
|
|
2256
|
+
return cached;
|
|
2257
|
+
const self = className(cls) ?? "(anonymous)";
|
|
2258
|
+
const result = { chain: [self] };
|
|
2259
|
+
memo.set(cls, result);
|
|
2260
|
+
const heritage = cls.heritageClauses?.find((clause) => clause.token === import_typescript5.default.SyntaxKind.ExtendsKeyword)?.types[0];
|
|
2261
|
+
if (!heritage || depth > 8)
|
|
2262
|
+
return result;
|
|
2263
|
+
const resolveExpression = (expression) => {
|
|
2264
|
+
const expr = unwrap(expression);
|
|
2265
|
+
if (import_typescript5.default.isCallExpression(expr)) {
|
|
2266
|
+
for (const argument of expr.arguments) {
|
|
2267
|
+
const found = resolveExpression(argument);
|
|
2268
|
+
if (found?.base)
|
|
2269
|
+
return found;
|
|
2270
|
+
}
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
const identifier = import_typescript5.default.isIdentifier(expr) ? expr : import_typescript5.default.isPropertyAccessExpression(expr) ? rootIdentifier(expr) : undefined;
|
|
2274
|
+
const member = import_typescript5.default.isPropertyAccessExpression(expr) ? expr.name.text : undefined;
|
|
2275
|
+
const direct = frameworkName(identifier, checker, member);
|
|
2276
|
+
if (direct)
|
|
2277
|
+
return { ...direct, chain: [direct.base] };
|
|
2278
|
+
const declaration = valueDeclaration(resolvedSymbol(import_typescript5.default.isPropertyAccessExpression(expr) ? expr.name : expr, checker));
|
|
2279
|
+
if (!declaration)
|
|
2280
|
+
return;
|
|
2281
|
+
if (import_typescript5.default.isClassDeclaration(declaration) || import_typescript5.default.isClassExpression(declaration))
|
|
2282
|
+
return frameworkBaseOf(declaration, checker, memo, depth + 1);
|
|
2283
|
+
const holder = import_typescript5.default.isBindingElement(declaration) ? declaration.parent.parent : declaration;
|
|
2284
|
+
const name = import_typescript5.default.isBindingElement(declaration) ? propertyNameText(declaration.propertyName ?? declaration.name) : undefined;
|
|
2285
|
+
if (import_typescript5.default.isVariableDeclaration(holder) && holder.initializer) {
|
|
2286
|
+
const init = unwrap(holder.initializer);
|
|
2287
|
+
if (import_typescript5.default.isClassExpression(init))
|
|
2288
|
+
return frameworkBaseOf(init, checker, memo, depth + 1);
|
|
2289
|
+
if (import_typescript5.default.isCallExpression(init)) {
|
|
2290
|
+
for (const argument of init.arguments) {
|
|
2291
|
+
const arg = unwrap(argument);
|
|
2292
|
+
if (!import_typescript5.default.isIdentifier(arg))
|
|
2293
|
+
continue;
|
|
2294
|
+
const found = frameworkName(arg, checker, name);
|
|
2295
|
+
if (found)
|
|
2296
|
+
return { ...found, chain: [found.base] };
|
|
2297
|
+
const nested = resolveExpression(arg);
|
|
2298
|
+
if (nested?.base)
|
|
2299
|
+
return nested;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
if (import_typescript5.default.isIdentifier(init) || import_typescript5.default.isPropertyAccessExpression(init))
|
|
2303
|
+
return resolveExpression(init);
|
|
2304
|
+
}
|
|
2305
|
+
return;
|
|
2306
|
+
};
|
|
2307
|
+
const parent = resolveExpression(heritage.expression);
|
|
2308
|
+
if (parent) {
|
|
2309
|
+
result.base = parent.base;
|
|
2310
|
+
result.module = parent.module;
|
|
2311
|
+
result.chain = [self, ...parent.chain];
|
|
2312
|
+
} else {
|
|
2313
|
+
result.chain = [self, heritage.expression.getText()];
|
|
2314
|
+
}
|
|
2315
|
+
return result;
|
|
2316
|
+
}
|
|
2317
|
+
function hookSink(memo) {
|
|
2318
|
+
return {
|
|
2319
|
+
id: "think-hook",
|
|
2320
|
+
sdk: "think-hook",
|
|
2321
|
+
match(cls, ctx) {
|
|
2322
|
+
const info = frameworkBaseOf(cls, ctx.checker, memo);
|
|
2323
|
+
if (!info.base || !HOOK_BASES.has(info.base))
|
|
2324
|
+
return [];
|
|
2325
|
+
const roles = [];
|
|
2326
|
+
for (const member of cls.members) {
|
|
2327
|
+
const name = propertyNameText(member.name);
|
|
2328
|
+
if (!name)
|
|
2329
|
+
continue;
|
|
2330
|
+
if ((import_typescript5.default.isMethodDeclaration(member) || import_typescript5.default.isGetAccessorDeclaration(member)) && HOOK_METHODS[name] && member.body) {
|
|
2331
|
+
roles.push({ role: HOOK_METHODS[name], node: member, values: returnExpressions(member) });
|
|
2332
|
+
} else if (import_typescript5.default.isMethodDeclaration(member) && TURN_HOOKS.has(name) && member.body) {
|
|
2333
|
+
const returns = returnExpressions(member);
|
|
2334
|
+
for (const [key, role] of Object.entries(TURN_CONFIG_KEYS)) {
|
|
2335
|
+
if (returns.some((ret) => {
|
|
2336
|
+
const value = unwrap(ret);
|
|
2337
|
+
return import_typescript5.default.isObjectLiteralExpression(value) && hasProperty(value, key);
|
|
2338
|
+
})) {
|
|
2339
|
+
roles.push({ role, node: member, values: returns, key });
|
|
2340
|
+
}
|
|
2341
|
+
}
|
|
2342
|
+
} else if (import_typescript5.default.isPropertyDeclaration(member) && HOOK_PROPERTIES[name] && member.initializer && !member.modifiers?.some((m) => m.kind === import_typescript5.default.SyntaxKind.StaticKeyword)) {
|
|
2343
|
+
roles.push({ role: HOOK_PROPERTIES[name], node: member.initializer });
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
if (roles.length === 0)
|
|
2347
|
+
return [];
|
|
2348
|
+
return [{ api: `${info.base === "Think" ? "think" : "agents"}.hook`, roles, anchor: cls.name ?? cls }];
|
|
2349
|
+
}
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
function createFrameworkMemo() {
|
|
2353
|
+
return new Map;
|
|
2354
|
+
}
|
|
2355
|
+
var CALL_SINKS = [anthropicSink, openaiSink, aiSdkSink, workersAiSink, fetchSink, providerFactorySink, agentEntrySink, clientChatSink];
|
|
2356
|
+
function registerCallSink(recognizer) {
|
|
2357
|
+
CALL_SINKS.push(recognizer);
|
|
2358
|
+
}
|
|
2359
|
+
function classSinks(memo) {
|
|
2360
|
+
return [hookSink(memo), ...EXTRA_CLASS_SINKS];
|
|
2361
|
+
}
|
|
2362
|
+
var EXTRA_CLASS_SINKS = [];
|
|
2363
|
+
function registerClassSink(recognizer) {
|
|
2364
|
+
EXTRA_CLASS_SINKS.push(recognizer);
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
// src/harness-extract/types.ts
|
|
2368
|
+
var EXTRACT_SCHEMA_VERSION = 1;
|
|
2369
|
+
// src/harness-extract/enumerators/index.ts
|
|
2370
|
+
var ENUMERATORS = [];
|
|
2371
|
+
// src/harness-extract/tools.ts
|
|
2372
|
+
var PASS_THROUGH2 = new Set(["ref", "call", "param", "oneOf", "lookup"]);
|
|
2373
|
+
var DEFINITION_KEYS = new Set(["description", "input_schema", "inputSchema", "parameters", "schema", "execute", "type", "strict"]);
|
|
2374
|
+
function member(tree, key) {
|
|
2375
|
+
const members = tree.children ?? [];
|
|
2376
|
+
for (let index = members.length - 1;index >= 0; index -= 1)
|
|
2377
|
+
if (members[index].key === key)
|
|
2378
|
+
return members[index];
|
|
2379
|
+
return;
|
|
2380
|
+
}
|
|
2381
|
+
function singleLiteral2(tree) {
|
|
2382
|
+
if (!tree)
|
|
2383
|
+
return;
|
|
2384
|
+
if (tree.kind === "literal")
|
|
2385
|
+
return tree.text;
|
|
2386
|
+
if (PASS_THROUGH2.has(tree.kind)) {
|
|
2387
|
+
const flow = valueChildren(tree);
|
|
2388
|
+
if (flow.length === 1)
|
|
2389
|
+
return singleLiteral2(flow[0]);
|
|
2390
|
+
}
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
function objectsOf(tree) {
|
|
2394
|
+
if (tree.kind === "object")
|
|
2395
|
+
return [tree];
|
|
2396
|
+
if (PASS_THROUGH2.has(tree.kind))
|
|
2397
|
+
return valueChildren(tree).flatMap(objectsOf);
|
|
2398
|
+
return [];
|
|
2399
|
+
}
|
|
2400
|
+
function definitionName(tree) {
|
|
2401
|
+
const fn = member(tree, "function");
|
|
2402
|
+
const fnObject = fn ? objectsOf(fn)[0] : undefined;
|
|
2403
|
+
const fnName = fnObject ? singleLiteral2(member(fnObject, "name")) : undefined;
|
|
2404
|
+
if (fnName && fnObject)
|
|
2405
|
+
return { name: fnName, path: fnObject.path, line: fnObject.line, via: "function.name" };
|
|
2406
|
+
const nameNode = member(tree, "name");
|
|
2407
|
+
const name = singleLiteral2(nameNode);
|
|
2408
|
+
const keys = (tree.children ?? []).map((child) => child.key ?? "");
|
|
2409
|
+
if (name && nameNode && keys.some((key) => DEFINITION_KEYS.has(key)))
|
|
2410
|
+
return { name, path: nameNode.path, line: nameNode.line, via: "name" };
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
function toolNamesOf(tree) {
|
|
2414
|
+
const out = { names: [], unresolved: [] };
|
|
2415
|
+
const visit = (node, inArray) => {
|
|
2416
|
+
if (node.kind === "array") {
|
|
2417
|
+
for (const child of node.children ?? [])
|
|
2418
|
+
visit(child, true);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
if (node.kind === "object") {
|
|
2422
|
+
const definition = definitionName(node);
|
|
2423
|
+
if (definition) {
|
|
2424
|
+
out.names.push(definition);
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
if (inArray) {
|
|
2428
|
+
out.unresolved.push({ ...node, note: "tool object without a literal name" });
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
for (const child of node.children ?? []) {
|
|
2432
|
+
if (child.key === "...")
|
|
2433
|
+
visit(child, false);
|
|
2434
|
+
else if (child.key)
|
|
2435
|
+
out.names.push({ name: child.key, path: child.path, line: child.line, via: "key" });
|
|
2436
|
+
}
|
|
2437
|
+
return;
|
|
2438
|
+
}
|
|
2439
|
+
if (PASS_THROUGH2.has(node.kind) && valueChildren(node).length > 0) {
|
|
2440
|
+
for (const child of valueChildren(node))
|
|
2441
|
+
visit(child, inArray);
|
|
2442
|
+
return;
|
|
2443
|
+
}
|
|
2444
|
+
out.unresolved.push(node);
|
|
2445
|
+
};
|
|
2446
|
+
visit(tree, false);
|
|
2447
|
+
return out;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
// src/harness-extract/index.ts
|
|
2451
|
+
var PROMPT_ROLES = new Set(["system", "messages", "prompt", "instructions"]);
|
|
2452
|
+
var MAX_HELPER_CALLERS = 200;
|
|
2453
|
+
var MAX_DERIVED = 5000;
|
|
2454
|
+
var MAX_CALLER_CHAIN = 3;
|
|
2455
|
+
var cache = new Map;
|
|
2456
|
+
function clearExtractCache() {
|
|
2457
|
+
cache.clear();
|
|
2458
|
+
}
|
|
2459
|
+
function extractHarness(rootDir, options = {}) {
|
|
2460
|
+
return extractHarnessWithContext(rootDir, options).result;
|
|
2461
|
+
}
|
|
2462
|
+
function extractHarnessWithContext(rootDir, options = {}) {
|
|
2463
|
+
const root = resolve2(rootDir);
|
|
2464
|
+
const { fresh, ...rest } = options;
|
|
2465
|
+
const key = `${root}\x00${JSON.stringify(rest)}`;
|
|
2466
|
+
const cached = fresh ? undefined : cache.get(key);
|
|
2467
|
+
if (cached)
|
|
2468
|
+
return cached;
|
|
2469
|
+
const output = runExtract(root, options);
|
|
2470
|
+
cache.set(key, output);
|
|
2471
|
+
return output;
|
|
2472
|
+
}
|
|
2473
|
+
function argRef(rootDir, node, key) {
|
|
2474
|
+
const source = node.getSourceFile();
|
|
2475
|
+
const ref = { path: relPath(rootDir, source.fileName), start: node.getStart(source), end: node.getEnd(), line: lineOf(node) };
|
|
2476
|
+
if (key !== undefined)
|
|
2477
|
+
ref.key = key;
|
|
2478
|
+
Object.defineProperty(ref, "node", { value: node, enumerable: false });
|
|
2479
|
+
return ref;
|
|
2480
|
+
}
|
|
2481
|
+
function namedEnclosingFunction(node) {
|
|
2482
|
+
for (let fn = enclosingFunction(node);fn; fn = enclosingFunction(fn)) {
|
|
2483
|
+
const name = functionName(fn);
|
|
2484
|
+
if (name)
|
|
2485
|
+
return { fn, name };
|
|
2486
|
+
}
|
|
2487
|
+
return;
|
|
2488
|
+
}
|
|
2489
|
+
function qualifiedName(fn, name) {
|
|
2490
|
+
const cls = enclosingClass(fn);
|
|
2491
|
+
const owner = cls && (fn.parent === cls || fn.parent && fn.parent.parent === cls) ? className(cls) : undefined;
|
|
2492
|
+
return owner ? `${owner}.${name}` : name;
|
|
2493
|
+
}
|
|
2494
|
+
function functionScope(rootDir, fn, name) {
|
|
2495
|
+
return `${relPath(rootDir, fn.getSourceFile().fileName)}#${qualifiedName(fn, name)}`;
|
|
2496
|
+
}
|
|
2497
|
+
function scopeOf(rootDir, node) {
|
|
2498
|
+
const named = namedEnclosingFunction(node);
|
|
2499
|
+
if (named)
|
|
2500
|
+
return functionScope(rootDir, named.fn, named.name);
|
|
2501
|
+
const path = relPath(rootDir, node.getSourceFile().fileName);
|
|
2502
|
+
let outermost;
|
|
2503
|
+
for (let fn = enclosingFunction(node);fn; fn = enclosingFunction(fn))
|
|
2504
|
+
outermost = fn;
|
|
2505
|
+
return outermost ? `${path}#L${lineOf(outermost)}` : path;
|
|
2506
|
+
}
|
|
2507
|
+
function callerChain(rootDir, anchor, calls, memo) {
|
|
2508
|
+
const start = namedEnclosingFunction(anchor);
|
|
2509
|
+
if (!start)
|
|
2510
|
+
return { callers: [], callerScopes: [] };
|
|
2511
|
+
const cached = memo.get(start.fn);
|
|
2512
|
+
if (cached)
|
|
2513
|
+
return cached;
|
|
2514
|
+
const chain = { callers: [], callerScopes: [] };
|
|
2515
|
+
const seen = new Set;
|
|
2516
|
+
let current = start;
|
|
2517
|
+
while (current && !seen.has(current.fn) && chain.callers.length <= MAX_CALLER_CHAIN) {
|
|
2518
|
+
seen.add(current.fn);
|
|
2519
|
+
chain.callers.unshift(qualifiedName(current.fn, current.name));
|
|
2520
|
+
chain.callerScopes.unshift(functionScope(rootDir, current.fn, current.name));
|
|
2521
|
+
const caller = calls.callersOf(current.fn, current.name, 1)[0];
|
|
2522
|
+
current = caller ? namedEnclosingFunction(caller) : undefined;
|
|
2523
|
+
}
|
|
2524
|
+
memo.set(start.fn, chain);
|
|
2525
|
+
return chain;
|
|
2526
|
+
}
|
|
2527
|
+
var AGENT_CLASS_BASES = new Set(["Think", "Agent", "AIChatAgent"]);
|
|
2528
|
+
function findAgentClasses(program, checker, memo) {
|
|
2529
|
+
const out = [];
|
|
2530
|
+
for (const source of program.getSourceFiles()) {
|
|
2531
|
+
if (source.isDeclarationFile || /[\\/]node_modules[\\/]/.test(source.fileName))
|
|
2532
|
+
continue;
|
|
2533
|
+
const visit = (node) => {
|
|
2534
|
+
if ((import_typescript6.default.isClassDeclaration(node) || import_typescript6.default.isClassExpression(node)) && node.heritageClauses) {
|
|
2535
|
+
const base = frameworkBaseOf(node, checker, memo).base;
|
|
2536
|
+
if (base && AGENT_CLASS_BASES.has(base))
|
|
2537
|
+
out.push(node);
|
|
2538
|
+
}
|
|
2539
|
+
import_typescript6.default.forEachChild(node, visit);
|
|
2540
|
+
};
|
|
2541
|
+
visit(source);
|
|
2542
|
+
}
|
|
2543
|
+
return out;
|
|
2544
|
+
}
|
|
2545
|
+
function describeEnclosing(rootDir, anchor, checker, memo, ownClass) {
|
|
2546
|
+
const fn = ownClass ? undefined : namedEnclosingFunction(anchor);
|
|
2547
|
+
const cls = ownClass ?? enclosingClass(anchor);
|
|
2548
|
+
let enclosingCls;
|
|
2549
|
+
if (cls) {
|
|
2550
|
+
const info = frameworkBaseOf(cls, checker, memo);
|
|
2551
|
+
const at = cls.name ?? cls;
|
|
2552
|
+
enclosingCls = { name: className(cls) ?? "(anonymous)", path: relPath(rootDir, cls.getSourceFile().fileName), line: lineOf(at), extendsChain: info.chain };
|
|
2553
|
+
if (info.base)
|
|
2554
|
+
enclosingCls.base = info.base;
|
|
2555
|
+
if (info.module)
|
|
2556
|
+
enclosingCls.baseModule = info.module;
|
|
2557
|
+
}
|
|
2558
|
+
const parts = [enclosingCls?.name, fn?.name].filter((part) => Boolean(part));
|
|
2559
|
+
return {
|
|
2560
|
+
enclosing: parts.length > 0 ? parts.join(".") : undefined,
|
|
2561
|
+
enclosingClass: enclosingCls,
|
|
2562
|
+
enclosingFunction: fn?.name
|
|
2563
|
+
};
|
|
2564
|
+
}
|
|
2565
|
+
function siteFields(sources, rootDir) {
|
|
2566
|
+
const out = { promptArgs: [] };
|
|
2567
|
+
for (const source of sources) {
|
|
2568
|
+
const ref = argRef(rootDir, source.arg.node, source.arg.key);
|
|
2569
|
+
if (source.role === "model")
|
|
2570
|
+
out.modelArg ??= ref;
|
|
2571
|
+
else if (source.role === "tools")
|
|
2572
|
+
out.toolsArg ??= ref;
|
|
2573
|
+
else
|
|
2574
|
+
out.promptArgs.push({ role: source.role, arg: ref });
|
|
2575
|
+
}
|
|
2576
|
+
if (!out.modelArg)
|
|
2577
|
+
delete out.modelArg;
|
|
2578
|
+
if (!out.toolsArg)
|
|
2579
|
+
delete out.toolsArg;
|
|
2580
|
+
return out;
|
|
2581
|
+
}
|
|
2582
|
+
function paramFlow(node, fn, checker, hops = 0) {
|
|
2583
|
+
if (!import_typescript6.default.isExpression(node) || hops > 2)
|
|
2584
|
+
return;
|
|
2585
|
+
const expr = unwrap(node);
|
|
2586
|
+
if (import_typescript6.default.isBinaryExpression(expr) && (expr.operatorToken.kind === import_typescript6.default.SyntaxKind.QuestionQuestionToken || expr.operatorToken.kind === import_typescript6.default.SyntaxKind.BarBarToken)) {
|
|
2587
|
+
return paramFlow(expr.left, fn, checker, hops);
|
|
2588
|
+
}
|
|
2589
|
+
if (import_typescript6.default.isPropertyAccessExpression(expr) && import_typescript6.default.isIdentifier(unwrap(expr.expression))) {
|
|
2590
|
+
const inner = paramFlow(expr.expression, fn, checker, hops);
|
|
2591
|
+
return inner && inner.key === undefined ? { param: inner.param, key: expr.name.text } : undefined;
|
|
2592
|
+
}
|
|
2593
|
+
if (!import_typescript6.default.isIdentifier(expr))
|
|
2594
|
+
return;
|
|
2595
|
+
const declaration = valueDeclaration(resolvedSymbol(expr, checker));
|
|
2596
|
+
if (!declaration)
|
|
2597
|
+
return;
|
|
2598
|
+
if (import_typescript6.default.isParameter(declaration) && declaration.parent === fn && !declaration.dotDotDotToken)
|
|
2599
|
+
return { param: declaration };
|
|
2600
|
+
if (import_typescript6.default.isBindingElement(declaration) && import_typescript6.default.isObjectBindingPattern(declaration.parent) && import_typescript6.default.isParameter(declaration.parent.parent) && declaration.parent.parent.parent === fn && !declaration.dotDotDotToken) {
|
|
2601
|
+
const key = propertyNameText(declaration.propertyName ?? declaration.name);
|
|
2602
|
+
return key ? { param: declaration.parent.parent, key } : undefined;
|
|
2603
|
+
}
|
|
2604
|
+
if (import_typescript6.default.isVariableDeclaration(declaration) && declaration.initializer && enclosingFunction(declaration) === fn && declaration.parent.flags & import_typescript6.default.NodeFlags.Const) {
|
|
2605
|
+
return paramFlow(declaration.initializer, fn, checker, hops + 1);
|
|
2606
|
+
}
|
|
2607
|
+
return;
|
|
2608
|
+
}
|
|
2609
|
+
function descendArg(argument, path) {
|
|
2610
|
+
let node = argument;
|
|
2611
|
+
let index = 0;
|
|
2612
|
+
for (;index < path.length; index += 1) {
|
|
2613
|
+
let value = unwrap(node);
|
|
2614
|
+
if (import_typescript6.default.isCallExpression(value) && value.expression.getText() === "JSON.stringify" && value.arguments[0])
|
|
2615
|
+
value = unwrap(value.arguments[0]);
|
|
2616
|
+
const next = import_typescript6.default.isObjectLiteralExpression(value) ? propertyValue(value, path[index]) : undefined;
|
|
2617
|
+
if (!next)
|
|
2618
|
+
break;
|
|
2619
|
+
node = next;
|
|
2620
|
+
}
|
|
2621
|
+
return index < path.length ? { node, key: path.slice(index).join(".") } : { node };
|
|
2622
|
+
}
|
|
2623
|
+
function extendBindings(bindings, caller) {
|
|
2624
|
+
if (bindings.length === 0)
|
|
2625
|
+
return caller;
|
|
2626
|
+
return bindings.map((binding) => ({ ...binding, outer: extendBindings(binding.outer ?? [], caller) }));
|
|
2627
|
+
}
|
|
2628
|
+
function runExtract(rootDir, options) {
|
|
2629
|
+
const started = Date.now();
|
|
2630
|
+
const timings = {};
|
|
2631
|
+
const warnings = [];
|
|
2632
|
+
const mark = (phase, since) => {
|
|
2633
|
+
const now = Date.now();
|
|
2634
|
+
timings[phase] = (timings[phase] ?? 0) + now - since;
|
|
2635
|
+
return now;
|
|
2636
|
+
};
|
|
2637
|
+
let repo;
|
|
2638
|
+
try {
|
|
2639
|
+
repo = buildPrograms(rootDir, options);
|
|
2640
|
+
warnings.push(...repo.warnings);
|
|
2641
|
+
} catch (error) {
|
|
2642
|
+
warnings.push(`programs: ${error.message}`);
|
|
2643
|
+
}
|
|
2644
|
+
let clock = mark("programs", started);
|
|
2645
|
+
const sites = [];
|
|
2646
|
+
const recognizerMs = {};
|
|
2647
|
+
const memo = createFrameworkMemo();
|
|
2648
|
+
const chainMemo = new Map;
|
|
2649
|
+
const wrapperSinks = {};
|
|
2650
|
+
const tracers = new Map;
|
|
2651
|
+
const toolsFor = (entry) => {
|
|
2652
|
+
let tools = tracers.get(entry);
|
|
2653
|
+
if (!tools) {
|
|
2654
|
+
const checker = entry.checker();
|
|
2655
|
+
const calls = new CallIndex(entry.program, checker);
|
|
2656
|
+
const modelArgOf = (call) => providerModelCall(call, checker)?.model;
|
|
2657
|
+
tools = { tracer: new ValueTracer(rootDir, checker, calls, options, modelArgOf), calls };
|
|
2658
|
+
tracers.set(entry, tools);
|
|
2659
|
+
}
|
|
2660
|
+
return tools;
|
|
2661
|
+
};
|
|
2662
|
+
for (const entry of repo?.entries ?? []) {
|
|
2663
|
+
try {
|
|
2664
|
+
const checker = entry.checker();
|
|
2665
|
+
const { calls } = toolsFor(entry);
|
|
2666
|
+
let agentClasses;
|
|
2667
|
+
const urlTracer = new ValueTracer(rootDir, checker, calls, { maxDepth: 6, maxNodes: 300, maxCallers: 2 });
|
|
2668
|
+
const ctx2 = { checker, urlTexts: (expression) => renderings(urlTracer.trace(expression)), frameworkBase: (cls) => frameworkBaseOf(cls, checker, memo), agentClasses: () => agentClasses ??= findAgentClasses(entry.program, checker, memo) };
|
|
2669
|
+
const classRecognizers = classSinks(memo);
|
|
2670
|
+
for (const file of entry.owned) {
|
|
2671
|
+
const source = entry.program.getSourceFile(file);
|
|
2672
|
+
if (!source)
|
|
2673
|
+
continue;
|
|
2674
|
+
const rel = relPath(rootDir, source.fileName);
|
|
2675
|
+
const add = (anchor, sdk, api, provider, roles2, ownClass) => {
|
|
2676
|
+
const sources = roles2.map((role) => ({ ...role, bindings: [], arg: { node: role.values?.length === 1 ? role.values[0] : role.node, key: role.key } }));
|
|
2677
|
+
const site = {
|
|
2678
|
+
id: `${rel}:${lineOf(anchor)}:${colOf(anchor)}`,
|
|
2679
|
+
path: rel,
|
|
2680
|
+
line: lineOf(anchor),
|
|
2681
|
+
col: colOf(anchor),
|
|
2682
|
+
language: "ts",
|
|
2683
|
+
callee: api,
|
|
2684
|
+
sdk,
|
|
2685
|
+
...provider ? { provider } : {},
|
|
2686
|
+
...siteFields(sources, rootDir),
|
|
2687
|
+
...describeEnclosing(rootDir, anchor, checker, memo, ownClass),
|
|
2688
|
+
...ownClass ? { scope: `${rel}#${className(ownClass) ?? `L${lineOf(ownClass)}`}`, callers: [className(ownClass) ?? "(anonymous)"], callerScopes: [`${rel}#${className(ownClass) ?? `L${lineOf(ownClass)}`}`] } : { scope: scopeOf(rootDir, anchor), ...callerChain(rootDir, anchor, calls, chainMemo) },
|
|
2689
|
+
isTest: isTestPath(rel),
|
|
2690
|
+
isEval: isEvalPath(rel)
|
|
2691
|
+
};
|
|
2692
|
+
sites.push({ site, entry, anchor, sources, level: 0 });
|
|
2693
|
+
};
|
|
2694
|
+
const visit = (node) => {
|
|
2695
|
+
if (import_typescript6.default.isCallExpression(node) || import_typescript6.default.isNewExpression(node)) {
|
|
2696
|
+
for (const recognizer of CALL_SINKS) {
|
|
2697
|
+
let match;
|
|
2698
|
+
const begin = performance.now();
|
|
2699
|
+
try {
|
|
2700
|
+
match = recognizer.match(node, ctx2);
|
|
2701
|
+
} catch (error) {
|
|
2702
|
+
warnings.push(`${rel}:${lineOf(node)} ${recognizer.id}: ${error.message}`);
|
|
2703
|
+
}
|
|
2704
|
+
recognizerMs[recognizer.id] = (recognizerMs[recognizer.id] ?? 0) + performance.now() - begin;
|
|
2705
|
+
if (match) {
|
|
2706
|
+
add(match.anchor ?? node, recognizer.sdk, match.api, match.provider, match.roles);
|
|
2707
|
+
break;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
} else if (import_typescript6.default.isClassDeclaration(node) || import_typescript6.default.isClassExpression(node)) {
|
|
2711
|
+
for (const recognizer of classRecognizers) {
|
|
2712
|
+
try {
|
|
2713
|
+
for (const match of recognizer.match(node, ctx2))
|
|
2714
|
+
add(match.anchor ?? node, recognizer.sdk, match.api, match.provider, match.roles, node);
|
|
2715
|
+
} catch (error) {
|
|
2716
|
+
warnings.push(`${rel}:${lineOf(node)} ${recognizer.id}: ${error.message}`);
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
import_typescript6.default.forEachChild(node, visit);
|
|
2721
|
+
};
|
|
2722
|
+
visit(source);
|
|
2723
|
+
}
|
|
2724
|
+
} catch (error) {
|
|
2725
|
+
warnings.push(`sinks ${entry.configPath ?? "(fallback)"}: ${error.message}`);
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
clock = mark("sinks", clock);
|
|
2729
|
+
for (const [id, ms] of Object.entries(recognizerMs))
|
|
2730
|
+
timings[`sinks.${id}`] = Math.round(ms);
|
|
2731
|
+
const seenIds = new Set(sites.map((entry) => entry.site.id));
|
|
2732
|
+
const rounds = options.helperDepth ?? 8;
|
|
2733
|
+
let frontier = sites.filter((entry) => entry.sources.every((source) => !source.values));
|
|
2734
|
+
let derivedCount = 0;
|
|
2735
|
+
for (let level = 1;level <= rounds && frontier.length > 0; level += 1) {
|
|
2736
|
+
const next = [];
|
|
2737
|
+
for (const inner of frontier) {
|
|
2738
|
+
if (derivedCount >= MAX_DERIVED)
|
|
2739
|
+
break;
|
|
2740
|
+
try {
|
|
2741
|
+
const named = namedEnclosingFunction(inner.anchor);
|
|
2742
|
+
if (!named)
|
|
2743
|
+
continue;
|
|
2744
|
+
const checker = inner.entry.checker();
|
|
2745
|
+
const flowing = inner.sources.map((source) => ({ source, flow: paramFlow(source.arg.node, named.fn, checker) })).filter((item) => Boolean(item.flow));
|
|
2746
|
+
if (flowing.length === 0)
|
|
2747
|
+
continue;
|
|
2748
|
+
const fnSource = named.fn.getSourceFile();
|
|
2749
|
+
const fnId = `${relPath(rootDir, fnSource.fileName)}:${lineOf(named.fn)}:${colOf(named.fn)}`;
|
|
2750
|
+
const wrapper = wrapperSinks[fnId] ??= { name: qualifiedName(named.fn, named.name), sinkId: inner.site.viaHelper ?? inner.site.id, roles: [] };
|
|
2751
|
+
for (const { source, flow } of flowing) {
|
|
2752
|
+
const param = flow.param.name.getText();
|
|
2753
|
+
if (!wrapper.roles.some((role) => role.role === source.role && role.param === param && role.key === flow.key)) {
|
|
2754
|
+
wrapper.roles.push({ role: source.role, param, index: named.fn.parameters.indexOf(flow.param), ...flow.key ? { key: flow.key } : {} });
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
const { calls } = toolsFor(inner.entry);
|
|
2758
|
+
for (const call of calls.callersOf(named.fn, named.name, MAX_HELPER_CALLERS)) {
|
|
2759
|
+
if (enclosingFunction(call) === named.fn)
|
|
2760
|
+
continue;
|
|
2761
|
+
const source = call.getSourceFile();
|
|
2762
|
+
const rel = relPath(rootDir, source.fileName);
|
|
2763
|
+
const id = `${rel}:${lineOf(call)}:${colOf(call)}`;
|
|
2764
|
+
if (seenIds.has(id))
|
|
2765
|
+
continue;
|
|
2766
|
+
const callerBindings = named.fn.parameters.map((param, index) => ({ param, expr: call.arguments[index] }));
|
|
2767
|
+
const sources = [];
|
|
2768
|
+
for (const { source: role, flow } of flowing) {
|
|
2769
|
+
const argument = call.arguments[named.fn.parameters.indexOf(flow.param)];
|
|
2770
|
+
if (!argument || import_typescript6.default.isSpreadElement(argument))
|
|
2771
|
+
continue;
|
|
2772
|
+
const arg = descendArg(argument, [flow.key, role.arg.key].filter((part) => Boolean(part)));
|
|
2773
|
+
sources.push({ ...role, bindings: extendBindings(role.bindings, callerBindings), arg });
|
|
2774
|
+
}
|
|
2775
|
+
if (sources.length === 0)
|
|
2776
|
+
continue;
|
|
2777
|
+
seenIds.add(id);
|
|
2778
|
+
const site = {
|
|
2779
|
+
id,
|
|
2780
|
+
path: rel,
|
|
2781
|
+
line: lineOf(call),
|
|
2782
|
+
col: colOf(call),
|
|
2783
|
+
language: "ts",
|
|
2784
|
+
callee: named.name,
|
|
2785
|
+
sdk: inner.site.sdk,
|
|
2786
|
+
...inner.site.provider ? { provider: inner.site.provider } : {},
|
|
2787
|
+
...siteFields(sources, rootDir),
|
|
2788
|
+
viaHelper: inner.site.viaHelper ?? inner.site.id,
|
|
2789
|
+
...describeEnclosing(rootDir, call, checker, memo),
|
|
2790
|
+
scope: scopeOf(rootDir, call),
|
|
2791
|
+
...callerChain(rootDir, call, calls, chainMemo),
|
|
2792
|
+
isTest: isTestPath(rel),
|
|
2793
|
+
isEval: isEvalPath(rel)
|
|
2794
|
+
};
|
|
2795
|
+
const derived = { site, entry: inner.entry, anchor: call, sources, level };
|
|
2796
|
+
sites.push(derived);
|
|
2797
|
+
next.push(derived);
|
|
2798
|
+
derivedCount += 1;
|
|
2799
|
+
}
|
|
2800
|
+
} catch (error) {
|
|
2801
|
+
warnings.push(`helpers ${inner.site.id}: ${error.message}`);
|
|
2802
|
+
}
|
|
2803
|
+
}
|
|
2804
|
+
frontier = next;
|
|
2805
|
+
if (level === rounds && next.length > 0)
|
|
2806
|
+
warnings.push(`wrapper-sink closure stopped after ${rounds} rounds`);
|
|
2807
|
+
}
|
|
2808
|
+
if (derivedCount >= MAX_DERIVED)
|
|
2809
|
+
warnings.push(`helper propagation stopped at ${MAX_DERIVED} derived call sites`);
|
|
2810
|
+
clock = mark("helpers", clock);
|
|
2811
|
+
const roles = [];
|
|
2812
|
+
const tracePrompts = options.tracePrompts ?? true;
|
|
2813
|
+
for (const entry of sites) {
|
|
2814
|
+
const { tracer } = toolsFor(entry.entry);
|
|
2815
|
+
for (const source of entry.sources) {
|
|
2816
|
+
if (!tracePrompts && PROMPT_ROLES.has(source.role))
|
|
2817
|
+
continue;
|
|
2818
|
+
let tree;
|
|
2819
|
+
try {
|
|
2820
|
+
tree = source.values ? tracer.traceAll(source.values, source.node) : tracer.trace(source.node, source.bindings);
|
|
2821
|
+
if (source.key !== undefined) {
|
|
2822
|
+
for (const segment of source.key.split("."))
|
|
2823
|
+
tree = selectKey(tree, segment, tracer.missing(source.arg.node, `property ${source.key} not found`));
|
|
2824
|
+
}
|
|
2825
|
+
} catch (error) {
|
|
2826
|
+
warnings.push(`trace ${entry.site.id} ${source.role}: ${error.message}`);
|
|
2827
|
+
tree = tracer.missing(source.arg.node, "trace failed");
|
|
2828
|
+
}
|
|
2829
|
+
if (source.role === "messages") {
|
|
2830
|
+
for (const split of splitMessages(tree)) {
|
|
2831
|
+
roles.push({ sink: entry.site, role: split.role, tree: split.tree, resolution: split.tree.resolution, ...split.message ? { message: split.message } : {} });
|
|
2832
|
+
}
|
|
2833
|
+
} else {
|
|
2834
|
+
roles.push({ sink: entry.site, role: source.role, tree, resolution: tree.resolution, ...source.message ? { message: source.message } : {} });
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
clock = mark("trace", clock);
|
|
2839
|
+
if (options.status ?? true) {
|
|
2840
|
+
try {
|
|
2841
|
+
const reach = buildImportGraphReachability(rootDir);
|
|
2842
|
+
for (const { site } of sites) {
|
|
2843
|
+
site.status = reach.inProd.has(site.path) ? "in_prod" : reach.reachable.has(site.path) ? "reachable" : "defined_only";
|
|
2844
|
+
}
|
|
2845
|
+
} catch (error) {
|
|
2846
|
+
warnings.push(`status: ${error.message}`);
|
|
2847
|
+
}
|
|
2848
|
+
mark("status", clock);
|
|
2849
|
+
}
|
|
2850
|
+
const result = {
|
|
2851
|
+
schemaVersion: EXTRACT_SCHEMA_VERSION,
|
|
2852
|
+
rootDir,
|
|
2853
|
+
files: repo?.files ?? 0,
|
|
2854
|
+
programs: repo?.entries.length ?? 0,
|
|
2855
|
+
durationMs: Date.now() - started,
|
|
2856
|
+
timings,
|
|
2857
|
+
callSites: sites.map((entry) => entry.site),
|
|
2858
|
+
roles,
|
|
2859
|
+
toolDefinitions: [],
|
|
2860
|
+
wrapperSinks,
|
|
2861
|
+
warnings
|
|
2862
|
+
};
|
|
2863
|
+
const fileKey = (path) => {
|
|
2864
|
+
const abs = resolve2(rootDir, path);
|
|
2865
|
+
return /\.svelte$/i.test(abs) ? svelteVirtualName(abs) : abs;
|
|
2866
|
+
};
|
|
2867
|
+
const lookup = (path) => repo?.owner.get(fileKey(path));
|
|
2868
|
+
const sourceFile = (path) => lookup(path)?.program.getSourceFile(fileKey(path));
|
|
2869
|
+
let files;
|
|
2870
|
+
const ctx = {
|
|
2871
|
+
rootDir,
|
|
2872
|
+
programs: repo?.entries.map((entry) => entry.program) ?? [],
|
|
2873
|
+
programFor: (path) => lookup(path)?.program,
|
|
2874
|
+
checkerFor: (path) => lookup(path)?.checker(),
|
|
2875
|
+
sourceFiles: () => files ??= [...repo?.owner.entries() ?? []].filter(([file]) => !isTestPath(relPath(rootDir, file))).map(([file, entry]) => entry.program.getSourceFile(file)).filter((file) => Boolean(file)),
|
|
2876
|
+
nodeAt: (ref) => {
|
|
2877
|
+
const source = sourceFile(ref.path);
|
|
2878
|
+
return source ? nodeSpanning(source, ref.start, ref.end) : undefined;
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
return { result, ctx };
|
|
2882
|
+
}
|
|
2883
|
+
function nodeSpanning(source, start, end) {
|
|
2884
|
+
let best;
|
|
2885
|
+
const visit = (node) => {
|
|
2886
|
+
const nodeStart = node.getStart(source);
|
|
2887
|
+
if (nodeStart > start || node.getEnd() < end)
|
|
2888
|
+
return;
|
|
2889
|
+
if (nodeStart === start && node.getEnd() === end) {
|
|
2890
|
+
best = node;
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
2893
|
+
best = node;
|
|
2894
|
+
import_typescript6.default.forEachChild(node, visit);
|
|
2895
|
+
};
|
|
2896
|
+
visit(source);
|
|
2897
|
+
return best;
|
|
2898
|
+
}
|
|
2899
|
+
function serializeExtractResult(result) {
|
|
2900
|
+
return JSON.parse(JSON.stringify(result));
|
|
2901
|
+
}
|
|
2902
|
+
function runEnumerators(enumerators, input, ctx) {
|
|
2903
|
+
const out = { runtimeAgents: [], artifacts: [], relationships: [], unknowns: [], warnings: [] };
|
|
2904
|
+
for (const enumerator of enumerators) {
|
|
2905
|
+
try {
|
|
2906
|
+
const part = enumerator.enumerate(input, ctx);
|
|
2907
|
+
out.runtimeAgents.push(...part.runtimeAgents ?? []);
|
|
2908
|
+
out.artifacts.push(...part.artifacts ?? []);
|
|
2909
|
+
out.relationships.push(...part.relationships ?? []);
|
|
2910
|
+
out.unknowns.push(...part.unknowns ?? []);
|
|
2911
|
+
out.warnings.push(...part.warnings ?? []);
|
|
2912
|
+
} catch (error) {
|
|
2913
|
+
out.warnings.push(`enumerator ${enumerator.id}: ${error.message}`);
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
return out;
|
|
2917
|
+
}
|
|
2918
|
+
function assignAgentIds(result, agentForScope) {
|
|
2919
|
+
const owners = (item) => {
|
|
2920
|
+
let ids = agentForScope(item.scope);
|
|
2921
|
+
for (const entry of item.callerScopes ?? []) {
|
|
2922
|
+
if (ids.length > 0)
|
|
2923
|
+
break;
|
|
2924
|
+
ids = agentForScope(entry);
|
|
2925
|
+
}
|
|
2926
|
+
return [...new Set(ids)];
|
|
2927
|
+
};
|
|
2928
|
+
for (const site of result.callSites) {
|
|
2929
|
+
const ids = owners(site);
|
|
2930
|
+
if (ids.length > 0)
|
|
2931
|
+
site.agentIds = ids;
|
|
2932
|
+
}
|
|
2933
|
+
for (const tool of result.toolDefinitions ?? []) {
|
|
2934
|
+
const ids = owners(tool);
|
|
2935
|
+
if (ids.length > 0)
|
|
2936
|
+
tool.agentIds = ids;
|
|
2937
|
+
}
|
|
2938
|
+
}
|
|
2939
|
+
export {
|
|
2940
|
+
valueChildren,
|
|
2941
|
+
toolNamesOf,
|
|
2942
|
+
serializeExtractResult,
|
|
2943
|
+
selectKey,
|
|
2944
|
+
runEnumerators,
|
|
2945
|
+
renderings,
|
|
2946
|
+
registerClassSink,
|
|
2947
|
+
registerCallSink,
|
|
2948
|
+
extractHarnessWithContext,
|
|
2949
|
+
extractHarness,
|
|
2950
|
+
clearExtractCache,
|
|
2951
|
+
assignAgentIds,
|
|
2952
|
+
allValues,
|
|
2953
|
+
EXTRACT_SCHEMA_VERSION,
|
|
2954
|
+
ENUMERATORS,
|
|
2955
|
+
CALL_SINKS
|
|
2956
|
+
};
|