@moda-ai/cli 1.55.72 → 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-xesfknb0.js → agent-nqykfqm0.js} +6 -6
- package/dist/{cli-gqkvypxh.js → cli-4bmxk8z9.js} +7 -7
- package/dist/{cli-ge6ty4hx.js → cli-h5ar0v9v.js} +1012 -41
- package/dist/{cli-9ww72mrd.js → cli-y333w08f.js} +1 -1
- package/dist/{cli-9dwq3vyj.js → cli-zyg6v6vq.js} +2 -2
- package/dist/cli.js +20 -20
- package/dist/{doctor-z29f8x00.js → doctor-180rzz99.js} +4 -4
- package/dist/{harness-qvszhbrt.js → harness-defgbftj.js} +4 -4
- package/dist/{harness-github-actions-awcd5ns1.js → harness-github-actions-p4011crc.js} +4 -4
- package/dist/{harness-report-3n7bg314.js → harness-report-1q7322xg.js} +1 -1
- package/dist/{index-tpwztst3.js → index-4z7h9mam.js} +4 -4
- package/dist/{index-badpwfw2.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-t62yzfxb.js → prompt-attribution-1s253fra.js} +4 -4
- package/dist/prompt-source-mcp.js +4 -4
- package/dist/{prompts-x74bqatj.js → prompts-gmdscxhk.js} +3 -3
- package/dist/{skills-pqhvfc1r.js → skills-knpeqryb.js} +3 -3
- package/dist/{sync-kbhbrksr.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";
|
|
@@ -9140,7 +9146,7 @@ function isUnder2(path, root) {
|
|
|
9140
9146
|
return true;
|
|
9141
9147
|
return path === root || path.startsWith(`${root}/`);
|
|
9142
9148
|
}
|
|
9143
|
-
function
|
|
9149
|
+
function stripJsonc2(text) {
|
|
9144
9150
|
let out = "";
|
|
9145
9151
|
let i = 0;
|
|
9146
9152
|
let inString = false;
|
|
@@ -9184,7 +9190,7 @@ function stripJsonc(text) {
|
|
|
9184
9190
|
}
|
|
9185
9191
|
function parseJsonLoose(text) {
|
|
9186
9192
|
try {
|
|
9187
|
-
return JSON.parse(
|
|
9193
|
+
return JSON.parse(stripJsonc2(text));
|
|
9188
9194
|
} catch {
|
|
9189
9195
|
return;
|
|
9190
9196
|
}
|
|
@@ -19031,7 +19037,7 @@ async function runHarnessCommand(context) {
|
|
|
19031
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.");
|
|
19032
19038
|
}
|
|
19033
19039
|
if (context.flags["github-actions"] === "true") {
|
|
19034
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
19040
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-p4011crc.js");
|
|
19035
19041
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
19036
19042
|
writeReport: (report2) => {
|
|
19037
19043
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -19177,7 +19183,15 @@ async function runHarnessCommand(context) {
|
|
|
19177
19183
|
}
|
|
19178
19184
|
const { artifacts, unknowns } = deterministicGraphItems(rootDir, promote === "all" ? undefined : promote);
|
|
19179
19185
|
tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
|
|
19180
|
-
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) };
|
|
19181
19195
|
const promoteWritten = [];
|
|
19182
19196
|
if (promoteOut && !context.dryRun) {
|
|
19183
19197
|
const target = resolve9(context.cwd, promoteOut);
|
|
@@ -19204,10 +19218,14 @@ async function runHarnessCommand(context) {
|
|
|
19204
19218
|
}
|
|
19205
19219
|
case "extract": {
|
|
19206
19220
|
writeHumanProgress(context, "Harness extract: tracing model call sites (no LLM, no network)...");
|
|
19207
|
-
const {
|
|
19208
|
-
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));
|
|
19209
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).`);
|
|
19210
|
-
context.output.writeData(serializeExtractResult(result), {
|
|
19228
|
+
context.output.writeData({ ...serializeExtractResult(result), graph }, {
|
|
19211
19229
|
status: result.warnings.length > 0 ? "degraded" : "success",
|
|
19212
19230
|
...result.warnings.length > 0 ? { warnings: result.warnings } : {}
|
|
19213
19231
|
});
|
|
@@ -19987,18 +20005,19 @@ function deterministicGraphItems(rootDir, concern) {
|
|
|
19987
20005
|
hydratePromptAndToolBodies(graph, rootDir);
|
|
19988
20006
|
return { artifacts: graph.artifacts, unknowns: graph.unknowns };
|
|
19989
20007
|
}
|
|
19990
|
-
var extractedModelsCache = new
|
|
20008
|
+
var extractedModelsCache = new WeakMap;
|
|
19991
20009
|
function extractedModelItems(rootDir) {
|
|
19992
20010
|
const empty = { artifacts: [], unknowns: [], rewritten: new Set, enabled: false };
|
|
19993
20011
|
if (process.env.MODA_HARNESS_EXTRACT === "0")
|
|
19994
20012
|
return empty;
|
|
19995
20013
|
const key = resolve9(rootDir);
|
|
19996
|
-
const cached = extractedModelsCache.get(key);
|
|
19997
|
-
if (cached)
|
|
19998
|
-
return cached;
|
|
19999
20014
|
let items = { ...empty, enabled: true };
|
|
20000
20015
|
try {
|
|
20001
|
-
const result =
|
|
20016
|
+
const { result, ctx } = extractHarnessWithContext(key);
|
|
20017
|
+
createAgentScopeResolver(result, ctx);
|
|
20018
|
+
const cached = extractedModelsCache.get(result);
|
|
20019
|
+
if (cached)
|
|
20020
|
+
return cached;
|
|
20002
20021
|
for (const warning of result.warnings)
|
|
20003
20022
|
process.stderr.write(`warning: harness extraction incomplete; ${warning}
|
|
20004
20023
|
`);
|
|
@@ -20008,11 +20027,11 @@ function extractedModelItems(rootDir) {
|
|
|
20008
20027
|
rewritten: new Set((result.rewrittenModels ?? []).map((entry) => normalizedModelId(entry.id))),
|
|
20009
20028
|
enabled: true
|
|
20010
20029
|
};
|
|
20030
|
+
extractedModelsCache.set(result, items);
|
|
20011
20031
|
} catch (error) {
|
|
20012
20032
|
process.stderr.write(`warning: harness extraction failed; model artifacts come from the candidate pre-pass only (${error instanceof Error ? error.message : String(error)})
|
|
20013
20033
|
`);
|
|
20014
20034
|
}
|
|
20015
|
-
extractedModelsCache.set(key, items);
|
|
20016
20035
|
return items;
|
|
20017
20036
|
}
|
|
20018
20037
|
var normalizedModelId = (name) => String(name ?? "").trim().toLowerCase();
|
|
@@ -20180,7 +20199,7 @@ function withCallSitePrompts(rootDir, promoted) {
|
|
|
20180
20199
|
const { result, ctx } = extractHarnessWithContext(rootDir);
|
|
20181
20200
|
const sites = result.callSites.filter((site) => !site.isTest);
|
|
20182
20201
|
const toolDefinitions = result.toolDefinitions ?? [];
|
|
20183
|
-
return promptArtifactsFromCallSites(sites, ctx, promoted, { toolDefinitions }).artifacts;
|
|
20202
|
+
return promptArtifactsFromCallSites(sites, ctx, promoted, { toolDefinitions, agentForScope: createAgentScopeResolver(result, ctx) }).artifacts;
|
|
20184
20203
|
} catch {
|
|
20185
20204
|
return promoted;
|
|
20186
20205
|
}
|
|
@@ -26390,25 +26409,29 @@ var REASON = {
|
|
|
26390
26409
|
config: "model id in model configuration next to a model call"
|
|
26391
26410
|
};
|
|
26392
26411
|
function modelArtifacts(result) {
|
|
26393
|
-
|
|
26394
|
-
|
|
26395
|
-
|
|
26396
|
-
|
|
26397
|
-
|
|
26398
|
-
|
|
26399
|
-
|
|
26400
|
-
|
|
26401
|
-
|
|
26402
|
-
|
|
26403
|
-
|
|
26404
|
-
|
|
26405
|
-
line:
|
|
26406
|
-
|
|
26407
|
-
|
|
26408
|
-
|
|
26409
|
-
|
|
26410
|
-
|
|
26411
|
-
|
|
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
|
+
});
|
|
26412
26435
|
}
|
|
26413
26436
|
function describeSource(source) {
|
|
26414
26437
|
const [kind, ...rest] = source.split(":");
|
|
@@ -26621,8 +26644,6 @@ function collectModelLiterals(rootDir) {
|
|
|
26621
26644
|
|
|
26622
26645
|
// src/harness-extract/types.ts
|
|
26623
26646
|
var EXTRACT_SCHEMA_VERSION = 1;
|
|
26624
|
-
// src/harness-extract/enumerators/index.ts
|
|
26625
|
-
var ENUMERATORS = [];
|
|
26626
26647
|
// src/harness-extract/tools.ts
|
|
26627
26648
|
var PASS_THROUGH2 = new Set(["ref", "call", "param", "oneOf", "lookup"]);
|
|
26628
26649
|
var DEFINITION_KEYS = new Set(["description", "input_schema", "inputSchema", "parameters", "schema", "execute", "type", "strict"]);
|
|
@@ -27242,4 +27263,954 @@ function assignAgentIds(result, agentForScope) {
|
|
|
27242
27263
|
}
|
|
27243
27264
|
}
|
|
27244
27265
|
|
|
27245
|
-
|
|
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 };
|