@moda-ai/cli 1.55.71 → 1.55.73
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/README.md +11 -0
- package/dist/{agent-6a97sf18.js → agent-nqykfqm0.js} +6 -6
- package/dist/{cli-0qnmrybh.js → cli-4bmxk8z9.js} +7 -7
- package/dist/{cli-tgjvf91h.js → cli-h5ar0v9v.js} +1063 -44
- package/dist/{cli-9ww72mrd.js → cli-y333w08f.js} +1 -1
- package/dist/{cli-1ykm231r.js → cli-zyg6v6vq.js} +2 -2
- package/dist/cli.js +20 -20
- package/dist/{doctor-0afher5t.js → doctor-180rzz99.js} +4 -4
- package/dist/{harness-29rxrwfg.js → harness-defgbftj.js} +4 -4
- package/dist/{harness-github-actions-6p1czt5h.js → harness-github-actions-p4011crc.js} +4 -4
- package/dist/{harness-report-3n7bg314.js → harness-report-1q7322xg.js} +1 -1
- package/dist/{index-8pzrw7v9.js → index-4z7h9mam.js} +4 -4
- package/dist/{index-vj7cr35e.js → index-6ycqrx13.js} +7 -7
- package/dist/index-femt9s00.js +33 -0
- package/dist/{production-intelligence-vsjhv4n2.js → production-intelligence-f9sd68te.js} +2 -2
- package/dist/{prompt-attribution-80nzjmz0.js → prompt-attribution-1s253fra.js} +4 -4
- package/dist/prompt-source-mcp.js +4 -4
- package/dist/{prompts-r1hp4gry.js → prompts-gmdscxhk.js} +3 -3
- package/dist/{skills-pqhvfc1r.js → skills-knpeqryb.js} +3 -3
- package/dist/{sync-fz5tfk4n.js → sync-asf3zmmn.js} +6 -6
- package/package.json +2 -1
- package/skills/integration/index.json +2 -2
- package/dist/{cli-k8hzbxtn.js → cli-1smcq5pf.js} +3 -3
- package/dist/{cli-qq4gd126.js → cli-6hpfw3vf.js} +3 -3
|
@@ -18,10 +18,12 @@ import {
|
|
|
18
18
|
artifactHasBody,
|
|
19
19
|
buildImportGraphReachability,
|
|
20
20
|
createHarnessReport,
|
|
21
|
+
detectBoundRuntimeClasses,
|
|
21
22
|
firstEvidencePath,
|
|
22
23
|
graphForReport,
|
|
23
24
|
hashHarnessReport,
|
|
24
25
|
hashStableJson,
|
|
26
|
+
isTestWorkerConfig,
|
|
25
27
|
loadHarnessReportForSync,
|
|
26
28
|
mergeBoundRuntimeClasses,
|
|
27
29
|
normalizeHarnessReport,
|
|
@@ -29,14 +31,11 @@ import {
|
|
|
29
31
|
requiresArtifactBody,
|
|
30
32
|
resolveHarnessReportPath,
|
|
31
33
|
stampRemoteSnapshotTruncation,
|
|
34
|
+
stripJsonc,
|
|
32
35
|
tagComponentStatus,
|
|
33
36
|
validateHarnessReport,
|
|
34
37
|
writeHarnessReportArtifacts
|
|
35
|
-
} from "./cli-
|
|
36
|
-
import {
|
|
37
|
-
createCommandContext,
|
|
38
|
-
stringOption
|
|
39
|
-
} from "./cli-5ms8rw8x.js";
|
|
38
|
+
} from "./cli-y333w08f.js";
|
|
40
39
|
import {
|
|
41
40
|
assertFlags,
|
|
42
41
|
assertPositionals,
|
|
@@ -46,6 +45,10 @@ import {
|
|
|
46
45
|
ApiError,
|
|
47
46
|
callControlAPI
|
|
48
47
|
} from "./cli-87xy1evx.js";
|
|
48
|
+
import {
|
|
49
|
+
createCommandContext,
|
|
50
|
+
stringOption
|
|
51
|
+
} from "./cli-5ms8rw8x.js";
|
|
49
52
|
import {
|
|
50
53
|
EXIT_DEGRADED,
|
|
51
54
|
embeddedTenantIdFromApiKey,
|
|
@@ -105,6 +108,9 @@ import {
|
|
|
105
108
|
__toESM
|
|
106
109
|
} from "./cli-0v6na3yp.js";
|
|
107
110
|
|
|
111
|
+
// src/harness-extract/enumerators/agents.ts
|
|
112
|
+
var import_typescript12 = __toESM(require_typescript(), 1);
|
|
113
|
+
|
|
108
114
|
// src/harness-extract/index.ts
|
|
109
115
|
var import_typescript10 = __toESM(require_typescript(), 1);
|
|
110
116
|
import { resolve as resolve13 } from "node:path";
|
|
@@ -3136,12 +3142,60 @@ function effectiveField(object, key) {
|
|
|
3136
3142
|
});
|
|
3137
3143
|
return fields;
|
|
3138
3144
|
}
|
|
3145
|
+
var WRITTEN_SYMBOLS = new WeakMap;
|
|
3146
|
+
function writtenSymbols(file, checker) {
|
|
3147
|
+
let written = WRITTEN_SYMBOLS.get(file);
|
|
3148
|
+
if (written)
|
|
3149
|
+
return written;
|
|
3150
|
+
const found = new Set;
|
|
3151
|
+
const add = (node) => {
|
|
3152
|
+
const root = rootIdentifier(node);
|
|
3153
|
+
const symbol = root ? resolvedSymbol(root, checker) : undefined;
|
|
3154
|
+
if (symbol)
|
|
3155
|
+
found.add(symbol);
|
|
3156
|
+
};
|
|
3157
|
+
const visit = (node) => {
|
|
3158
|
+
if (import_typescript5.default.isBinaryExpression(node) && node.operatorToken.kind >= import_typescript5.default.SyntaxKind.FirstAssignment && node.operatorToken.kind <= import_typescript5.default.SyntaxKind.LastAssignment)
|
|
3159
|
+
add(node.left);
|
|
3160
|
+
else if (import_typescript5.default.isDeleteExpression(node))
|
|
3161
|
+
add(node.expression);
|
|
3162
|
+
else if ((import_typescript5.default.isPrefixUnaryExpression(node) || import_typescript5.default.isPostfixUnaryExpression(node)) && (node.operator === import_typescript5.default.SyntaxKind.PlusPlusToken || node.operator === import_typescript5.default.SyntaxKind.MinusMinusToken))
|
|
3163
|
+
add(node.operand);
|
|
3164
|
+
else if (import_typescript5.default.isCallExpression(node) && node.arguments.length > 0) {
|
|
3165
|
+
const callee = unwrap(node.expression);
|
|
3166
|
+
if (import_typescript5.default.isPropertyAccessExpression(callee) && callee.name.text === "assign")
|
|
3167
|
+
add(node.arguments[0]);
|
|
3168
|
+
}
|
|
3169
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
3170
|
+
};
|
|
3171
|
+
visit(file);
|
|
3172
|
+
written = found;
|
|
3173
|
+
WRITTEN_SYMBOLS.set(file, written);
|
|
3174
|
+
return written;
|
|
3175
|
+
}
|
|
3176
|
+
function gatewayRequestLiteral(argument, checker) {
|
|
3177
|
+
const value = unwrap(argument);
|
|
3178
|
+
if (import_typescript5.default.isObjectLiteralExpression(value))
|
|
3179
|
+
return value;
|
|
3180
|
+
if (!import_typescript5.default.isIdentifier(value))
|
|
3181
|
+
return;
|
|
3182
|
+
const symbol = resolvedSymbol(value, checker);
|
|
3183
|
+
const declaration = valueDeclaration(symbol);
|
|
3184
|
+
if (!symbol || !declaration || !import_typescript5.default.isVariableDeclaration(declaration) || !declaration.initializer)
|
|
3185
|
+
return;
|
|
3186
|
+
if (!(import_typescript5.default.getCombinedNodeFlags(declaration) & import_typescript5.default.NodeFlags.Const))
|
|
3187
|
+
return;
|
|
3188
|
+
const literal = unwrap(declaration.initializer);
|
|
3189
|
+
if (!import_typescript5.default.isObjectLiteralExpression(literal))
|
|
3190
|
+
return;
|
|
3191
|
+
return writtenSymbols(declaration.getSourceFile(), checker).has(symbol) ? undefined : literal;
|
|
3192
|
+
}
|
|
3139
3193
|
var GATEWAY_METHODS = new Set(["call", "stream"]);
|
|
3140
3194
|
var GATEWAY_BODY_KEYS = { system: "system", messages: "messages", prompt: "prompt", model: "model", tools: "tools" };
|
|
3141
3195
|
var modelGatewaySink = {
|
|
3142
3196
|
id: "model-gateway",
|
|
3143
3197
|
sdk: "model-gateway",
|
|
3144
|
-
match(call) {
|
|
3198
|
+
match(call, ctx) {
|
|
3145
3199
|
if (!import_typescript5.default.isCallExpression(call) || call.arguments.length !== 1)
|
|
3146
3200
|
return;
|
|
3147
3201
|
const callee = unwrap(call.expression);
|
|
@@ -3150,8 +3204,8 @@ var modelGatewaySink = {
|
|
|
3150
3204
|
const receiver = unwrap(callee.expression);
|
|
3151
3205
|
if (!import_typescript5.default.isPropertyAccessExpression(receiver) || receiver.name.text !== "models")
|
|
3152
3206
|
return;
|
|
3153
|
-
const request =
|
|
3154
|
-
if (!
|
|
3207
|
+
const request = gatewayRequestLiteral(call.arguments[0], ctx.checker);
|
|
3208
|
+
if (!request || !propertyValue(request, "kind"))
|
|
3155
3209
|
return;
|
|
3156
3210
|
const roles = [];
|
|
3157
3211
|
for (const body of effectiveField(request, "body")) {
|
|
@@ -9092,7 +9146,7 @@ function isUnder2(path, root) {
|
|
|
9092
9146
|
return true;
|
|
9093
9147
|
return path === root || path.startsWith(`${root}/`);
|
|
9094
9148
|
}
|
|
9095
|
-
function
|
|
9149
|
+
function stripJsonc2(text) {
|
|
9096
9150
|
let out = "";
|
|
9097
9151
|
let i = 0;
|
|
9098
9152
|
let inString = false;
|
|
@@ -9136,7 +9190,7 @@ function stripJsonc(text) {
|
|
|
9136
9190
|
}
|
|
9137
9191
|
function parseJsonLoose(text) {
|
|
9138
9192
|
try {
|
|
9139
|
-
return JSON.parse(
|
|
9193
|
+
return JSON.parse(stripJsonc2(text));
|
|
9140
9194
|
} catch {
|
|
9141
9195
|
return;
|
|
9142
9196
|
}
|
|
@@ -18983,7 +19037,7 @@ async function runHarnessCommand(context) {
|
|
|
18983
19037
|
throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
|
|
18984
19038
|
}
|
|
18985
19039
|
if (context.flags["github-actions"] === "true") {
|
|
18986
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
19040
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-p4011crc.js");
|
|
18987
19041
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
18988
19042
|
writeReport: (report2) => {
|
|
18989
19043
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -19129,7 +19183,15 @@ async function runHarnessCommand(context) {
|
|
|
19129
19183
|
}
|
|
19130
19184
|
const { artifacts, unknowns } = deterministicGraphItems(rootDir, promote === "all" ? undefined : promote);
|
|
19131
19185
|
tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
|
|
19132
|
-
const
|
|
19186
|
+
const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-4z7h9mam.js");
|
|
19187
|
+
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-femt9s00.js");
|
|
19188
|
+
let components = { runtimeAgents: [], artifacts: [], warnings: [] };
|
|
19189
|
+
if (promote === "all" || promote === "topology" || promote === "tools") {
|
|
19190
|
+
const { result, ctx } = extractHarnessWithContext2(rootDir);
|
|
19191
|
+
const found = enumerateHarnessComponents(result, ctx);
|
|
19192
|
+
components = promote === "tools" ? { ...found, artifacts: found.artifacts.filter((entry) => entry.type === "tool") } : promote === "topology" ? { ...found, artifacts: found.artifacts.filter((entry) => entry.type !== "tool") } : found;
|
|
19193
|
+
}
|
|
19194
|
+
const promoted = { concern: promote, unknowns, ...mergeEnumeratedComponents(artifacts, components) };
|
|
19133
19195
|
const promoteWritten = [];
|
|
19134
19196
|
if (promoteOut && !context.dryRun) {
|
|
19135
19197
|
const target = resolve9(context.cwd, promoteOut);
|
|
@@ -19156,10 +19218,14 @@ async function runHarnessCommand(context) {
|
|
|
19156
19218
|
}
|
|
19157
19219
|
case "extract": {
|
|
19158
19220
|
writeHumanProgress(context, "Harness extract: tracing model call sites (no LLM, no network)...");
|
|
19159
|
-
const {
|
|
19160
|
-
const
|
|
19221
|
+
const { extractHarnessWithContext: extractHarnessWithContext2, serializeExtractResult } = await import("./index-4z7h9mam.js");
|
|
19222
|
+
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-femt9s00.js");
|
|
19223
|
+
const { result, ctx } = extractHarnessWithContext2(rootDir, { fresh: true });
|
|
19224
|
+
const artifacts = deterministicArtifacts(rootDir);
|
|
19225
|
+
tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
|
|
19226
|
+
const graph = mergeEnumeratedComponents(artifacts, enumerateHarnessComponents(result, ctx));
|
|
19161
19227
|
writeHumanProgress(context, `Harness extract: ${result.callSites.length} call sites, ${result.roles.length} traced roles across ${result.files} files (${result.programs} programs, ${result.durationMs.toLocaleString()} ms).`);
|
|
19162
|
-
context.output.writeData(serializeExtractResult(result), {
|
|
19228
|
+
context.output.writeData({ ...serializeExtractResult(result), graph }, {
|
|
19163
19229
|
status: result.warnings.length > 0 ? "degraded" : "success",
|
|
19164
19230
|
...result.warnings.length > 0 ? { warnings: result.warnings } : {}
|
|
19165
19231
|
});
|
|
@@ -19939,18 +20005,19 @@ function deterministicGraphItems(rootDir, concern) {
|
|
|
19939
20005
|
hydratePromptAndToolBodies(graph, rootDir);
|
|
19940
20006
|
return { artifacts: graph.artifacts, unknowns: graph.unknowns };
|
|
19941
20007
|
}
|
|
19942
|
-
var extractedModelsCache = new
|
|
20008
|
+
var extractedModelsCache = new WeakMap;
|
|
19943
20009
|
function extractedModelItems(rootDir) {
|
|
19944
20010
|
const empty = { artifacts: [], unknowns: [], rewritten: new Set, enabled: false };
|
|
19945
20011
|
if (process.env.MODA_HARNESS_EXTRACT === "0")
|
|
19946
20012
|
return empty;
|
|
19947
20013
|
const key = resolve9(rootDir);
|
|
19948
|
-
const cached = extractedModelsCache.get(key);
|
|
19949
|
-
if (cached)
|
|
19950
|
-
return cached;
|
|
19951
20014
|
let items = { ...empty, enabled: true };
|
|
19952
20015
|
try {
|
|
19953
|
-
const result =
|
|
20016
|
+
const { result, ctx } = extractHarnessWithContext(key);
|
|
20017
|
+
createAgentScopeResolver(result, ctx);
|
|
20018
|
+
const cached = extractedModelsCache.get(result);
|
|
20019
|
+
if (cached)
|
|
20020
|
+
return cached;
|
|
19954
20021
|
for (const warning of result.warnings)
|
|
19955
20022
|
process.stderr.write(`warning: harness extraction incomplete; ${warning}
|
|
19956
20023
|
`);
|
|
@@ -19960,11 +20027,11 @@ function extractedModelItems(rootDir) {
|
|
|
19960
20027
|
rewritten: new Set((result.rewrittenModels ?? []).map((entry) => normalizedModelId(entry.id))),
|
|
19961
20028
|
enabled: true
|
|
19962
20029
|
};
|
|
20030
|
+
extractedModelsCache.set(result, items);
|
|
19963
20031
|
} catch (error) {
|
|
19964
20032
|
process.stderr.write(`warning: harness extraction failed; model artifacts come from the candidate pre-pass only (${error instanceof Error ? error.message : String(error)})
|
|
19965
20033
|
`);
|
|
19966
20034
|
}
|
|
19967
|
-
extractedModelsCache.set(key, items);
|
|
19968
20035
|
return items;
|
|
19969
20036
|
}
|
|
19970
20037
|
var normalizedModelId = (name) => String(name ?? "").trim().toLowerCase();
|
|
@@ -20132,7 +20199,7 @@ function withCallSitePrompts(rootDir, promoted) {
|
|
|
20132
20199
|
const { result, ctx } = extractHarnessWithContext(rootDir);
|
|
20133
20200
|
const sites = result.callSites.filter((site) => !site.isTest);
|
|
20134
20201
|
const toolDefinitions = result.toolDefinitions ?? [];
|
|
20135
|
-
return promptArtifactsFromCallSites(sites, ctx, promoted, { toolDefinitions }).artifacts;
|
|
20202
|
+
return promptArtifactsFromCallSites(sites, ctx, promoted, { toolDefinitions, agentForScope: createAgentScopeResolver(result, ctx) }).artifacts;
|
|
20136
20203
|
} catch {
|
|
20137
20204
|
return promoted;
|
|
20138
20205
|
}
|
|
@@ -26342,25 +26409,29 @@ var REASON = {
|
|
|
26342
26409
|
config: "model id in model configuration next to a model call"
|
|
26343
26410
|
};
|
|
26344
26411
|
function modelArtifacts(result) {
|
|
26345
|
-
|
|
26346
|
-
|
|
26347
|
-
|
|
26348
|
-
|
|
26349
|
-
|
|
26350
|
-
|
|
26351
|
-
|
|
26352
|
-
|
|
26353
|
-
|
|
26354
|
-
|
|
26355
|
-
|
|
26356
|
-
|
|
26357
|
-
line:
|
|
26358
|
-
|
|
26359
|
-
|
|
26360
|
-
|
|
26361
|
-
|
|
26362
|
-
|
|
26363
|
-
|
|
26412
|
+
const owners = new Map(result.callSites.map((site) => [site.id, site.agentIds ?? []]));
|
|
26413
|
+
return (result.models ?? []).map((model) => {
|
|
26414
|
+
const agentIds = [...new Set(model.calledFrom.flatMap((site) => owners.get(site.callSite) ?? []))].sort();
|
|
26415
|
+
return {
|
|
26416
|
+
id: `model_config_${slug(model.id)}_${createHash9("sha256").update(model.id).digest("hex").slice(0, 8)}`,
|
|
26417
|
+
type: "model_config",
|
|
26418
|
+
name: model.id,
|
|
26419
|
+
scope: agentIds.length === 1 ? "agent" : "shared",
|
|
26420
|
+
usedByAgentIds: agentIds,
|
|
26421
|
+
confidence: CONFIDENCE[model.resolution],
|
|
26422
|
+
confidenceReason: model.resolution === "config" ? "Read from a model-named setting in source; no call site passes it directly." : "Traced from a model call site's model argument to this literal.",
|
|
26423
|
+
evidence: [
|
|
26424
|
+
{ path: model.definition.path, line: model.definition.line, reason: REASON[model.resolution] },
|
|
26425
|
+
...model.calledFrom.slice(0, MAX_CALL_SITE_EVIDENCE).map((site) => ({
|
|
26426
|
+
path: site.path,
|
|
26427
|
+
line: site.line,
|
|
26428
|
+
reason: `model call site${site.enclosing ? ` in ${site.enclosing}` : ""} (${site.callee})`
|
|
26429
|
+
}))
|
|
26430
|
+
],
|
|
26431
|
+
calledFrom: model.calledFrom.map((site) => ({ path: site.path, line: site.line, ...site.enclosing ? { enclosing: site.enclosing } : {} })),
|
|
26432
|
+
resolution: model.resolution
|
|
26433
|
+
};
|
|
26434
|
+
});
|
|
26364
26435
|
}
|
|
26365
26436
|
function describeSource(source) {
|
|
26366
26437
|
const [kind, ...rest] = source.split(":");
|
|
@@ -26573,8 +26644,6 @@ function collectModelLiterals(rootDir) {
|
|
|
26573
26644
|
|
|
26574
26645
|
// src/harness-extract/types.ts
|
|
26575
26646
|
var EXTRACT_SCHEMA_VERSION = 1;
|
|
26576
|
-
// src/harness-extract/enumerators/index.ts
|
|
26577
|
-
var ENUMERATORS = [];
|
|
26578
26647
|
// src/harness-extract/tools.ts
|
|
26579
26648
|
var PASS_THROUGH2 = new Set(["ref", "call", "param", "oneOf", "lookup"]);
|
|
26580
26649
|
var DEFINITION_KEYS = new Set(["description", "input_schema", "inputSchema", "parameters", "schema", "execute", "type", "strict"]);
|
|
@@ -27194,4 +27263,954 @@ function assignAgentIds(result, agentForScope) {
|
|
|
27194
27263
|
}
|
|
27195
27264
|
}
|
|
27196
27265
|
|
|
27197
|
-
|
|
27266
|
+
// src/harness-extract/enumerators/common.ts
|
|
27267
|
+
var import_typescript11 = __toESM(require_typescript(), 1);
|
|
27268
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync15 } from "node:fs";
|
|
27269
|
+
import { dirname as dirname10, join as join13, posix as posix2, relative as relative10 } from "node:path";
|
|
27270
|
+
var cache2 = new WeakMap;
|
|
27271
|
+
var SKIP = new Set(["node_modules", "dist", "build", "out", "vendor", "coverage", "__pycache__"]);
|
|
27272
|
+
var TEST_PATH4 = /(?:^|\/)(?:test|tests|__tests__|test-fixtures|fixtures?|__fixtures__|__mocks__|e2e)\/|\.(?:test|spec)\.[cm]?[jt]sx?$/i;
|
|
27273
|
+
var EVAL_PATH2 = /(?:^|\/)evals?\/|\.evals?\.[cm]?[jt]sx?$/i;
|
|
27274
|
+
function enumerationRepository(ctx) {
|
|
27275
|
+
const existing = cache2.get(ctx);
|
|
27276
|
+
if (existing)
|
|
27277
|
+
return existing;
|
|
27278
|
+
const files = [];
|
|
27279
|
+
const walk = (dir) => {
|
|
27280
|
+
for (const entry of readdirSync8(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
27281
|
+
const abs = join13(dir, entry.name);
|
|
27282
|
+
if (entry.isDirectory()) {
|
|
27283
|
+
if (!entry.name.startsWith(".") && !SKIP.has(entry.name))
|
|
27284
|
+
walk(abs);
|
|
27285
|
+
} else if (entry.isFile() && /\.(?:[cm]?[jt]sx?|py|jsonc?|toml)$/.test(entry.name) && !/\.d\.[cm]?ts$/.test(entry.name)) {
|
|
27286
|
+
const path = relative10(ctx.rootDir, abs).split("\\").join("/");
|
|
27287
|
+
try {
|
|
27288
|
+
const text = readFileSync15(abs, "utf8");
|
|
27289
|
+
if (text.length > 1024 * 1024)
|
|
27290
|
+
continue;
|
|
27291
|
+
const source = ctx.programFor(path)?.getSourceFile(abs) ?? import_typescript11.default.createSourceFile(abs, text, import_typescript11.default.ScriptTarget.Latest, true, path.endsWith("tsx") ? import_typescript11.default.ScriptKind.TSX : import_typescript11.default.ScriptKind.TS);
|
|
27292
|
+
files.push({ path, text, source });
|
|
27293
|
+
} catch {}
|
|
27294
|
+
}
|
|
27295
|
+
}
|
|
27296
|
+
};
|
|
27297
|
+
walk(ctx.rootDir);
|
|
27298
|
+
const workers = [];
|
|
27299
|
+
const paths = new Set(files.map((file) => file.path));
|
|
27300
|
+
const closure = (main) => {
|
|
27301
|
+
const found = new Set, pending = [main];
|
|
27302
|
+
for (let index = 0;index < pending.length; index++) {
|
|
27303
|
+
const path = pending[index];
|
|
27304
|
+
if (found.has(path))
|
|
27305
|
+
continue;
|
|
27306
|
+
found.add(path);
|
|
27307
|
+
const file = files.find((entry) => entry.path === path);
|
|
27308
|
+
if (!file)
|
|
27309
|
+
continue;
|
|
27310
|
+
for (const ref of import_typescript11.default.preProcessFile(file.text, true, true).importedFiles) {
|
|
27311
|
+
if (!ref.fileName.startsWith("."))
|
|
27312
|
+
continue;
|
|
27313
|
+
const base = posix2.normalize(posix2.join(posix2.dirname(path), ref.fileName)).replace(/\.[cm]?js$/, "");
|
|
27314
|
+
const target = [base, ...[".ts", ".tsx", ".js", ".mjs", "/index.ts", "/index.js"].map((suffix) => base + suffix)].find((candidate) => paths.has(candidate));
|
|
27315
|
+
if (target)
|
|
27316
|
+
pending.push(target);
|
|
27317
|
+
}
|
|
27318
|
+
}
|
|
27319
|
+
return found;
|
|
27320
|
+
};
|
|
27321
|
+
for (const file of files)
|
|
27322
|
+
if (/(?:^|\/)wrangler(?:\.[\w.-]+)?\.(?:jsonc?|toml)$/.test(file.path)) {
|
|
27323
|
+
try {
|
|
27324
|
+
const config2 = file.path.endsWith(".toml") ? parse(file.text) : JSON.parse(stripJsonc(file.text));
|
|
27325
|
+
const variants = [["default", config2], ...Object.entries(config2.env ?? {}).map(([name, section]) => [name, { ...config2, ...section, queues: section.queues, workflows: section.workflows }])];
|
|
27326
|
+
for (const [environment, section] of variants) {
|
|
27327
|
+
if (typeof section.main !== "string" || isTestWorkerConfig({ path: file.path, name: section.name, mains: [section.main] }))
|
|
27328
|
+
continue;
|
|
27329
|
+
const main = posix2.normalize(posix2.join(dirname10(file.path), section.main));
|
|
27330
|
+
workers.push({ id: `${file.path}#${environment}`, main, cron: Boolean(section.triggers?.crons?.length), queueBindings: new Set((section.queues?.producers ?? []).flatMap((producer) => typeof producer.binding === "string" ? [producer.binding] : [])), workflowClasses: (section.workflows ?? []).flatMap((binding) => typeof binding.class_name === "string" && !binding.script_name ? [binding.class_name] : []), files: closure(main) });
|
|
27331
|
+
}
|
|
27332
|
+
} catch {}
|
|
27333
|
+
}
|
|
27334
|
+
const queueBindingsFor = (path) => {
|
|
27335
|
+
const owners = workers.filter((worker) => worker.files.has(path));
|
|
27336
|
+
return new Set(owners[0] ? [...owners[0].queueBindings].filter((binding) => owners.every((worker) => worker.queueBindings.has(binding))) : []);
|
|
27337
|
+
};
|
|
27338
|
+
const reach = buildImportGraphReachability(ctx.rootDir);
|
|
27339
|
+
const repo = { files, workers, queueBindingsFor, cronEntrypoints: new Set(workers.filter((worker) => worker.cron).map((worker) => worker.main)), deployedFiles: reach.inProd, status: (path) => reach.inProd.has(path) || reach.reachable.has(path) ? "reachable" : "defined_only" };
|
|
27340
|
+
cache2.set(ctx, repo);
|
|
27341
|
+
return repo;
|
|
27342
|
+
}
|
|
27343
|
+
function lineOf5(node) {
|
|
27344
|
+
return node.getSourceFile().getLineAndCharacterOfPosition(node.getStart()).line + 1;
|
|
27345
|
+
}
|
|
27346
|
+
function nameOf(node) {
|
|
27347
|
+
if (!node)
|
|
27348
|
+
return;
|
|
27349
|
+
if (import_typescript11.default.isComputedPropertyName(node) && import_typescript11.default.isStringLiteralLike(node.expression))
|
|
27350
|
+
return node.expression.text;
|
|
27351
|
+
return import_typescript11.default.isIdentifier(node) || import_typescript11.default.isStringLiteralLike(node) || import_typescript11.default.isNumericLiteral(node) ? node.text : undefined;
|
|
27352
|
+
}
|
|
27353
|
+
function visit(node, fn) {
|
|
27354
|
+
fn(node);
|
|
27355
|
+
import_typescript11.default.forEachChild(node, (child) => visit(child, fn));
|
|
27356
|
+
}
|
|
27357
|
+
function componentId(kind, path, name) {
|
|
27358
|
+
return `${kind}:${path}:${name}`;
|
|
27359
|
+
}
|
|
27360
|
+
function artifact(type, name, file, node, reason, status) {
|
|
27361
|
+
return { id: componentId(type, file.path, name), type, name, scope: "shared", sourcePath: file.path, usedByAgentIds: [], confidence: 1, evidence: [{ path: file.path, line: lineOf5(node), reason }], status };
|
|
27362
|
+
}
|
|
27363
|
+
function agent(name, file, node, reason, status) {
|
|
27364
|
+
return { id: componentId("agent", file.path, name), name, kind: "runtime_agent", root: ".", entrypointIds: [], channelAdapterIds: [], artifactIds: [], identityNamespaceIds: [], deploymentIds: [], frameworkIds: [], modelProviderIds: [], confidence: 1, evidence: [{ path: file.path, line: lineOf5(node), reason }], status };
|
|
27365
|
+
}
|
|
27366
|
+
function emptyResult() {
|
|
27367
|
+
return { runtimeAgents: [], artifacts: [], warnings: [] };
|
|
27368
|
+
}
|
|
27369
|
+
function stableResult(result) {
|
|
27370
|
+
const unique2 = (values) => [...new Map(values.map((x) => [x.id, x])).values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
27371
|
+
return { runtimeAgents: unique2(result.runtimeAgents), artifacts: unique2(result.artifacts), warnings: [...new Set(result.warnings)].sort() };
|
|
27372
|
+
}
|
|
27373
|
+
|
|
27374
|
+
// src/harness-extract/enumerators/agents.ts
|
|
27375
|
+
function agentForScope(scope, enumeration) {
|
|
27376
|
+
return enumeration.agentForScope(scope);
|
|
27377
|
+
}
|
|
27378
|
+
function createAgentScopeResolver(result, ctx) {
|
|
27379
|
+
return enumerateAgents(result, ctx).agentForScope;
|
|
27380
|
+
}
|
|
27381
|
+
var enumerations = new WeakMap;
|
|
27382
|
+
var AGENT_BASES3 = new Set(["Think", "Agent", "AIChatAgent", "McpAgent"]);
|
|
27383
|
+
var HTTP_METHODS2 = new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"]);
|
|
27384
|
+
function routeOf(fn, file) {
|
|
27385
|
+
const name = functionName(fn);
|
|
27386
|
+
if (name && HTTP_METHODS2.has(name) && /(?:^|\/)(?:route|\+server)\.[cm]?[jt]sx?$/.test(file.path))
|
|
27387
|
+
return `${name} ${file.path}`;
|
|
27388
|
+
const parent = fn.parent;
|
|
27389
|
+
if (parent && import_typescript12.default.isCallExpression(parent) && import_typescript12.default.isPropertyAccessExpression(parent.expression) && /^(get|post|put|patch|delete|all|on)$/.test(parent.expression.name.text)) {
|
|
27390
|
+
const path = parent.arguments.find(import_typescript12.default.isStringLiteralLike);
|
|
27391
|
+
if (path)
|
|
27392
|
+
return `${parent.expression.name.text.toUpperCase()} ${path.text} (${file.path})`;
|
|
27393
|
+
}
|
|
27394
|
+
return;
|
|
27395
|
+
}
|
|
27396
|
+
function enumerateAgents(result, ctx) {
|
|
27397
|
+
const cached = enumerations.get(ctx);
|
|
27398
|
+
if (cached)
|
|
27399
|
+
return cached;
|
|
27400
|
+
const repo = enumerationRepository(ctx);
|
|
27401
|
+
const scopes = new Map;
|
|
27402
|
+
const byNode = new Map;
|
|
27403
|
+
const classes = [];
|
|
27404
|
+
const bound = new Set(detectBoundRuntimeClasses(ctx.rootDir).filter((x) => x.kind === "durable_object").map((x) => x.className));
|
|
27405
|
+
const memo = createFrameworkMemo();
|
|
27406
|
+
const keyOf = (node) => `${node.getSourceFile().fileName}:${node.getStart()}`;
|
|
27407
|
+
for (const file of repo.files) {
|
|
27408
|
+
if (!/\.[cm]?[jt]sx?$/.test(file.path) || TEST_PATH4.test(file.path) || EVAL_PATH2.test(file.path) || /^scripts\//.test(file.path) && !repo.deployedFiles.has(file.path))
|
|
27409
|
+
continue;
|
|
27410
|
+
const checker = ctx.checkerFor(file.path);
|
|
27411
|
+
visit(file.source, (node) => {
|
|
27412
|
+
if ((import_typescript12.default.isClassDeclaration(node) || import_typescript12.default.isClassExpression(node)) && node.name) {
|
|
27413
|
+
const name2 = node.name.text;
|
|
27414
|
+
const info = checker ? frameworkBaseOf(node, checker, memo) : undefined;
|
|
27415
|
+
const directBase = node.heritageClauses?.flatMap((h) => h.types).map((x) => x.expression.getText()) ?? [];
|
|
27416
|
+
const protocolEvents = new Set;
|
|
27417
|
+
visit(node, (member2) => {
|
|
27418
|
+
if (import_typescript12.default.isStringLiteralLike(member2))
|
|
27419
|
+
protocolEvents.add(member2.text);
|
|
27420
|
+
});
|
|
27421
|
+
const realtime = protocolEvents.has("session.update") && protocolEvents.has("response.create") && [...protocolEvents].some((event) => event.includes("function_call"));
|
|
27422
|
+
const exported = import_typescript12.default.getCombinedModifierFlags(node) & import_typescript12.default.ModifierFlags.Export;
|
|
27423
|
+
const abstract = import_typescript12.default.getCombinedModifierFlags(node) & import_typescript12.default.ModifierFlags.Abstract;
|
|
27424
|
+
if (!abstract && (exported || bound.has(name2)) && (info?.base && AGENT_BASES3.has(info.base) || directBase.some((x) => AGENT_BASES3.has(x)) || exported && realtime)) {
|
|
27425
|
+
classes.push({ file, node, name: name2, chain: info?.chain ?? [name2, ...directBase] });
|
|
27426
|
+
}
|
|
27427
|
+
}
|
|
27428
|
+
if (!isFunctionLike(node) || !node.body)
|
|
27429
|
+
return;
|
|
27430
|
+
const name = functionName(node);
|
|
27431
|
+
const cls = enclosingClass(node)?.name?.text;
|
|
27432
|
+
const route = routeOf(node, file);
|
|
27433
|
+
const label = cls && name ? `${cls}.${name}` : name ?? route ?? `${file.path}:${lineOf5(node)}`;
|
|
27434
|
+
const scope = {
|
|
27435
|
+
key: keyOf(node),
|
|
27436
|
+
label,
|
|
27437
|
+
aliases: [label, ...name ? [name] : [], ...route ? [route] : [], `${file.path}::${label}`, `${file.path}#${label}`],
|
|
27438
|
+
file,
|
|
27439
|
+
node,
|
|
27440
|
+
className: cls,
|
|
27441
|
+
route,
|
|
27442
|
+
calls: new Set,
|
|
27443
|
+
virtualCalls: new Map,
|
|
27444
|
+
deployedCalls: new Set,
|
|
27445
|
+
callsByWorker: new Map(repo.workers.map((worker) => [worker.id, new Set])),
|
|
27446
|
+
callers: new Set,
|
|
27447
|
+
hasModel: false,
|
|
27448
|
+
modelWorkers: new Set,
|
|
27449
|
+
hasTools: false,
|
|
27450
|
+
toolFeedback: false,
|
|
27451
|
+
configuredSteps: false,
|
|
27452
|
+
hasLoop: false,
|
|
27453
|
+
forcedOutput: false
|
|
27454
|
+
};
|
|
27455
|
+
const qualified = (fn, fnName) => {
|
|
27456
|
+
const owner = enclosingClass(fn);
|
|
27457
|
+
return owner?.name && (fn.parent === owner || fn.parent?.parent === owner) ? `${owner.name.text}.${fnName}` : fnName;
|
|
27458
|
+
};
|
|
27459
|
+
if (name) {
|
|
27460
|
+
const parts = [qualified(node, name)];
|
|
27461
|
+
const member2 = import_typescript12.default.isMethodDeclaration(node) || import_typescript12.default.isGetAccessorDeclaration(node) || import_typescript12.default.isSetAccessorDeclaration(node) ? node : import_typescript12.default.isPropertyAssignment(node.parent) ? node.parent : undefined;
|
|
27462
|
+
const object = member2 && import_typescript12.default.isObjectLiteralExpression(member2.parent) ? member2.parent : undefined;
|
|
27463
|
+
if (object)
|
|
27464
|
+
parts.unshift(import_typescript12.default.isVariableDeclaration(object.parent) && import_typescript12.default.isIdentifier(object.parent.name) ? object.parent.name.text : `L${lineOf5(object)}`);
|
|
27465
|
+
for (let outer = (object ?? node).parent;outer; outer = outer.parent) {
|
|
27466
|
+
if (isFunctionLike(outer)) {
|
|
27467
|
+
const outerName = functionName(outer);
|
|
27468
|
+
if (outerName)
|
|
27469
|
+
parts.unshift(qualified(outer, outerName));
|
|
27470
|
+
}
|
|
27471
|
+
}
|
|
27472
|
+
scope.aliases.push(`${file.path}#${parts.join(".")}`);
|
|
27473
|
+
}
|
|
27474
|
+
scope.aliases.push(scope.key);
|
|
27475
|
+
scopes.set(scope.key, scope);
|
|
27476
|
+
byNode.set(node, scope);
|
|
27477
|
+
});
|
|
27478
|
+
}
|
|
27479
|
+
const classChain = (node, seen = new Set) => {
|
|
27480
|
+
if (seen.has(keyOf(node)))
|
|
27481
|
+
return [];
|
|
27482
|
+
seen.add(keyOf(node));
|
|
27483
|
+
const checker = ctx.checkerFor(node.getSourceFile().fileName.slice(ctx.rootDir.length + 1));
|
|
27484
|
+
const bases = node.heritageClauses?.flatMap((clause) => clause.types).flatMap((base) => {
|
|
27485
|
+
const declaration = checker && valueDeclaration(resolvedSymbol(base.expression, checker));
|
|
27486
|
+
return declaration && import_typescript12.default.isClassLike(declaration) ? classChain(declaration, seen) : [];
|
|
27487
|
+
}) ?? [];
|
|
27488
|
+
return [node, ...bases];
|
|
27489
|
+
};
|
|
27490
|
+
for (const cls of classes)
|
|
27491
|
+
cls.nodes = classChain(cls.node);
|
|
27492
|
+
const virtualEdges = new Map;
|
|
27493
|
+
const nearest = (node) => {
|
|
27494
|
+
for (let current = node;current; current = current.parent) {
|
|
27495
|
+
const scope = byNode.get(current);
|
|
27496
|
+
if (scope)
|
|
27497
|
+
return scope;
|
|
27498
|
+
}
|
|
27499
|
+
return;
|
|
27500
|
+
};
|
|
27501
|
+
const bindingTruth = (condition, worker) => {
|
|
27502
|
+
if (condition.kind === import_typescript12.default.SyntaxKind.TrueKeyword)
|
|
27503
|
+
return true;
|
|
27504
|
+
if (condition.kind === import_typescript12.default.SyntaxKind.FalseKeyword)
|
|
27505
|
+
return false;
|
|
27506
|
+
if (import_typescript12.default.isPrefixUnaryExpression(condition) && condition.operator === import_typescript12.default.SyntaxKind.ExclamationToken) {
|
|
27507
|
+
const value = bindingTruth(condition.operand, worker);
|
|
27508
|
+
return value === undefined ? undefined : !value;
|
|
27509
|
+
}
|
|
27510
|
+
if (import_typescript12.default.isPropertyAccessExpression(condition) && /^(?:this\.)?env$/.test(condition.expression.getText()) && (worker ? repo.workers.find((entry) => entry.id === worker)?.queueBindings : repo.queueBindingsFor(condition.getSourceFile().fileName.slice(ctx.rootDir.length + 1)))?.has(condition.name.text))
|
|
27511
|
+
return true;
|
|
27512
|
+
return;
|
|
27513
|
+
};
|
|
27514
|
+
const returns = (node) => Boolean(node && (import_typescript12.default.isReturnStatement(node) || import_typescript12.default.isBlock(node) && node.statements.length && import_typescript12.default.isReturnStatement(node.statements[node.statements.length - 1])));
|
|
27515
|
+
const deployed = (node, worker) => {
|
|
27516
|
+
for (let current = node;current.parent; current = current.parent) {
|
|
27517
|
+
const parent = current.parent;
|
|
27518
|
+
if (import_typescript12.default.isIfStatement(parent)) {
|
|
27519
|
+
const truth = bindingTruth(parent.expression, worker);
|
|
27520
|
+
if (truth !== undefined && (current === parent.thenStatement ? !truth : current === parent.elseStatement ? truth : false))
|
|
27521
|
+
return false;
|
|
27522
|
+
}
|
|
27523
|
+
if (import_typescript12.default.isBlock(parent))
|
|
27524
|
+
for (const prior of parent.statements) {
|
|
27525
|
+
if (prior.getStart() >= current.getStart())
|
|
27526
|
+
break;
|
|
27527
|
+
if (import_typescript12.default.isIfStatement(prior)) {
|
|
27528
|
+
const truth = bindingTruth(prior.expression, worker);
|
|
27529
|
+
if (truth !== undefined && returns(truth ? prior.thenStatement : prior.elseStatement))
|
|
27530
|
+
return false;
|
|
27531
|
+
}
|
|
27532
|
+
}
|
|
27533
|
+
}
|
|
27534
|
+
return true;
|
|
27535
|
+
};
|
|
27536
|
+
const markModel = (scope, node) => {
|
|
27537
|
+
scope.hasModel = true;
|
|
27538
|
+
for (const worker of repo.workers)
|
|
27539
|
+
if (deployed(node, worker.id))
|
|
27540
|
+
scope.modelWorkers.add(worker.id);
|
|
27541
|
+
};
|
|
27542
|
+
for (const site of result.callSites) {
|
|
27543
|
+
if (site.isTest || site.isEval)
|
|
27544
|
+
continue;
|
|
27545
|
+
const file = repo.files.find((x) => x.path === site.path);
|
|
27546
|
+
if (!file)
|
|
27547
|
+
continue;
|
|
27548
|
+
const offset = file.source.getPositionOfLineAndCharacter(Math.max(0, site.line - 1), Math.max(0, site.col - 1));
|
|
27549
|
+
let anchor = file.source;
|
|
27550
|
+
const descend = (node) => {
|
|
27551
|
+
if (node.getStart() <= offset && node.getEnd() >= offset) {
|
|
27552
|
+
anchor = node;
|
|
27553
|
+
import_typescript12.default.forEachChild(node, descend);
|
|
27554
|
+
}
|
|
27555
|
+
};
|
|
27556
|
+
descend(file.source);
|
|
27557
|
+
const scope = nearest(anchor);
|
|
27558
|
+
if (!scope)
|
|
27559
|
+
continue;
|
|
27560
|
+
markModel(scope, anchor);
|
|
27561
|
+
const tools = site.toolsArg ? ctx.nodeAt(site.toolsArg) : undefined;
|
|
27562
|
+
scope.hasTools ||= Boolean(tools && !(import_typescript12.default.isObjectLiteralExpression(tools) && tools.properties.length === 0) && !(import_typescript12.default.isArrayLiteralExpression(tools) && tools.elements.length === 0));
|
|
27563
|
+
scope.aliases.push(site.scope);
|
|
27564
|
+
}
|
|
27565
|
+
const targetsOf = (node, file) => {
|
|
27566
|
+
const checker = ctx.checkerFor(file.path);
|
|
27567
|
+
if (!checker)
|
|
27568
|
+
return [];
|
|
27569
|
+
const at = import_typescript12.default.isPropertyAccessExpression(node) ? node.name : node;
|
|
27570
|
+
const declaration = valueDeclaration(resolvedSymbol(at, checker));
|
|
27571
|
+
if (!declaration)
|
|
27572
|
+
return [];
|
|
27573
|
+
const direct = byNode.get(declaration) ?? scopes.get(keyOf(declaration));
|
|
27574
|
+
if (direct)
|
|
27575
|
+
return [direct];
|
|
27576
|
+
if (import_typescript12.default.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
27577
|
+
const fn = byNode.get(declaration.initializer) ?? scopes.get(keyOf(declaration.initializer));
|
|
27578
|
+
if (fn)
|
|
27579
|
+
return [fn];
|
|
27580
|
+
}
|
|
27581
|
+
return [];
|
|
27582
|
+
};
|
|
27583
|
+
for (const scope of scopes.values()) {
|
|
27584
|
+
const inspect = (node) => {
|
|
27585
|
+
if (node !== scope.node && isFunctionLike(node)) {
|
|
27586
|
+
return;
|
|
27587
|
+
}
|
|
27588
|
+
if (import_typescript12.default.isWhileStatement(node) || import_typescript12.default.isDoStatement(node) || import_typescript12.default.isForStatement(node) || import_typescript12.default.isForOfStatement(node))
|
|
27589
|
+
scope.hasLoop = true;
|
|
27590
|
+
if ((import_typescript12.default.isIdentifier(node) || import_typescript12.default.isStringLiteralLike(node)) && /^(?:tool_calls|toolCalls|tool_use|tool_result|tool_results|toolResults)$/.test(node.text)) {
|
|
27591
|
+
scope.hasTools = true;
|
|
27592
|
+
scope.toolFeedback = true;
|
|
27593
|
+
}
|
|
27594
|
+
if (import_typescript12.default.isObjectLiteralExpression(node)) {
|
|
27595
|
+
const fields = new Map(node.properties.filter(import_typescript12.default.isPropertyAssignment).map((p2) => [nameOf(p2.name), p2.initializer]));
|
|
27596
|
+
const type = fields.get("type");
|
|
27597
|
+
if (type && import_typescript12.default.isStringLiteralLike(type) && type.text === "tool" && fields.has("name"))
|
|
27598
|
+
scope.forcedOutput = true;
|
|
27599
|
+
}
|
|
27600
|
+
if (import_typescript12.default.isCallExpression(node) || import_typescript12.default.isNewExpression(node)) {
|
|
27601
|
+
const callee = node.expression.getText();
|
|
27602
|
+
if (/(?:chat\.)?completions\.create$|messages\.(?:create|stream)$|responses\.(?:create|stream)$/.test(callee))
|
|
27603
|
+
markModel(scope, node);
|
|
27604
|
+
if (/\.runTurn$/.test(callee) && scope.node.parameters.some((param) => /tools/i.test(param.name.getText())))
|
|
27605
|
+
markModel(scope, node);
|
|
27606
|
+
const connect = (at) => {
|
|
27607
|
+
for (const target of byNode.has(at) ? [byNode.get(at)] : targetsOf(at, scope.file)) {
|
|
27608
|
+
if (import_typescript12.default.isPropertyAccessExpression(at) && at.expression.kind === import_typescript12.default.SyntaxKind.ThisKeyword) {
|
|
27609
|
+
virtualEdges.set(`${scope.key}|${target.key}`, at.name.text);
|
|
27610
|
+
scope.virtualCalls.set(target.key, at.name.text);
|
|
27611
|
+
}
|
|
27612
|
+
scope.calls.add(target.key);
|
|
27613
|
+
if (deployed(at))
|
|
27614
|
+
scope.deployedCalls.add(target.key);
|
|
27615
|
+
for (const [worker, calls] of scope.callsByWorker)
|
|
27616
|
+
if (deployed(at, worker))
|
|
27617
|
+
calls.add(target.key);
|
|
27618
|
+
target.callers.add(scope.key);
|
|
27619
|
+
}
|
|
27620
|
+
};
|
|
27621
|
+
connect(node.expression);
|
|
27622
|
+
const connectArgument = (at) => {
|
|
27623
|
+
if (isFunctionLike(at)) {
|
|
27624
|
+
connect(at);
|
|
27625
|
+
return;
|
|
27626
|
+
}
|
|
27627
|
+
if (import_typescript12.default.isIdentifier(at) || import_typescript12.default.isPropertyAccessExpression(at))
|
|
27628
|
+
connect(at);
|
|
27629
|
+
import_typescript12.default.forEachChild(at, connectArgument);
|
|
27630
|
+
};
|
|
27631
|
+
for (const argument of node.arguments ?? [])
|
|
27632
|
+
connectArgument(argument);
|
|
27633
|
+
for (const argument of node.arguments ?? [])
|
|
27634
|
+
if (import_typescript12.default.isObjectLiteralExpression(argument)) {
|
|
27635
|
+
const fields = new Set(argument.properties.map((p2) => nameOf(p2.name)));
|
|
27636
|
+
if (fields.has("model") && fields.has("messages") && fields.has("tools")) {
|
|
27637
|
+
markModel(scope, node);
|
|
27638
|
+
scope.hasTools = true;
|
|
27639
|
+
}
|
|
27640
|
+
}
|
|
27641
|
+
if (/(?:^|\.)(?:stepCountIs|isStepCount)$/.test(node.expression.getText()) && node.arguments?.[0] && import_typescript12.default.isNumericLiteral(node.arguments?.[0]) && Number(node.arguments?.[0].text) > 1) {
|
|
27642
|
+
scope.hasLoop = true;
|
|
27643
|
+
scope.configuredSteps = true;
|
|
27644
|
+
}
|
|
27645
|
+
}
|
|
27646
|
+
if (import_typescript12.default.isPropertyAssignment(node) && nameOf(node.name) === "maxSteps" && import_typescript12.default.isNumericLiteral(node.initializer) && Number(node.initializer.text) > 1) {
|
|
27647
|
+
scope.hasLoop = true;
|
|
27648
|
+
scope.configuredSteps = true;
|
|
27649
|
+
}
|
|
27650
|
+
import_typescript12.default.forEachChild(node, inspect);
|
|
27651
|
+
};
|
|
27652
|
+
inspect(scope.node);
|
|
27653
|
+
}
|
|
27654
|
+
const modelQueue = [...scopes.values()].filter((scope) => scope.hasModel);
|
|
27655
|
+
for (let index = 0;index < modelQueue.length; index++) {
|
|
27656
|
+
const scope = modelQueue[index];
|
|
27657
|
+
if (scope.reachesModel)
|
|
27658
|
+
continue;
|
|
27659
|
+
scope.reachesModel = true;
|
|
27660
|
+
for (const caller of scope.callers) {
|
|
27661
|
+
const parent = scopes.get(caller);
|
|
27662
|
+
if (parent && !parent.reachesModel)
|
|
27663
|
+
modelQueue.push(parent);
|
|
27664
|
+
}
|
|
27665
|
+
}
|
|
27666
|
+
const agents = new Map;
|
|
27667
|
+
const owners = new Map;
|
|
27668
|
+
const assign = (key, id) => {
|
|
27669
|
+
let values = owners.get(key);
|
|
27670
|
+
if (!values)
|
|
27671
|
+
owners.set(key, values = new Set);
|
|
27672
|
+
values.add(id);
|
|
27673
|
+
};
|
|
27674
|
+
for (const cls of classes) {
|
|
27675
|
+
const emitted = agent(cls.name, cls.file, cls.node, "Concrete agent/framework class or realtime model/tool bridge", repo.status(cls.file.path));
|
|
27676
|
+
agents.set(emitted.id, emitted);
|
|
27677
|
+
}
|
|
27678
|
+
for (const scope of scopes.values()) {
|
|
27679
|
+
let nestedInFunction = false;
|
|
27680
|
+
for (let parent = scope.node.parent;parent && !import_typescript12.default.isClassLike(parent); parent = parent.parent)
|
|
27681
|
+
if (isFunctionLike(parent)) {
|
|
27682
|
+
nestedInFunction = true;
|
|
27683
|
+
break;
|
|
27684
|
+
}
|
|
27685
|
+
if (scope.className && !nestedInFunction) {
|
|
27686
|
+
let member2 = scope.node;
|
|
27687
|
+
while (member2.parent && !import_typescript12.default.isClassLike(member2.parent))
|
|
27688
|
+
member2 = member2.parent;
|
|
27689
|
+
const memberName = "name" in member2 ? nameOf(member2.name) : undefined;
|
|
27690
|
+
for (const cls of classes) {
|
|
27691
|
+
const ownerClass = enclosingClass(scope.node);
|
|
27692
|
+
const baseIndex = cls.nodes.findIndex((node) => ownerClass && keyOf(node) === keyOf(ownerClass));
|
|
27693
|
+
if (baseIndex < 0)
|
|
27694
|
+
continue;
|
|
27695
|
+
const overridden = memberName && cls.nodes.slice(0, baseIndex).some((node) => node.members.some((candidate) => nameOf(candidate.name) === memberName));
|
|
27696
|
+
if (!overridden)
|
|
27697
|
+
assign(scope.key, componentId("agent", cls.file.path, cls.name));
|
|
27698
|
+
}
|
|
27699
|
+
}
|
|
27700
|
+
if (!scope.className && !scope.forcedOutput && scope.hasLoop && scope.hasTools && (scope.toolFeedback || scope.configuredSteps) && scope.reachesModel) {
|
|
27701
|
+
let boundary = scope;
|
|
27702
|
+
for (let parent = scope.node.parent;parent; parent = parent.parent) {
|
|
27703
|
+
const outer = byNode.get(parent);
|
|
27704
|
+
if (outer?.route) {
|
|
27705
|
+
boundary = outer;
|
|
27706
|
+
break;
|
|
27707
|
+
}
|
|
27708
|
+
}
|
|
27709
|
+
const name = boundary.route ?? functionName(boundary.node);
|
|
27710
|
+
if (!name)
|
|
27711
|
+
continue;
|
|
27712
|
+
const emitted = agent(name, boundary.file, scope.node, "Function or route owns a multi-step model/tool feedback loop", repo.status(boundary.file.path));
|
|
27713
|
+
agents.set(emitted.id, emitted);
|
|
27714
|
+
assign(boundary.key, emitted.id);
|
|
27715
|
+
}
|
|
27716
|
+
}
|
|
27717
|
+
let changed = true;
|
|
27718
|
+
while (changed) {
|
|
27719
|
+
changed = false;
|
|
27720
|
+
for (const scope of scopes.values())
|
|
27721
|
+
for (const callee of scope.calls)
|
|
27722
|
+
for (const id of owners.get(scope.key) ?? []) {
|
|
27723
|
+
let targetKey = callee;
|
|
27724
|
+
const virtual = virtualEdges.get(`${scope.key}|${callee}`), concrete = classes.find((cls) => componentId("agent", cls.file.path, cls.name) === id);
|
|
27725
|
+
if (virtual && concrete) {
|
|
27726
|
+
const implementation = concrete.nodes.flatMap((node) => node.members.filter((member2) => nameOf(member2.name) === virtual))[0];
|
|
27727
|
+
if (implementation && scopes.has(keyOf(implementation)))
|
|
27728
|
+
targetKey = keyOf(implementation);
|
|
27729
|
+
}
|
|
27730
|
+
const before = owners.get(targetKey)?.size ?? 0;
|
|
27731
|
+
assign(targetKey, id);
|
|
27732
|
+
changed ||= (owners.get(targetKey)?.size ?? 0) !== before;
|
|
27733
|
+
}
|
|
27734
|
+
}
|
|
27735
|
+
const scopeOwners = new Map;
|
|
27736
|
+
const mergeAlias = (label, ids) => {
|
|
27737
|
+
let values = scopeOwners.get(label);
|
|
27738
|
+
if (!values)
|
|
27739
|
+
scopeOwners.set(label, values = new Set);
|
|
27740
|
+
for (const id of ids)
|
|
27741
|
+
values.add(id);
|
|
27742
|
+
};
|
|
27743
|
+
const classAliases = new Map;
|
|
27744
|
+
for (const cls of classes)
|
|
27745
|
+
for (const base of cls.nodes) {
|
|
27746
|
+
if (!base.name)
|
|
27747
|
+
continue;
|
|
27748
|
+
const qualified = `${base.getSourceFile().fileName.slice(ctx.rootDir.length + 1)}#${base.name.text}`;
|
|
27749
|
+
mergeAlias(qualified, [componentId("agent", cls.file.path, cls.name)]);
|
|
27750
|
+
let variants = classAliases.get(base.name.text);
|
|
27751
|
+
if (!variants)
|
|
27752
|
+
classAliases.set(base.name.text, variants = new Set);
|
|
27753
|
+
variants.add(qualified);
|
|
27754
|
+
}
|
|
27755
|
+
for (const [name, variants] of classAliases)
|
|
27756
|
+
if (variants.size === 1)
|
|
27757
|
+
mergeAlias(name, scopeOwners.get([...variants][0]) ?? []);
|
|
27758
|
+
const aliases = new Map;
|
|
27759
|
+
for (const scope of scopes.values())
|
|
27760
|
+
for (const alias of scope.aliases) {
|
|
27761
|
+
const matches = aliases.get(alias) ?? [];
|
|
27762
|
+
matches.push(scope);
|
|
27763
|
+
aliases.set(alias, matches);
|
|
27764
|
+
}
|
|
27765
|
+
for (const [alias, matches] of aliases) {
|
|
27766
|
+
const candidates = matches.map((scope) => [...owners.get(scope.key) ?? []].sort());
|
|
27767
|
+
if (candidates.every((ids) => JSON.stringify(ids) === JSON.stringify(candidates[0])))
|
|
27768
|
+
mergeAlias(alias, candidates[0]);
|
|
27769
|
+
}
|
|
27770
|
+
const output = {
|
|
27771
|
+
runtimeAgents: [...agents.values()].sort((a, b) => a.id.localeCompare(b.id)),
|
|
27772
|
+
agentForScope: (scope) => scope ? [...scopeOwners.get(scope) ?? []].sort() : [],
|
|
27773
|
+
scopes: [...scopes.values()]
|
|
27774
|
+
};
|
|
27775
|
+
enumerations.set(ctx, output);
|
|
27776
|
+
assignAgentIds(result, output.agentForScope);
|
|
27777
|
+
return output;
|
|
27778
|
+
}
|
|
27779
|
+
|
|
27780
|
+
// src/harness-extract/enumerators/workflows.ts
|
|
27781
|
+
var import_typescript13 = __toESM(require_typescript(), 1);
|
|
27782
|
+
function enumerateWorkflows(result, ctx) {
|
|
27783
|
+
const output = emptyResult();
|
|
27784
|
+
const repo = enumerationRepository(ctx);
|
|
27785
|
+
const nodeKey = (node) => `${node.getSourceFile().fileName}:${node.getStart()}`;
|
|
27786
|
+
const bindings = new Set;
|
|
27787
|
+
for (const worker of repo.workers) {
|
|
27788
|
+
const file = repo.files.find((entry) => entry.path === worker.main), checker = file && ctx.checkerFor(file.path);
|
|
27789
|
+
const module = file && checker?.getSymbolAtLocation(file.source);
|
|
27790
|
+
if (!module || !checker)
|
|
27791
|
+
continue;
|
|
27792
|
+
for (const name of worker.workflowClasses) {
|
|
27793
|
+
let exported = checker.getExportsOfModule(module).find((symbol) => symbol.name === name);
|
|
27794
|
+
if (exported && exported.flags & import_typescript13.default.SymbolFlags.Alias)
|
|
27795
|
+
exported = checker.getAliasedSymbol(exported);
|
|
27796
|
+
const declaration = exported && valueDeclaration(exported);
|
|
27797
|
+
if (declaration && import_typescript13.default.isClassDeclaration(declaration))
|
|
27798
|
+
bindings.add(nodeKey(declaration));
|
|
27799
|
+
}
|
|
27800
|
+
}
|
|
27801
|
+
const memo = createFrameworkMemo();
|
|
27802
|
+
for (const file of repo.files) {
|
|
27803
|
+
if (!/\.[cm]?[jt]sx?$/.test(file.path) || TEST_PATH4.test(file.path) || EVAL_PATH2.test(file.path))
|
|
27804
|
+
continue;
|
|
27805
|
+
visit(file.source, (node) => {
|
|
27806
|
+
if (!import_typescript13.default.isClassDeclaration(node) || !node.name || import_typescript13.default.getCombinedModifierFlags(node) & import_typescript13.default.ModifierFlags.Abstract)
|
|
27807
|
+
return;
|
|
27808
|
+
const checker = ctx.checkerFor(file.path);
|
|
27809
|
+
const base = checker ? frameworkBaseOf(node, checker, memo)?.base : undefined;
|
|
27810
|
+
const directBase = node.heritageClauses?.flatMap((h) => h.types).map((x) => x.expression.getText()) ?? [];
|
|
27811
|
+
if (!bindings.has(nodeKey(node)) && base !== "WorkflowEntrypoint" && base !== "AgentWorkflow" && !directBase.some((x) => /^(?:WorkflowEntrypoint|AgentWorkflow)$/.test(x)))
|
|
27812
|
+
return;
|
|
27813
|
+
const entry = artifact("entrypoint", node.name.text, file, node, "Concrete Workflow class or Wrangler workflow binding", repo.status(file.path));
|
|
27814
|
+
entry.id = componentId("workflow", file.path, node.name.text);
|
|
27815
|
+
if (bindings.has(nodeKey(node))) {
|
|
27816
|
+
Object.assign(entry, { componentKind: "workflow", trigger: "workflow_binding" });
|
|
27817
|
+
}
|
|
27818
|
+
output.artifacts.push(entry);
|
|
27819
|
+
});
|
|
27820
|
+
}
|
|
27821
|
+
for (const worker of repo.workers.filter((entry) => entry.cron)) {
|
|
27822
|
+
const scopes = enumerateAgents(result, ctx).scopes;
|
|
27823
|
+
const byKey = new Map(scopes.map((scope) => [scope.key, scope]));
|
|
27824
|
+
const implementations = new Map, workerClasses = new Set;
|
|
27825
|
+
const deployedCalls = (scope) => {
|
|
27826
|
+
const calls = scope.callsByWorker.get(worker.id) ?? scope.deployedCalls;
|
|
27827
|
+
const cls = enclosingClass(scope.node);
|
|
27828
|
+
if (!cls || !workerClasses.has(nodeKey(cls)))
|
|
27829
|
+
return calls;
|
|
27830
|
+
const member2 = scope.node.parent === cls ? scope.node : scope.node.parent;
|
|
27831
|
+
if (import_typescript13.default.getCombinedModifierFlags(member2) & import_typescript13.default.ModifierFlags.Static)
|
|
27832
|
+
return calls;
|
|
27833
|
+
return new Set([...calls].map((key) => {
|
|
27834
|
+
const method = scope.virtualCalls.get(key);
|
|
27835
|
+
return method && implementations.has(method) ? implementations.get(method) : key;
|
|
27836
|
+
}));
|
|
27837
|
+
};
|
|
27838
|
+
const modelScopes = new Set(scopes.filter((scope) => scope.modelWorkers.has(worker.id)).map((scope) => scope.key));
|
|
27839
|
+
const mainFile = repo.files.find((file) => file.path === worker.main), checker = mainFile && ctx.checkerFor(mainFile.path);
|
|
27840
|
+
const exportedNodes = new Set, visited = new Set;
|
|
27841
|
+
const resolveWorker = (node) => {
|
|
27842
|
+
if (!node || visited.has(node))
|
|
27843
|
+
return;
|
|
27844
|
+
visited.add(node);
|
|
27845
|
+
if (import_typescript13.default.isParenthesizedExpression(node) || import_typescript13.default.isAsExpression(node) || import_typescript13.default.isSatisfiesExpression(node) || import_typescript13.default.isNonNullExpression(node)) {
|
|
27846
|
+
resolveWorker(node.expression);
|
|
27847
|
+
return;
|
|
27848
|
+
}
|
|
27849
|
+
if (import_typescript13.default.isCallExpression(node) && /(?:^|\.)withSentry$/.test(node.expression.getText())) {
|
|
27850
|
+
for (const argument of node.arguments)
|
|
27851
|
+
resolveWorker(argument);
|
|
27852
|
+
return;
|
|
27853
|
+
}
|
|
27854
|
+
if (import_typescript13.default.isExportAssignment(node)) {
|
|
27855
|
+
resolveWorker(node.expression);
|
|
27856
|
+
return;
|
|
27857
|
+
}
|
|
27858
|
+
if (import_typescript13.default.isVariableDeclaration(node)) {
|
|
27859
|
+
resolveWorker(node.initializer);
|
|
27860
|
+
return;
|
|
27861
|
+
}
|
|
27862
|
+
if (import_typescript13.default.isIdentifier(node) && checker) {
|
|
27863
|
+
resolveWorker(valueDeclaration(resolvedSymbol(node, checker)));
|
|
27864
|
+
return;
|
|
27865
|
+
}
|
|
27866
|
+
exportedNodes.add(node);
|
|
27867
|
+
};
|
|
27868
|
+
const module = mainFile && checker?.getSymbolAtLocation(mainFile.source);
|
|
27869
|
+
const exported = module && checker?.getExportsOfModule(module).find((symbol2) => symbol2.name === "default");
|
|
27870
|
+
const symbol = exported && checker && (exported.flags & import_typescript13.default.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported);
|
|
27871
|
+
resolveWorker(symbol && valueDeclaration(symbol));
|
|
27872
|
+
const collectImplementations = (node) => {
|
|
27873
|
+
if (!import_typescript13.default.isClassLike(node) || workerClasses.has(nodeKey(node)))
|
|
27874
|
+
return;
|
|
27875
|
+
workerClasses.add(nodeKey(node));
|
|
27876
|
+
for (const member2 of node.members) {
|
|
27877
|
+
if (import_typescript13.default.getCombinedModifierFlags(member2) & import_typescript13.default.ModifierFlags.Static)
|
|
27878
|
+
continue;
|
|
27879
|
+
const name = nameOf(member2.name);
|
|
27880
|
+
const implementation = byKey.get(nodeKey(member2)) ?? (import_typescript13.default.isPropertyDeclaration(member2) && member2.initializer ? byKey.get(nodeKey(member2.initializer)) : undefined);
|
|
27881
|
+
if (name && !implementations.has(name))
|
|
27882
|
+
implementations.set(name, implementation?.key ?? "(non-callable override)");
|
|
27883
|
+
}
|
|
27884
|
+
if (checker)
|
|
27885
|
+
for (const base of node.heritageClauses?.flatMap((clause) => clause.types) ?? []) {
|
|
27886
|
+
const declaration = valueDeclaration(resolvedSymbol(base.expression, checker));
|
|
27887
|
+
if (declaration)
|
|
27888
|
+
collectImplementations(declaration);
|
|
27889
|
+
}
|
|
27890
|
+
};
|
|
27891
|
+
for (const node of exportedNodes)
|
|
27892
|
+
collectImplementations(node);
|
|
27893
|
+
let changed = true;
|
|
27894
|
+
while (changed) {
|
|
27895
|
+
changed = false;
|
|
27896
|
+
for (const scope of scopes)
|
|
27897
|
+
if (!modelScopes.has(scope.key) && [...deployedCalls(scope)].some((key) => modelScopes.has(key))) {
|
|
27898
|
+
modelScopes.add(scope.key);
|
|
27899
|
+
changed = true;
|
|
27900
|
+
}
|
|
27901
|
+
}
|
|
27902
|
+
const scheduledNodes = new Set;
|
|
27903
|
+
const resolveScheduled = (node, seen2 = new Set) => {
|
|
27904
|
+
if (!node || seen2.has(node))
|
|
27905
|
+
return;
|
|
27906
|
+
seen2.add(node);
|
|
27907
|
+
if (import_typescript13.default.isIdentifier(node) && checker) {
|
|
27908
|
+
resolveScheduled(valueDeclaration(resolvedSymbol(node, checker)), seen2);
|
|
27909
|
+
return;
|
|
27910
|
+
}
|
|
27911
|
+
if (import_typescript13.default.isVariableDeclaration(node) || import_typescript13.default.isPropertyAssignment(node) || import_typescript13.default.isPropertyDeclaration(node)) {
|
|
27912
|
+
resolveScheduled(node.initializer, seen2);
|
|
27913
|
+
return;
|
|
27914
|
+
}
|
|
27915
|
+
if (import_typescript13.default.isShorthandPropertyAssignment(node)) {
|
|
27916
|
+
resolveScheduled(checker && valueDeclaration(checker.getShorthandAssignmentValueSymbol(node)), seen2);
|
|
27917
|
+
return;
|
|
27918
|
+
}
|
|
27919
|
+
if (import_typescript13.default.isParenthesizedExpression(node) || import_typescript13.default.isAsExpression(node) || import_typescript13.default.isSatisfiesExpression(node) || import_typescript13.default.isNonNullExpression(node)) {
|
|
27920
|
+
resolveScheduled(node.expression, seen2);
|
|
27921
|
+
return;
|
|
27922
|
+
}
|
|
27923
|
+
scheduledNodes.add(node);
|
|
27924
|
+
};
|
|
27925
|
+
const collectScheduled = (node, seen2 = new Set) => {
|
|
27926
|
+
if (seen2.has(node))
|
|
27927
|
+
return;
|
|
27928
|
+
seen2.add(node);
|
|
27929
|
+
const members = import_typescript13.default.isObjectLiteralExpression(node) ? node.properties : import_typescript13.default.isClassLike(node) ? node.members : [];
|
|
27930
|
+
const handlers = members.filter((member2) => nameOf(member2.name) === "scheduled" && !(import_typescript13.default.getCombinedModifierFlags(member2) & import_typescript13.default.ModifierFlags.Static));
|
|
27931
|
+
for (const member2 of handlers)
|
|
27932
|
+
resolveScheduled(member2);
|
|
27933
|
+
if (!handlers.length && import_typescript13.default.isClassLike(node) && checker)
|
|
27934
|
+
for (const base of node.heritageClauses?.flatMap((clause) => clause.types) ?? []) {
|
|
27935
|
+
const declaration = valueDeclaration(resolvedSymbol(base.expression, checker));
|
|
27936
|
+
if (declaration)
|
|
27937
|
+
collectScheduled(declaration, seen2);
|
|
27938
|
+
}
|
|
27939
|
+
};
|
|
27940
|
+
for (const node of exportedNodes)
|
|
27941
|
+
collectScheduled(node);
|
|
27942
|
+
const roots = scopes.filter((scope) => [...scheduledNodes].some((node) => node.getSourceFile().fileName === scope.node.getSourceFile().fileName && node.getStart() === scope.node.getStart()));
|
|
27943
|
+
const seen = new Set;
|
|
27944
|
+
const queue = roots.flatMap((scope) => scope.modelWorkers.has(worker.id) ? [scope.key] : [...deployedCalls(scope)]);
|
|
27945
|
+
for (let i = 0;i < queue.length; i++) {
|
|
27946
|
+
const key = queue[i];
|
|
27947
|
+
if (seen.has(key))
|
|
27948
|
+
continue;
|
|
27949
|
+
seen.add(key);
|
|
27950
|
+
const scope = byKey.get(key);
|
|
27951
|
+
if (!scope)
|
|
27952
|
+
continue;
|
|
27953
|
+
if (!modelScopes.has(scope.key)) {
|
|
27954
|
+
if (/(?:Cron|Pipeline)$/.test(scope.label)) {
|
|
27955
|
+
const entry = artifact("entrypoint", scope.label, scope.file, scope.node, "Scheduled entrypoint has no deployed model step on its own pipeline", repo.status(scope.file.path));
|
|
27956
|
+
const proof = [...scope.calls].map((callee) => byKey.get(callee)).filter((callee) => callee?.reachesModel).map((callee) => `${callee.file.path}#${callee.label}`);
|
|
27957
|
+
Object.assign(entry, { exclusionReason: scope.reachesModel ? "Model reachable only through a queue consumer or statically excluded fallback" : "No model reachable from scheduled pipeline", proofPath: [`${scope.file.path}#${scope.label}`, ...proof] });
|
|
27958
|
+
output.artifacts.push(entry);
|
|
27959
|
+
} else
|
|
27960
|
+
queue.push(...deployedCalls(scope));
|
|
27961
|
+
continue;
|
|
27962
|
+
}
|
|
27963
|
+
if (/(?:Cron|Pipeline)$/.test(scope.label) || scope.modelWorkers.has(worker.id)) {
|
|
27964
|
+
const entry = artifact("entrypoint", scope.label, scope.file, scope.node, "Cron dispatch reaches this model-backed pipeline", repo.status(scope.file.path));
|
|
27965
|
+
entry.id = componentId("workflow", scope.file.path, scope.label);
|
|
27966
|
+
entry.componentKind = "workflow";
|
|
27967
|
+
entry.trigger = "cron";
|
|
27968
|
+
output.artifacts.push(entry);
|
|
27969
|
+
if (roots.includes(scope))
|
|
27970
|
+
queue.push(...deployedCalls(scope));
|
|
27971
|
+
} else
|
|
27972
|
+
queue.push(...deployedCalls(scope));
|
|
27973
|
+
}
|
|
27974
|
+
}
|
|
27975
|
+
return stableResult(output);
|
|
27976
|
+
}
|
|
27977
|
+
|
|
27978
|
+
// src/harness-extract/enumerators/catalog.ts
|
|
27979
|
+
var import_typescript14 = __toESM(require_typescript(), 1);
|
|
27980
|
+
var THINK_WORKSPACE_TOOLS = ["read", "write", "edit", "list", "find", "grep", "delete"];
|
|
27981
|
+
function strings(expression, checker, seen = new Set) {
|
|
27982
|
+
if (!expression)
|
|
27983
|
+
return [];
|
|
27984
|
+
const node = unwrap(expression);
|
|
27985
|
+
if (seen.has(node))
|
|
27986
|
+
return [];
|
|
27987
|
+
seen.add(node);
|
|
27988
|
+
if (import_typescript14.default.isIdentifier(node)) {
|
|
27989
|
+
const declaration = checker && valueDeclaration(resolvedSymbol(node, checker));
|
|
27990
|
+
if (!declaration || !import_typescript14.default.isVariableDeclaration(declaration))
|
|
27991
|
+
return [];
|
|
27992
|
+
return strings(declaration.initializer, checker, seen);
|
|
27993
|
+
}
|
|
27994
|
+
if (import_typescript14.default.isArrayLiteralExpression(node))
|
|
27995
|
+
return node.elements.flatMap((entry) => import_typescript14.default.isSpreadElement(entry) ? strings(entry.expression, checker, seen) : strings(entry, checker, seen));
|
|
27996
|
+
if (import_typescript14.default.isStringLiteralLike(node))
|
|
27997
|
+
return [{ name: node.text, node }];
|
|
27998
|
+
if (import_typescript14.default.isNewExpression(node) && node.expression.getText() === "Set")
|
|
27999
|
+
return strings(node.arguments?.[0], checker, seen);
|
|
28000
|
+
return [];
|
|
28001
|
+
}
|
|
28002
|
+
function property(object, name) {
|
|
28003
|
+
const entry = object.properties.find((item) => item.name && nameOf(item.name) === name);
|
|
28004
|
+
return entry && import_typescript14.default.isPropertyAssignment(entry) ? entry.initializer : entry && import_typescript14.default.isShorthandPropertyAssignment(entry) ? entry.name : undefined;
|
|
28005
|
+
}
|
|
28006
|
+
function inheritedTrue(node, propertyName2, checker, seen = new Set) {
|
|
28007
|
+
if (seen.has(node))
|
|
28008
|
+
return false;
|
|
28009
|
+
seen.add(node);
|
|
28010
|
+
const own = node.members.find((member2) => nameOf(member2.name) === propertyName2);
|
|
28011
|
+
if (own && import_typescript14.default.isPropertyDeclaration(own) && own.initializer)
|
|
28012
|
+
return unwrap(own.initializer).kind === import_typescript14.default.SyntaxKind.TrueKeyword;
|
|
28013
|
+
if (checker)
|
|
28014
|
+
for (const base of node.heritageClauses?.flatMap((h) => h.types) ?? []) {
|
|
28015
|
+
const declaration = valueDeclaration(resolvedSymbol(base.expression, checker));
|
|
28016
|
+
if (declaration && (import_typescript14.default.isClassDeclaration(declaration) || import_typescript14.default.isClassExpression(declaration)))
|
|
28017
|
+
return inheritedTrue(declaration, propertyName2, checker, seen);
|
|
28018
|
+
}
|
|
28019
|
+
return false;
|
|
28020
|
+
}
|
|
28021
|
+
function enumerateToolCatalog(result, ctx) {
|
|
28022
|
+
const output = emptyResult(), repo = enumerationRepository(ctx), agents = enumerateAgents(result, ctx);
|
|
28023
|
+
const agentByName = new Map(agents.runtimeAgents.map((entry) => [entry.name, entry.id]));
|
|
28024
|
+
const symbolOwners = new Map;
|
|
28025
|
+
for (const scope of agents.scopes) {
|
|
28026
|
+
const owners = agents.agentForScope(scope.key);
|
|
28027
|
+
const checker = ctx.checkerFor(scope.file.path);
|
|
28028
|
+
if (!owners.length || !checker)
|
|
28029
|
+
continue;
|
|
28030
|
+
visit(scope.node, (node) => {
|
|
28031
|
+
if (!import_typescript14.default.isIdentifier(node) || !/ALLOW|MCP_NAME/.test(node.text))
|
|
28032
|
+
return;
|
|
28033
|
+
const declaration = valueDeclaration(resolvedSymbol(node, checker));
|
|
28034
|
+
if (!declaration || !import_typescript14.default.isVariableDeclaration(declaration) || !import_typescript14.default.isIdentifier(declaration.name))
|
|
28035
|
+
return;
|
|
28036
|
+
const key = `${declaration.getSourceFile().fileName}:${declaration.name.text}`;
|
|
28037
|
+
let existing = symbolOwners.get(key);
|
|
28038
|
+
if (!existing)
|
|
28039
|
+
symbolOwners.set(key, existing = new Set);
|
|
28040
|
+
for (const id of owners)
|
|
28041
|
+
existing.add(id);
|
|
28042
|
+
});
|
|
28043
|
+
}
|
|
28044
|
+
const ownersAt = (node, path) => {
|
|
28045
|
+
const scope = agents.scopes.filter((s) => s.file.path === path && s.node.getStart() <= node.getStart() && s.node.getEnd() >= node.getEnd()).sort((a, b) => a.node.getWidth() - b.node.getWidth())[0];
|
|
28046
|
+
return scope ? agents.agentForScope(scope.key) : [];
|
|
28047
|
+
};
|
|
28048
|
+
const memo = createFrameworkMemo();
|
|
28049
|
+
const thinkIds = new Set;
|
|
28050
|
+
for (const runtime of agents.runtimeAgents) {
|
|
28051
|
+
const file = repo.files.find((entry) => entry.path === runtime.evidence[0]?.path), checker = file && ctx.checkerFor(file.path);
|
|
28052
|
+
if (!file || !checker)
|
|
28053
|
+
continue;
|
|
28054
|
+
visit(file.source, (node) => {
|
|
28055
|
+
if ((import_typescript14.default.isClassDeclaration(node) || import_typescript14.default.isClassExpression(node)) && node.name?.text === runtime.name && frameworkBaseOf(node, checker, memo)?.base === "Think")
|
|
28056
|
+
thinkIds.add(runtime.id);
|
|
28057
|
+
});
|
|
28058
|
+
}
|
|
28059
|
+
const add = (name, file, node, source, reason, owners = []) => {
|
|
28060
|
+
const evidenceFile = repo.files.find((entry2) => entry2.source.fileName === node.getSourceFile().fileName) ?? file;
|
|
28061
|
+
const entry = artifact("tool", name, evidenceFile, node, reason, repo.status(file.path));
|
|
28062
|
+
entry.catalogSource = source;
|
|
28063
|
+
entry.usedByAgentIds = owners;
|
|
28064
|
+
output.artifacts.push(entry);
|
|
28065
|
+
return entry;
|
|
28066
|
+
};
|
|
28067
|
+
for (const file of repo.files) {
|
|
28068
|
+
if (!/\.[cm]?[jt]sx?$/.test(file.path) || TEST_PATH4.test(file.path) || EVAL_PATH2.test(file.path) || /^scripts\//.test(file.path) && !repo.deployedFiles.has(file.path))
|
|
28069
|
+
continue;
|
|
28070
|
+
const checker = ctx.checkerFor(file.path), declarations = new Map;
|
|
28071
|
+
visit(file.source, (node) => {
|
|
28072
|
+
if (import_typescript14.default.isVariableDeclaration(node) && import_typescript14.default.isIdentifier(node.name) && node.initializer)
|
|
28073
|
+
declarations.set(node.name.text, node.initializer);
|
|
28074
|
+
});
|
|
28075
|
+
visit(file.source, (node) => {
|
|
28076
|
+
if ((import_typescript14.default.isClassDeclaration(node) || import_typescript14.default.isClassExpression(node)) && node.name && agentByName.has(node.name.text)) {
|
|
28077
|
+
const info = checker ? frameworkBaseOf(node, checker, memo) : undefined;
|
|
28078
|
+
const directThink = node.heritageClauses?.some((h) => h.types.some((t) => t.expression.getText() === "Think"));
|
|
28079
|
+
if (info?.base === "Think" || directThink) {
|
|
28080
|
+
const owners2 = agents.agentForScope(`${file.path}#${node.name.text}`);
|
|
28081
|
+
const names = [...THINK_WORKSPACE_TOOLS];
|
|
28082
|
+
if (inheritedTrue(node, "workspaceBash", checker))
|
|
28083
|
+
names.push("bash");
|
|
28084
|
+
for (const name of names)
|
|
28085
|
+
add(name, file, node, "think", "Think workspace tool inherited by this concrete agent", owners2);
|
|
28086
|
+
}
|
|
28087
|
+
}
|
|
28088
|
+
if (import_typescript14.default.isPropertyAccessExpression(node) && node.name.text === "activate_skill" || import_typescript14.default.isPropertyAssignment(node) && nameOf(node.name) === "activate_skill") {
|
|
28089
|
+
const owner = ownersAt(node, file.path);
|
|
28090
|
+
add("activate_skill", file, node, "think", "Source explicitly exposes Think skill activation", owner);
|
|
28091
|
+
}
|
|
28092
|
+
if (import_typescript14.default.isCallExpression(node) && import_typescript14.default.isPropertyAccessExpression(node.expression) && /^(?:registerTool|tool)$/.test(node.expression.name.text) && checker) {
|
|
28093
|
+
const receiver = valueDeclaration(resolvedSymbol(node.expression.expression, checker));
|
|
28094
|
+
const init = receiver && import_typescript14.default.isVariableDeclaration(receiver) && receiver.initializer ? unwrap(receiver.initializer) : undefined;
|
|
28095
|
+
const origin = init && import_typescript14.default.isNewExpression(init) && import_typescript14.default.isIdentifier(init.expression) ? importOrigin(init.expression, checker) : undefined;
|
|
28096
|
+
const name = node.arguments[0];
|
|
28097
|
+
if (origin?.module.startsWith("@modelcontextprotocol/sdk/") && origin.imported === "McpServer" && name && import_typescript14.default.isStringLiteralLike(name)) {
|
|
28098
|
+
add(name.text, file, name, "mcp_server", "MCP SDK server explicitly registers this model-facing tool name", ownersAt(node, file.path));
|
|
28099
|
+
}
|
|
28100
|
+
}
|
|
28101
|
+
if (import_typescript14.default.isCallExpression(node) && import_typescript14.default.isPropertyAccessExpression(node.expression) && node.expression.expression.getText() === "Output" && node.expression.name.text === "object") {
|
|
28102
|
+
const owners2 = ownersAt(node, file.path).filter((id) => thinkIds.has(id));
|
|
28103
|
+
if (owners2.length && checker && import_typescript14.default.isIdentifier(node.expression.expression) && ["ai", "@cloudflare/think"].includes(importOrigin(node.expression.expression, checker)?.module ?? ""))
|
|
28104
|
+
add("think_final_answer", file, node, "think", "Think structured output is offered as the framework final-answer tool", owners2);
|
|
28105
|
+
}
|
|
28106
|
+
if (import_typescript14.default.isCallExpression(node) && import_typescript14.default.isIdentifier(node.expression) && node.expression.text === "createExecuteRuntime") {
|
|
28107
|
+
const owners2 = ownersAt(node, file.path).filter((id) => thinkIds.has(id));
|
|
28108
|
+
if (owners2.length && checker && importOrigin(node.expression, checker)?.module.startsWith("@cloudflare/think"))
|
|
28109
|
+
add("execute", file, node, "think", "Think Code Mode runtime explicitly enabled for this agent", owners2);
|
|
28110
|
+
}
|
|
28111
|
+
if (!import_typescript14.default.isObjectLiteralExpression(node))
|
|
28112
|
+
return;
|
|
28113
|
+
const serverNames = strings(property(node, "name"), checker), allow = property(node, "allow");
|
|
28114
|
+
if (serverNames.length !== 1 || !allow || !property(node, "url"))
|
|
28115
|
+
return;
|
|
28116
|
+
const server = serverNames[0].name;
|
|
28117
|
+
const owners = ownersAt(node, file.path);
|
|
28118
|
+
if (import_typescript14.default.isStringLiteralLike(unwrap(allow)) && unwrap(allow).text === "all") {
|
|
28119
|
+
const entry = add(`${server} dynamic MCP tools`, file, allow, "mcp_dynamic_group", "Server schemas are admitted dynamically as one bounded catalog group", owners);
|
|
28120
|
+
entry.serverName = server;
|
|
28121
|
+
entry.dynamicGroup = true;
|
|
28122
|
+
entry.namePattern = `tool_<${server}ServerId>_*`;
|
|
28123
|
+
return;
|
|
28124
|
+
}
|
|
28125
|
+
for (const tool of strings(allow, checker)) {
|
|
28126
|
+
const name = `tool_<${server}ServerIdNoDashes>_${tool.name}`;
|
|
28127
|
+
const entry = add(name, file, tool.node, "mcp_allowlist", "Literal MCP allowlist converted by the Agents SDK tool_<serverId>_<name> contract", owners);
|
|
28128
|
+
entry.id = componentId("tool", file.path, `${server}:${name}`);
|
|
28129
|
+
entry.serverName = server;
|
|
28130
|
+
entry.namePattern = name;
|
|
28131
|
+
}
|
|
28132
|
+
});
|
|
28133
|
+
for (const [name, initializer] of declarations) {
|
|
28134
|
+
const match = name.match(/^(.*)_ALLOWED_TOOLS$/);
|
|
28135
|
+
if (!match)
|
|
28136
|
+
continue;
|
|
28137
|
+
const serverName = strings(declarations.get(`${match[1]}_MCP_NAME`), checker)[0]?.name;
|
|
28138
|
+
if (!serverName)
|
|
28139
|
+
continue;
|
|
28140
|
+
for (const tool of strings(initializer, checker)) {
|
|
28141
|
+
const entry = add(`${serverName}_${tool.name}`, file, tool.node, "mcp_allowlist", "Explicit named MCP allowlist with server-prefixed model name");
|
|
28142
|
+
entry.serverName = serverName;
|
|
28143
|
+
entry.usedByAgentIds = [...symbolOwners.get(`${file.source.fileName}:${name}`) ?? []].sort();
|
|
28144
|
+
}
|
|
28145
|
+
}
|
|
28146
|
+
}
|
|
28147
|
+
const merged = new Map;
|
|
28148
|
+
for (const item of output.artifacts) {
|
|
28149
|
+
const previous = merged.get(item.name);
|
|
28150
|
+
if (previous) {
|
|
28151
|
+
previous.usedByAgentIds = [...new Set([...previous.usedByAgentIds, ...item.usedByAgentIds])].sort();
|
|
28152
|
+
const seen = new Set(previous.evidence.map((e) => `${e.path}:${e.line}`));
|
|
28153
|
+
previous.evidence.push(...item.evidence.filter((e) => !seen.has(`${e.path}:${e.line}`)));
|
|
28154
|
+
if (item.status === "in_prod" || item.status === "reachable" && previous.status === "defined_only")
|
|
28155
|
+
previous.status = item.status;
|
|
28156
|
+
} else {
|
|
28157
|
+
item.id = `tool:catalog:${item.name}`;
|
|
28158
|
+
merged.set(item.name, item);
|
|
28159
|
+
}
|
|
28160
|
+
}
|
|
28161
|
+
output.artifacts = [...merged.values()];
|
|
28162
|
+
return stableResult(output);
|
|
28163
|
+
}
|
|
28164
|
+
|
|
28165
|
+
// src/harness-extract/enumerators/index.ts
|
|
28166
|
+
var ENUMERATORS = [
|
|
28167
|
+
{ id: "agents", enumerate: ({ result }, ctx) => ({ runtimeAgents: enumerateAgents(result, ctx).runtimeAgents }) },
|
|
28168
|
+
{ id: "workflows", enumerate: ({ result }, ctx) => enumerateWorkflows(result, ctx) },
|
|
28169
|
+
{ id: "framework-mcp-catalog", enumerate: ({ result }, ctx) => enumerateToolCatalog(result, ctx) }
|
|
28170
|
+
];
|
|
28171
|
+
function enumerateHarnessComponents(result, ctx) {
|
|
28172
|
+
const agents = enumerateAgents(result, ctx), workflows = enumerateWorkflows(result, ctx), catalog = enumerateToolCatalog(result, ctx);
|
|
28173
|
+
return stableResult({ runtimeAgents: agents.runtimeAgents, artifacts: [...workflows.artifacts, ...catalog.artifacts], warnings: [...workflows.warnings, ...catalog.warnings] });
|
|
28174
|
+
}
|
|
28175
|
+
function mergeEnumeratedComponents(artifacts, components) {
|
|
28176
|
+
const merged = new Map;
|
|
28177
|
+
const definitions = new Map;
|
|
28178
|
+
for (const item of [...artifacts, ...components.artifacts]) {
|
|
28179
|
+
const key = item.type === "tool" ? `tool:${item.name}` : item.id;
|
|
28180
|
+
if (item.type === "tool" && item.body) {
|
|
28181
|
+
let variants = definitions.get(key);
|
|
28182
|
+
if (!variants)
|
|
28183
|
+
definitions.set(key, variants = []);
|
|
28184
|
+
if (!variants.some((entry) => entry.id === item.id && entry.body === item.body))
|
|
28185
|
+
variants.push({ id: item.id, sourcePath: item.sourcePath, body: item.body, evidence: [...item.evidence], usedByAgentIds: [...item.usedByAgentIds] });
|
|
28186
|
+
}
|
|
28187
|
+
const previous = merged.get(key);
|
|
28188
|
+
if (!previous) {
|
|
28189
|
+
merged.set(key, { ...item, evidence: [...item.evidence], usedByAgentIds: [...item.usedByAgentIds] });
|
|
28190
|
+
continue;
|
|
28191
|
+
}
|
|
28192
|
+
const rank = { defined_only: 0, reachable: 1, in_prod: 2 };
|
|
28193
|
+
if (item.status && (!previous.status || rank[item.status] > rank[previous.status]))
|
|
28194
|
+
previous.status = item.status;
|
|
28195
|
+
previous.usedByAgentIds = [...new Set([...previous.usedByAgentIds, ...item.usedByAgentIds])].sort();
|
|
28196
|
+
const evidence = new Set(previous.evidence.map((entry) => `${entry.path}:${entry.line}`));
|
|
28197
|
+
previous.evidence.push(...item.evidence.filter((entry) => !evidence.has(`${entry.path}:${entry.line}`)));
|
|
28198
|
+
if (!previous.body && item.body && !previous.definitionVariants)
|
|
28199
|
+
previous.body = item.body;
|
|
28200
|
+
}
|
|
28201
|
+
for (const [key, variants] of definitions) {
|
|
28202
|
+
const item = merged.get(key);
|
|
28203
|
+
if (variants.length > 1 || item.id !== variants[0].id)
|
|
28204
|
+
item.definitionVariants = variants;
|
|
28205
|
+
if (new Set(variants.map((entry) => entry.body)).size > 1)
|
|
28206
|
+
delete item.body;
|
|
28207
|
+
}
|
|
28208
|
+
const output = [...merged.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
28209
|
+
const runtimeAgents = components.runtimeAgents.map((entry) => ({
|
|
28210
|
+
...entry,
|
|
28211
|
+
artifactIds: [...new Set([...entry.artifactIds, ...output.filter((item) => item.usedByAgentIds.includes(entry.id)).map((item) => item.id)])].sort()
|
|
28212
|
+
}));
|
|
28213
|
+
return { runtimeAgents, artifacts: output };
|
|
28214
|
+
}
|
|
28215
|
+
|
|
28216
|
+
export { startRemoteAnalyze, pollRemoteAnalyzeUntilDone, isRecoverableRemoteRun, checkPromptMapping, safePromptEvidencePath, discoverHarnessPromptSources, valueChildren, selectKey, allValues, renderings, CALL_SINKS, registerCallSink, registerClassSink, isModelId, collectModels, modelArtifacts, modelUnknowns, collectModelLiterals, EXTRACT_SCHEMA_VERSION, agentForScope, createAgentScopeResolver, enumerateAgents, enumerateWorkflows, enumerateToolCatalog, ENUMERATORS, enumerateHarnessComponents, mergeEnumeratedComponents, toolNamesOf, clearExtractCache, extractHarness, extractHarnessWithContext, serializeExtractResult, runEnumerators, assignAgentIds, runHarnessCommand, writeHarnessAnalyzeResult, emitWrittenArtifacts, analyzeHarnessPrompts, isToolGroupPlaceholder, repairExternalAnalystReport, deriveRelationshipsFromGraph, deterministicArtifacts, deterministicGraphItems, mergeDeterministicArtifacts, analystRefutations, describeCodingAgentEvent, analystEventProgress, isRetryableExternalAnalystFailure, sleep, summarizeInvalidAnalystReport, isDeterministicLocalAnalyst, resolveHarnessAnalyzeConcern, resolveExternalHarnessAnalystInvocation, detectAvailableCodingAgents, codingAgentDisplayName, runCodingAgent, readOnlyClaudeExtraArgs, resolveAnalystModel, renderExternalHarnessAnalystPrompt, CONCERN_CANDIDATE_KINDS, SEED_CANDIDATE_KIND_LABELS, renderAnalystCandidateLines, renderAnalystSeedLines, truncateText, scanHarness, summarizeHarness, buildSourceSnapshot, writeHumanProgress, describeSyncIdentity, describeSyncTenantLabel, findFresherHarnessReports, writeHarnessArtifacts, assertHarnessGraphSyncQuality, graphForSync, inventoryFiles, numericEnv, numericEnvAllowZero, computeDeterministicFloor, stableId, titleFromId, promptNameFromPath };
|