@moda-ai/cli 1.55.89 → 1.55.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-svqnv0b8.js → agent-a6hz6vfr.js} +9 -9
- package/dist/{cli-p5grm12t.js → cli-0semcakc.js} +184 -5
- package/dist/{cli-5ms8rw8x.js → cli-13zdcv4w.js} +1 -1
- package/dist/{cli-z1t3sf7b.js → cli-1nd4339b.js} +1 -1
- package/dist/{cli-n1406hqg.js → cli-62e1vy8f.js} +3 -3
- package/dist/{cli-22yvg5kh.js → cli-6ga6kmdp.js} +2 -2
- package/dist/{cli-6hveza1a.js → cli-8v6v3ket.js} +7 -7
- package/dist/{cli-snswkrxd.js → cli-998n4kz9.js} +1 -1
- package/dist/{cli-9p2cdy58.js → cli-aqk56bkg.js} +320 -221
- package/dist/{cli-cqmntvnv.js → cli-c9v875xv.js} +5 -5
- package/dist/{cli-87xy1evx.js → cli-dxajrq9h.js} +1 -1
- package/dist/{cli-rrggdmf8.js → cli-qwnkv4jy.js} +1 -1
- package/dist/{cli-p1rrq2sq.js → cli-t29r8b6f.js} +1 -1
- package/dist/{cli-1smcq5pf.js → cli-t8vmcbe0.js} +4 -4
- package/dist/{cli-6hpfw3vf.js → cli-wm0p9kn2.js} +2 -2
- package/dist/cli.js +22 -21
- package/dist/{doctor-xcx7nc0v.js → doctor-72qrmfe7.js} +8 -8
- package/dist/{harness-github-actions-18v41647.js → harness-github-actions-9a48sd2r.js} +7 -7
- package/dist/{harness-a55w36em.js → harness-kr06zrhh.js} +7 -7
- package/dist/{index-g3zsqcjg.js → index-5q79y09b.js} +7 -7
- package/dist/{index-rdzd700n.js → index-t4fncjwa.js} +7 -7
- package/dist/{index-zg3g49f4.js → index-vx6eysne.js} +13 -13
- package/dist/{production-intelligence-f9sd68te.js → production-intelligence-1y884f69.js} +4 -4
- package/dist/{profile-commands-1fdvrs5y.js → profile-commands-tav5q639.js} +5 -5
- package/dist/{prompt-attribution-fyas5gnw.js → prompt-attribution-1cwnp7fb.js} +7 -7
- package/dist/prompt-source-mcp.js +7 -7
- package/dist/{prompt-sources-87qsxhdt.js → prompt-sources-x5z4p7n5.js} +2 -2
- package/dist/{prompts-qzbj61ca.js → prompts-hczy41m5.js} +6 -6
- package/dist/{provision-ya3vebee.js → provision-d0sxcka1.js} +6 -6
- package/dist/{registry-c64qr7ta.js → registry-4mhr7xsd.js} +4 -4
- package/dist/{skills-knpeqryb.js → skills-hf8fa7w7.js} +6 -6
- package/dist/{sync-t8psyfc9.js → sync-e2aydwa0.js} +9 -9
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
|
@@ -40,15 +40,15 @@ import {
|
|
|
40
40
|
assertFlags,
|
|
41
41
|
assertPositionals,
|
|
42
42
|
requireTenant
|
|
43
|
-
} from "./cli-
|
|
43
|
+
} from "./cli-6ga6kmdp.js";
|
|
44
44
|
import {
|
|
45
45
|
ApiError,
|
|
46
46
|
callControlAPI
|
|
47
|
-
} from "./cli-
|
|
47
|
+
} from "./cli-dxajrq9h.js";
|
|
48
48
|
import {
|
|
49
49
|
createCommandContext,
|
|
50
50
|
stringOption
|
|
51
|
-
} from "./cli-
|
|
51
|
+
} from "./cli-13zdcv4w.js";
|
|
52
52
|
import {
|
|
53
53
|
EXIT_DEGRADED,
|
|
54
54
|
embeddedTenantIdFromApiKey,
|
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
resolveModaBaseUrl,
|
|
60
60
|
resolveTenantId,
|
|
61
61
|
shellArg
|
|
62
|
-
} from "./cli-
|
|
62
|
+
} from "./cli-1nd4339b.js";
|
|
63
63
|
import {
|
|
64
64
|
CliInputError,
|
|
65
65
|
CliInputRequiredError
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
extractPythonSource,
|
|
75
75
|
resolvePromptSource,
|
|
76
76
|
validatePromptSource
|
|
77
|
-
} from "./cli-
|
|
77
|
+
} from "./cli-t29r8b6f.js";
|
|
78
78
|
import {
|
|
79
79
|
$isMap,
|
|
80
80
|
$isNode,
|
|
@@ -91,17 +91,21 @@ import {
|
|
|
91
91
|
DEFAULT_MAX_INVENTORY_TEXT_BYTES,
|
|
92
92
|
MAX_RECORDED_SKIPS,
|
|
93
93
|
MAX_SCANNED_FILE_BYTES,
|
|
94
|
+
MAX_STORED_ARTIFACT_BODY_BYTES,
|
|
94
95
|
SKIPPED_DIRS,
|
|
96
|
+
captureFullArtifactBodies,
|
|
97
|
+
fitGraphForSync,
|
|
95
98
|
isEvalLikePath,
|
|
96
99
|
isSecretishPath,
|
|
97
100
|
isSkippedDir,
|
|
98
101
|
isSkippedPathPrefix,
|
|
99
102
|
isTextFile,
|
|
100
103
|
packSnapshot,
|
|
104
|
+
redactArtifactBody,
|
|
101
105
|
redactDeep,
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
} from "./cli-
|
|
106
|
+
shouldInventoryFile,
|
|
107
|
+
storeShortenedArtifactBodies
|
|
108
|
+
} from "./cli-0semcakc.js";
|
|
105
109
|
import {
|
|
106
110
|
CALL_SINKS,
|
|
107
111
|
CallIndex,
|
|
@@ -487,12 +491,12 @@ function buildPrograms(rootDir, options = {}) {
|
|
|
487
491
|
|
|
488
492
|
// src/harness-extract/emit-models.ts
|
|
489
493
|
var import_typescript7 = __toESM(require_typescript(), 1);
|
|
490
|
-
import { createHash as
|
|
494
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
491
495
|
import { readFileSync as readFileSync16, readdirSync as readdirSync8, statSync as statSync5 } from "node:fs";
|
|
492
496
|
import { join as join13, resolve as resolve13 } from "node:path";
|
|
493
497
|
|
|
494
498
|
// src/harness-candidate-promotion.ts
|
|
495
|
-
import { createHash as
|
|
499
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
496
500
|
import { readdirSync as readdirSync7, readFileSync as readFileSync15, statSync as statSync4 } from "node:fs";
|
|
497
501
|
import { extname as extname8, posix as posix2, resolve as resolve12 } from "node:path";
|
|
498
502
|
|
|
@@ -704,22 +708,6 @@ function readSourcePathRelativeToEvidence(artifact, rootDir) {
|
|
|
704
708
|
}
|
|
705
709
|
return;
|
|
706
710
|
}
|
|
707
|
-
var PRIVATE_KEY_BLOCK = /-----BEGIN ([A-Z ]*)PRIVATE KEY-----(?:[\s\S]*?-----END \1PRIVATE KEY-----|(?:(?:\r\n|\r|\n)[ \t]*[A-Za-z0-9+/=]+[ \t]*(?=[\r\n]|$))*)/g;
|
|
708
|
-
function maskPrivateKeyBlock(block) {
|
|
709
|
-
return block.split(/(\r\n|\r|\n)/).map((part, index) => index === 0 ? "[REDACTED PRIVATE KEY]" : index % 2 === 1 ? part : "").join("");
|
|
710
|
-
}
|
|
711
|
-
var CREDENTIAL_FIELD = /(\b(?:[A-Za-z0-9]+[_-])*(?:api[_-]?key|apikey|secret(?:[_-]?key)?|password|passwd|access[_-]?token|auth[_-]?token|refresh[_-]?token|client[_-]?secret|private[_-]?key)\b["']?\s*[:=]\s*["']?)(?![<${]|process\.env|os\.environ)([^\s"'`,;]{8,})/gi;
|
|
712
|
-
var CALL_OR_INDEX = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*[([]/;
|
|
713
|
-
var DOTTED_REFERENCE = /^[A-Za-z_$][\w$]{0,39}(?:\.[A-Za-z_$][\w$]{0,39})+$/;
|
|
714
|
-
function isCredentialReference(field, value) {
|
|
715
|
-
if (/["']$/.test(field))
|
|
716
|
-
return false;
|
|
717
|
-
return CALL_OR_INDEX.test(value) || DOTTED_REFERENCE.test(value);
|
|
718
|
-
}
|
|
719
|
-
function redactArtifactBody(body) {
|
|
720
|
-
const masked = body.replace(PRIVATE_KEY_BLOCK, maskPrivateKeyBlock).replace(CREDENTIAL_FIELD, (match, field, value) => isCredentialReference(field, value) ? match : `${field}[REDACTED]`);
|
|
721
|
-
return redactSnapshotText(masked).text;
|
|
722
|
-
}
|
|
723
711
|
function hydratePromptAndToolBodies(graph, rootDir) {
|
|
724
712
|
for (const artifact of graph.artifacts) {
|
|
725
713
|
if (requiresArtifactBody(artifact.type) && !artifactHasBody(artifact)) {
|
|
@@ -1275,7 +1263,7 @@ function withTemplateOwners(templates, refs, agentsForCallSite, scopes = []) {
|
|
|
1275
1263
|
}
|
|
1276
1264
|
|
|
1277
1265
|
// src/harness.ts
|
|
1278
|
-
import { createHash as
|
|
1266
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
1279
1267
|
import { execFileSync as execFileSync3, spawn } from "node:child_process";
|
|
1280
1268
|
import { homedir, tmpdir as tmpdir2 } from "node:os";
|
|
1281
1269
|
import { fileURLToPath } from "node:url";
|
|
@@ -1407,6 +1395,112 @@ function harnessAgentIdentities(value) {
|
|
|
1407
1395
|
});
|
|
1408
1396
|
}
|
|
1409
1397
|
|
|
1398
|
+
// src/harness-body-store.ts
|
|
1399
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1400
|
+
|
|
1401
|
+
// src/harness-sync-limits.ts
|
|
1402
|
+
var MAX_HARNESS_SYNC_GRAPH_BYTES = 2000000;
|
|
1403
|
+
var MAX_HARNESS_SYNC_REQUEST_BYTES = 2000000;
|
|
1404
|
+
function assertHarnessSyncRequestSize(body) {
|
|
1405
|
+
const requestBytes = Buffer.byteLength(JSON.stringify(body), "utf8");
|
|
1406
|
+
if (requestBytes > MAX_HARNESS_SYNC_REQUEST_BYTES) {
|
|
1407
|
+
throw new CliInputError(`Harness sync request is too large (${requestBytes.toLocaleString()} bytes; limit ${MAX_HARNESS_SYNC_REQUEST_BYTES.toLocaleString()}).`, "Run `moda harness analyze --path=<agent-dir>` to narrow the harness root.");
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
function assertHarnessGraphSyncSize(graph) {
|
|
1411
|
+
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
1412
|
+
throw new CliInputError("Harness graph must be an object before sync.");
|
|
1413
|
+
}
|
|
1414
|
+
const graphBytes = Buffer.byteLength(JSON.stringify(graph), "utf8");
|
|
1415
|
+
if (graphBytes > MAX_HARNESS_SYNC_GRAPH_BYTES) {
|
|
1416
|
+
throw new CliInputError(`Harness graph is too large to sync (${graphBytes.toLocaleString()} bytes; limit ${MAX_HARNESS_SYNC_GRAPH_BYTES.toLocaleString()}).`, [
|
|
1417
|
+
"Run `moda harness analyze --path=<agent-dir>` to narrow the harness root.",
|
|
1418
|
+
"Reduce captured prompt/tool bodies if the graph grew too large.",
|
|
1419
|
+
"Split multiple agent roots into separate harness syncs per tenant."
|
|
1420
|
+
].join(`
|
|
1421
|
+
`));
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
// src/harness-body-store.ts
|
|
1426
|
+
function sha256Hex(text) {
|
|
1427
|
+
return Promise.resolve(createHash2("sha256").update(text, "utf8").digest("hex"));
|
|
1428
|
+
}
|
|
1429
|
+
function graphBytes(graph) {
|
|
1430
|
+
return Buffer.byteLength(JSON.stringify(graph), "utf8");
|
|
1431
|
+
}
|
|
1432
|
+
async function prepareHarnessGraphForSync(graph, store, maxBytes = MAX_HARNESS_SYNC_GRAPH_BYTES, options = {}) {
|
|
1433
|
+
if (!graph || typeof graph !== "object" || graphBytes(graph) <= maxBytes) {
|
|
1434
|
+
return { graph, shortened: 0, uploaded: 0, storeFailed: false, storeFailedBodies: 0, unstorableBodies: 0 };
|
|
1435
|
+
}
|
|
1436
|
+
const copy = structuredClone(graph);
|
|
1437
|
+
const fullBodies = await captureFullArtifactBodies(copy, sha256Hex);
|
|
1438
|
+
const artifacts = Array.isArray(copy.artifacts) ? copy.artifacts.filter((artifact) => Boolean(artifact) && typeof artifact === "object") : [];
|
|
1439
|
+
const capturedBodies = new Map(artifacts.map((artifact) => [artifact, artifact.body]));
|
|
1440
|
+
const shortened = fitGraphForSync(copy, maxBytes, fullBodies);
|
|
1441
|
+
const unstorableBodies = artifacts.filter((artifact) => artifact.body !== capturedBodies.get(artifact) && typeof artifact.bodyHash !== "string").length;
|
|
1442
|
+
if (shortened === 0 || !store || options.requireStorable && unstorableBodies > 0) {
|
|
1443
|
+
return { graph: copy, shortened, uploaded: 0, storeFailed: false, storeFailedBodies: 0, unstorableBodies };
|
|
1444
|
+
}
|
|
1445
|
+
const stored = await storeShortenedArtifactBodies(copy, fullBodies, store, { keepHashesOnError: true });
|
|
1446
|
+
const storeFailed = stored.error !== undefined;
|
|
1447
|
+
return {
|
|
1448
|
+
graph: copy,
|
|
1449
|
+
shortened,
|
|
1450
|
+
uploaded: stored.uploaded,
|
|
1451
|
+
storeFailed,
|
|
1452
|
+
storeFailedBodies: storeFailed ? stored.referenced : 0,
|
|
1453
|
+
unstorableBodies
|
|
1454
|
+
};
|
|
1455
|
+
}
|
|
1456
|
+
function requestBytes(request) {
|
|
1457
|
+
return graphBytes({ ...request, dryRun: false });
|
|
1458
|
+
}
|
|
1459
|
+
function isRecord(value) {
|
|
1460
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1461
|
+
}
|
|
1462
|
+
function reportFieldsWithoutGraph(body) {
|
|
1463
|
+
const report = body.report;
|
|
1464
|
+
if (!isRecord(report) || !("graph" in report))
|
|
1465
|
+
return {};
|
|
1466
|
+
const { graph: _graph, ...reportWithoutGraph } = report;
|
|
1467
|
+
const fields = { report: reportWithoutGraph };
|
|
1468
|
+
if (body.reportHash === undefined)
|
|
1469
|
+
return fields;
|
|
1470
|
+
const reportHash = hashStableJson(reportWithoutGraph);
|
|
1471
|
+
fields.reportHash = reportHash;
|
|
1472
|
+
const approval = body.reportApproval;
|
|
1473
|
+
if (isRecord(approval) && approval.reportHash === body.reportHash) {
|
|
1474
|
+
fields.reportApproval = { ...approval, reportHash, approvedReportHash: body.reportHash };
|
|
1475
|
+
}
|
|
1476
|
+
return fields;
|
|
1477
|
+
}
|
|
1478
|
+
async function prepareHarnessSyncRequest(body, store, maxRequestBytes = MAX_HARNESS_SYNC_REQUEST_BYTES, maxGraphBytes = MAX_HARNESS_SYNC_GRAPH_BYTES, options = {}) {
|
|
1479
|
+
const { dryRun: _dryRun, ...rest } = body;
|
|
1480
|
+
if (requestBytes(rest) <= maxRequestBytes && graphBytes(rest.graph) <= maxGraphBytes) {
|
|
1481
|
+
return { request: rest, shortened: 0, uploaded: 0, storeFailed: false, storeFailedBodies: 0, unstorableBodies: 0 };
|
|
1482
|
+
}
|
|
1483
|
+
const request = { ...rest, ...reportFieldsWithoutGraph(rest) };
|
|
1484
|
+
const envelopeBytes = requestBytes({ ...request, graph: null });
|
|
1485
|
+
const budget = Math.min(maxGraphBytes, maxRequestBytes - envelopeBytes);
|
|
1486
|
+
const { graph, ...prepared } = await prepareHarnessGraphForSync(rest.graph, store, Math.max(0, budget), options);
|
|
1487
|
+
return { request: { ...request, graph }, ...prepared };
|
|
1488
|
+
}
|
|
1489
|
+
function controlApiArtifactBodyStore(call) {
|
|
1490
|
+
return {
|
|
1491
|
+
async missing(hashes) {
|
|
1492
|
+
const result = await call("/harnesses/bodies/missing", {
|
|
1493
|
+
method: "POST",
|
|
1494
|
+
body: JSON.stringify({ hashes })
|
|
1495
|
+
});
|
|
1496
|
+
return Array.isArray(result?.missing) ? result.missing.filter((hash) => typeof hash === "string") : [];
|
|
1497
|
+
},
|
|
1498
|
+
upload(bodies) {
|
|
1499
|
+
return call("/harnesses/bodies", { method: "POST", body: JSON.stringify({ bodies }) });
|
|
1500
|
+
}
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1410
1504
|
// src/analyst-tui.ts
|
|
1411
1505
|
class AnalystTui {
|
|
1412
1506
|
state;
|
|
@@ -2102,13 +2196,13 @@ function entrypointOf(command, modelRouting) {
|
|
|
2102
2196
|
return { entrypoint: { kind: "command", ...command ? { command } : {}, ...hasRouting ? { modelRouting } : {} } };
|
|
2103
2197
|
}
|
|
2104
2198
|
// ../../packages/harness-bundle/src/register/collect.ts
|
|
2105
|
-
import { createHash as
|
|
2199
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
2106
2200
|
import { execFileSync } from "node:child_process";
|
|
2107
2201
|
import { copyFileSync, createReadStream, existsSync as existsSync6, mkdirSync as mkdirSync3, realpathSync as realpathSync6, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
2108
2202
|
import { dirname as dirname7, join as join8 } from "node:path";
|
|
2109
2203
|
|
|
2110
2204
|
// ../../packages/harness-bundle/src/collect/collect.ts
|
|
2111
|
-
import { createHash as
|
|
2205
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
2112
2206
|
import { closeSync, existsSync as existsSync3, lstatSync as lstatSync2, openSync, readdirSync as readdirSync2, readFileSync as readFileSync4, readlinkSync, readSync, realpathSync as realpathSync3 } from "node:fs";
|
|
2113
2207
|
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join4, relative as relative3, resolve as resolve5, sep } from "node:path";
|
|
2114
2208
|
|
|
@@ -6247,7 +6341,7 @@ function detectEncoding(buf) {
|
|
|
6247
6341
|
}
|
|
6248
6342
|
}
|
|
6249
6343
|
function sha256(buf) {
|
|
6250
|
-
return
|
|
6344
|
+
return createHash3("sha256").update(buf).digest("hex");
|
|
6251
6345
|
}
|
|
6252
6346
|
var DROP_FIRST = ["data", "binary", "asset", "generated"];
|
|
6253
6347
|
var KEEP = [
|
|
@@ -6316,7 +6410,7 @@ function rangeCovered(ranges, start, end) {
|
|
|
6316
6410
|
}
|
|
6317
6411
|
|
|
6318
6412
|
// ../../packages/harness-bundle/src/collect/write.ts
|
|
6319
|
-
import { createHash as
|
|
6413
|
+
import { createHash as createHash4, randomUUID } from "node:crypto";
|
|
6320
6414
|
import { createWriteStream, existsSync as existsSync4, lstatSync as lstatSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync3, readFileSync as readFileSync5, readlinkSync as readlinkSync2, realpathSync as realpathSync4, renameSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
6321
6415
|
import { dirname as dirname5, isAbsolute as isAbsolute5, join as join5, relative as relative4, resolve as resolve6, sep as sep2 } from "node:path";
|
|
6322
6416
|
import { Readable, Transform } from "node:stream";
|
|
@@ -6515,7 +6609,7 @@ function* tarChunks(files) {
|
|
|
6515
6609
|
}
|
|
6516
6610
|
async function writeTarGz(files, path) {
|
|
6517
6611
|
mkdirSync2(dirname5(path), { recursive: true });
|
|
6518
|
-
const tarHash =
|
|
6612
|
+
const tarHash = createHash4("sha256");
|
|
6519
6613
|
await pipeline(Readable.from(tarChunks(files)), new Transform({
|
|
6520
6614
|
transform(chunk, _encoding, callback) {
|
|
6521
6615
|
tarHash.update(chunk);
|
|
@@ -6743,7 +6837,7 @@ function parseJsonLoose(text) {
|
|
|
6743
6837
|
return;
|
|
6744
6838
|
}
|
|
6745
6839
|
}
|
|
6746
|
-
function
|
|
6840
|
+
function isRecord2(value) {
|
|
6747
6841
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6748
6842
|
}
|
|
6749
6843
|
function asString(value) {
|
|
@@ -7941,7 +8035,7 @@ function readManifest(dir) {
|
|
|
7941
8035
|
return;
|
|
7942
8036
|
try {
|
|
7943
8037
|
const parsed = JSON.parse(readFileSync6(path, "utf8"));
|
|
7944
|
-
if (
|
|
8038
|
+
if (isRecord2(parsed) && parsed.schema === HARNESS_BUNDLE_SCHEMA && Array.isArray(parsed.files)) {
|
|
7945
8039
|
return parsed;
|
|
7946
8040
|
}
|
|
7947
8041
|
} catch {
|
|
@@ -7977,7 +8071,7 @@ function makeFile(path, text, categories) {
|
|
|
7977
8071
|
};
|
|
7978
8072
|
}
|
|
7979
8073
|
function isValidEntry(value) {
|
|
7980
|
-
return
|
|
8074
|
+
return isRecord2(value) && typeof value.path === "string" && typeof value.bytes === "number" && Array.isArray(value.categories) && value.categories.every((c) => typeof c === "string") && (value.encoding === "text" || value.encoding === "binary");
|
|
7981
8075
|
}
|
|
7982
8076
|
function staysInside(root, abs) {
|
|
7983
8077
|
try {
|
|
@@ -8013,7 +8107,7 @@ function loadFiles(dir, opts = {}) {
|
|
|
8013
8107
|
if (isValidEntry(raw))
|
|
8014
8108
|
entries.push(raw);
|
|
8015
8109
|
else
|
|
8016
|
-
skipped.push({ path:
|
|
8110
|
+
skipped.push({ path: isRecord2(raw) && typeof raw.path === "string" ? raw.path : "(unnamed)", reason: "invalid_entry" });
|
|
8017
8111
|
}
|
|
8018
8112
|
const contentRoot = contentRootFor(dir, entries);
|
|
8019
8113
|
entries.sort((a, b) => cmp(a.path, b.path));
|
|
@@ -8099,7 +8193,7 @@ function loadFiles(dir, opts = {}) {
|
|
|
8099
8193
|
return { files, truncated, skipped };
|
|
8100
8194
|
}
|
|
8101
8195
|
function isValidEnv(value) {
|
|
8102
|
-
return
|
|
8196
|
+
return isRecord2(value) && typeof value.name === "string" && Array.isArray(value.sources) && typeof value.classification === "string" && typeof value.hasExampleValue === "boolean";
|
|
8103
8197
|
}
|
|
8104
8198
|
|
|
8105
8199
|
// ../../packages/harness-bundle/src/detect/frameworks.ts
|
|
@@ -10254,7 +10348,7 @@ function parsePackageJsons(files) {
|
|
|
10254
10348
|
continue;
|
|
10255
10349
|
try {
|
|
10256
10350
|
const json = JSON.parse(f.text);
|
|
10257
|
-
if (
|
|
10351
|
+
if (isRecord2(json))
|
|
10258
10352
|
out.push({ path: f.path, root: dirname6(f.path), json });
|
|
10259
10353
|
} catch {}
|
|
10260
10354
|
}
|
|
@@ -10267,7 +10361,7 @@ function fromPackageJson(f, out) {
|
|
|
10267
10361
|
} catch {
|
|
10268
10362
|
return;
|
|
10269
10363
|
}
|
|
10270
|
-
if (!
|
|
10364
|
+
if (!isRecord2(json))
|
|
10271
10365
|
return;
|
|
10272
10366
|
for (const [field, dev] of [
|
|
10273
10367
|
["dependencies", false],
|
|
@@ -10276,7 +10370,7 @@ function fromPackageJson(f, out) {
|
|
|
10276
10370
|
["devDependencies", true]
|
|
10277
10371
|
]) {
|
|
10278
10372
|
const deps = json[field];
|
|
10279
|
-
if (!
|
|
10373
|
+
if (!isRecord2(deps))
|
|
10280
10374
|
continue;
|
|
10281
10375
|
for (const name of Object.keys(deps).sort()) {
|
|
10282
10376
|
out.push({ eco: "npm", name, path: f.path, line: lineOfToken(f.text, `"${name}"`), dev });
|
|
@@ -10307,49 +10401,49 @@ function fromPyproject(f, out) {
|
|
|
10307
10401
|
if (name && name !== "python")
|
|
10308
10402
|
out.push({ eco: "pypi", name, path: f.path, line: lineOfToken(f.text, name), dev });
|
|
10309
10403
|
};
|
|
10310
|
-
const project =
|
|
10404
|
+
const project = isRecord2(doc.project) ? doc.project : {};
|
|
10311
10405
|
for (const req of asArray(project.dependencies))
|
|
10312
10406
|
if (typeof req === "string")
|
|
10313
10407
|
add(req, false);
|
|
10314
|
-
const optional =
|
|
10408
|
+
const optional = isRecord2(project["optional-dependencies"]) ? project["optional-dependencies"] : {};
|
|
10315
10409
|
for (const [group, reqs] of Object.entries(optional)) {
|
|
10316
10410
|
for (const req of asArray(reqs))
|
|
10317
10411
|
if (typeof req === "string")
|
|
10318
10412
|
add(req, /dev|test|lint|doc/i.test(group));
|
|
10319
10413
|
}
|
|
10320
|
-
const groups =
|
|
10414
|
+
const groups = isRecord2(doc["dependency-groups"]) ? doc["dependency-groups"] : {};
|
|
10321
10415
|
for (const reqs of Object.values(groups))
|
|
10322
10416
|
for (const req of asArray(reqs))
|
|
10323
10417
|
if (typeof req === "string")
|
|
10324
10418
|
add(req, true);
|
|
10325
|
-
const tool =
|
|
10326
|
-
const poetry =
|
|
10327
|
-
if (
|
|
10419
|
+
const tool = isRecord2(doc.tool) ? doc.tool : {};
|
|
10420
|
+
const poetry = isRecord2(tool.poetry) ? tool.poetry : {};
|
|
10421
|
+
if (isRecord2(poetry.dependencies))
|
|
10328
10422
|
for (const name of Object.keys(poetry.dependencies))
|
|
10329
10423
|
add(name, false);
|
|
10330
|
-
if (
|
|
10424
|
+
if (isRecord2(poetry["dev-dependencies"]))
|
|
10331
10425
|
for (const name of Object.keys(poetry["dev-dependencies"]))
|
|
10332
10426
|
add(name, true);
|
|
10333
|
-
if (
|
|
10427
|
+
if (isRecord2(poetry.group)) {
|
|
10334
10428
|
for (const [group, body] of Object.entries(poetry.group)) {
|
|
10335
|
-
if (
|
|
10429
|
+
if (isRecord2(body) && isRecord2(body.dependencies)) {
|
|
10336
10430
|
for (const name of Object.keys(body.dependencies))
|
|
10337
10431
|
add(name, /dev|test|lint|doc/i.test(group));
|
|
10338
10432
|
}
|
|
10339
10433
|
}
|
|
10340
10434
|
}
|
|
10341
|
-
const uv =
|
|
10435
|
+
const uv = isRecord2(tool.uv) ? tool.uv : {};
|
|
10342
10436
|
for (const req of asArray(uv["dev-dependencies"]))
|
|
10343
10437
|
if (typeof req === "string")
|
|
10344
10438
|
add(req, true);
|
|
10345
|
-
const hatch =
|
|
10439
|
+
const hatch = isRecord2(tool.hatch) && isRecord2(tool.hatch.metadata) && isRecord2(tool.hatch.metadata.hooks) ? tool.hatch.metadata.hooks : {};
|
|
10346
10440
|
for (const hook of Object.values(hatch)) {
|
|
10347
|
-
if (!
|
|
10441
|
+
if (!isRecord2(hook))
|
|
10348
10442
|
continue;
|
|
10349
10443
|
for (const req of asArray(hook.dependencies))
|
|
10350
10444
|
if (typeof req === "string")
|
|
10351
10445
|
add(req, false);
|
|
10352
|
-
const extra =
|
|
10446
|
+
const extra = isRecord2(hook["optional-dependencies"]) ? hook["optional-dependencies"] : {};
|
|
10353
10447
|
for (const [group, reqs] of Object.entries(extra))
|
|
10354
10448
|
for (const req of asArray(reqs))
|
|
10355
10449
|
if (typeof req === "string")
|
|
@@ -10368,7 +10462,7 @@ function fromPipfile(f, out) {
|
|
|
10368
10462
|
["dev-packages", true]
|
|
10369
10463
|
]) {
|
|
10370
10464
|
const pkgs = doc[section];
|
|
10371
|
-
if (
|
|
10465
|
+
if (isRecord2(pkgs)) {
|
|
10372
10466
|
for (const name of Object.keys(pkgs)) {
|
|
10373
10467
|
out.push({ eco: "pypi", name: name.toLowerCase(), path: f.path, line: lineOfToken(f.text, name), dev });
|
|
10374
10468
|
}
|
|
@@ -10550,7 +10644,7 @@ var SLS_EVENT_TRIGGERS = {
|
|
|
10550
10644
|
alexaSkill: "event"
|
|
10551
10645
|
};
|
|
10552
10646
|
function envFromVariables(ctx, vars, file, sourceLabel) {
|
|
10553
|
-
if (!
|
|
10647
|
+
if (!isRecord2(vars))
|
|
10554
10648
|
return;
|
|
10555
10649
|
for (const name of Object.keys(vars).sort()) {
|
|
10556
10650
|
const value = vars[name];
|
|
@@ -10561,10 +10655,10 @@ function envFromVariables(ctx, vars, file, sourceLabel) {
|
|
|
10561
10655
|
function cfnResources(ctx, resources, file, runtime) {
|
|
10562
10656
|
for (const logicalId of Object.keys(resources).sort()) {
|
|
10563
10657
|
const res = resources[logicalId];
|
|
10564
|
-
if (!
|
|
10658
|
+
if (!isRecord2(res))
|
|
10565
10659
|
continue;
|
|
10566
10660
|
const type = asString(res.Type) ?? "";
|
|
10567
|
-
const props =
|
|
10661
|
+
const props = isRecord2(res.Properties) ? res.Properties : {};
|
|
10568
10662
|
let spec = CFN_RESOURCES[type];
|
|
10569
10663
|
if (!spec && (type === "AWS::RDS::DBInstance" || type === "AWS::RDS::DBCluster")) {
|
|
10570
10664
|
spec = { capability: "database", provider: rdsEngineProvider(asString(props.Engine)), cls: "engine" };
|
|
@@ -10580,61 +10674,61 @@ function handlerPath(codeUri, handler, root) {
|
|
|
10580
10674
|
return codeUri ? `${joinPath(root, codeUri)}/${handler}` : joinPath(root, handler);
|
|
10581
10675
|
}
|
|
10582
10676
|
function detectSam(ctx, file, doc) {
|
|
10583
|
-
const resources =
|
|
10677
|
+
const resources = isRecord2(doc.Resources) ? doc.Resources : undefined;
|
|
10584
10678
|
if (!resources)
|
|
10585
10679
|
return;
|
|
10586
10680
|
const root = dirname6(file.path);
|
|
10587
|
-
const globals =
|
|
10681
|
+
const globals = isRecord2(doc.Globals) && isRecord2(doc.Globals.Function) ? doc.Globals.Function : {};
|
|
10588
10682
|
const runtime = newRuntime("aws_lambda", root, [file.path], [ev(file, /AWS::Serverless|AWSTemplateFormatVersion/)], 0.95);
|
|
10589
10683
|
const g = languageFromRuntime(asString(globals.Runtime));
|
|
10590
|
-
envFromVariables(ctx,
|
|
10684
|
+
envFromVariables(ctx, isRecord2(globals.Environment) ? globals.Environment.Variables : undefined, file, "Globals");
|
|
10591
10685
|
for (const logicalId of Object.keys(resources).sort()) {
|
|
10592
10686
|
const res = resources[logicalId];
|
|
10593
|
-
if (!
|
|
10687
|
+
if (!isRecord2(res))
|
|
10594
10688
|
continue;
|
|
10595
10689
|
const type = asString(res.Type);
|
|
10596
10690
|
if (type !== "AWS::Serverless::Function" && type !== "AWS::Lambda::Function")
|
|
10597
10691
|
continue;
|
|
10598
|
-
const props =
|
|
10692
|
+
const props = isRecord2(res.Properties) ? res.Properties : {};
|
|
10599
10693
|
const lang = languageFromRuntime(asString(props.Runtime) ?? asString(globals.Runtime));
|
|
10600
10694
|
runtime.language ??= lang.language ?? g.language;
|
|
10601
10695
|
runtime.runtimeVersion ??= lang.version ?? g.version;
|
|
10602
10696
|
const handler = asString(props.Handler) ?? asString(globals.Handler);
|
|
10603
|
-
const codeUri = asString(props.CodeUri) ?? asString(globals.CodeUri) ?? (
|
|
10604
|
-
const events =
|
|
10697
|
+
const codeUri = asString(props.CodeUri) ?? asString(globals.CodeUri) ?? (isRecord2(props.Code) ? undefined : asString(props.Code));
|
|
10698
|
+
const events = isRecord2(props.Events) ? props.Events : {};
|
|
10605
10699
|
const triggers = new Set;
|
|
10606
10700
|
for (const evt of Object.values(events)) {
|
|
10607
|
-
if (
|
|
10701
|
+
if (isRecord2(evt))
|
|
10608
10702
|
triggers.add(SAM_EVENT_TRIGGERS[asString(evt.Type) ?? ""] ?? "event");
|
|
10609
10703
|
}
|
|
10610
|
-
if (
|
|
10704
|
+
if (isRecord2(props.FunctionUrlConfig))
|
|
10611
10705
|
triggers.add("http");
|
|
10612
10706
|
const trigger = triggers.has("http") ? "http" : [...triggers][0] ?? "event";
|
|
10613
10707
|
const entry = { name: logicalId, trigger };
|
|
10614
10708
|
if (handler)
|
|
10615
10709
|
entry.handler = handlerPath(codeUri, handler, root);
|
|
10616
10710
|
else if (asString(props.PackageType) === "Image") {
|
|
10617
|
-
const meta =
|
|
10711
|
+
const meta = isRecord2(res.Metadata) ? res.Metadata : {};
|
|
10618
10712
|
const ctxDir = asString(meta.DockerContext);
|
|
10619
10713
|
entry.handler = ctxDir ? `${joinPath(root, ctxDir)}/${asString(meta.Dockerfile) ?? "Dockerfile"}` : undefined;
|
|
10620
10714
|
}
|
|
10621
10715
|
runtime.entrypoints.push(entry);
|
|
10622
|
-
envFromVariables(ctx,
|
|
10716
|
+
envFromVariables(ctx, isRecord2(props.Environment) ? props.Environment.Variables : undefined, file, logicalId);
|
|
10623
10717
|
}
|
|
10624
10718
|
cfnResources(ctx, resources, file, runtime);
|
|
10625
10719
|
const ids = Object.keys(resources);
|
|
10626
10720
|
const direct = (text, self) => ids.filter((id) => id !== self && new RegExp(`\\b${escapeRe(id)}\\b`).test(text));
|
|
10627
|
-
const globalsText = JSON.stringify(
|
|
10721
|
+
const globalsText = JSON.stringify(isRecord2(doc.Globals) && isRecord2(doc.Globals.Function) ? doc.Globals.Function : {});
|
|
10628
10722
|
const refs = new Map;
|
|
10629
10723
|
for (const [fnId, res] of Object.entries(resources)) {
|
|
10630
|
-
if (!
|
|
10724
|
+
if (!isRecord2(res) || !/^AWS::(?:Serverless|Lambda)::Function$/.test(asString(res.Type) ?? ""))
|
|
10631
10725
|
continue;
|
|
10632
10726
|
const seen = new Set(direct(`${JSON.stringify(res.Properties ?? {})} ${globalsText}`, fnId));
|
|
10633
10727
|
const queue = [...seen];
|
|
10634
10728
|
while (queue.length > 0) {
|
|
10635
10729
|
const id = queue.shift();
|
|
10636
10730
|
const other = resources[id];
|
|
10637
|
-
if (!
|
|
10731
|
+
if (!isRecord2(other) || /^AWS::(?:Serverless|Lambda)::Function$/.test(asString(other.Type) ?? ""))
|
|
10638
10732
|
continue;
|
|
10639
10733
|
for (const next of direct(JSON.stringify(other.Properties ?? {}), id)) {
|
|
10640
10734
|
if (next !== fnId && !seen.has(next)) {
|
|
@@ -10651,7 +10745,7 @@ function detectSam(ctx, file, doc) {
|
|
|
10651
10745
|
return runtime;
|
|
10652
10746
|
}
|
|
10653
10747
|
function detectServerless(ctx, file, doc) {
|
|
10654
|
-
const provider =
|
|
10748
|
+
const provider = isRecord2(doc.provider) ? doc.provider : {};
|
|
10655
10749
|
const providerName = asString(provider.name) ?? "aws";
|
|
10656
10750
|
const root = dirname6(file.path);
|
|
10657
10751
|
const kind = providerName === "google" ? "gcp_cloud_functions" : providerName === "azure" ? "azure_functions" : "aws_lambda";
|
|
@@ -10660,14 +10754,14 @@ function detectServerless(ctx, file, doc) {
|
|
|
10660
10754
|
runtime.language = lang.language;
|
|
10661
10755
|
runtime.runtimeVersion = lang.version;
|
|
10662
10756
|
envFromVariables(ctx, provider.environment, file, "provider.environment");
|
|
10663
|
-
const functions =
|
|
10757
|
+
const functions = isRecord2(doc.functions) ? doc.functions : {};
|
|
10664
10758
|
for (const name of Object.keys(functions).sort()) {
|
|
10665
10759
|
const fn = functions[name];
|
|
10666
|
-
if (!
|
|
10760
|
+
if (!isRecord2(fn))
|
|
10667
10761
|
continue;
|
|
10668
10762
|
const triggers = new Set;
|
|
10669
10763
|
for (const evt of asArray(fn.events)) {
|
|
10670
|
-
if (
|
|
10764
|
+
if (isRecord2(evt))
|
|
10671
10765
|
for (const key of Object.keys(evt))
|
|
10672
10766
|
triggers.add(SLS_EVENT_TRIGGERS[key] ?? "event");
|
|
10673
10767
|
}
|
|
@@ -10692,7 +10786,7 @@ function detectServerless(ctx, file, doc) {
|
|
|
10692
10786
|
const line = at(m.index);
|
|
10693
10787
|
ctx.env.push({ name: m[1], source: `${file.path}:${line}`, evidence: { path: file.path, line, excerpt: excerpt(splitLines(file.text)[line - 1]), detector: DETECTOR5 } });
|
|
10694
10788
|
}
|
|
10695
|
-
const resources =
|
|
10789
|
+
const resources = isRecord2(doc.resources) && isRecord2(doc.resources.Resources) ? doc.resources.Resources : undefined;
|
|
10696
10790
|
if (resources)
|
|
10697
10791
|
cfnResources(ctx, resources, file, runtime);
|
|
10698
10792
|
return runtime;
|
|
@@ -10786,7 +10880,7 @@ function detectAws(input) {
|
|
|
10786
10880
|
const name = basename3(file.path);
|
|
10787
10881
|
if (/^serverless\.ya?ml$/.test(name)) {
|
|
10788
10882
|
const doc = loadYaml(file.text);
|
|
10789
|
-
if (!
|
|
10883
|
+
if (!isRecord2(doc)) {
|
|
10790
10884
|
ctx.gaps.push({ kind: "unparseable_config", message: `Could not parse ${file.path}`, evidence: [{ path: file.path, detector: DETECTOR5 }] });
|
|
10791
10885
|
continue;
|
|
10792
10886
|
}
|
|
@@ -10795,7 +10889,7 @@ function detectAws(input) {
|
|
|
10795
10889
|
out.push(rt);
|
|
10796
10890
|
} else if (isCfnTemplate(file)) {
|
|
10797
10891
|
const doc = file.path.endsWith(".json") ? safeJson(file.text) : loadYaml(file.text);
|
|
10798
|
-
if (!
|
|
10892
|
+
if (!isRecord2(doc)) {
|
|
10799
10893
|
ctx.gaps.push({ kind: "unparseable_config", message: `Could not parse ${file.path}`, evidence: [{ path: file.path, detector: DETECTOR5 }] });
|
|
10800
10894
|
continue;
|
|
10801
10895
|
}
|
|
@@ -10830,7 +10924,7 @@ function parseWrangler(file) {
|
|
|
10830
10924
|
}
|
|
10831
10925
|
}
|
|
10832
10926
|
const parsed = parseJsonLoose(file.text);
|
|
10833
|
-
return
|
|
10927
|
+
return isRecord2(parsed) ? parsed : undefined;
|
|
10834
10928
|
}
|
|
10835
10929
|
function ev2(file, token) {
|
|
10836
10930
|
const re = typeof token === "string" ? new RegExp(escapeRe(token)) : token;
|
|
@@ -10838,10 +10932,10 @@ function ev2(file, token) {
|
|
|
10838
10932
|
}
|
|
10839
10933
|
function sections(config) {
|
|
10840
10934
|
const out = [config];
|
|
10841
|
-
if (
|
|
10935
|
+
if (isRecord2(config.env))
|
|
10842
10936
|
for (const key of Object.keys(config.env).sort()) {
|
|
10843
10937
|
const env = config.env[key];
|
|
10844
|
-
if (
|
|
10938
|
+
if (isRecord2(env))
|
|
10845
10939
|
out.push(env);
|
|
10846
10940
|
}
|
|
10847
10941
|
return out;
|
|
@@ -10877,7 +10971,7 @@ function detectCloudflare(input) {
|
|
|
10877
10971
|
const hasFetch = !mainFile || /\bfetch\s*[(:]|\bexport\s+default\s+(?:app|router|server)\b|routeAgentRequest|new\s+Hono\b|\bon_fetch\b|WorkerEntrypoint/.test(text);
|
|
10878
10972
|
if (hasFetch)
|
|
10879
10973
|
runtime.entrypoints.push({ name: "fetch", handler: `${mainPath}#default.fetch`, trigger: "http" });
|
|
10880
|
-
if (mainFile && /(?:^|[\s{,])(?:async\s+)?scheduled\s*\(\s*\w|\bscheduled\s*:\s*(?:async\s*)?(?:\(|function)|\bon_scheduled\b/m.test(text) && asArray(
|
|
10974
|
+
if (mainFile && /(?:^|[\s{,])(?:async\s+)?scheduled\s*\(\s*\w|\bscheduled\s*:\s*(?:async\s*)?(?:\(|function)|\bon_scheduled\b/m.test(text) && asArray(isRecord2(config.triggers) ? config.triggers.crons : undefined).length === 0) {
|
|
10881
10975
|
runtime.entrypoints.push({ name: "scheduled", handler: `${mainPath}#default.scheduled`, trigger: "cron" });
|
|
10882
10976
|
}
|
|
10883
10977
|
if (!mainFile) {
|
|
@@ -10886,7 +10980,7 @@ function detectCloudflare(input) {
|
|
|
10886
10980
|
} else if (pagesOut) {
|
|
10887
10981
|
runtime.entrypoints.push({ name: "pages", handler: joinPath(root, "functions"), trigger: "http" });
|
|
10888
10982
|
}
|
|
10889
|
-
const triggers =
|
|
10983
|
+
const triggers = isRecord2(config.triggers) ? config.triggers : {};
|
|
10890
10984
|
for (const cron of asArray(triggers.crons)) {
|
|
10891
10985
|
if (typeof cron === "string")
|
|
10892
10986
|
runtime.entrypoints.push({ name: `cron ${cron}`, handler: main ? `${joinPath(root, main)}#default.scheduled` : undefined, trigger: "cron" });
|
|
@@ -10903,16 +10997,16 @@ function detectCloudflare(input) {
|
|
|
10903
10997
|
runtime.bindings.push(resource ? { name, type: normalized, resource } : { name, type: normalized });
|
|
10904
10998
|
return true;
|
|
10905
10999
|
};
|
|
10906
|
-
const produced = new Set(sections(config).flatMap((section) => asArray(
|
|
11000
|
+
const produced = new Set(sections(config).flatMap((section) => asArray(isRecord2(section.queues) ? section.queues.producers : undefined).map((p2) => isRecord2(p2) ? asString(p2.queue) : undefined)));
|
|
10907
11001
|
for (const section of sections(config)) {
|
|
10908
11002
|
for (const [field, spec] of Object.entries(WORKERS_BINDINGS)) {
|
|
10909
11003
|
const raw = section[field];
|
|
10910
11004
|
if (raw === undefined)
|
|
10911
11005
|
continue;
|
|
10912
11006
|
if (field === "queues") {
|
|
10913
|
-
const queues =
|
|
11007
|
+
const queues = isRecord2(raw) ? raw : {};
|
|
10914
11008
|
for (const producer of asArray(queues.producers)) {
|
|
10915
|
-
if (!
|
|
11009
|
+
if (!isRecord2(producer))
|
|
10916
11010
|
continue;
|
|
10917
11011
|
const name = asString(producer.binding) ?? "QUEUE";
|
|
10918
11012
|
const resource = asString(producer.queue);
|
|
@@ -10921,7 +11015,7 @@ function detectCloudflare(input) {
|
|
|
10921
11015
|
}
|
|
10922
11016
|
}
|
|
10923
11017
|
for (const consumer of asArray(queues.consumers)) {
|
|
10924
|
-
if (!
|
|
11018
|
+
if (!isRecord2(consumer))
|
|
10925
11019
|
continue;
|
|
10926
11020
|
const queue = asString(consumer.queue) ?? "queue";
|
|
10927
11021
|
if (addBinding(queue, "QueueConsumer", queue)) {
|
|
@@ -10934,7 +11028,7 @@ function detectCloudflare(input) {
|
|
|
10934
11028
|
}
|
|
10935
11029
|
const items = Array.isArray(raw) ? raw : [raw];
|
|
10936
11030
|
for (const item of items) {
|
|
10937
|
-
if (!
|
|
11031
|
+
if (!isRecord2(item))
|
|
10938
11032
|
continue;
|
|
10939
11033
|
const name = asString(item.binding) ?? asString(item.name) ?? spec.type.toUpperCase();
|
|
10940
11034
|
const resource = asString(item.database_name) ?? asString(item.bucket_name) ?? asString(item.index_name) ?? asString(item.service) ?? asString(item.dataset) ?? asString(item.namespace) ?? asString(item.id);
|
|
@@ -10964,9 +11058,9 @@ function detectCloudflare(input) {
|
|
|
10964
11058
|
}
|
|
10965
11059
|
}
|
|
10966
11060
|
}
|
|
10967
|
-
const durable =
|
|
11061
|
+
const durable = isRecord2(section.durable_objects) ? section.durable_objects : {};
|
|
10968
11062
|
for (const item of asArray(durable.bindings)) {
|
|
10969
|
-
if (!
|
|
11063
|
+
if (!isRecord2(item))
|
|
10970
11064
|
continue;
|
|
10971
11065
|
const name = asString(item.name) ?? "DO";
|
|
10972
11066
|
const className2 = asString(item.class_name);
|
|
@@ -10981,19 +11075,19 @@ function detectCloudflare(input) {
|
|
|
10981
11075
|
}
|
|
10982
11076
|
}
|
|
10983
11077
|
for (const item of asArray(section.workflows)) {
|
|
10984
|
-
if (
|
|
11078
|
+
if (isRecord2(item))
|
|
10985
11079
|
addBinding(asString(item.binding) ?? "WORKFLOW", "Workflow", asString(item.class_name));
|
|
10986
11080
|
}
|
|
10987
11081
|
for (const item of asArray(section.containers)) {
|
|
10988
|
-
if (
|
|
11082
|
+
if (isRecord2(item))
|
|
10989
11083
|
addBinding(asString(item.class_name) ?? "CONTAINER", "Container", asString(item.image));
|
|
10990
11084
|
}
|
|
10991
|
-
if (
|
|
11085
|
+
if (isRecord2(section.assets)) {
|
|
10992
11086
|
const binding = asString(section.assets.binding);
|
|
10993
11087
|
if (binding)
|
|
10994
11088
|
addBinding(binding, "Assets", asString(section.assets.directory));
|
|
10995
11089
|
}
|
|
10996
|
-
if (
|
|
11090
|
+
if (isRecord2(section.vars)) {
|
|
10997
11091
|
for (const key of Object.keys(section.vars).sort()) {
|
|
10998
11092
|
const value = section.vars[key];
|
|
10999
11093
|
ctx.env.push({
|
|
@@ -11005,7 +11099,7 @@ function detectCloudflare(input) {
|
|
|
11005
11099
|
}
|
|
11006
11100
|
}
|
|
11007
11101
|
const secrets = section.secrets;
|
|
11008
|
-
const required =
|
|
11102
|
+
const required = isRecord2(secrets) ? asArray(secrets.required) : asArray(secrets);
|
|
11009
11103
|
for (const s of required)
|
|
11010
11104
|
if (typeof s === "string")
|
|
11011
11105
|
ctx.env.push({ name: s, source: `${file.path} secrets` });
|
|
@@ -11196,7 +11290,7 @@ function detachDockerfile(byRoot, contributions, c) {
|
|
|
11196
11290
|
}
|
|
11197
11291
|
function composeServices(ctx, file, byRoot, contributions, relocated) {
|
|
11198
11292
|
const doc = loadYaml(file.text);
|
|
11199
|
-
if (!
|
|
11293
|
+
if (!isRecord2(doc) || !isRecord2(doc.services))
|
|
11200
11294
|
return;
|
|
11201
11295
|
const base = dirname6(file.path);
|
|
11202
11296
|
const at = lineIndex(file.text);
|
|
@@ -11207,7 +11301,7 @@ function composeServices(ctx, file, byRoot, contributions, relocated) {
|
|
|
11207
11301
|
};
|
|
11208
11302
|
for (const name of Object.keys(doc.services).sort()) {
|
|
11209
11303
|
const svc = doc.services[name];
|
|
11210
|
-
if (!
|
|
11304
|
+
if (!isRecord2(svc))
|
|
11211
11305
|
continue;
|
|
11212
11306
|
const line = lineOfService(name);
|
|
11213
11307
|
const evidence = { path: file.path, line, excerpt: line ? excerpt(lines[line - 1]) : undefined, detector: `${DETECTOR7}.compose` };
|
|
@@ -11216,11 +11310,11 @@ function composeServices(ctx, file, byRoot, contributions, relocated) {
|
|
|
11216
11310
|
const ports = asArray(svc.ports);
|
|
11217
11311
|
const svcEntrypoint = composeArgs(svc.entrypoint);
|
|
11218
11312
|
const svcCommand = composeArgs(svc.command);
|
|
11219
|
-
let serviceRoot = build !== undefined ? joinPath(base, typeof build === "string" ? build :
|
|
11313
|
+
let serviceRoot = build !== undefined ? joinPath(base, typeof build === "string" ? build : isRecord2(build) ? asString(build.context) ?? "." : ".") : undefined;
|
|
11220
11314
|
if (build !== undefined) {
|
|
11221
|
-
const context = typeof build === "string" ? build :
|
|
11315
|
+
const context = typeof build === "string" ? build : isRecord2(build) ? asString(build.context) ?? "." : ".";
|
|
11222
11316
|
const contextRoot = joinPath(base, context);
|
|
11223
|
-
const dockerfile = joinPath(contextRoot, (
|
|
11317
|
+
const dockerfile = joinPath(contextRoot, (isRecord2(build) ? asString(build.dockerfile) : undefined) ?? "Dockerfile");
|
|
11224
11318
|
const dfDir = dirname6(dockerfile);
|
|
11225
11319
|
const projectDir = dfDir !== contextRoot && isUnder2(dfDir, contextRoot) && ctx.files.some((f) => dirname6(f.path) === dfDir && PROJECT_MANIFEST.test(basename3(f.path)));
|
|
11226
11320
|
const root = projectDir ? dfDir : contextRoot;
|
|
@@ -11240,7 +11334,7 @@ function composeServices(ctx, file, byRoot, contributions, relocated) {
|
|
|
11240
11334
|
else if (contribution.entry)
|
|
11241
11335
|
runtime.entrypoints = runtime.entrypoints.filter((e) => e !== contribution.entry);
|
|
11242
11336
|
}
|
|
11243
|
-
const target =
|
|
11337
|
+
const target = isRecord2(build) ? asString(build.target)?.toLowerCase() : undefined;
|
|
11244
11338
|
const targetStage = target ? contribution?.df.stages[target] : undefined;
|
|
11245
11339
|
if (targetStage) {
|
|
11246
11340
|
const lang = languageFromImage(targetStage.base);
|
|
@@ -11277,7 +11371,7 @@ function composeServices(ctx, file, byRoot, contributions, relocated) {
|
|
|
11277
11371
|
const [k, ...v] = item.split("=");
|
|
11278
11372
|
pairs.push([k, v.length > 0 ? v.join("=") : undefined]);
|
|
11279
11373
|
}
|
|
11280
|
-
} else if (
|
|
11374
|
+
} else if (isRecord2(env)) {
|
|
11281
11375
|
for (const [k, v] of Object.entries(env))
|
|
11282
11376
|
pairs.push([k, v === null || v === undefined ? undefined : String(v)]);
|
|
11283
11377
|
}
|
|
@@ -11396,16 +11490,16 @@ function knativeServices(ctx, file, runtime) {
|
|
|
11396
11490
|
}
|
|
11397
11491
|
for (const doc of Array.isArray(docs) ? docs : [docs]) {
|
|
11398
11492
|
const json = doc.toJS?.();
|
|
11399
|
-
if (!
|
|
11493
|
+
if (!isRecord2(json) || json.kind !== "Service")
|
|
11400
11494
|
continue;
|
|
11401
|
-
const spec =
|
|
11495
|
+
const spec = isRecord2(json.spec) && isRecord2(json.spec.template) && isRecord2(json.spec.template.spec) ? json.spec.template.spec : {};
|
|
11402
11496
|
for (const container of asArray(spec.containers)) {
|
|
11403
|
-
if (!
|
|
11497
|
+
if (!isRecord2(container))
|
|
11404
11498
|
continue;
|
|
11405
11499
|
const strings = (v) => asArray(v).filter((c) => typeof c === "string");
|
|
11406
11500
|
const cmd = strings(container.command);
|
|
11407
11501
|
const args = strings(container.args);
|
|
11408
|
-
const name =
|
|
11502
|
+
const name = isRecord2(json.metadata) ? asString(json.metadata.name) ?? "service" : "service";
|
|
11409
11503
|
const entry = { name, trigger: "http" };
|
|
11410
11504
|
const image = asString(container.image);
|
|
11411
11505
|
if (image)
|
|
@@ -11421,7 +11515,7 @@ function knativeServices(ctx, file, runtime) {
|
|
|
11421
11515
|
}
|
|
11422
11516
|
runtime.entrypoints.push(entry);
|
|
11423
11517
|
for (const env of asArray(container.env)) {
|
|
11424
|
-
if (
|
|
11518
|
+
if (isRecord2(env) && typeof env.name === "string") {
|
|
11425
11519
|
ctx.env.push({ name: env.name, source: `${file.path} env`, value: asString(env.value), evidence: { path: file.path, line: findLine(file.text, new RegExp(`name:\\s*${escapeRe(env.name)}\\b`)), detector: DETECTOR8 } });
|
|
11426
11520
|
}
|
|
11427
11521
|
}
|
|
@@ -11498,18 +11592,18 @@ function detectGcp(input, roots) {
|
|
|
11498
11592
|
if (basename3(file.path) !== "firebase.json")
|
|
11499
11593
|
continue;
|
|
11500
11594
|
const json = parseJsonLoose(file.text);
|
|
11501
|
-
if (!
|
|
11595
|
+
if (!isRecord2(json) || json.functions === undefined)
|
|
11502
11596
|
continue;
|
|
11503
11597
|
const entries = Array.isArray(json.functions) ? json.functions : [json.functions];
|
|
11504
11598
|
for (const fn of entries) {
|
|
11505
|
-
const source =
|
|
11599
|
+
const source = isRecord2(fn) ? asString(fn.source) ?? "functions" : "functions";
|
|
11506
11600
|
const root = joinPath(dirname6(file.path), source);
|
|
11507
11601
|
const rt = get(root, file.path, "gcp_cloud_functions");
|
|
11508
11602
|
rt.evidence.unshift(evidenceAt(file.path, file.text, findLine(file.text, /"functions"/), `${DETECTOR8}.firebase`));
|
|
11509
11603
|
}
|
|
11510
11604
|
}
|
|
11511
11605
|
for (const pkg of input.packageJsons) {
|
|
11512
|
-
const scripts =
|
|
11606
|
+
const scripts = isRecord2(pkg.json.scripts) ? pkg.json.scripts : {};
|
|
11513
11607
|
for (const [script, cmd] of Object.entries(scripts)) {
|
|
11514
11608
|
if (typeof cmd !== "string" || !/functions-framework/.test(cmd))
|
|
11515
11609
|
continue;
|
|
@@ -11656,7 +11750,7 @@ function detectAzure(input) {
|
|
|
11656
11750
|
if (basename3(hostFile.path) !== "host.json")
|
|
11657
11751
|
continue;
|
|
11658
11752
|
const host = parseJsonLoose(hostFile.text);
|
|
11659
|
-
if (!
|
|
11753
|
+
if (!isRecord2(host) || host.version !== undefined && !String(host.version).startsWith("2"))
|
|
11660
11754
|
continue;
|
|
11661
11755
|
const root = dirname6(hostFile.path);
|
|
11662
11756
|
const runtime = newRuntime("azure_functions", root, [hostFile.path], [evidenceAt(hostFile.path, hostFile.text, findLine(hostFile.text, /version/), DETECTOR9)], 0.9);
|
|
@@ -11678,7 +11772,7 @@ function detectAzure(input) {
|
|
|
11678
11772
|
if (settings) {
|
|
11679
11773
|
runtime.configFiles.push(settings.path);
|
|
11680
11774
|
const json = parseJsonLoose(settings.text);
|
|
11681
|
-
const values =
|
|
11775
|
+
const values = isRecord2(json) && isRecord2(json.Values) ? json.Values : {};
|
|
11682
11776
|
for (const name of Object.keys(values).sort()) {
|
|
11683
11777
|
ctx.env.push({ name, source: `${settings.path} Values`, value: asString(values[name]), evidence: evidenceAt(settings.path, settings.text, findLine(settings.text, new RegExp(`"${escapeRe(name)}"`)), DETECTOR9) });
|
|
11684
11778
|
}
|
|
@@ -11705,12 +11799,12 @@ function detectAzure(input) {
|
|
|
11705
11799
|
}
|
|
11706
11800
|
function handleFunctionJson(file, runtime, addDep) {
|
|
11707
11801
|
const json = parseJsonLoose(file.text);
|
|
11708
|
-
if (!
|
|
11802
|
+
if (!isRecord2(json))
|
|
11709
11803
|
return;
|
|
11710
11804
|
const fnName = basename3(dirname6(file.path));
|
|
11711
11805
|
let trigger = "unknown";
|
|
11712
11806
|
for (const b of asArray(json.bindings)) {
|
|
11713
|
-
if (!
|
|
11807
|
+
if (!isRecord2(b))
|
|
11714
11808
|
continue;
|
|
11715
11809
|
const raw = asString(b.type) ?? "";
|
|
11716
11810
|
const type = azureBindingType(raw);
|
|
@@ -11857,8 +11951,8 @@ function detectProcesses(input, roots) {
|
|
|
11857
11951
|
const map = new Map;
|
|
11858
11952
|
for (const pkg of packageJsons) {
|
|
11859
11953
|
const json = pkg.json;
|
|
11860
|
-
const deps = { ...
|
|
11861
|
-
const scripts =
|
|
11954
|
+
const deps = { ...isRecord2(json.dependencies) ? json.dependencies : {} };
|
|
11955
|
+
const scripts = isRecord2(json.scripts) ? json.scripts : {};
|
|
11862
11956
|
const bin = json.bin;
|
|
11863
11957
|
const server = Object.keys(deps).some((d) => SERVER_NPM.has(d));
|
|
11864
11958
|
const agent = Object.keys(deps).some((d) => AGENT_NPM.has(d));
|
|
@@ -11878,7 +11972,7 @@ function detectProcesses(input, roots) {
|
|
|
11878
11972
|
addEntry(rt, { name: "start", command: shellCommand(start), trigger });
|
|
11879
11973
|
if (typeof bin === "string")
|
|
11880
11974
|
addEntry(rt, { name: asString(json.name) ?? "bin", handler: joinPath(pkg.root, bin), command: ["node", joinPath(bin)], trigger: "cli" });
|
|
11881
|
-
else if (
|
|
11975
|
+
else if (isRecord2(bin))
|
|
11882
11976
|
for (const [name, target] of Object.entries(bin)) {
|
|
11883
11977
|
if (typeof target === "string")
|
|
11884
11978
|
addEntry(rt, { name, handler: joinPath(pkg.root, target), command: ["node", joinPath(target)], trigger: "cli" });
|
|
@@ -11976,10 +12070,10 @@ function pyprojectScripts(file, map) {
|
|
|
11976
12070
|
} catch {
|
|
11977
12071
|
return;
|
|
11978
12072
|
}
|
|
11979
|
-
const project =
|
|
11980
|
-
const tool =
|
|
11981
|
-
const poetry =
|
|
11982
|
-
const scripts = { ...
|
|
12073
|
+
const project = isRecord2(doc.project) ? doc.project : {};
|
|
12074
|
+
const tool = isRecord2(doc.tool) ? doc.tool : {};
|
|
12075
|
+
const poetry = isRecord2(tool.poetry) ? tool.poetry : {};
|
|
12076
|
+
const scripts = { ...isRecord2(poetry.scripts) ? poetry.scripts : {}, ...isRecord2(project.scripts) ? project.scripts : {} };
|
|
11983
12077
|
const names = Object.keys(scripts).sort();
|
|
11984
12078
|
if (names.length === 0)
|
|
11985
12079
|
return;
|
|
@@ -11994,16 +12088,16 @@ function pyprojectScripts(file, map) {
|
|
|
11994
12088
|
}
|
|
11995
12089
|
function langgraph(file, map) {
|
|
11996
12090
|
const json = parseJsonLoose(file.text);
|
|
11997
|
-
if (!
|
|
12091
|
+
if (!isRecord2(json))
|
|
11998
12092
|
return;
|
|
11999
12093
|
const root = dirname6(file.path);
|
|
12000
|
-
const graphs =
|
|
12094
|
+
const graphs = isRecord2(json.graphs) ? json.graphs : {};
|
|
12001
12095
|
const isJs = Object.values(graphs).some((g) => typeof g === "string" && /\.[cm]?[jt]s:/.test(g));
|
|
12002
12096
|
const rt = upsert(map, isJs ? "node_process" : "python_process", root, file.path);
|
|
12003
12097
|
rt.frameworks = [...new Set([...rt.frameworks ?? [], "langgraph"])].sort();
|
|
12004
12098
|
for (const name of Object.keys(graphs).sort()) {
|
|
12005
12099
|
const ref = graphs[name];
|
|
12006
|
-
const spec = typeof ref === "string" ? ref :
|
|
12100
|
+
const spec = typeof ref === "string" ? ref : isRecord2(ref) ? asString(ref.path) : undefined;
|
|
12007
12101
|
if (!spec)
|
|
12008
12102
|
continue;
|
|
12009
12103
|
const [p2, attr] = spec.split(":");
|
|
@@ -12149,10 +12243,10 @@ function detectVercel(input) {
|
|
|
12149
12243
|
const { ctx, packageJsons } = input;
|
|
12150
12244
|
const roots = new Map;
|
|
12151
12245
|
for (const pkg of packageJsons) {
|
|
12152
|
-
const deps = { ...
|
|
12246
|
+
const deps = { ...isRecord2(pkg.json.dependencies) ? pkg.json.dependencies : {}, ...isRecord2(pkg.json.devDependencies) ? pkg.json.devDependencies : {} };
|
|
12153
12247
|
if (!("next" in deps))
|
|
12154
12248
|
continue;
|
|
12155
|
-
const scripts =
|
|
12249
|
+
const scripts = isRecord2(pkg.json.scripts) ? pkg.json.scripts : {};
|
|
12156
12250
|
const start = asString(scripts.start) ?? asString(scripts.dev);
|
|
12157
12251
|
roots.set(pkg.root, { configFiles: [pkg.path], next: true, start: start ? splitCommand(start) : undefined });
|
|
12158
12252
|
}
|
|
@@ -12207,8 +12301,8 @@ function detectVercel(input) {
|
|
|
12207
12301
|
}
|
|
12208
12302
|
if (info.vercelJson) {
|
|
12209
12303
|
const json = parseJsonLoose(info.vercelJson.text);
|
|
12210
|
-
for (const cron of
|
|
12211
|
-
if (
|
|
12304
|
+
for (const cron of isRecord2(json) ? asArray(json.crons) : []) {
|
|
12305
|
+
if (isRecord2(cron) && typeof cron.path === "string")
|
|
12212
12306
|
runtime.entrypoints.push({ name: `cron ${asString(cron.schedule) ?? ""} ${cron.path}`.trim(), handler: cron.path, trigger: "cron" });
|
|
12213
12307
|
}
|
|
12214
12308
|
}
|
|
@@ -12248,7 +12342,7 @@ function readOptions(cfg, paths2, read, depth = 0) {
|
|
|
12248
12342
|
if (depth > 8 || !paths2.has(cfg))
|
|
12249
12343
|
return null;
|
|
12250
12344
|
const json = parseJsonLoose(read(cfg) ?? "");
|
|
12251
|
-
if (!
|
|
12345
|
+
if (!isRecord2(json))
|
|
12252
12346
|
return null;
|
|
12253
12347
|
const dir = dirname6(cfg);
|
|
12254
12348
|
const merged = {};
|
|
@@ -12261,10 +12355,10 @@ function readOptions(cfg, paths2, read, depth = 0) {
|
|
|
12261
12355
|
if (parent?.paths !== undefined)
|
|
12262
12356
|
merged.paths = parent.paths;
|
|
12263
12357
|
}
|
|
12264
|
-
const opts =
|
|
12358
|
+
const opts = isRecord2(json.compilerOptions) ? json.compilerOptions : {};
|
|
12265
12359
|
if (typeof opts.baseUrl === "string")
|
|
12266
12360
|
merged.baseUrl = joinPath(dir, opts.baseUrl);
|
|
12267
|
-
if (
|
|
12361
|
+
if (isRecord2(opts.paths)) {
|
|
12268
12362
|
merged.paths = {
|
|
12269
12363
|
base: typeof opts.baseUrl === "string" ? joinPath(dir, opts.baseUrl) : merged.baseUrl ?? dir,
|
|
12270
12364
|
list: Object.entries(opts.paths).map(([key, value]) => {
|
|
@@ -12318,17 +12412,17 @@ function exportTargets(value) {
|
|
|
12318
12412
|
return [value];
|
|
12319
12413
|
if (Array.isArray(value))
|
|
12320
12414
|
return value.flatMap(exportTargets);
|
|
12321
|
-
if (
|
|
12415
|
+
if (isRecord2(value))
|
|
12322
12416
|
return Object.values(value).flatMap(exportTargets);
|
|
12323
12417
|
return [];
|
|
12324
12418
|
}
|
|
12325
12419
|
function packageEntry(dir, sub, paths2, read) {
|
|
12326
12420
|
const json = parseJsonLoose(read(joinPath(dir, "package.json")) ?? "");
|
|
12327
12421
|
const fields = [];
|
|
12328
|
-
if (
|
|
12422
|
+
if (isRecord2(json)) {
|
|
12329
12423
|
const exp = json.exports;
|
|
12330
12424
|
const key = sub ? `./${sub}` : ".";
|
|
12331
|
-
if (
|
|
12425
|
+
if (isRecord2(exp) && Object.keys(exp).some((k) => k.startsWith("."))) {
|
|
12332
12426
|
if (exp[key] !== undefined)
|
|
12333
12427
|
fields.push(...exportTargets(exp[key]));
|
|
12334
12428
|
else {
|
|
@@ -12367,7 +12461,7 @@ function packageImportTargets(spec, from, paths2, read) {
|
|
|
12367
12461
|
const manifest = joinPath(d, "package.json");
|
|
12368
12462
|
if (paths2.has(manifest)) {
|
|
12369
12463
|
const json = parseJsonLoose(read(manifest) ?? "");
|
|
12370
|
-
const imports =
|
|
12464
|
+
const imports = isRecord2(json) && isRecord2(json.imports) ? json.imports : undefined;
|
|
12371
12465
|
if (imports) {
|
|
12372
12466
|
const targets = [];
|
|
12373
12467
|
if (imports[spec] !== undefined)
|
|
@@ -12643,14 +12737,14 @@ var ANCESTOR_ORM = [
|
|
|
12643
12737
|
var CODE_FILE2 = /\.(?:[cm]?[jt]sx?|py)$/;
|
|
12644
12738
|
function pyDependencyNames(doc) {
|
|
12645
12739
|
const out = [];
|
|
12646
|
-
const project =
|
|
12740
|
+
const project = isRecord2(doc.project) ? doc.project : {};
|
|
12647
12741
|
for (const req of asArray(project.dependencies)) {
|
|
12648
12742
|
const m = typeof req === "string" ? /^\s*([A-Za-z0-9][\w.-]*)/.exec(req) : null;
|
|
12649
12743
|
if (m)
|
|
12650
12744
|
out.push(m[1]);
|
|
12651
12745
|
}
|
|
12652
|
-
const poetry =
|
|
12653
|
-
if (
|
|
12746
|
+
const poetry = isRecord2(doc.tool) && isRecord2(doc.tool.poetry) ? doc.tool.poetry : {};
|
|
12747
|
+
if (isRecord2(poetry.dependencies))
|
|
12654
12748
|
out.push(...Object.keys(poetry.dependencies));
|
|
12655
12749
|
return out.map(pyName);
|
|
12656
12750
|
}
|
|
@@ -12661,7 +12755,7 @@ function npmDeps(json) {
|
|
|
12661
12755
|
const out = [];
|
|
12662
12756
|
for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
12663
12757
|
const deps = json[field];
|
|
12664
|
-
if (
|
|
12758
|
+
if (isRecord2(deps))
|
|
12665
12759
|
out.push(...Object.keys(deps));
|
|
12666
12760
|
}
|
|
12667
12761
|
return out;
|
|
@@ -12680,7 +12774,7 @@ function directDeps(dir, byPath, npmNames, pyNames, goModules, workspaces) {
|
|
|
12680
12774
|
const pkg = byPath.get(joinPath(dir, "package.json"));
|
|
12681
12775
|
if (pkg) {
|
|
12682
12776
|
const json = parseJsonLoose(pkg.text);
|
|
12683
|
-
if (
|
|
12777
|
+
if (isRecord2(json)) {
|
|
12684
12778
|
for (const name of npmDeps(json)) {
|
|
12685
12779
|
const target = npmNames.get(name);
|
|
12686
12780
|
if (target !== undefined)
|
|
@@ -12690,11 +12784,11 @@ function directDeps(dir, byPath, npmNames, pyNames, goModules, workspaces) {
|
|
|
12690
12784
|
}
|
|
12691
12785
|
const pyproject = tomlDoc(byPath.get(joinPath(dir, "pyproject.toml")));
|
|
12692
12786
|
if (pyproject) {
|
|
12693
|
-
const tool =
|
|
12694
|
-
const uv =
|
|
12695
|
-
const sources =
|
|
12787
|
+
const tool = isRecord2(pyproject.tool) ? pyproject.tool : {};
|
|
12788
|
+
const uv = isRecord2(tool.uv) ? tool.uv : {};
|
|
12789
|
+
const sources = isRecord2(uv.sources) ? uv.sources : {};
|
|
12696
12790
|
for (const [name, src] of Object.entries(sources)) {
|
|
12697
|
-
if (!
|
|
12791
|
+
if (!isRecord2(src))
|
|
12698
12792
|
continue;
|
|
12699
12793
|
if (src.workspace === true) {
|
|
12700
12794
|
const target = pyNames.get(pyName(name));
|
|
@@ -12714,13 +12808,13 @@ function directDeps(dir, byPath, npmNames, pyNames, goModules, workspaces) {
|
|
|
12714
12808
|
out.push(target);
|
|
12715
12809
|
}
|
|
12716
12810
|
}
|
|
12717
|
-
const poetry =
|
|
12718
|
-
const groups = [poetry.dependencies, ...
|
|
12811
|
+
const poetry = isRecord2(tool.poetry) ? tool.poetry : {};
|
|
12812
|
+
const groups = [poetry.dependencies, ...isRecord2(poetry.group) ? Object.values(poetry.group).map((g) => isRecord2(g) ? g.dependencies : undefined) : []];
|
|
12719
12813
|
for (const deps of groups) {
|
|
12720
|
-
if (!
|
|
12814
|
+
if (!isRecord2(deps))
|
|
12721
12815
|
continue;
|
|
12722
12816
|
for (const spec of Object.values(deps)) {
|
|
12723
|
-
const path =
|
|
12817
|
+
const path = isRecord2(spec) ? asString(spec.path) : undefined;
|
|
12724
12818
|
if (path)
|
|
12725
12819
|
out.push(joinPath(dir, path));
|
|
12726
12820
|
}
|
|
@@ -12760,13 +12854,13 @@ function directDeps(dir, byPath, npmNames, pyNames, goModules, workspaces) {
|
|
|
12760
12854
|
return out;
|
|
12761
12855
|
}
|
|
12762
12856
|
function composeBuildsUnder(svc, base, root) {
|
|
12763
|
-
if (!
|
|
12857
|
+
if (!isRecord2(svc) || svc.build === undefined)
|
|
12764
12858
|
return false;
|
|
12765
12859
|
const build = svc.build;
|
|
12766
|
-
const context = joinPath(base, typeof build === "string" ? build :
|
|
12860
|
+
const context = joinPath(base, typeof build === "string" ? build : isRecord2(build) ? asString(build.context) ?? "." : ".");
|
|
12767
12861
|
if (isUnder2(context, root))
|
|
12768
12862
|
return true;
|
|
12769
|
-
const dockerfile =
|
|
12863
|
+
const dockerfile = isRecord2(build) ? asString(build.dockerfile) : undefined;
|
|
12770
12864
|
return dockerfile !== undefined && isUnder2(joinPath(context, dockerfile), root);
|
|
12771
12865
|
}
|
|
12772
12866
|
function computeScope(files, root) {
|
|
@@ -12780,12 +12874,12 @@ function computeScope(files, root) {
|
|
|
12780
12874
|
const name = basename3(f.path);
|
|
12781
12875
|
if (name === "package.json") {
|
|
12782
12876
|
const json = parseJsonLoose(f.text);
|
|
12783
|
-
if (
|
|
12877
|
+
if (isRecord2(json) && typeof json.name === "string")
|
|
12784
12878
|
npmNames.set(json.name, dirname6(f.path));
|
|
12785
12879
|
} else if (name === "pyproject.toml") {
|
|
12786
12880
|
const doc = tomlDoc(f);
|
|
12787
|
-
const project = doc &&
|
|
12788
|
-
const poetry = doc &&
|
|
12881
|
+
const project = doc && isRecord2(doc.project) ? doc.project : undefined;
|
|
12882
|
+
const poetry = doc && isRecord2(doc.tool) && isRecord2(doc.tool.poetry) ? doc.tool.poetry : undefined;
|
|
12789
12883
|
const projectName = asString(project?.name) ?? asString(poetry?.name);
|
|
12790
12884
|
if (projectName)
|
|
12791
12885
|
pyNames.set(pyName(projectName), dirname6(f.path));
|
|
@@ -12800,16 +12894,16 @@ function computeScope(files, root) {
|
|
|
12800
12894
|
if (basename3(f.path) !== "pyproject.toml")
|
|
12801
12895
|
continue;
|
|
12802
12896
|
const doc = tomlDoc(f);
|
|
12803
|
-
const uv = doc &&
|
|
12804
|
-
if (!uv || !
|
|
12897
|
+
const uv = doc && isRecord2(doc.tool) && isRecord2(doc.tool.uv) ? doc.tool.uv : undefined;
|
|
12898
|
+
if (!uv || !isRecord2(uv.workspace))
|
|
12805
12899
|
continue;
|
|
12806
12900
|
const base = dirname6(f.path);
|
|
12807
12901
|
const members = asArray(uv.workspace.members).filter((m) => typeof m === "string").map((m) => globRegex(joinPath(base, m)));
|
|
12808
12902
|
if (!members.some((re) => re.test(root) || [...pyNames.values()].some((d) => isUnder2(root, d) && re.test(d))))
|
|
12809
12903
|
continue;
|
|
12810
12904
|
const sources = new Map;
|
|
12811
|
-
for (const [name, src] of Object.entries(
|
|
12812
|
-
if (!
|
|
12905
|
+
for (const [name, src] of Object.entries(isRecord2(uv.sources) ? uv.sources : {})) {
|
|
12906
|
+
if (!isRecord2(src))
|
|
12813
12907
|
continue;
|
|
12814
12908
|
const target = src.workspace === true ? pyNames.get(pyName(name)) : asString(src.path) ? joinPath(base, asString(src.path)) : undefined;
|
|
12815
12909
|
if (target !== undefined)
|
|
@@ -12875,7 +12969,7 @@ function computeScope(files, root) {
|
|
|
12875
12969
|
const rel2 = base === "." ? root : root.slice(base.length + 1);
|
|
12876
12970
|
if (/compose/.test(name)) {
|
|
12877
12971
|
const doc = loadYaml(f.text);
|
|
12878
|
-
const services =
|
|
12972
|
+
const services = isRecord2(doc) && isRecord2(doc.services) ? doc.services : {};
|
|
12879
12973
|
if (Object.values(services).some((svc) => composeBuildsUnder(svc, base, root)))
|
|
12880
12974
|
configs.add(f.path);
|
|
12881
12975
|
} else if (new RegExp(`(?:^|[\\s"'=:/])\\.?/?${rel2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?:[/"'\\s]|$)`, "m").test(f.text)) {
|
|
@@ -12984,8 +13078,8 @@ function scopeComposeImages(ctx, scope) {
|
|
|
12984
13078
|
if (base === scope.root)
|
|
12985
13079
|
continue;
|
|
12986
13080
|
const doc = loadYaml(f.text);
|
|
12987
|
-
const services =
|
|
12988
|
-
const builds = services.some((svc) =>
|
|
13081
|
+
const services = isRecord2(doc) && isRecord2(doc.services) ? Object.values(doc.services) : [];
|
|
13082
|
+
const builds = services.some((svc) => isRecord2(svc) && svc.build !== undefined);
|
|
12989
13083
|
if (!builds)
|
|
12990
13084
|
optional.add(f.path);
|
|
12991
13085
|
}
|
|
@@ -12999,14 +13093,14 @@ function scopeComposeImages(ctx, scope) {
|
|
|
12999
13093
|
if (!/compose/.test(basename3(path)))
|
|
13000
13094
|
continue;
|
|
13001
13095
|
const doc = loadYaml(ctx.byPath.get(path)?.text ?? "");
|
|
13002
|
-
const services =
|
|
13096
|
+
const services = isRecord2(doc) && isRecord2(doc.services) ? doc.services : {};
|
|
13003
13097
|
const base = path.includes("/") ? path.slice(0, path.lastIndexOf("/")) : ".";
|
|
13004
13098
|
const deps = new Set;
|
|
13005
13099
|
let declared = false;
|
|
13006
13100
|
for (const svc of Object.values(services)) {
|
|
13007
|
-
if (!
|
|
13101
|
+
if (!isRecord2(svc) || !composeBuildsUnder(svc, base, scope.root))
|
|
13008
13102
|
continue;
|
|
13009
|
-
const names = [...Array.isArray(svc.depends_on) ? svc.depends_on :
|
|
13103
|
+
const names = [...Array.isArray(svc.depends_on) ? svc.depends_on : isRecord2(svc.depends_on) ? Object.keys(svc.depends_on) : [], ...Array.isArray(svc.links) ? svc.links : []];
|
|
13010
13104
|
for (const n of names)
|
|
13011
13105
|
if (typeof n === "string") {
|
|
13012
13106
|
declared = true;
|
|
@@ -13140,7 +13234,7 @@ function scriptLocalFilter(ctx, runtimes) {
|
|
|
13140
13234
|
}
|
|
13141
13235
|
function lifecycleScripts(text) {
|
|
13142
13236
|
const json = parseJsonLoose(text);
|
|
13143
|
-
const scripts = new Map(Object.entries(
|
|
13237
|
+
const scripts = new Map(Object.entries(isRecord2(json) && isRecord2(json.scripts) ? json.scripts : {}).filter((e) => typeof e[1] === "string"));
|
|
13144
13238
|
const selected = new Set([...scripts.keys()].filter((name) => /^(?:pre|post)?(?:start|serve|build|install|prepare)(?::[\w:-]+)?$/.test(name)));
|
|
13145
13239
|
const queue = [...selected];
|
|
13146
13240
|
while (queue.length > 0) {
|
|
@@ -13474,7 +13568,7 @@ function detectDependencies(input) {
|
|
|
13474
13568
|
}
|
|
13475
13569
|
|
|
13476
13570
|
// ../../packages/harness-bundle/src/register/harness-digest.ts
|
|
13477
|
-
import { createHash as
|
|
13571
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
13478
13572
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
13479
13573
|
import { join as join7 } from "node:path";
|
|
13480
13574
|
|
|
@@ -13550,7 +13644,7 @@ function harnessFiles(manifest, map, read) {
|
|
|
13550
13644
|
if (basename3(p2) !== "package.json")
|
|
13551
13645
|
continue;
|
|
13552
13646
|
const json = parseJsonLoose(read(p2) ?? "");
|
|
13553
|
-
if (
|
|
13647
|
+
if (isRecord2(json) && typeof json.name === "string")
|
|
13554
13648
|
workspacePackages.set(json.name, dirname6(p2));
|
|
13555
13649
|
}
|
|
13556
13650
|
for (const f of importClosure({ entries, paths: paths2, read, workspacePackages }).files)
|
|
@@ -13578,7 +13672,7 @@ function harnessDigest(manifest, map, filesDir) {
|
|
|
13578
13672
|
};
|
|
13579
13673
|
const byPath = new Map(manifest.files.map((f) => [f.path, f]));
|
|
13580
13674
|
const links = new Map(manifest.files.flatMap((f) => f.symlinkTarget !== undefined ? [[f.path, f.symlinkTarget]] : []));
|
|
13581
|
-
const hash =
|
|
13675
|
+
const hash = createHash5("sha256");
|
|
13582
13676
|
hash.update(JSON.stringify({
|
|
13583
13677
|
v: 1,
|
|
13584
13678
|
detector: DETECTOR_VERSION,
|
|
@@ -13628,10 +13722,10 @@ function wranglerAssetDirs(configPath, text) {
|
|
|
13628
13722
|
raw.push(m[1]);
|
|
13629
13723
|
} else {
|
|
13630
13724
|
const json = parseJsonLoose(text);
|
|
13631
|
-
if (
|
|
13632
|
-
if (
|
|
13725
|
+
if (isRecord2(json)) {
|
|
13726
|
+
if (isRecord2(json.assets) && typeof json.assets.directory === "string")
|
|
13633
13727
|
raw.push(json.assets.directory);
|
|
13634
|
-
if (
|
|
13728
|
+
if (isRecord2(json.site) && typeof json.site.bucket === "string")
|
|
13635
13729
|
raw.push(json.site.bucket);
|
|
13636
13730
|
}
|
|
13637
13731
|
}
|
|
@@ -13711,7 +13805,7 @@ function insideCheckout(dir) {
|
|
|
13711
13805
|
}
|
|
13712
13806
|
}
|
|
13713
13807
|
async function digestFile(path) {
|
|
13714
|
-
const hash =
|
|
13808
|
+
const hash = createHash6("sha256");
|
|
13715
13809
|
await new Promise((resolve7, reject) => {
|
|
13716
13810
|
createReadStream(path).on("data", (chunk) => hash.update(chunk)).on("error", reject).on("end", () => resolve7());
|
|
13717
13811
|
});
|
|
@@ -14207,7 +14301,7 @@ function formatBytes(bytes) {
|
|
|
14207
14301
|
}
|
|
14208
14302
|
|
|
14209
14303
|
// src/harness-prompt-sources.ts
|
|
14210
|
-
import { createHash as
|
|
14304
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
14211
14305
|
import { extname as extname5 } from "node:path";
|
|
14212
14306
|
|
|
14213
14307
|
// src/prompt-source-verification/index.ts
|
|
@@ -14777,7 +14871,7 @@ function normalizeUsage(reviewed, endpointVerified, reviewedConsumerCited = fals
|
|
|
14777
14871
|
|
|
14778
14872
|
// src/harness-prompt-sources.ts
|
|
14779
14873
|
var CODE2 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".py"]);
|
|
14780
|
-
var shortHash = (text) =>
|
|
14874
|
+
var shortHash = (text) => createHash7("sha256").update(text).digest("hex").slice(0, 20);
|
|
14781
14875
|
var TEST_PATH3 = /(^|\/)(?:test|tests|__tests__|fixtures?|test-fixtures)(?:[_-]|\/|$)|\.(?:test|spec)\.[^.]+$/i;
|
|
14782
14876
|
var MAX_CODE_PROMPT_PATHS = 64;
|
|
14783
14877
|
var identity = (source) => JSON.stringify([source.path, source.selector ?? null]);
|
|
@@ -15825,23 +15919,6 @@ function unresolvedReports(resolution, sites) {
|
|
|
15825
15919
|
function promptArtifactsFromCallSites(callSites, context, promoted, options = {}) {
|
|
15826
15920
|
return assemblePromptArtifacts(resolvePromptArguments(callSites, context, options), callSites, promoted, options);
|
|
15827
15921
|
}
|
|
15828
|
-
|
|
15829
|
-
// src/harness-sync-limits.ts
|
|
15830
|
-
var MAX_HARNESS_SYNC_GRAPH_BYTES = 2000000;
|
|
15831
|
-
function assertHarnessGraphSyncSize(graph) {
|
|
15832
|
-
if (!graph || typeof graph !== "object" || Array.isArray(graph)) {
|
|
15833
|
-
throw new CliInputError("Harness graph must be an object before sync.");
|
|
15834
|
-
}
|
|
15835
|
-
const graphBytes = Buffer.byteLength(JSON.stringify(graph), "utf8");
|
|
15836
|
-
if (graphBytes > MAX_HARNESS_SYNC_GRAPH_BYTES) {
|
|
15837
|
-
throw new CliInputError(`Harness graph is too large to sync (${graphBytes.toLocaleString()} bytes; limit ${MAX_HARNESS_SYNC_GRAPH_BYTES.toLocaleString()}).`, [
|
|
15838
|
-
"Run `moda harness analyze --path=<agent-dir>` to narrow the harness root.",
|
|
15839
|
-
"Reduce captured prompt/tool bodies if the graph grew too large.",
|
|
15840
|
-
"Split multiple agent roots into separate harness syncs per tenant."
|
|
15841
|
-
].join(`
|
|
15842
|
-
`));
|
|
15843
|
-
}
|
|
15844
|
-
}
|
|
15845
15922
|
// src/harness.ts
|
|
15846
15923
|
var MODA_DIR = ".moda";
|
|
15847
15924
|
var HARNESS_PATH = join12(MODA_DIR, "harness.json");
|
|
@@ -15875,6 +15952,7 @@ var HARNESS_FAMILY_FLAGS = [
|
|
|
15875
15952
|
"remote",
|
|
15876
15953
|
"repair",
|
|
15877
15954
|
"report",
|
|
15955
|
+
"require-full-bodies",
|
|
15878
15956
|
"run",
|
|
15879
15957
|
"run-id",
|
|
15880
15958
|
"shards",
|
|
@@ -16159,7 +16237,7 @@ async function runHarnessCommand(context) {
|
|
|
16159
16237
|
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.");
|
|
16160
16238
|
}
|
|
16161
16239
|
if (context.flags["github-actions"] === "true") {
|
|
16162
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
16240
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-9a48sd2r.js");
|
|
16163
16241
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
16164
16242
|
writeReport: (report2) => {
|
|
16165
16243
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -16310,8 +16388,8 @@ async function runHarnessCommand(context) {
|
|
|
16310
16388
|
}
|
|
16311
16389
|
const { artifacts, unknowns, canonicalAgentIdentities } = deterministicGraphItems(rootDir, promote === "all" ? undefined : promote);
|
|
16312
16390
|
tagComponentStatus({ runtimeAgents: [], artifacts }, rootDir);
|
|
16313
|
-
const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-
|
|
16314
|
-
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-
|
|
16391
|
+
const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-t4fncjwa.js");
|
|
16392
|
+
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-5q79y09b.js");
|
|
16315
16393
|
let components = { runtimeAgents: [], artifacts: [], warnings: [] };
|
|
16316
16394
|
if (promote === "all" || promote === "topology" || promote === "tools") {
|
|
16317
16395
|
const { result, ctx } = extractHarnessWithContext2(rootDir);
|
|
@@ -16377,8 +16455,8 @@ async function runHarnessCommand(context) {
|
|
|
16377
16455
|
}
|
|
16378
16456
|
case "extract": {
|
|
16379
16457
|
writeHumanProgress(context, "Harness extract: tracing model call sites (no LLM, no network)...");
|
|
16380
|
-
const { extractHarnessWithContext: extractHarnessWithContext2, serializeExtractResult } = await import("./index-
|
|
16381
|
-
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-
|
|
16458
|
+
const { extractHarnessWithContext: extractHarnessWithContext2, serializeExtractResult } = await import("./index-t4fncjwa.js");
|
|
16459
|
+
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-5q79y09b.js");
|
|
16382
16460
|
const { result, ctx } = extractHarnessWithContext2(rootDir, { fresh: true });
|
|
16383
16461
|
const items = deterministicGraphItems(rootDir);
|
|
16384
16462
|
const artifacts = items.artifacts;
|
|
@@ -16873,7 +16951,7 @@ function reportJsonCandidates(output) {
|
|
|
16873
16951
|
function parseHarnessReportCandidate(candidate) {
|
|
16874
16952
|
try {
|
|
16875
16953
|
const parsed = JSON.parse(candidate.trim());
|
|
16876
|
-
if (
|
|
16954
|
+
if (isRecord3(parsed) && parsed.schemaVersion === "harness_report.v0.1") {
|
|
16877
16955
|
return parsed;
|
|
16878
16956
|
}
|
|
16879
16957
|
} catch {
|
|
@@ -17180,7 +17258,7 @@ function repairExternalAnalystReport(report, rootDir, options = {}) {
|
|
|
17180
17258
|
];
|
|
17181
17259
|
if (owners.some((owner) => knownAgents.has(owner)))
|
|
17182
17260
|
continue;
|
|
17183
|
-
const id = `unresolved_tool_owner_${
|
|
17261
|
+
const id = `unresolved_tool_owner_${createHash8("sha256").update(artifact2.id).digest("hex").slice(0, 16)}`;
|
|
17184
17262
|
if (!normalized.graph.unknowns.some((unknown) => unknown.id === id))
|
|
17185
17263
|
normalized.graph.unknowns.push({
|
|
17186
17264
|
id,
|
|
@@ -17285,8 +17363,8 @@ var CONCERN_PROMOTED_ARTIFACT_TYPES = {
|
|
|
17285
17363
|
evals: new Set(["model_config", "eval"])
|
|
17286
17364
|
};
|
|
17287
17365
|
async function deterministicFloorGraph(rootDir, options = {}) {
|
|
17288
|
-
const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-
|
|
17289
|
-
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-
|
|
17366
|
+
const { extractHarnessWithContext: extractHarnessWithContext2 } = await import("./index-t4fncjwa.js");
|
|
17367
|
+
const { enumerateHarnessComponents, mergeEnumeratedComponents } = await import("./index-5q79y09b.js");
|
|
17290
17368
|
const { result, ctx } = extractHarnessWithContext2(rootDir);
|
|
17291
17369
|
const items = deterministicGraphItems(rootDir);
|
|
17292
17370
|
const components = mergeEnumeratedComponents(items.artifacts, enumerateHarnessComponents(result, ctx));
|
|
@@ -17440,7 +17518,7 @@ function mergeDeterministicArtifacts(graph, rootDir, options = {}) {
|
|
|
17440
17518
|
}
|
|
17441
17519
|
const extracted = !allowedTypes || allowedTypes.has("model_config") ? extractedModelItems(rootDir) : { artifacts: [], unknowns: [], rewritten: new Set, enabled: false };
|
|
17442
17520
|
promoted = withExtractedModels(promoted, extracted, rootDir);
|
|
17443
|
-
if (extracted.enabled &&
|
|
17521
|
+
if (extracted.enabled && isRecord3(graph.scan)) {
|
|
17444
17522
|
try {
|
|
17445
17523
|
const { literals, truncated } = collectModelLiterals(rootDir);
|
|
17446
17524
|
const scan = graph.scan;
|
|
@@ -17564,7 +17642,7 @@ function remapCanonicalArtifactAgents(graph, artifacts = graph.artifacts, dropUn
|
|
|
17564
17642
|
}
|
|
17565
17643
|
for (const [agentId, artifactIds] of unresolved) {
|
|
17566
17644
|
const identity2 = canonical.get(agentId);
|
|
17567
|
-
const id = `unresolved_agent_links_${
|
|
17645
|
+
const id = `unresolved_agent_links_${createHash8("sha256").update(agentId).digest("hex").slice(0, 16)}`;
|
|
17568
17646
|
if (graph.unknowns.some((unknown) => unknown.id === id))
|
|
17569
17647
|
continue;
|
|
17570
17648
|
graph.unknowns.push({
|
|
@@ -17853,18 +17931,18 @@ function extractAgentTextFromOutput(output) {
|
|
|
17853
17931
|
`);
|
|
17854
17932
|
}
|
|
17855
17933
|
function extractTextFromAgentEvent(event) {
|
|
17856
|
-
if (!
|
|
17934
|
+
if (!isRecord3(event))
|
|
17857
17935
|
return;
|
|
17858
17936
|
const directText = stringValue(event.text) ?? stringValue(event.message) ?? stringValue(event.delta) ?? stringValue(event.result);
|
|
17859
17937
|
if (directText)
|
|
17860
17938
|
return directText;
|
|
17861
|
-
const message =
|
|
17939
|
+
const message = isRecord3(event.message) ? event.message : undefined;
|
|
17862
17940
|
const messageText = message ? stringValue(message.text) ?? stringValue(message.content) : undefined;
|
|
17863
17941
|
if (messageText)
|
|
17864
17942
|
return messageText;
|
|
17865
17943
|
const content = Array.isArray(message?.content) ? message.content : Array.isArray(event.content) ? event.content : [];
|
|
17866
17944
|
const textParts = content.map((part) => {
|
|
17867
|
-
if (!
|
|
17945
|
+
if (!isRecord3(part))
|
|
17868
17946
|
return;
|
|
17869
17947
|
return stringValue(part.text) ?? stringValue(part.content);
|
|
17870
17948
|
}).filter((part) => Boolean(part));
|
|
@@ -18102,9 +18180,9 @@ function formatExternalAgentDisplayEvent(event, adapter) {
|
|
|
18102
18180
|
`;
|
|
18103
18181
|
}
|
|
18104
18182
|
function extractAgentEventTelemetry(event) {
|
|
18105
|
-
const message =
|
|
18106
|
-
const usage =
|
|
18107
|
-
const modelUsage =
|
|
18183
|
+
const message = isRecord3(event.message) ? event.message : undefined;
|
|
18184
|
+
const usage = isRecord3(event.usage) ? event.usage : isRecord3(message?.usage) ? message.usage : undefined;
|
|
18185
|
+
const modelUsage = isRecord3(event.modelUsage) ? event.modelUsage : undefined;
|
|
18108
18186
|
const model = stringValue(event.model) ?? stringValue(message?.model) ?? (modelUsage ? Object.keys(modelUsage)[0] : undefined);
|
|
18109
18187
|
const durationValue = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
18110
18188
|
const durationMs = durationValue(event.duration_ms) ?? durationValue(event.durationMs) ?? durationValue(event.duration_api_ms);
|
|
@@ -18118,7 +18196,7 @@ function extractAgentEventTelemetry(event) {
|
|
|
18118
18196
|
}
|
|
18119
18197
|
function parseExternalAgentEvent(event) {
|
|
18120
18198
|
const body = parseExternalAgentEventBody(event);
|
|
18121
|
-
if (!
|
|
18199
|
+
if (!isRecord3(event))
|
|
18122
18200
|
return body;
|
|
18123
18201
|
const telemetry = extractAgentEventTelemetry(event);
|
|
18124
18202
|
if (!telemetry)
|
|
@@ -18130,10 +18208,10 @@ function parseExternalAgentEvent(event) {
|
|
|
18130
18208
|
return { kind: "system", message: "usage update", telemetryOnly: true, ...telemetry };
|
|
18131
18209
|
}
|
|
18132
18210
|
function parseExternalAgentEventBody(event) {
|
|
18133
|
-
if (!
|
|
18211
|
+
if (!isRecord3(event))
|
|
18134
18212
|
return { kind: "agent_text", message: truncateText(String(event), 500) };
|
|
18135
|
-
const msg =
|
|
18136
|
-
const call =
|
|
18213
|
+
const msg = isRecord3(event.msg) ? event.msg : undefined;
|
|
18214
|
+
const call = isRecord3(event.call) ? event.call : undefined;
|
|
18137
18215
|
const type = stringValue(event.type) ?? stringValue(event.event) ?? stringValue(msg?.type);
|
|
18138
18216
|
const subtype = stringValue(event.subtype);
|
|
18139
18217
|
if (type === "rate_limit_event")
|
|
@@ -18147,7 +18225,7 @@ function parseExternalAgentEventBody(event) {
|
|
|
18147
18225
|
if (directText && !isLowSignalEventType(type)) {
|
|
18148
18226
|
return { kind: "agent_text", message: truncateText(firstMeaningfulLine(directText), 500) };
|
|
18149
18227
|
}
|
|
18150
|
-
const message =
|
|
18228
|
+
const message = isRecord3(event.message) ? event.message : undefined;
|
|
18151
18229
|
const messageText = message ? stringValue(message.text) ?? stringValue(message.content) : undefined;
|
|
18152
18230
|
if (messageText && !isLowSignalEventType(type)) {
|
|
18153
18231
|
return { kind: "agent_text", message: truncateText(firstMeaningfulLine(messageText), 500) };
|
|
@@ -18168,7 +18246,7 @@ function parseExternalAgentEventBody(event) {
|
|
|
18168
18246
|
return;
|
|
18169
18247
|
}
|
|
18170
18248
|
function parseAgentContentPart(part) {
|
|
18171
|
-
if (!
|
|
18249
|
+
if (!isRecord3(part))
|
|
18172
18250
|
return;
|
|
18173
18251
|
const partType = stringValue(part.type);
|
|
18174
18252
|
if (partType === "tool_use" || partType === "tool_call") {
|
|
@@ -18190,7 +18268,7 @@ function parseAgentContentPart(part) {
|
|
|
18190
18268
|
return;
|
|
18191
18269
|
}
|
|
18192
18270
|
function toolInputDetail(input) {
|
|
18193
|
-
if (!
|
|
18271
|
+
if (!isRecord3(input))
|
|
18194
18272
|
return;
|
|
18195
18273
|
const value = stringValue(input.file_path) ?? stringValue(input.filePath) ?? stringValue(input.path) ?? stringValue(input.notebook_path) ?? stringValue(input.command) ?? stringValue(input.cmd) ?? stringValue(input.pattern) ?? stringValue(input.query);
|
|
18196
18274
|
return value ? truncateText(firstMeaningfulLine(value), 300) : undefined;
|
|
@@ -18208,7 +18286,7 @@ function analystDisplayName(adapter) {
|
|
|
18208
18286
|
return "Cursor";
|
|
18209
18287
|
return "Codex";
|
|
18210
18288
|
}
|
|
18211
|
-
function
|
|
18289
|
+
function isRecord3(value) {
|
|
18212
18290
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
18213
18291
|
}
|
|
18214
18292
|
function stringValue(value) {
|
|
@@ -19284,15 +19362,36 @@ function plannedDryRunRemote(plan) {
|
|
|
19284
19362
|
};
|
|
19285
19363
|
}
|
|
19286
19364
|
async function syncHarnessWithRemote(context, body) {
|
|
19287
|
-
assertHarnessGraphSyncSize(body.graph);
|
|
19288
19365
|
const profileOptions = { profile: context.profile, env: context.env };
|
|
19289
19366
|
const hasApiKey = Boolean(resolveApiKey(profileOptions));
|
|
19367
|
+
const requireFullBodies = context.flags["require-full-bodies"] === "true";
|
|
19368
|
+
const prepared = await prepareHarnessSyncRequest(body, !context.dryRun && hasApiKey ? controlApiArtifactBodyStore((endpoint, init) => callControlAPI(endpoint, init, profileOptions)) : undefined, undefined, undefined, { requireStorable: requireFullBodies });
|
|
19369
|
+
assertHarnessGraphSyncSize(prepared.request.graph);
|
|
19370
|
+
assertHarnessSyncRequestSize({ ...prepared.request, dryRun: context.dryRun });
|
|
19371
|
+
if (prepared.shortened > 0 && context.dryRun) {
|
|
19372
|
+
writeHarnessNotice(context, "The graph is over the sync limit, so its largest bodies are shortened. A dry run uploads none of their full text; the real sync uploads it.");
|
|
19373
|
+
}
|
|
19374
|
+
const bodiesLabel = (count) => `${count} shortened ${count === 1 ? "body" : "bodies"}`;
|
|
19375
|
+
if (prepared.unstorableBodies > 0) {
|
|
19376
|
+
const count = bodiesLabel(prepared.unstorableBodies);
|
|
19377
|
+
if (requireFullBodies) {
|
|
19378
|
+
throw new CliInputError(`${count} ${prepared.unstorableBodies === 1 ? "is" : "are"} over the ${MAX_STORED_ARTIFACT_BODY_BYTES.toLocaleString()}-byte full-body limit and cannot be stored, so nothing was synced (--require-full-bodies).`, "Split the largest artifacts into smaller files, or drop --require-full-bodies to sync with shortened bodies.");
|
|
19379
|
+
}
|
|
19380
|
+
writeHarnessNotice(context, `${count} ${prepared.unstorableBodies === 1 ? "is" : "are"} over the ${MAX_STORED_ARTIFACT_BODY_BYTES.toLocaleString()}-byte full-body limit; the harness syncs with them shortened and their full text is not stored.`);
|
|
19381
|
+
}
|
|
19382
|
+
if (prepared.storeFailed) {
|
|
19383
|
+
const count = bodiesLabel(prepared.storeFailedBodies);
|
|
19384
|
+
if (requireFullBodies) {
|
|
19385
|
+
throw new CliInputError(`Uploading the full text of ${count} failed, so nothing was synced (--require-full-bodies).`, "Rerun `moda harness sync`, or drop --require-full-bodies to sync with shortened bodies.");
|
|
19386
|
+
}
|
|
19387
|
+
writeHarnessNotice(context, `Uploading the full text of ${count} failed; the harness syncs with shortened bodies and their full text is not retrievable yet. Rerun \`moda harness sync\` to upload it (the version does not change).`);
|
|
19388
|
+
}
|
|
19290
19389
|
if (context.dryRun && !hasApiKey)
|
|
19291
19390
|
return;
|
|
19292
19391
|
return await callControlAPI("/harnesses/sync", {
|
|
19293
19392
|
method: "POST",
|
|
19294
19393
|
body: JSON.stringify({
|
|
19295
|
-
...
|
|
19394
|
+
...prepared.request,
|
|
19296
19395
|
dryRun: context.dryRun
|
|
19297
19396
|
})
|
|
19298
19397
|
}, profileOptions);
|
|
@@ -21068,7 +21167,7 @@ function normalizePath3(path) {
|
|
|
21068
21167
|
return path.split(sep5).join("/");
|
|
21069
21168
|
}
|
|
21070
21169
|
function hashText(text) {
|
|
21071
|
-
return
|
|
21170
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
21072
21171
|
}
|
|
21073
21172
|
|
|
21074
21173
|
// src/harness-candidates.ts
|
|
@@ -22984,7 +23083,7 @@ function capPromotedEvidence(artifact2) {
|
|
|
22984
23083
|
artifact2.evidence = artifact2.evidence.slice(0, max);
|
|
22985
23084
|
}
|
|
22986
23085
|
function distinctStableId(prefix, raw) {
|
|
22987
|
-
return `${stableId(prefix, raw.replace(/\./g, "-"))}_${
|
|
23086
|
+
return `${stableId(prefix, raw.replace(/\./g, "-"))}_${createHash9("sha256").update(raw).digest("hex").slice(0, 8)}`;
|
|
22988
23087
|
}
|
|
22989
23088
|
function promoteModelIds(occurrences, context) {
|
|
22990
23089
|
const out = [];
|
|
@@ -23841,7 +23940,7 @@ function modelArtifacts(result) {
|
|
|
23841
23940
|
return (result.models ?? []).map((model) => {
|
|
23842
23941
|
const agentIds = [...new Set(model.calledFrom.flatMap((site) => owners.get(site.callSite) ?? []))].sort();
|
|
23843
23942
|
return {
|
|
23844
|
-
id: `model_config_${slug(model.id)}_${
|
|
23943
|
+
id: `model_config_${slug(model.id)}_${createHash10("sha256").update(model.id).digest("hex").slice(0, 8)}`,
|
|
23845
23944
|
type: "model_config",
|
|
23846
23945
|
name: model.id,
|
|
23847
23946
|
scope: agentIds.length === 1 ? "agent" : "shared",
|