@tradejs/cli 3.1.27-beta.248 → 3.1.27-beta.250

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.
@@ -34,8 +34,8 @@ __export(runtimeEvidence_exports, {
34
34
  runtimeEvidence: () => runtimeEvidence
35
35
  });
36
36
  module.exports = __toCommonJS(runtimeEvidence_exports);
37
- var import_promises3 = __toESM(require("fs/promises"));
38
- var import_node_path3 = __toESM(require("path"));
37
+ var import_promises4 = __toESM(require("fs/promises"));
38
+ var import_node_path4 = __toESM(require("path"));
39
39
  var import_args = __toESM(require("args"));
40
40
  var import_chalk = __toESM(require("chalk"));
41
41
 
@@ -851,35 +851,51 @@ var verifyRuntimeEvidenceBundle = async (bundleDir) => {
851
851
  artifact
852
852
  };
853
853
  };
854
-
855
- // src/lib/runtimeLineage.ts
856
- var import_node_crypto2 = require("crypto");
857
- var normalizeForStableJson = (value) => {
858
- if (Array.isArray(value)) {
859
- return value.map(normalizeForStableJson);
860
- }
861
- if (value && typeof value === "object") {
862
- return Object.fromEntries(
863
- Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalizeForStableJson(entry)])
854
+ var discoverRuntimeEvidenceBundles = async (rootDir) => {
855
+ const bundles = [];
856
+ const visit = async (directory, depth) => {
857
+ if (depth > 8) return;
858
+ let entries;
859
+ try {
860
+ entries = await import_promises.default.readdir(directory, { withFileTypes: true });
861
+ } catch (error) {
862
+ if (error.code === "ENOENT") return;
863
+ throw error;
864
+ }
865
+ const names = new Set(entries.map((entry) => entry.name));
866
+ if (names.has(RUNTIME_EVIDENCE_MANIFEST_FILE) && names.has(RUNTIME_EVIDENCE_PAYLOAD_FILE) && names.has(RUNTIME_EVIDENCE_COMPLETE_FILE)) {
867
+ bundles.push(directory);
868
+ return;
869
+ }
870
+ await Promise.all(
871
+ entries.filter(
872
+ (entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
873
+ ).map((entry) => visit(import_node_path.default.join(directory, entry.name), depth + 1))
864
874
  );
865
- }
866
- return value;
875
+ };
876
+ await visit(rootDir, 0);
877
+ return bundles.sort();
867
878
  };
868
- var fingerprintRuntimeValue = (value) => (0, import_node_crypto2.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
869
- var runtimeLineageKey = (lineage) => [
870
- "v3",
871
- lineage.deploymentCompositionId,
872
- lineage.strategyRevision,
873
- lineage.strategyPackageVersion,
874
- `deps:${fingerprintRuntimeValue(lineage.strategyDependencyVersions).slice(0, 16)}`,
875
- lineage.runtimePackageVersion
876
- ].join(":");
877
879
 
878
- // src/lib/runtimeEvidenceProducer.ts
880
+ // src/lib/runtimeEvidenceCompositionSnapshots.ts
879
881
  var import_node_crypto3 = require("crypto");
882
+ var import_promises3 = __toESM(require("fs/promises"));
883
+ var import_node_path3 = __toESM(require("path"));
884
+
885
+ // src/lib/runtimeEvidenceProducer.ts
886
+ var import_node_crypto2 = require("crypto");
880
887
  var import_promises2 = __toESM(require("fs/promises"));
881
888
  var import_node_path2 = __toESM(require("path"));
882
- var sha2562 = (value) => (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
889
+ var isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
890
+ var sha2562 = (value) => (0, import_node_crypto2.createHash)("sha256").update(value).digest("hex");
891
+ var parseRuntimeEvidenceProducer = (value) => {
892
+ const producer = isRecord2(value) ? value : null;
893
+ const runtimePackageManifest = isRecord2(producer?.runtimePackageManifest) ? producer.runtimePackageManifest : null;
894
+ if (producer?.schemaVersion !== 1 || typeof producer.projectSha !== "string" || !/^[a-f0-9]{40}$/.test(producer.projectSha) || typeof producer.imageDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(producer.imageDigest) || runtimePackageManifest?.file !== "runtime-package-manifest.json" || typeof runtimePackageManifest.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(runtimePackageManifest.sha256)) {
895
+ throw new Error("Runtime evidence producer image identity is invalid");
896
+ }
897
+ return producer;
898
+ };
883
899
  var resolveRuntimeEvidenceProducer = async ({
884
900
  projectRoot: projectRoot2,
885
901
  required
@@ -925,6 +941,241 @@ var resolveRuntimeEvidenceProducer = async ({
925
941
  };
926
942
  };
927
943
 
944
+ // src/lib/runtimeEvidenceCompositionSnapshots.ts
945
+ var SNAPSHOT_FILE = "snapshot.json";
946
+ var MANIFEST_FILE = "manifest.json";
947
+ var COMPLETE_FILE = ".complete";
948
+ var isRecord3 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
949
+ var sha2563 = (value) => (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
950
+ var parseManifest2 = (value) => {
951
+ const manifest = isRecord3(value) ? value : null;
952
+ const payload = isRecord3(manifest?.payload) ? manifest.payload : null;
953
+ if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-evidence-composition-snapshot" || typeof manifest.createdAt !== "number" || typeof manifest.userName !== "string" || typeof manifest.deploymentId !== "string" || typeof manifest.deploymentCompositionId !== "string" || payload?.file !== SNAPSHOT_FILE || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number") {
954
+ throw new Error("Invalid runtime evidence composition snapshot manifest");
955
+ }
956
+ return manifest;
957
+ };
958
+ var verifyRuntimeEvidenceCompositionSnapshot = async (bundleDir) => {
959
+ const [manifestText, payload, completeText] = await Promise.all([
960
+ import_promises3.default.readFile(import_node_path3.default.join(bundleDir, MANIFEST_FILE), "utf8"),
961
+ import_promises3.default.readFile(import_node_path3.default.join(bundleDir, SNAPSHOT_FILE)),
962
+ import_promises3.default.readFile(import_node_path3.default.join(bundleDir, COMPLETE_FILE), "utf8")
963
+ ]);
964
+ const manifest = parseManifest2(JSON.parse(manifestText));
965
+ if (completeText.trim() !== manifest.deploymentCompositionId) {
966
+ throw new Error(`Invalid completion marker in ${bundleDir}`);
967
+ }
968
+ if (payload.byteLength !== manifest.payload.bytes || sha2563(payload) !== manifest.payload.sha256) {
969
+ throw new Error(
970
+ `Runtime evidence snapshot checksum mismatch in ${bundleDir}`
971
+ );
972
+ }
973
+ const value = JSON.parse(payload.toString("utf8"));
974
+ const record = isRecord3(value) ? value : null;
975
+ if (record?.schemaVersion !== 1 || record.reportType !== "runtime-evidence-composition-snapshot" || record.userName !== manifest.userName) {
976
+ throw new Error(
977
+ `Invalid runtime evidence snapshot payload in ${bundleDir}`
978
+ );
979
+ }
980
+ const deployment = parseRuntimeEvidenceDeploymentSnapshot(record.deployment);
981
+ const producer = parseRuntimeEvidenceProducer(record.producer);
982
+ if (deployment.id !== manifest.deploymentId || deployment.deploymentCompositionId !== manifest.deploymentCompositionId) {
983
+ throw new Error(
984
+ `Runtime evidence snapshot identity mismatch in ${bundleDir}`
985
+ );
986
+ }
987
+ return { bundleDir, deployment, producer };
988
+ };
989
+ var discoverRuntimeEvidenceCompositionSnapshots = async (evidenceRoot) => {
990
+ const rootDir = import_node_path3.default.join(evidenceRoot, "snapshots");
991
+ const bundleDirs = [];
992
+ let deployments;
993
+ try {
994
+ deployments = await import_promises3.default.readdir(rootDir, { withFileTypes: true });
995
+ } catch (error) {
996
+ if (error.code === "ENOENT") return [];
997
+ throw error;
998
+ }
999
+ for (const deployment of deployments.filter((entry) => entry.isDirectory())) {
1000
+ const deploymentDir = import_node_path3.default.join(rootDir, deployment.name);
1001
+ const compositions = await import_promises3.default.readdir(deploymentDir, {
1002
+ withFileTypes: true
1003
+ });
1004
+ bundleDirs.push(
1005
+ ...compositions.filter(
1006
+ (entry) => entry.isDirectory() && !entry.name.startsWith(".") && !entry.name.includes(".tmp-")
1007
+ ).map((entry) => import_node_path3.default.join(deploymentDir, entry.name))
1008
+ );
1009
+ }
1010
+ return Promise.all(
1011
+ bundleDirs.sort().map(verifyRuntimeEvidenceCompositionSnapshot)
1012
+ );
1013
+ };
1014
+
1015
+ // src/lib/runtimeEvidenceCompositions.ts
1016
+ var stableSnapshotIdentity = (deployment) => JSON.stringify({ ...deployment, tickers: void 0 });
1017
+ var producerIdentity = (producer) => JSON.stringify(producer);
1018
+ var loadRuntimeEvidenceCompositionSnapshots = async ({
1019
+ publishRoot,
1020
+ currentDeployment,
1021
+ currentProducer
1022
+ }) => {
1023
+ const snapshots = /* @__PURE__ */ new Map();
1024
+ const register = (snapshot) => {
1025
+ const compositionId = snapshot.deployment.deploymentCompositionId;
1026
+ const known = snapshots.get(compositionId);
1027
+ if (known && (stableSnapshotIdentity(known.deployment) !== stableSnapshotIdentity(snapshot.deployment) || producerIdentity(known.producer) !== producerIdentity(snapshot.producer))) {
1028
+ throw new Error(
1029
+ `Conflicting runtime evidence snapshot for composition ${compositionId}`
1030
+ );
1031
+ }
1032
+ snapshots.set(compositionId, snapshot);
1033
+ };
1034
+ const compositionSnapshots = await discoverRuntimeEvidenceCompositionSnapshots(publishRoot);
1035
+ for (const snapshot of compositionSnapshots) {
1036
+ if (snapshot.deployment.id !== currentDeployment.id) continue;
1037
+ register({
1038
+ deployment: { ...snapshot.deployment, tickers: void 0 },
1039
+ producer: snapshot.producer
1040
+ });
1041
+ }
1042
+ const bundleDirs = await discoverRuntimeEvidenceBundles(publishRoot);
1043
+ for (const bundleDir of bundleDirs) {
1044
+ const bundle = await verifyRuntimeEvidenceBundle(bundleDir);
1045
+ const deployment = parseRuntimeEvidenceDeploymentSnapshot(
1046
+ bundle.artifact.deployment
1047
+ );
1048
+ if (deployment.id !== currentDeployment.id) continue;
1049
+ if (bundle.artifact.producer == null) continue;
1050
+ register({
1051
+ deployment: { ...deployment, tickers: void 0 },
1052
+ producer: parseRuntimeEvidenceProducer(bundle.artifact.producer)
1053
+ });
1054
+ }
1055
+ const historicalCurrent = snapshots.get(
1056
+ currentDeployment.deploymentCompositionId
1057
+ );
1058
+ if (historicalCurrent && stableSnapshotIdentity(historicalCurrent.deployment) !== stableSnapshotIdentity(currentDeployment)) {
1059
+ throw new Error(
1060
+ `Current runtime deployment conflicts with stored composition ${currentDeployment.deploymentCompositionId}`
1061
+ );
1062
+ }
1063
+ snapshots.set(currentDeployment.deploymentCompositionId, {
1064
+ deployment: { ...currentDeployment, tickers: void 0 },
1065
+ producer: currentProducer
1066
+ });
1067
+ return snapshots;
1068
+ };
1069
+ var rowCompositionId = (row) => row.runtimeLineage?.deploymentCompositionId ?? row.lineage?.deploymentCompositionId ?? null;
1070
+ var rowTimestamp = (row) => {
1071
+ for (const field of [
1072
+ "firstTimestamp",
1073
+ "entryTimestamp",
1074
+ "timestamp",
1075
+ "lastTimestamp"
1076
+ ]) {
1077
+ const value = row[field];
1078
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1079
+ }
1080
+ return Number.POSITIVE_INFINITY;
1081
+ };
1082
+ var belongsToSnapshot = (row, deployment) => {
1083
+ const strategy = activeRuntimeEvidenceStrategies(deployment).find(
1084
+ (candidate) => candidate.strategyName === row.strategy
1085
+ );
1086
+ return Boolean(
1087
+ strategy && row.deploymentId === deployment.id && row.accountId === deployment.accountId && runtimeLineageMatchesStrategySnapshot({
1088
+ lineage: row.runtimeLineage ?? row.lineage,
1089
+ deployment,
1090
+ strategy
1091
+ })
1092
+ );
1093
+ };
1094
+ var splitRuntimeEvidenceByComposition = ({
1095
+ evidence,
1096
+ snapshots,
1097
+ includeEmptyCompositionIds = [],
1098
+ ignoreUnknownCompositions = false
1099
+ }) => {
1100
+ const observed = /* @__PURE__ */ new Set();
1101
+ for (const row of [
1102
+ ...evidence.trades,
1103
+ ...evidence.signals,
1104
+ ...evidence.evaluations,
1105
+ ...evidence.lineageScopes
1106
+ ]) {
1107
+ const compositionId = rowCompositionId(row);
1108
+ if (compositionId) observed.add(compositionId);
1109
+ }
1110
+ for (const compositionId of includeEmptyCompositionIds) {
1111
+ observed.add(compositionId);
1112
+ }
1113
+ const missing = [...observed].filter(
1114
+ (compositionId) => !snapshots.has(compositionId)
1115
+ );
1116
+ if (missing.length && !ignoreUnknownCompositions) {
1117
+ throw new Error(
1118
+ `Runtime evidence has no verified deployment snapshot for composition(s): ${missing.sort().join(", ")}`
1119
+ );
1120
+ }
1121
+ return [...observed].filter((compositionId) => snapshots.has(compositionId)).map((compositionId) => snapshots.get(compositionId)).map(({ deployment, producer }) => {
1122
+ const trades = evidence.trades.filter(
1123
+ (row) => belongsToSnapshot(row, deployment)
1124
+ );
1125
+ const signals = evidence.signals.filter(
1126
+ (row) => belongsToSnapshot(row, deployment)
1127
+ );
1128
+ const evaluations = evidence.evaluations.filter(
1129
+ (row) => belongsToSnapshot(row, deployment)
1130
+ );
1131
+ const lineageScopes = evidence.lineageScopes.filter(
1132
+ (row) => belongsToSnapshot(row, deployment)
1133
+ );
1134
+ const timestamps = [
1135
+ ...trades,
1136
+ ...signals,
1137
+ ...evaluations,
1138
+ ...lineageScopes
1139
+ ].map((row) => rowTimestamp(row));
1140
+ return {
1141
+ deployment,
1142
+ producer,
1143
+ trades,
1144
+ signals,
1145
+ evaluations,
1146
+ lineageScopes,
1147
+ firstTimestamp: Math.min(...timestamps)
1148
+ };
1149
+ }).sort(
1150
+ (left, right) => left.firstTimestamp - right.firstTimestamp || left.deployment.deploymentCompositionId.localeCompare(
1151
+ right.deployment.deploymentCompositionId
1152
+ )
1153
+ );
1154
+ };
1155
+
1156
+ // src/lib/runtimeLineage.ts
1157
+ var import_node_crypto4 = require("crypto");
1158
+ var normalizeForStableJson = (value) => {
1159
+ if (Array.isArray(value)) {
1160
+ return value.map(normalizeForStableJson);
1161
+ }
1162
+ if (value && typeof value === "object") {
1163
+ return Object.fromEntries(
1164
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, normalizeForStableJson(entry)])
1165
+ );
1166
+ }
1167
+ return value;
1168
+ };
1169
+ var fingerprintRuntimeValue = (value) => (0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
1170
+ var runtimeLineageKey = (lineage) => [
1171
+ "v3",
1172
+ lineage.deploymentCompositionId,
1173
+ lineage.strategyRevision,
1174
+ lineage.strategyPackageVersion,
1175
+ `deps:${fingerprintRuntimeValue(lineage.strategyDependencyVersions).slice(0, 16)}`,
1176
+ lineage.runtimePackageVersion
1177
+ ].join(":");
1178
+
928
1179
  // src/scripts/runtimeEvidence.ts
929
1180
  import_args.default.option(["u", "user"], "Use user config", "root");
930
1181
  import_args.default.option(
@@ -1015,15 +1266,30 @@ var runtimeEvidence = async () => {
1015
1266
  projectRoot,
1016
1267
  deploymentId
1017
1268
  });
1018
- const activeStrategies = activeRuntimeEvidenceStrategies(
1019
- deploymentSnapshot
1020
- ).map(({ strategyName }) => strategyName);
1021
1269
  const requestedStrategies = parseStrategyFilter(flags.strategy);
1022
- const strategies = requestedStrategies.length ? requestedStrategies : activeStrategies;
1270
+ const evidence = await collectRuntimeDebugEvidence({
1271
+ userName: flags.user,
1272
+ startTime,
1273
+ endTime,
1274
+ strategies: requestedStrategies.length ? requestedStrategies : void 0,
1275
+ deploymentId
1276
+ });
1277
+ const snapshots = publishDir && producer ? await loadRuntimeEvidenceCompositionSnapshots({
1278
+ publishRoot: import_node_path4.default.resolve(projectRoot, publishDir),
1279
+ currentDeployment: deploymentSnapshot,
1280
+ currentProducer: producer
1281
+ }) : /* @__PURE__ */ new Map([
1282
+ [
1283
+ deploymentSnapshot.deploymentCompositionId,
1284
+ { deployment: deploymentSnapshot, producer }
1285
+ ]
1286
+ ]);
1023
1287
  const declaredStrategies = new Set(
1024
- deploymentSnapshot.strategies.map(({ strategyName }) => strategyName)
1288
+ [...snapshots.values()].flatMap(
1289
+ ({ deployment }) => deployment.strategies.map(({ strategyName }) => strategyName)
1290
+ )
1025
1291
  );
1026
- const unknownStrategies = strategies.filter(
1292
+ const unknownStrategies = requestedStrategies.filter(
1027
1293
  (strategyName) => !declaredStrategies.has(strategyName)
1028
1294
  );
1029
1295
  if (unknownStrategies.length) {
@@ -1031,97 +1297,94 @@ var runtimeEvidence = async () => {
1031
1297
  `Strategies are not declared in ${deploymentId}: ${unknownStrategies.join(", ")}`
1032
1298
  );
1033
1299
  }
1034
- const evidence = await collectRuntimeDebugEvidence({
1035
- userName: flags.user,
1036
- startTime,
1037
- endTime,
1038
- strategies,
1039
- deploymentId
1300
+ const compositionRows = splitRuntimeEvidenceByComposition({
1301
+ evidence,
1302
+ snapshots,
1303
+ includeEmptyCompositionIds: publishDir ? [] : [deploymentSnapshot.deploymentCompositionId],
1304
+ ignoreUnknownCompositions: !publishDir
1040
1305
  });
1041
- const activeSnapshots = new Map(
1042
- activeRuntimeEvidenceStrategies(deploymentSnapshot).map((strategy) => [
1043
- strategy.strategyName,
1044
- strategy
1045
- ])
1046
- );
1047
- const belongsToCurrentDeployment = (row) => {
1048
- const snapshot = activeSnapshots.get(row.strategy);
1049
- return Boolean(
1050
- snapshot && row.deploymentId === deploymentSnapshot.id && row.accountId === deploymentSnapshot.accountId && runtimeLineageMatchesStrategySnapshot({
1051
- lineage: row.runtimeLineage,
1052
- deployment: deploymentSnapshot,
1053
- strategy: snapshot
1054
- })
1306
+ const artifacts = compositionRows.map((composition) => {
1307
+ const strategies = activeRuntimeEvidenceStrategies(composition.deployment).map(({ strategyName }) => strategyName).filter(
1308
+ (strategyName) => !requestedStrategies.length || requestedStrategies.includes(strategyName)
1055
1309
  );
1056
- };
1057
- const currentSignals = evidence.signals.filter(belongsToCurrentDeployment);
1058
- const currentEvaluations = evidence.evaluations.filter(
1059
- belongsToCurrentDeployment
1060
- );
1061
- const currentTrades = evidence.trades.filter(belongsToCurrentDeployment);
1062
- const currentLineageScopes = evidence.lineageScopes.filter(
1063
- (scope) => belongsToCurrentDeployment({
1064
- ...scope,
1065
- runtimeLineage: scope.lineage
1066
- })
1067
- );
1068
- const runtime = buildRuntimeEvidenceReportPayload({
1069
- userName: flags.user,
1070
- startTime,
1071
- endTime,
1072
- signals: currentSignals,
1073
- evaluations: currentEvaluations,
1074
- trades: currentTrades,
1075
- lineageScopes: currentLineageScopes
1076
- });
1077
- const deployment = resolveRuntimeEvidenceTickerUniverse({
1078
- deployment: deploymentSnapshot,
1079
- lineageScopes: currentLineageScopes
1080
- });
1081
- const artifact = {
1082
- reportType: "runtime-evidence",
1083
- generatedAt: Date.now(),
1084
- ...producer ? { producer } : {},
1085
- userName: flags.user,
1086
- window: {
1310
+ const runtime = buildRuntimeEvidenceReportPayload({
1311
+ userName: flags.user,
1087
1312
  startTime,
1088
1313
  endTime,
1089
- startIso: new Date(startTime).toISOString(),
1090
- endIso: new Date(endTime).toISOString(),
1091
- source
1092
- },
1093
- strategies,
1094
- deployment,
1095
- runtime
1096
- };
1097
- const outPath = import_node_path3.default.resolve(projectRoot, String(flags.out));
1098
- await import_promises3.default.mkdir(import_node_path3.default.dirname(outPath), { recursive: true });
1099
- await import_promises3.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
1314
+ signals: composition.signals,
1315
+ evaluations: composition.evaluations,
1316
+ trades: composition.trades,
1317
+ lineageScopes: composition.lineageScopes
1318
+ });
1319
+ const deployment = resolveRuntimeEvidenceTickerUniverse({
1320
+ deployment: composition.deployment,
1321
+ lineageScopes: composition.lineageScopes
1322
+ });
1323
+ return {
1324
+ artifact: {
1325
+ reportType: "runtime-evidence",
1326
+ generatedAt: Date.now(),
1327
+ ...composition.producer ? { producer: composition.producer } : {},
1328
+ ...producer && composition.producer && composition.producer !== producer ? { collector: producer } : {},
1329
+ userName: flags.user,
1330
+ window: {
1331
+ startTime,
1332
+ endTime,
1333
+ startIso: new Date(startTime).toISOString(),
1334
+ endIso: new Date(endTime).toISOString(),
1335
+ source
1336
+ },
1337
+ strategies,
1338
+ deployment,
1339
+ runtime
1340
+ },
1341
+ composition
1342
+ };
1343
+ });
1344
+ const current = artifacts.find(
1345
+ ({ artifact: artifact2 }) => artifact2.deployment.deploymentCompositionId === deploymentSnapshot.deploymentCompositionId
1346
+ ) ?? artifacts.at(-1);
1347
+ if (!current) {
1348
+ throw new Error("Runtime evidence window has no versioned runtime rows");
1349
+ }
1350
+ const artifact = current.artifact;
1351
+ const outPath = import_node_path4.default.resolve(projectRoot, String(flags.out));
1352
+ await import_promises4.default.mkdir(import_node_path4.default.dirname(outPath), { recursive: true });
1353
+ await import_promises4.default.writeFile(outPath, `${JSON.stringify(artifact, null, 2)}
1100
1354
  `, "utf8");
1101
- const published = publishDir ? await publishRuntimeEvidenceBundle({
1102
- publishRoot: import_node_path3.default.resolve(projectRoot, publishDir),
1103
- deploymentId,
1104
- userName: String(flags.user),
1105
- startTime,
1106
- endTime,
1107
- artifact,
1108
- counts: artifact.runtime.counts,
1109
- lineageKeys: [
1110
- ...currentSignals.map((signal) => signal.runtimeLineage),
1111
- ...currentEvaluations.map((evaluation) => evaluation.runtimeLineage),
1112
- ...currentTrades.map((trade) => trade.runtimeLineage),
1113
- ...currentLineageScopes.map((scope) => scope.lineage)
1114
- ].filter((lineage) => lineage != null).map(runtimeLineageKey).filter((key, index, values) => values.indexOf(key) === index)
1115
- }) : null;
1355
+ const published = publishDir ? await Promise.all(
1356
+ artifacts.map(
1357
+ ({ artifact: artifact2, composition }) => publishRuntimeEvidenceBundle({
1358
+ publishRoot: import_node_path4.default.resolve(projectRoot, publishDir),
1359
+ deploymentId,
1360
+ userName: String(flags.user),
1361
+ startTime,
1362
+ endTime,
1363
+ artifact: artifact2,
1364
+ counts: artifact2.runtime.counts,
1365
+ lineageKeys: [
1366
+ ...composition.signals.map((signal) => signal.runtimeLineage),
1367
+ ...composition.evaluations.map(
1368
+ (evaluation) => evaluation.runtimeLineage
1369
+ ),
1370
+ ...composition.trades.map((trade) => trade.runtimeLineage),
1371
+ ...composition.lineageScopes.map((scope) => scope.lineage)
1372
+ ].filter((lineage) => lineage != null).map(runtimeLineageKey).filter((key, index, values) => values.indexOf(key) === index)
1373
+ })
1374
+ )
1375
+ ) : [];
1116
1376
  console.log(import_chalk.default.green(`Wrote ${outPath}`));
1117
- if (published) {
1118
- console.log(import_chalk.default.green(`Published ${published.bundleDir}`));
1377
+ for (const bundle of published) {
1378
+ console.log(import_chalk.default.green(`Published ${bundle.bundleDir}`));
1119
1379
  }
1120
1380
  console.log(
1121
1381
  JSON.stringify(
1122
1382
  {
1123
- strategies: artifact.strategies,
1124
- runtimeCounts: artifact.runtime.counts
1383
+ compositions: artifacts.map(({ artifact: artifact2 }) => ({
1384
+ deploymentCompositionId: artifact2.deployment.deploymentCompositionId,
1385
+ strategies: artifact2.strategies,
1386
+ runtimeCounts: artifact2.runtime.counts
1387
+ }))
1125
1388
  },
1126
1389
  null,
1127
1390
  2