@tradejs/cli 3.1.21 → 3.1.22
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/cli.js +1643 -806
- package/dist/lib/runtimeEvidenceProducer.js +98 -0
- package/dist/lib/runtimeEvidenceSync.js +8 -3
- package/dist/lib/runtimeFeedbackArtifacts.js +566 -0
- package/dist/lib/runtimeFeedbackReplay.js +808 -0
- package/dist/lib/runtimeFeedbackSync.js +350 -0
- package/dist/scripts/replay.js +9 -6
- package/dist/scripts/replayRunner.js +9 -6
- package/dist/scripts/replayRuntimeEvidence.js +4 -0
- package/dist/scripts/runtimeEvidence.js +62 -7
- package/dist/scripts/runtimeFeedbackReplay.js +850 -0
- package/dist/scripts/runtimeFeedbackSync.js +411 -0
- package/dist/scripts/runtimeScorecard.js +217 -39
- package/package.json +9 -7
|
@@ -34,9 +34,9 @@ __export(runtimeScorecard_exports, {
|
|
|
34
34
|
runtimeScorecard: () => runtimeScorecard
|
|
35
35
|
});
|
|
36
36
|
module.exports = __toCommonJS(runtimeScorecard_exports);
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
37
|
+
var import_promises6 = __toESM(require("fs/promises"));
|
|
38
|
+
var import_node_crypto6 = require("crypto");
|
|
39
|
+
var import_node_path6 = __toESM(require("path"));
|
|
40
40
|
var import_args = __toESM(require("args"));
|
|
41
41
|
var import_chalk = __toESM(require("chalk"));
|
|
42
42
|
|
|
@@ -316,22 +316,177 @@ var discoverRuntimeEvidenceBundles = async (rootDir) => {
|
|
|
316
316
|
return bundles.sort();
|
|
317
317
|
};
|
|
318
318
|
|
|
319
|
-
// src/lib/
|
|
320
|
-
var
|
|
319
|
+
// src/lib/runtimeFeedbackArtifacts.ts
|
|
320
|
+
var import_node_crypto3 = require("crypto");
|
|
321
|
+
var import_promises3 = __toESM(require("fs/promises"));
|
|
322
|
+
var import_node_path3 = __toESM(require("path"));
|
|
323
|
+
|
|
324
|
+
// src/lib/runtimeEvidenceProducer.ts
|
|
325
|
+
var import_node_crypto2 = require("crypto");
|
|
321
326
|
var import_promises2 = __toESM(require("fs/promises"));
|
|
322
327
|
var import_node_path2 = __toESM(require("path"));
|
|
328
|
+
var isRecord2 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
329
|
+
var parseRuntimeEvidenceProducer = (value) => {
|
|
330
|
+
const producer = isRecord2(value) ? value : null;
|
|
331
|
+
const runtimePackageManifest = isRecord2(producer?.runtimePackageManifest) ? producer.runtimePackageManifest : null;
|
|
332
|
+
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)) {
|
|
333
|
+
throw new Error("Runtime evidence producer image identity is invalid");
|
|
334
|
+
}
|
|
335
|
+
return producer;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// src/lib/runtimeFeedbackArtifacts.ts
|
|
339
|
+
var RUNTIME_FEEDBACK_MANIFEST_FILE = "manifest.json";
|
|
340
|
+
var RUNTIME_FEEDBACK_REPLAY_FILE = "replay-runtime-evidence.json";
|
|
341
|
+
var RUNTIME_FEEDBACK_LOG_FILE = "replay.log";
|
|
342
|
+
var RUNTIME_FEEDBACK_COMPLETE_FILE = ".complete";
|
|
343
|
+
var isRecord3 = (value) => value != null && typeof value === "object" && !Array.isArray(value);
|
|
344
|
+
var sha2562 = (value) => (0, import_node_crypto3.createHash)("sha256").update(value).digest("hex");
|
|
345
|
+
var parsePayload = (value, expectedFile) => {
|
|
346
|
+
const payload = isRecord3(value) ? value : null;
|
|
347
|
+
if (payload?.file !== expectedFile || typeof payload.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(payload.sha256) || typeof payload.bytes !== "number" || !Number.isFinite(payload.bytes) || payload.bytes < 0) {
|
|
348
|
+
throw new Error(`Invalid runtime feedback payload: ${expectedFile}`);
|
|
349
|
+
}
|
|
350
|
+
return payload;
|
|
351
|
+
};
|
|
352
|
+
var parseManifest2 = (value) => {
|
|
353
|
+
const manifest = isRecord3(value) ? value : null;
|
|
354
|
+
const window = isRecord3(manifest?.window) ? manifest.window : null;
|
|
355
|
+
const runtimeEvidence = isRecord3(manifest?.runtimeEvidence) ? manifest.runtimeEvidence : null;
|
|
356
|
+
const safety = isRecord3(manifest?.safety) ? manifest.safety : null;
|
|
357
|
+
const payloads = isRecord3(manifest?.payloads) ? manifest.payloads : null;
|
|
358
|
+
if (manifest?.schemaVersion !== 1 || manifest.reportType !== "runtime-feedback-replay" || typeof manifest.artifactId !== "string" || !manifest.artifactId.trim() || typeof manifest.runId !== "string" || !manifest.runId.trim() || typeof manifest.deploymentId !== "string" || !manifest.deploymentId.trim() || typeof manifest.deploymentCompositionId !== "string" || !/^dc1:[a-f0-9]{16}$/.test(manifest.deploymentCompositionId) || typeof manifest.userName !== "string" || !manifest.userName.trim() || typeof manifest.createdAt !== "number" || typeof window?.startTime !== "number" || typeof window.endTime !== "number" || typeof runtimeEvidence?.artifactId !== "string" || typeof runtimeEvidence.payloadSha256 !== "string" || !/^[a-f0-9]{64}$/.test(runtimeEvidence.payloadSha256) || !Array.isArray(manifest.activeStrategies) || manifest.activeStrategies.length === 0 || !manifest.activeStrategies.every(
|
|
359
|
+
(strategy) => typeof strategy === "string" && strategy.trim()
|
|
360
|
+
) || typeof manifest.cycleCount !== "number" || !Number.isFinite(manifest.cycleCount) || manifest.cycleCount <= 0 || safety?.cacheOnly !== true || safety.externalOrderPlacement !== false || safety.redis !== "isolated" || safety.timescale !== "read_only") {
|
|
361
|
+
throw new Error("Invalid runtime feedback replay manifest");
|
|
362
|
+
}
|
|
363
|
+
const replayEvidence = parsePayload(
|
|
364
|
+
payloads?.replayEvidence,
|
|
365
|
+
RUNTIME_FEEDBACK_REPLAY_FILE
|
|
366
|
+
);
|
|
367
|
+
const log = parsePayload(payloads?.log, RUNTIME_FEEDBACK_LOG_FILE);
|
|
368
|
+
return {
|
|
369
|
+
...manifest,
|
|
370
|
+
producer: parseRuntimeEvidenceProducer(manifest.producer),
|
|
371
|
+
payloads: {
|
|
372
|
+
replayEvidence: {
|
|
373
|
+
...replayEvidence,
|
|
374
|
+
file: RUNTIME_FEEDBACK_REPLAY_FILE
|
|
375
|
+
},
|
|
376
|
+
log: { ...log, file: RUNTIME_FEEDBACK_LOG_FILE }
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
};
|
|
380
|
+
var assertReplayMatchesRuntimeEvidence = ({
|
|
381
|
+
replayEvidence,
|
|
382
|
+
runtimeEvidence
|
|
383
|
+
}) => {
|
|
384
|
+
if (replayEvidence.reportType !== "replay-runtime-evidence") {
|
|
385
|
+
throw new Error("Runtime feedback replay payload has the wrong reportType");
|
|
386
|
+
}
|
|
387
|
+
const replayWindow = isRecord3(replayEvidence.window) ? replayEvidence.window : null;
|
|
388
|
+
if (replayWindow?.startTime !== runtimeEvidence.manifest.window.startTime || replayWindow.endTime !== runtimeEvidence.manifest.window.endTime) {
|
|
389
|
+
throw new Error("Runtime feedback replay window does not match evidence");
|
|
390
|
+
}
|
|
391
|
+
const runtimeDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
392
|
+
runtimeEvidence.artifact.deployment
|
|
393
|
+
);
|
|
394
|
+
const replayDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
395
|
+
replayEvidence.deployment
|
|
396
|
+
);
|
|
397
|
+
if (replayDeployment.id !== runtimeDeployment.id || replayDeployment.deploymentCompositionId !== runtimeDeployment.deploymentCompositionId) {
|
|
398
|
+
throw new Error(
|
|
399
|
+
"Runtime feedback replay deployment does not match evidence"
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
var verifyRuntimeFeedbackReplayBundle = async (bundleDir) => {
|
|
404
|
+
const manifestPath = import_node_path3.default.join(bundleDir, RUNTIME_FEEDBACK_MANIFEST_FILE);
|
|
405
|
+
const replayEvidencePath = import_node_path3.default.join(bundleDir, RUNTIME_FEEDBACK_REPLAY_FILE);
|
|
406
|
+
const logPath = import_node_path3.default.join(bundleDir, RUNTIME_FEEDBACK_LOG_FILE);
|
|
407
|
+
const completePath = import_node_path3.default.join(bundleDir, RUNTIME_FEEDBACK_COMPLETE_FILE);
|
|
408
|
+
const [manifestText, replayPayload, logPayload, completeText] = await Promise.all([
|
|
409
|
+
import_promises3.default.readFile(manifestPath, "utf8"),
|
|
410
|
+
import_promises3.default.readFile(replayEvidencePath),
|
|
411
|
+
import_promises3.default.readFile(logPath),
|
|
412
|
+
import_promises3.default.readFile(completePath, "utf8")
|
|
413
|
+
]);
|
|
414
|
+
const manifest = parseManifest2(JSON.parse(manifestText));
|
|
415
|
+
if (completeText.trim() !== manifest.artifactId) {
|
|
416
|
+
throw new Error(`Invalid runtime feedback completion marker: ${bundleDir}`);
|
|
417
|
+
}
|
|
418
|
+
for (const [payload, descriptor] of [
|
|
419
|
+
[replayPayload, manifest.payloads.replayEvidence],
|
|
420
|
+
[logPayload, manifest.payloads.log]
|
|
421
|
+
]) {
|
|
422
|
+
if (payload.byteLength !== descriptor.bytes) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
`Runtime feedback payload size mismatch: ${descriptor.file}`
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
if (sha2562(payload) !== descriptor.sha256) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
`Runtime feedback payload checksum mismatch: ${descriptor.file}`
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const replayEvidence = JSON.parse(replayPayload.toString("utf8"));
|
|
434
|
+
if (replayEvidence.reportType !== "replay-runtime-evidence") {
|
|
435
|
+
throw new Error("Invalid runtime feedback replay evidence payload");
|
|
436
|
+
}
|
|
437
|
+
const replayWindow = isRecord3(replayEvidence.window) ? replayEvidence.window : null;
|
|
438
|
+
const replay = isRecord3(replayEvidence.replay) ? replayEvidence.replay : null;
|
|
439
|
+
const replayDeployment = parseRuntimeEvidenceDeploymentSnapshot(
|
|
440
|
+
replayEvidence.deployment
|
|
441
|
+
);
|
|
442
|
+
const replayStrategies = activeRuntimeEvidenceStrategies(replayDeployment).map(({ strategyName }) => strategyName).sort();
|
|
443
|
+
if (replayEvidence.userName !== manifest.userName || replayWindow?.startTime !== manifest.window.startTime || replayWindow.endTime !== manifest.window.endTime || replayDeployment.id !== manifest.deploymentId || replayDeployment.deploymentCompositionId !== manifest.deploymentCompositionId || Number(replay?.cycleCount) !== manifest.cycleCount || JSON.stringify(replayStrategies) !== JSON.stringify([...manifest.activeStrategies].sort())) {
|
|
444
|
+
throw new Error("Runtime feedback replay payload does not match manifest");
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
bundleDir,
|
|
448
|
+
manifestPath,
|
|
449
|
+
replayEvidencePath,
|
|
450
|
+
logPath,
|
|
451
|
+
manifest,
|
|
452
|
+
replayEvidence
|
|
453
|
+
};
|
|
454
|
+
};
|
|
455
|
+
var verifyRuntimeFeedbackReplaySource = async ({
|
|
456
|
+
bundleDir,
|
|
457
|
+
runtimeEvidenceBundleDir
|
|
458
|
+
}) => {
|
|
459
|
+
const [feedback, runtimeEvidence] = await Promise.all([
|
|
460
|
+
verifyRuntimeFeedbackReplayBundle(bundleDir),
|
|
461
|
+
verifyRuntimeEvidenceBundle(runtimeEvidenceBundleDir)
|
|
462
|
+
]);
|
|
463
|
+
if (feedback.manifest.runtimeEvidence.artifactId !== runtimeEvidence.manifest.artifactId || feedback.manifest.runtimeEvidence.payloadSha256 !== runtimeEvidence.manifest.payload.sha256) {
|
|
464
|
+
throw new Error("Runtime feedback bundle references different evidence");
|
|
465
|
+
}
|
|
466
|
+
assertReplayMatchesRuntimeEvidence({
|
|
467
|
+
replayEvidence: feedback.replayEvidence,
|
|
468
|
+
runtimeEvidence
|
|
469
|
+
});
|
|
470
|
+
return { feedback, runtimeEvidence };
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// src/lib/runtimeEvidenceSync.ts
|
|
474
|
+
var import_node_child_process = require("child_process");
|
|
475
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
476
|
+
var import_node_path4 = __toESM(require("path"));
|
|
323
477
|
var import_node_util = require("util");
|
|
324
478
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
325
479
|
var safeSegment = (value, fallback) => {
|
|
326
480
|
const normalized = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
327
481
|
return normalized && normalized !== "." && normalized !== ".." ? normalized : fallback;
|
|
328
482
|
};
|
|
329
|
-
var receiptPath = (receiptsRoot, artifactId) =>
|
|
483
|
+
var receiptPath = (receiptsRoot, artifactId) => import_node_path4.default.join(receiptsRoot, `${safeSegment(artifactId, "artifact")}.json`);
|
|
330
484
|
var markRuntimeEvidenceBundleProcessed = async ({
|
|
331
485
|
evidenceRoot,
|
|
332
486
|
deploymentId,
|
|
333
487
|
bundleDir,
|
|
334
|
-
scorecardPath
|
|
488
|
+
scorecardPath,
|
|
489
|
+
runtimeFeedback
|
|
335
490
|
}) => {
|
|
336
491
|
const safeDeploymentId = safeSegment(deploymentId, "production");
|
|
337
492
|
const verified = await verifyRuntimeEvidenceBundle(bundleDir);
|
|
@@ -340,29 +495,33 @@ var markRuntimeEvidenceBundleProcessed = async ({
|
|
|
340
495
|
`Artifact deployment mismatch: expected ${safeDeploymentId}, received ${verified.manifest.deploymentId}`
|
|
341
496
|
);
|
|
342
497
|
}
|
|
343
|
-
const receiptsRoot =
|
|
498
|
+
const receiptsRoot = import_node_path4.default.join(evidenceRoot, "receipts", safeDeploymentId);
|
|
344
499
|
const finalPath = receiptPath(receiptsRoot, verified.manifest.artifactId);
|
|
345
500
|
const temporaryPath = `${finalPath}.tmp-${process.pid}`;
|
|
346
501
|
const receipt = {
|
|
347
|
-
schemaVersion: 1,
|
|
502
|
+
schemaVersion: runtimeFeedback ? 2 : 1,
|
|
348
503
|
artifactId: verified.manifest.artifactId,
|
|
349
504
|
payloadSha256: verified.manifest.payload.sha256,
|
|
350
505
|
processedAt: Date.now(),
|
|
351
|
-
scorecardPath: scorecardPath ?? null
|
|
506
|
+
scorecardPath: scorecardPath ?? null,
|
|
507
|
+
...runtimeFeedback ? {
|
|
508
|
+
runtimeFeedbackArtifactId: runtimeFeedback.artifactId,
|
|
509
|
+
replayEvidenceSha256: runtimeFeedback.replayEvidenceSha256
|
|
510
|
+
} : {}
|
|
352
511
|
};
|
|
353
|
-
await
|
|
354
|
-
await
|
|
512
|
+
await import_promises4.default.mkdir(receiptsRoot, { recursive: true });
|
|
513
|
+
await import_promises4.default.writeFile(
|
|
355
514
|
temporaryPath,
|
|
356
515
|
`${JSON.stringify(receipt, null, 2)}
|
|
357
516
|
`,
|
|
358
517
|
"utf8"
|
|
359
518
|
);
|
|
360
|
-
await
|
|
519
|
+
await import_promises4.default.rename(temporaryPath, finalPath);
|
|
361
520
|
return finalPath;
|
|
362
521
|
};
|
|
363
522
|
|
|
364
523
|
// src/lib/runtimeLineage.ts
|
|
365
|
-
var
|
|
524
|
+
var import_node_crypto4 = require("crypto");
|
|
366
525
|
var normalizeForStableJson = (value) => {
|
|
367
526
|
if (Array.isArray(value)) {
|
|
368
527
|
return value.map(normalizeForStableJson);
|
|
@@ -374,7 +533,7 @@ var normalizeForStableJson = (value) => {
|
|
|
374
533
|
}
|
|
375
534
|
return value;
|
|
376
535
|
};
|
|
377
|
-
var fingerprintRuntimeValue = (value) => (0,
|
|
536
|
+
var fingerprintRuntimeValue = (value) => (0, import_node_crypto4.createHash)("sha256").update(JSON.stringify(normalizeForStableJson(value))).digest("hex").slice(0, 16);
|
|
378
537
|
var runtimeLineageKey = (lineage) => [
|
|
379
538
|
"v3",
|
|
380
539
|
lineage.deploymentCompositionId,
|
|
@@ -1089,9 +1248,9 @@ ${reactions}
|
|
|
1089
1248
|
};
|
|
1090
1249
|
|
|
1091
1250
|
// src/lib/strategyRelease.ts
|
|
1092
|
-
var
|
|
1093
|
-
var
|
|
1094
|
-
var
|
|
1251
|
+
var import_node_crypto5 = require("crypto");
|
|
1252
|
+
var import_promises5 = __toESM(require("fs/promises"));
|
|
1253
|
+
var import_node_path5 = __toESM(require("path"));
|
|
1095
1254
|
var import_types2 = require("@tradejs/types");
|
|
1096
1255
|
var import_strategyReleaseEvidence = require("@tradejs/infra/strategyReleaseEvidence");
|
|
1097
1256
|
|
|
@@ -1565,10 +1724,10 @@ var createStrategyReleaseManifest = (input) => {
|
|
|
1565
1724
|
strategy: input.strategy,
|
|
1566
1725
|
createdAt: input.createdAt,
|
|
1567
1726
|
compositionId,
|
|
1568
|
-
evidence: input.evidence.map(({ kind, artifactId, sha256:
|
|
1727
|
+
evidence: input.evidence.map(({ kind, artifactId, sha256: sha2563 }) => ({
|
|
1569
1728
|
kind,
|
|
1570
1729
|
artifactId,
|
|
1571
|
-
sha256:
|
|
1730
|
+
sha256: sha2563
|
|
1572
1731
|
})),
|
|
1573
1732
|
verdict
|
|
1574
1733
|
};
|
|
@@ -1592,7 +1751,7 @@ var createStrategyReleaseManifest = (input) => {
|
|
|
1592
1751
|
};
|
|
1593
1752
|
};
|
|
1594
1753
|
var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
1595
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
1754
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises5.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
1596
1755
|
const envelope = value;
|
|
1597
1756
|
assert(
|
|
1598
1757
|
envelope?.schema === "tradejs-strategy-release-envelope/v1",
|
|
@@ -1643,19 +1802,19 @@ var verifyStrategyReleaseEnvelope = async (valueOrPath) => {
|
|
|
1643
1802
|
return envelope;
|
|
1644
1803
|
};
|
|
1645
1804
|
var verifyStrategyEvidenceMarkerEnvelope = async (valueOrPath) => {
|
|
1646
|
-
const value = typeof valueOrPath === "string" ? JSON.parse(await
|
|
1805
|
+
const value = typeof valueOrPath === "string" ? JSON.parse(await import_promises5.default.readFile(valueOrPath, "utf8")) : valueOrPath;
|
|
1647
1806
|
return (0, import_strategyReleaseEvidence.verifyStrategyEvidenceMarkerEnvelope)(value);
|
|
1648
1807
|
};
|
|
1649
1808
|
var writeJsonAtomic = async (filePath, value) => {
|
|
1650
1809
|
const temporaryPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
1651
|
-
await
|
|
1652
|
-
await
|
|
1810
|
+
await import_promises5.default.mkdir(import_node_path5.default.dirname(filePath), { recursive: true });
|
|
1811
|
+
await import_promises5.default.writeFile(
|
|
1653
1812
|
temporaryPath,
|
|
1654
1813
|
`${canonicalStrategyReleaseJson(value)}
|
|
1655
1814
|
`,
|
|
1656
1815
|
"utf8"
|
|
1657
1816
|
);
|
|
1658
|
-
await
|
|
1817
|
+
await import_promises5.default.rename(temporaryPath, filePath);
|
|
1659
1818
|
};
|
|
1660
1819
|
var publishStrategyLiveDiagnosis = async ({
|
|
1661
1820
|
rootDir,
|
|
@@ -1721,13 +1880,13 @@ var publishStrategyLiveDiagnosis = async ({
|
|
|
1721
1880
|
markers,
|
|
1722
1881
|
sourceArtifacts
|
|
1723
1882
|
});
|
|
1724
|
-
const diagnosisPath =
|
|
1883
|
+
const diagnosisPath = import_node_path5.default.join(
|
|
1725
1884
|
rootDir,
|
|
1726
1885
|
"diagnoses",
|
|
1727
1886
|
safeSegment2(diagnosis.strategy, "strategy"),
|
|
1728
1887
|
`${diagnosisId}.json`
|
|
1729
1888
|
);
|
|
1730
|
-
const markerPath =
|
|
1889
|
+
const markerPath = import_node_path5.default.join(
|
|
1731
1890
|
rootDir,
|
|
1732
1891
|
"markers",
|
|
1733
1892
|
safeSegment2(diagnosis.strategy, "strategy"),
|
|
@@ -1799,15 +1958,15 @@ var flags = import_args.default.parse(process.argv);
|
|
|
1799
1958
|
var projectRoot = String(process.env.PROJECT_CWD || process.cwd()).trim() || process.cwd();
|
|
1800
1959
|
var resolveOptionalPath = (value) => {
|
|
1801
1960
|
const raw = String(value ?? "").trim();
|
|
1802
|
-
return raw ?
|
|
1961
|
+
return raw ? import_node_path6.default.resolve(projectRoot, raw) : null;
|
|
1803
1962
|
};
|
|
1804
|
-
var readJson = async (filePath) => filePath ? JSON.parse(await
|
|
1963
|
+
var readJson = async (filePath) => filePath ? JSON.parse(await import_promises6.default.readFile(filePath, "utf8")) : void 0;
|
|
1805
1964
|
var assertReportType = (artifact, expected, label) => {
|
|
1806
1965
|
if (artifact != null && (!artifact || typeof artifact !== "object" || Array.isArray(artifact) || artifact.reportType !== expected)) {
|
|
1807
1966
|
throw new Error(`${label} must be a ${expected} artifact`);
|
|
1808
1967
|
}
|
|
1809
1968
|
};
|
|
1810
|
-
var sha256File = async (filePath) => (0,
|
|
1969
|
+
var sha256File = async (filePath) => (0, import_node_crypto6.createHash)("sha256").update(await import_promises6.default.readFile(filePath)).digest("hex");
|
|
1811
1970
|
var loadHistoryArtifacts = async (historyDir) => {
|
|
1812
1971
|
if (!historyDir) return [];
|
|
1813
1972
|
const bundleDirs = await discoverRuntimeEvidenceBundles(historyDir);
|
|
@@ -1877,13 +2036,13 @@ var runtimeScorecard = async () => {
|
|
|
1877
2036
|
strategy: scorecardStrategy,
|
|
1878
2037
|
llmComparatorPolicy: verifiedRelease?.manifest.prospective.llmComparatorPolicy ?? "ai_approved_only"
|
|
1879
2038
|
});
|
|
1880
|
-
const outPath =
|
|
2039
|
+
const outPath = import_node_path6.default.resolve(projectRoot, String(flags.out));
|
|
1881
2040
|
const markdownPath = outPath.replace(/\.json$/i, "") + ".md";
|
|
1882
|
-
await
|
|
2041
|
+
await import_promises6.default.mkdir(import_node_path6.default.dirname(outPath), { recursive: true });
|
|
1883
2042
|
await Promise.all([
|
|
1884
|
-
|
|
2043
|
+
import_promises6.default.writeFile(outPath, `${JSON.stringify(scorecard, null, 2)}
|
|
1885
2044
|
`, "utf8"),
|
|
1886
|
-
|
|
2045
|
+
import_promises6.default.writeFile(
|
|
1887
2046
|
markdownPath,
|
|
1888
2047
|
formatRuntimeScorecardMarkdown(scorecard),
|
|
1889
2048
|
"utf8"
|
|
@@ -1897,7 +2056,7 @@ var runtimeScorecard = async () => {
|
|
|
1897
2056
|
const diagnosisPath = diagnosis ? outPath.replace(/\.json$/i, "") + ".diagnosis.json" : null;
|
|
1898
2057
|
const strategyReleaseRoot = resolveOptionalPath(flags.strategyReleaseRoot);
|
|
1899
2058
|
if (diagnosis && diagnosisPath) {
|
|
1900
|
-
await
|
|
2059
|
+
await import_promises6.default.writeFile(
|
|
1901
2060
|
diagnosisPath,
|
|
1902
2061
|
`${JSON.stringify(diagnosis, null, 2)}
|
|
1903
2062
|
`,
|
|
@@ -1918,7 +2077,7 @@ var runtimeScorecard = async () => {
|
|
|
1918
2077
|
composition: verifiedRelease?.manifest.composition,
|
|
1919
2078
|
sourceArtifacts: await Promise.all(
|
|
1920
2079
|
sourcePaths.map(async (sourcePath) => ({
|
|
1921
|
-
artifactId:
|
|
2080
|
+
artifactId: import_node_path6.default.basename(sourcePath),
|
|
1922
2081
|
path: sourcePath,
|
|
1923
2082
|
sha256: await sha256File(sourcePath)
|
|
1924
2083
|
}))
|
|
@@ -1928,11 +2087,30 @@ var runtimeScorecard = async () => {
|
|
|
1928
2087
|
}
|
|
1929
2088
|
let receiptPath2 = null;
|
|
1930
2089
|
if (flags.markProcessed) {
|
|
2090
|
+
const runtimeEvidenceBundle = await verifyRuntimeEvidenceBundle(
|
|
2091
|
+
import_node_path6.default.dirname(runtimeEvidencePath)
|
|
2092
|
+
);
|
|
2093
|
+
const feedbackSource = replayEvidencePath ? await verifyRuntimeFeedbackReplaySource({
|
|
2094
|
+
bundleDir: import_node_path6.default.dirname(replayEvidencePath),
|
|
2095
|
+
runtimeEvidenceBundleDir: import_node_path6.default.dirname(runtimeEvidencePath)
|
|
2096
|
+
}).catch((error) => {
|
|
2097
|
+
if (runtimeEvidenceBundle.artifact.producer) throw error;
|
|
2098
|
+
return null;
|
|
2099
|
+
}) : null;
|
|
2100
|
+
if (runtimeEvidenceBundle.artifact.producer && !feedbackSource) {
|
|
2101
|
+
throw new Error(
|
|
2102
|
+
"Image-bound runtime evidence requires a verified production replay bundle before it can be marked processed"
|
|
2103
|
+
);
|
|
2104
|
+
}
|
|
1931
2105
|
receiptPath2 = await markRuntimeEvidenceBundleProcessed({
|
|
1932
|
-
evidenceRoot:
|
|
2106
|
+
evidenceRoot: import_node_path6.default.resolve(projectRoot, String(flags.evidenceDir)),
|
|
1933
2107
|
deploymentId: String(flags.deployment),
|
|
1934
|
-
bundleDir:
|
|
1935
|
-
scorecardPath: outPath
|
|
2108
|
+
bundleDir: import_node_path6.default.dirname(runtimeEvidencePath),
|
|
2109
|
+
scorecardPath: outPath,
|
|
2110
|
+
runtimeFeedback: feedbackSource ? {
|
|
2111
|
+
artifactId: feedbackSource.feedback.manifest.artifactId,
|
|
2112
|
+
replayEvidenceSha256: feedbackSource.feedback.manifest.payloads.replayEvidence.sha256
|
|
2113
|
+
} : null
|
|
1936
2114
|
});
|
|
1937
2115
|
}
|
|
1938
2116
|
console.log(import_chalk.default.green(`Wrote ${outPath}`));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradejs/cli",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.22",
|
|
4
4
|
"description": "Official CLI for the TradeJS TypeScript framework: infra setup, backtests, signals, bots, and ML workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"tradejs",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"tradejs": "dist/cli.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@tradejs/connectors": "^3.1.
|
|
40
|
-
"@tradejs/core": "^3.1.
|
|
41
|
-
"@tradejs/indicators": "^3.1.
|
|
42
|
-
"@tradejs/infra": "^3.1.
|
|
43
|
-
"@tradejs/node": "^3.1.
|
|
39
|
+
"@tradejs/connectors": "^3.1.22",
|
|
40
|
+
"@tradejs/core": "^3.1.22",
|
|
41
|
+
"@tradejs/indicators": "^3.1.22",
|
|
42
|
+
"@tradejs/infra": "^3.1.22",
|
|
43
|
+
"@tradejs/node": "^3.1.22",
|
|
44
44
|
"@tradejs/strategy-kit": "3.0.3",
|
|
45
|
-
"@tradejs/types": "^3.1.
|
|
45
|
+
"@tradejs/types": "^3.1.22",
|
|
46
46
|
"args": "^5.0.3",
|
|
47
47
|
"bcryptjs": "^2.4.3",
|
|
48
48
|
"chalk": "4.1.2",
|
|
@@ -84,6 +84,8 @@
|
|
|
84
84
|
"signals": "yarn run run:dist signals",
|
|
85
85
|
"results": "yarn run run:dist results",
|
|
86
86
|
"replay-runtime-evidence": "yarn run run:dist replay-runtime-evidence",
|
|
87
|
+
"runtime-feedback-replay": "yarn run run:dist runtime-feedback-replay",
|
|
88
|
+
"runtime-feedback-sync": "yarn run run:dist runtime-feedback-sync",
|
|
87
89
|
"runtime-evidence": "yarn run run:dist runtime-evidence",
|
|
88
90
|
"runtime-evidence-sync": "yarn run run:dist runtime-evidence-sync",
|
|
89
91
|
"runtime-scorecard": "yarn run run:dist runtime-scorecard",
|