cool-workflow 0.1.80 → 0.1.81
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +42 -2
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/agent-config.js +21 -7
- package/dist/candidate-scoring.js +42 -22
- package/dist/capability-core.js +94 -17
- package/dist/capability-registry.js +138 -171
- package/dist/cli.js +90 -100
- package/dist/collaboration.js +5 -6
- package/dist/commit.js +20 -6
- package/dist/compare.js +18 -0
- package/dist/coordinator/classify.js +45 -0
- package/dist/coordinator/paths.js +42 -0
- package/dist/coordinator/util.js +129 -0
- package/dist/coordinator.js +127 -300
- package/dist/dispatch.js +35 -0
- package/dist/drive.js +7 -7
- package/dist/error-feedback.js +8 -4
- package/dist/evidence-reasoning.js +1 -1
- package/dist/execution-backend/agent.js +331 -0
- package/dist/execution-backend/probes.js +96 -0
- package/dist/execution-backend/util.js +47 -0
- package/dist/execution-backend.js +67 -420
- package/dist/mcp-server.js +34 -173
- package/dist/multi-agent/graph.js +84 -0
- package/dist/multi-agent/helpers.js +145 -0
- package/dist/multi-agent/paths.js +22 -0
- package/dist/multi-agent-eval/format.js +194 -0
- package/dist/multi-agent-eval/normalize.js +51 -0
- package/dist/multi-agent-eval.js +39 -244
- package/dist/multi-agent-host.js +0 -19
- package/dist/multi-agent.js +125 -314
- package/dist/node-snapshot.js +3 -3
- package/dist/observability/format.js +61 -0
- package/dist/observability/intake.js +98 -0
- package/dist/observability.js +14 -160
- package/dist/operator-ux/format.js +364 -0
- package/dist/operator-ux.js +22 -363
- package/dist/orchestrator/report.js +8 -0
- package/dist/orchestrator.js +25 -8
- package/dist/reclamation.js +26 -21
- package/dist/run-export.js +138 -14
- package/dist/run-registry/derive.js +172 -0
- package/dist/run-registry/format.js +124 -0
- package/dist/run-registry/gc.js +251 -0
- package/dist/run-registry/policy.js +16 -0
- package/dist/run-registry/queue.js +116 -0
- package/dist/run-registry.js +78 -593
- package/dist/run-state-schema.js +1 -0
- package/dist/sandbox-profile.js +43 -2
- package/dist/state-explosion/format.js +159 -0
- package/dist/state-explosion/helpers.js +82 -0
- package/dist/state-explosion.js +65 -283
- package/dist/state-node.js +19 -4
- package/dist/telemetry-attestation.js +55 -0
- package/dist/telemetry-demo.js +15 -3
- package/dist/telemetry-ledger.js +60 -15
- package/dist/topology.js +25 -8
- package/dist/triggers.js +33 -14
- package/dist/trust-audit.js +145 -33
- package/dist/version.js +1 -1
- package/dist/worker-isolation/helpers.js +51 -0
- package/dist/worker-isolation/paths.js +46 -0
- package/dist/worker-isolation.js +39 -115
- package/docs/agent-delegation-drive.7.md +13 -0
- package/docs/cli-mcp-parity.7.md +4 -0
- package/docs/contract-migration-tooling.7.md +2 -0
- package/docs/control-plane-scheduling.7.md +2 -0
- package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
- package/docs/durable-state-and-locking.7.md +4 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +2 -0
- package/docs/execution-backends.7.md +2 -0
- package/docs/index.md +1 -0
- package/docs/launch/launch-kit.md +46 -23
- package/docs/launch/pre-launch-checklist.md +14 -14
- package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
- package/docs/multi-agent-eval-replay-harness.7.md +2 -0
- package/docs/multi-agent-operator-ux.7.md +2 -0
- package/docs/multi-agent-trust-policy-audit.7.md +27 -0
- package/docs/node-snapshot-diff-replay.7.md +2 -0
- package/docs/observability-cost-accounting.7.md +2 -0
- package/docs/project-index.md +18 -5
- package/docs/real-execution-backends.7.md +2 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +2 -0
- package/docs/run-registry-control-plane.7.md +54 -8
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/state-explosion-management.7.md +2 -0
- package/docs/team-collaboration.7.md +2 -0
- package/docs/trust-model.md +267 -0
- package/docs/vendor-manifest-loadability.7.md +43 -0
- package/docs/web-desktop-workbench.7.md +2 -0
- package/manifest/plugin.manifest.json +1 -1
- package/package.json +4 -2
- package/scripts/agents/builtin-templates.json +7 -0
- package/scripts/bump-version.js +5 -11
- package/scripts/canonical-apps-list.js +64 -0
- package/scripts/canonical-apps.js +19 -4
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
- package/scripts/parity-check.js +5 -0
- package/scripts/release-check.js +5 -1
- package/scripts/version-sync-check.js +5 -8
- package/dist/capability-dispatcher.js +0 -86
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const orchestrator_1 = require("./orchestrator");
|
|
10
|
-
const capability_registry_1 = require("./capability-registry");
|
|
11
10
|
const capability_core_1 = require("./capability-core");
|
|
12
11
|
const observability_1 = require("./observability");
|
|
13
12
|
const telemetry_demo_1 = require("./telemetry-demo");
|
|
@@ -70,8 +69,6 @@ async function main() {
|
|
|
70
69
|
printJson((0, capability_core_1.appRun)(runner, { ...args.options, appId: required(appIdOrPath, "app id") }));
|
|
71
70
|
return;
|
|
72
71
|
default:
|
|
73
|
-
if (await tryDispatchCli(args, runner))
|
|
74
|
-
return;
|
|
75
72
|
throw new Error("Usage: cw.js app list|show|validate|init|package|run [app-id|path]");
|
|
76
73
|
}
|
|
77
74
|
}
|
|
@@ -128,8 +125,6 @@ async function main() {
|
|
|
128
125
|
return;
|
|
129
126
|
}
|
|
130
127
|
default:
|
|
131
|
-
if (await tryDispatchCli(args, runner))
|
|
132
|
-
return;
|
|
133
128
|
throw new Error("Usage: cw.js state check <run-id> [--state PATH] [--write]");
|
|
134
129
|
}
|
|
135
130
|
}
|
|
@@ -175,8 +170,6 @@ async function main() {
|
|
|
175
170
|
process.stdout.write(`${(0, operator_ux_1.formatOperatorReport)(runner.operatorReport(required(runId, "run id")))}\n`);
|
|
176
171
|
return;
|
|
177
172
|
default:
|
|
178
|
-
if (await tryDispatchCli(args, runner))
|
|
179
|
-
return;
|
|
180
173
|
throw new Error("Usage: cw.js operator status|report <run-id> [--json]");
|
|
181
174
|
}
|
|
182
175
|
}
|
|
@@ -227,8 +220,6 @@ async function main() {
|
|
|
227
220
|
return;
|
|
228
221
|
}
|
|
229
222
|
default:
|
|
230
|
-
if (await tryDispatchCli(args, runner))
|
|
231
|
-
return;
|
|
232
223
|
throw new Error("Usage: cw.js topology list|show <topology-id>|show <run-id> <topology-run-id>|validate <topology-id>|apply <run-id> <topology-id>|summary <run-id>|graph <run-id>");
|
|
233
224
|
}
|
|
234
225
|
}
|
|
@@ -252,8 +243,6 @@ async function main() {
|
|
|
252
243
|
return;
|
|
253
244
|
}
|
|
254
245
|
default:
|
|
255
|
-
if (await tryDispatchCli(args, runner))
|
|
256
|
-
return;
|
|
257
246
|
throw new Error("Usage: cw.js summary refresh|show <run-id> [--json]");
|
|
258
247
|
}
|
|
259
248
|
}
|
|
@@ -410,8 +399,6 @@ async function main() {
|
|
|
410
399
|
}
|
|
411
400
|
return;
|
|
412
401
|
default:
|
|
413
|
-
if (await tryDispatchCli(args, runner))
|
|
414
|
-
return;
|
|
415
402
|
throw new Error("Usage: cw.js multi-agent run|status|step|blackboard|score|select|summary|summarize|graph|dependencies|failures|evidence|reasoning|show|role|group|membership|fanout|fanin <run-id> [id]");
|
|
416
403
|
}
|
|
417
404
|
}
|
|
@@ -440,8 +427,6 @@ async function main() {
|
|
|
440
427
|
result = runner.evalReport(required(first, "replay id or path"));
|
|
441
428
|
break;
|
|
442
429
|
default:
|
|
443
|
-
if (await tryDispatchCli(args, runner))
|
|
444
|
-
return;
|
|
445
430
|
throw new Error("Usage: cw.js eval snapshot <run-id> --id <snapshot-id> | replay <snapshot-id-or-path> | compare <baseline-id-or-path> <replay-id-or-path> | score <replay-id-or-path> | gate <suite-id-or-path> | report <replay-id-or-path>");
|
|
446
431
|
}
|
|
447
432
|
if (wantsJson(args.options))
|
|
@@ -510,8 +495,6 @@ async function main() {
|
|
|
510
495
|
default:
|
|
511
496
|
break;
|
|
512
497
|
}
|
|
513
|
-
if (await tryDispatchCli(args, runner))
|
|
514
|
-
return;
|
|
515
498
|
throw new Error("Usage: cw.js blackboard summary|summarize|graph|resolve <run-id> | topic create <run-id> | message post|list <run-id> | context put <run-id> | artifact add|list <run-id> | snapshot <run-id>");
|
|
516
499
|
}
|
|
517
500
|
case "coordinator": {
|
|
@@ -524,8 +507,6 @@ async function main() {
|
|
|
524
507
|
printJson(runner.recordCoordinatorDecision(required(runId, "run id"), args.options));
|
|
525
508
|
return;
|
|
526
509
|
default:
|
|
527
|
-
if (await tryDispatchCli(args, runner))
|
|
528
|
-
return;
|
|
529
510
|
throw new Error("Usage: cw.js coordinator summary <run-id> | coordinator decision <run-id> --kind <kind> --outcome <outcome> --reason TEXT");
|
|
530
511
|
}
|
|
531
512
|
}
|
|
@@ -538,16 +519,18 @@ async function main() {
|
|
|
538
519
|
case "show":
|
|
539
520
|
printJson(runner.showSandboxProfile(required(profileIdOrFile, "profile id"), args.options));
|
|
540
521
|
return;
|
|
541
|
-
case "validate":
|
|
542
|
-
|
|
522
|
+
case "validate": {
|
|
523
|
+
const result = runner.validateSandboxProfile(required(profileIdOrFile, "profile file"), args.options);
|
|
524
|
+
printJson(result);
|
|
525
|
+
if (!result.valid)
|
|
526
|
+
process.exitCode = 1;
|
|
543
527
|
return;
|
|
528
|
+
}
|
|
544
529
|
case "choose":
|
|
545
530
|
case "resolve":
|
|
546
531
|
printJson((0, capability_core_1.sandboxChoose)(runner, { ...args.options, profileId: profileIdOrFile || args.options.profileId }));
|
|
547
532
|
return;
|
|
548
533
|
default:
|
|
549
|
-
if (await tryDispatchCli(args, runner))
|
|
550
|
-
return;
|
|
551
534
|
throw new Error("Usage: cw.js sandbox list|show|validate|choose|resolve [profile-id|profile-file]");
|
|
552
535
|
}
|
|
553
536
|
}
|
|
@@ -574,8 +557,6 @@ async function main() {
|
|
|
574
557
|
return;
|
|
575
558
|
}
|
|
576
559
|
default:
|
|
577
|
-
if (await tryDispatchCli(args, runner))
|
|
578
|
-
return;
|
|
579
560
|
throw new Error("Usage: cw.js backend list|show|probe [backend-id] | cw.js backend agent config [show|set] [--agent-command ... --agent-endpoint ... --agent-model ...]");
|
|
580
561
|
}
|
|
581
562
|
}
|
|
@@ -586,8 +567,6 @@ async function main() {
|
|
|
586
567
|
printJson(runner.showContract(required(runId, "run id"), contractId));
|
|
587
568
|
return;
|
|
588
569
|
default:
|
|
589
|
-
if (await tryDispatchCli(args, runner))
|
|
590
|
-
return;
|
|
591
570
|
throw new Error("Usage: cw.js contract show <run-id> [contract-id]");
|
|
592
571
|
}
|
|
593
572
|
}
|
|
@@ -615,12 +594,14 @@ async function main() {
|
|
|
615
594
|
case "replay":
|
|
616
595
|
printJson(runner.nodeReplay(required(runId, "run id"), required(nodeId, "snapshot id")));
|
|
617
596
|
return;
|
|
618
|
-
case "verify":
|
|
619
|
-
|
|
597
|
+
case "verify": {
|
|
598
|
+
const verdict = runner.nodeReplayVerify(required(runId, "run id"), required(nodeId, "replay id"));
|
|
599
|
+
printJson(verdict);
|
|
600
|
+
if (!verdict.pass)
|
|
601
|
+
process.exitCode = 1;
|
|
620
602
|
return;
|
|
603
|
+
}
|
|
621
604
|
default:
|
|
622
|
-
if (await tryDispatchCli(args, runner))
|
|
623
|
-
return;
|
|
624
605
|
throw new Error("Usage: cw.js node list|show|graph|snapshot|diff|replay|verify <run-id> [node-id|snapshot-id|replay-id]");
|
|
625
606
|
}
|
|
626
607
|
}
|
|
@@ -630,15 +611,21 @@ async function main() {
|
|
|
630
611
|
case "list":
|
|
631
612
|
printJson(runner.migrationList());
|
|
632
613
|
return;
|
|
633
|
-
case "check":
|
|
634
|
-
|
|
614
|
+
case "check": {
|
|
615
|
+
const report = runner.migrationCheck(required(target, "target (run-id or state/app file)"), args.options);
|
|
616
|
+
printJson(report);
|
|
617
|
+
if (report.status === "unsupported")
|
|
618
|
+
process.exitCode = 1;
|
|
635
619
|
return;
|
|
636
|
-
|
|
637
|
-
|
|
620
|
+
}
|
|
621
|
+
case "prove": {
|
|
622
|
+
const proof = runner.migrationProve(required(target, "target (run-id or state/app file)"), args.options);
|
|
623
|
+
printJson(proof);
|
|
624
|
+
if (!proof.pass)
|
|
625
|
+
process.exitCode = 1;
|
|
638
626
|
return;
|
|
627
|
+
}
|
|
639
628
|
default:
|
|
640
|
-
if (await tryDispatchCli(args, runner))
|
|
641
|
-
return;
|
|
642
629
|
throw new Error("Usage: cw.js migration list|check|prove [target] [--contract run-state|workflow-app]");
|
|
643
630
|
}
|
|
644
631
|
}
|
|
@@ -669,8 +656,6 @@ async function main() {
|
|
|
669
656
|
printJson(runner.resolveFeedback(required(runId, "run id"), required(feedbackId, "feedback id"), args.options));
|
|
670
657
|
return;
|
|
671
658
|
default:
|
|
672
|
-
if (await tryDispatchCli(args, runner))
|
|
673
|
-
return;
|
|
674
659
|
throw new Error("Usage: cw.js feedback list|show|summary|collect|task|resolve <run-id> [feedback-id]");
|
|
675
660
|
}
|
|
676
661
|
}
|
|
@@ -698,14 +683,18 @@ async function main() {
|
|
|
698
683
|
printJson(runner.recordWorkerOutput(required(runId, "run id"), required(workerId, "worker id"), required(resultPath, "result file"), args.options));
|
|
699
684
|
return;
|
|
700
685
|
case "fail":
|
|
701
|
-
printJson(runner.recordWorkerFailure(required(runId, "run id"), required(workerId, "worker id"), String(args.options.message ||
|
|
686
|
+
printJson(runner.recordWorkerFailure(required(runId, "run id"), required(workerId, "worker id"), String(args.options.message || required(resultPath, "failure message")), args.options));
|
|
702
687
|
return;
|
|
703
|
-
case "validate":
|
|
704
|
-
|
|
688
|
+
case "validate": {
|
|
689
|
+
// Non-null = a boundary violation: a validate verb must report an invalid
|
|
690
|
+
// verdict through its exit code, not just print it and exit 0.
|
|
691
|
+
const violation = runner.validateWorker(required(runId, "run id"), required(workerId, "worker id"), resultPath);
|
|
692
|
+
printJson(violation);
|
|
693
|
+
if (violation)
|
|
694
|
+
process.exitCode = 1;
|
|
705
695
|
return;
|
|
696
|
+
}
|
|
706
697
|
default:
|
|
707
|
-
if (await tryDispatchCli(args, runner))
|
|
708
|
-
return;
|
|
709
698
|
throw new Error("Usage: cw.js worker list|summary|show|manifest|output|fail|validate <run-id> [worker-id] [result-file]");
|
|
710
699
|
}
|
|
711
700
|
}
|
|
@@ -715,6 +704,19 @@ async function main() {
|
|
|
715
704
|
case "summary":
|
|
716
705
|
printJson(runner.auditSummary(required(runId, "run id")));
|
|
717
706
|
return;
|
|
707
|
+
case "verify": {
|
|
708
|
+
const result = (0, capability_core_1.auditVerify)(runner, { ...args.options, runId: required(runId, "run id") });
|
|
709
|
+
printJson(result);
|
|
710
|
+
// Fail-closed: any unverified chain exits non-zero so `cw audit verify
|
|
711
|
+
// <run> && deploy` stops — mirrors the telemetry-verify guard. verifyTrustAudit
|
|
712
|
+
// returns verified:true for a truly absent/empty chain (nothing to prove),
|
|
713
|
+
// so this stays exit 0 there; a FULLY-corrupt log reports present:false but
|
|
714
|
+
// verified:false (corruptLines>0) and must NOT be conflated with absent — the
|
|
715
|
+
// earlier `present && ...` guard let that severe tamper escape (exit 0).
|
|
716
|
+
if (!result.verified)
|
|
717
|
+
process.exitCode = 1;
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
718
720
|
case "worker":
|
|
719
721
|
printJson(runner.workerAudit(required(runId, "run id"), required(id, "worker id")));
|
|
720
722
|
return;
|
|
@@ -768,8 +770,6 @@ async function main() {
|
|
|
768
770
|
printJson(runner.recordAuditDecision(required(runId, "run id"), required(id, "worker id"), args.options));
|
|
769
771
|
return;
|
|
770
772
|
default:
|
|
771
|
-
if (await tryDispatchCli(args, runner))
|
|
772
|
-
return;
|
|
773
773
|
throw new Error("Usage: cw.js audit summary|worker|provenance|multi-agent|policy|role|blackboard|judge|attest|decision <run-id> [worker-id|role-id]");
|
|
774
774
|
}
|
|
775
775
|
}
|
|
@@ -804,8 +804,6 @@ async function main() {
|
|
|
804
804
|
process.stdout.write(`${(0, operator_ux_1.formatCandidateSummary)(runner.summarizeCandidateOperatorRecords(required(runId, "run id")))}\n`);
|
|
805
805
|
return;
|
|
806
806
|
default:
|
|
807
|
-
if (await tryDispatchCli(args, runner))
|
|
808
|
-
return;
|
|
809
807
|
throw new Error("Usage: cw.js candidate list|show|register|score|rank|select|reject|summary <run-id> [candidate-id]");
|
|
810
808
|
}
|
|
811
809
|
}
|
|
@@ -835,8 +833,6 @@ async function main() {
|
|
|
835
833
|
process.stdout.write(`${runner.formatCommentList(result.comments)}\n`);
|
|
836
834
|
return;
|
|
837
835
|
}
|
|
838
|
-
if (await tryDispatchCli(args, runner))
|
|
839
|
-
return;
|
|
840
836
|
throw new Error("Usage: cw.js comment add <kind> <run-id> <target-id> --body <text> | comment list <run-id> [--json]");
|
|
841
837
|
}
|
|
842
838
|
case "handoff": {
|
|
@@ -910,8 +906,6 @@ async function main() {
|
|
|
910
906
|
return;
|
|
911
907
|
}
|
|
912
908
|
default:
|
|
913
|
-
if (await tryDispatchCli(args, runner))
|
|
914
|
-
return;
|
|
915
909
|
throw new Error("Usage: cw.js schedule create|list|delete|due|complete|pause|resume|run-now|history|daemon");
|
|
916
910
|
}
|
|
917
911
|
}
|
|
@@ -937,8 +931,6 @@ async function main() {
|
|
|
937
931
|
printJson(triggers.events(idOrKind));
|
|
938
932
|
return;
|
|
939
933
|
default:
|
|
940
|
-
if (await tryDispatchCli(args, runner))
|
|
941
|
-
return;
|
|
942
934
|
throw new Error("Usage: cw.js routine create|list|delete|fire|events");
|
|
943
935
|
}
|
|
944
936
|
}
|
|
@@ -963,8 +955,6 @@ async function main() {
|
|
|
963
955
|
return;
|
|
964
956
|
}
|
|
965
957
|
default:
|
|
966
|
-
if (await tryDispatchCli(args, runner))
|
|
967
|
-
return;
|
|
968
958
|
throw new Error("Usage: cw.js registry refresh|show [--scope repo|home] [--json]");
|
|
969
959
|
}
|
|
970
960
|
}
|
|
@@ -996,7 +986,15 @@ async function main() {
|
|
|
996
986
|
// run end-to-end by delegating each worker to the agent backend. Distinct from
|
|
997
987
|
// the run-REGISTRY verbs below. `--preview` (or the `run drive <run-id>` form)
|
|
998
988
|
// is the read-only, deterministic next-step preview.
|
|
999
|
-
|
|
989
|
+
//
|
|
990
|
+
// A run-REGISTRY subcommand keyword (resume/show/...) must NOT be intercepted
|
|
991
|
+
// here just because it carries a --drive flag of its own — e.g.
|
|
992
|
+
// `run resume <id> --drive` is the resume verb's opt-in continuation, not
|
|
993
|
+
// `run <app=resume> --drive`. Fall through to the switch for those keywords.
|
|
994
|
+
const runRegistrySubcommand = new Set([
|
|
995
|
+
"drive", "search", "list", "show", "resume", "archive", "rerun", "export", "import", "verify-import", "inspect-archive"
|
|
996
|
+
]);
|
|
997
|
+
if (args.options.drive && !runRegistrySubcommand.has(String(args.positionals[0] || ""))) {
|
|
1000
998
|
const target = args.positionals[0];
|
|
1001
999
|
const runId = optionalArg(args.options.run) || optionalArg(args.options.runId);
|
|
1002
1000
|
if (args.options.preview) {
|
|
@@ -1051,7 +1049,7 @@ async function main() {
|
|
|
1051
1049
|
return;
|
|
1052
1050
|
}
|
|
1053
1051
|
case "resume": {
|
|
1054
|
-
const result = (0, capability_core_1.runResume)(registry, required(id, "run id"), args.options);
|
|
1052
|
+
const result = (0, capability_core_1.runResume)(registry, runner, required(id, "run id"), args.options);
|
|
1055
1053
|
if (wantsJson(args.options))
|
|
1056
1054
|
printJson(result);
|
|
1057
1055
|
else
|
|
@@ -1070,13 +1068,27 @@ async function main() {
|
|
|
1070
1068
|
case "import":
|
|
1071
1069
|
printJson((0, capability_core_1.runImportArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path }));
|
|
1072
1070
|
return;
|
|
1073
|
-
case "verify-import":
|
|
1074
|
-
|
|
1071
|
+
case "verify-import": {
|
|
1072
|
+
const result = (0, capability_core_1.runVerifyImport)(runner, required(id || optionalArg(args.options.runId || args.options.run), "run id"), args.options);
|
|
1073
|
+
printJson(result);
|
|
1074
|
+
// Fail-closed ONLY behind --strict, so the default exit stays 0
|
|
1075
|
+
// (byte-identical). With --strict, any failed restore check — including
|
|
1076
|
+
// the new trust-audit row — exits 1 for `verify-import && restore`.
|
|
1077
|
+
if (Boolean(args.options.strict) && !result.ok)
|
|
1078
|
+
process.exitCode = 1;
|
|
1079
|
+
return;
|
|
1080
|
+
}
|
|
1081
|
+
case "inspect-archive": {
|
|
1082
|
+
const result = (0, capability_core_1.runInspectArchive)(runner, { ...args.options, archive: id || args.options.archive || args.options.path });
|
|
1083
|
+
printJson(result);
|
|
1084
|
+
// Read-only diagnostic: exit 1 when the archive fails any integrity check,
|
|
1085
|
+
// so `cw run inspect-archive <path> && restore` stops on a bad archive.
|
|
1086
|
+
if (!result.ok)
|
|
1087
|
+
process.exitCode = 1;
|
|
1075
1088
|
return;
|
|
1089
|
+
}
|
|
1076
1090
|
default:
|
|
1077
|
-
|
|
1078
|
-
return;
|
|
1079
|
-
throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--repo R --question Q]");
|
|
1091
|
+
throw new Error("Usage: cw.js run search|list|show|resume|archive|rerun|drive|export|import|verify-import|inspect-archive [run-id|archive] [--scope repo|home] [--json] | cw.js run <app> --drive [--once] [--repo R --question Q]");
|
|
1080
1092
|
}
|
|
1081
1093
|
}
|
|
1082
1094
|
case "queue": {
|
|
@@ -1101,8 +1113,6 @@ async function main() {
|
|
|
1101
1113
|
printJson((0, capability_core_1.queueShow)(registry, required(id, "queue id")));
|
|
1102
1114
|
return;
|
|
1103
1115
|
default:
|
|
1104
|
-
if (await tryDispatchCli(args, runner))
|
|
1105
|
-
return;
|
|
1106
1116
|
throw new Error("Usage: cw.js queue add|list|drain|show [queue-id] [--repo PATH] [--priority N]");
|
|
1107
1117
|
}
|
|
1108
1118
|
}
|
|
@@ -1138,8 +1148,6 @@ async function main() {
|
|
|
1138
1148
|
return;
|
|
1139
1149
|
}
|
|
1140
1150
|
default:
|
|
1141
|
-
if (await tryDispatchCli(args, runner))
|
|
1142
|
-
return;
|
|
1143
1151
|
throw new Error("Usage: cw.js sched plan|lease|release|complete|reclaim|reset|policy [show|set] [id] [--maxConcurrent N --maxAttempts N ...]");
|
|
1144
1152
|
}
|
|
1145
1153
|
}
|
|
@@ -1172,11 +1180,18 @@ async function main() {
|
|
|
1172
1180
|
printJson(result);
|
|
1173
1181
|
else
|
|
1174
1182
|
process.stdout.write(`${(0, run_registry_1.formatGcVerify)(result)}\n`);
|
|
1183
|
+
// Fail closed ONLY on a real integrity failure: a run that WAS reclaimed
|
|
1184
|
+
// but no longer re-proves. A not-reclaimed run has nothing to verify
|
|
1185
|
+
// (reclaimed:false/verified:false) and must not be treated as a failure.
|
|
1186
|
+
// LIMIT (honest): a DELETED reclaimed.json reads as reclaimed:false, so
|
|
1187
|
+
// proof-deletion is indistinguishable from never-reclaimed here without
|
|
1188
|
+
// an independent witness (e.g. a trust-audit reclamation event) — a
|
|
1189
|
+
// follow-up. This guard is still strictly better than the prior exit-0.
|
|
1190
|
+
if (result.reclaimed && !result.verified)
|
|
1191
|
+
process.exitCode = 1;
|
|
1175
1192
|
return;
|
|
1176
1193
|
}
|
|
1177
1194
|
default:
|
|
1178
|
-
if (await tryDispatchCli(args, runner))
|
|
1179
|
-
return;
|
|
1180
1195
|
throw new Error("Usage: cw.js gc plan|run|verify [run-id] [--reclaimAfterArchiveDays N] [--keep-scratch] [--keep-snapshots] [--limit N] [--json]");
|
|
1181
1196
|
}
|
|
1182
1197
|
}
|
|
@@ -1198,12 +1213,15 @@ async function main() {
|
|
|
1198
1213
|
printJson(result);
|
|
1199
1214
|
else
|
|
1200
1215
|
process.stdout.write(`${(0, telemetry_demo_1.formatTelemetryVerify)(result)}\n`);
|
|
1216
|
+
// Fail closed: a forged/edited/corrupt ledger verifies false — report it
|
|
1217
|
+
// through the exit code so `cw telemetry verify <run> && deploy` cannot
|
|
1218
|
+
// pass on a lie. (Absent ledger = present:false/verified:true -> exit 0.)
|
|
1219
|
+
if (!result.verified)
|
|
1220
|
+
process.exitCode = 1;
|
|
1201
1221
|
return;
|
|
1202
1222
|
}
|
|
1203
1223
|
default:
|
|
1204
|
-
|
|
1205
|
-
return;
|
|
1206
|
-
throw new Error("Usage: cw.js telemetry verify <run-id> [--json]");
|
|
1224
|
+
throw new Error("Usage: cw.js telemetry verify <run-id> [--pubkey <pem-or-path>] [--json]");
|
|
1207
1225
|
}
|
|
1208
1226
|
}
|
|
1209
1227
|
case "demo": {
|
|
@@ -1222,8 +1240,6 @@ async function main() {
|
|
|
1222
1240
|
return;
|
|
1223
1241
|
}
|
|
1224
1242
|
default:
|
|
1225
|
-
if (await tryDispatchCli(args, runner))
|
|
1226
|
-
return;
|
|
1227
1243
|
throw new Error("Usage: cw.js demo tamper [--json]");
|
|
1228
1244
|
}
|
|
1229
1245
|
}
|
|
@@ -1256,39 +1272,13 @@ async function main() {
|
|
|
1256
1272
|
return;
|
|
1257
1273
|
}
|
|
1258
1274
|
default:
|
|
1259
|
-
if (await tryDispatchCli(args, runner))
|
|
1260
|
-
return;
|
|
1261
1275
|
throw new Error("Usage: cw.js workbench serve [--port N] [--once] | view <run-id> [--json]");
|
|
1262
1276
|
}
|
|
1263
1277
|
}
|
|
1264
1278
|
default:
|
|
1265
|
-
if (await tryDispatchCli(args, runner))
|
|
1266
|
-
return;
|
|
1267
1279
|
throw new Error(`Unknown command: ${args.command}`);
|
|
1268
1280
|
}
|
|
1269
1281
|
}
|
|
1270
|
-
/** Try to dispatch a command through the dynamic capability registry.
|
|
1271
|
-
* Mechanism: reconstructs the full CLI path, resolves a handler, invokes it.
|
|
1272
|
-
* Policy: unknown commands fall through to the legacy switch; this is a thin pipe.
|
|
1273
|
-
* Returns true when the command was dispatched. */
|
|
1274
|
-
async function tryDispatchCli(args, runner) {
|
|
1275
|
-
const cliPath = [args.command, ...args.positionals].filter((token) => typeof token === "string");
|
|
1276
|
-
if (!cliPath.length)
|
|
1277
|
-
return false;
|
|
1278
|
-
const capabilityId = (0, capability_registry_1.resolveCliPath)(cliPath);
|
|
1279
|
-
if (!capabilityId)
|
|
1280
|
-
return false;
|
|
1281
|
-
const handler = (0, capability_registry_1.getCapabilityHandler)(capabilityId);
|
|
1282
|
-
if (!handler)
|
|
1283
|
-
return false;
|
|
1284
|
-
const result = await (0, capability_registry_1.dispatchCapability)(capabilityId, args.options, {
|
|
1285
|
-
runner,
|
|
1286
|
-
cwd: String(args.options.cwd || process.cwd())
|
|
1287
|
-
});
|
|
1288
|
-
if (wantsJson(args.options) || handler.descriptor.cli?.jsonMode === "default")
|
|
1289
|
-
printJson(result);
|
|
1290
|
-
return true;
|
|
1291
|
-
}
|
|
1292
1282
|
function required(value, label) {
|
|
1293
1283
|
if (!value)
|
|
1294
1284
|
throw new Error(`Missing ${label}`);
|
package/dist/collaboration.js
CHANGED
|
@@ -553,7 +553,7 @@ function buildTimeline(run) {
|
|
|
553
553
|
summary: `review policy: ${policy.requiredApprovals} approval(s) from [${policy.authorizedRoles.join(", ")}] for [${policy.appliesTo.join(", ")}]`
|
|
554
554
|
});
|
|
555
555
|
}
|
|
556
|
-
return entries.sort(
|
|
556
|
+
return entries.sort(compareByCreated);
|
|
557
557
|
}
|
|
558
558
|
function buildNextActions(run, states, policy) {
|
|
559
559
|
const actions = [];
|
|
@@ -674,8 +674,10 @@ function targetKey(target) {
|
|
|
674
674
|
return `${target.kind}:${target.id}`;
|
|
675
675
|
}
|
|
676
676
|
function createCollabId(run, kind, count) {
|
|
677
|
-
|
|
678
|
-
|
|
677
|
+
// Deterministic (FreeBSD-audit L12/L13): caller-supplied count (approvals/comments/
|
|
678
|
+
// handoffs length), no wall-clock stamp. The collab id is bound into the trust-audit
|
|
679
|
+
// chain via linkedAuditEventIds, so a stable id keeps that reproducible.
|
|
680
|
+
return `collab-${(0, state_1.safeFileName)(kind)}-${String(count + 1).padStart(4, "0")}`;
|
|
679
681
|
}
|
|
680
682
|
function persist(run, options) {
|
|
681
683
|
if (options.persist === false)
|
|
@@ -685,9 +687,6 @@ function persist(run, options) {
|
|
|
685
687
|
function compareByCreated(left, right) {
|
|
686
688
|
return left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id);
|
|
687
689
|
}
|
|
688
|
-
function compareTimeline(left, right) {
|
|
689
|
-
return left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id);
|
|
690
|
-
}
|
|
691
690
|
function compact(value) {
|
|
692
691
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
693
692
|
}
|
package/dist/commit.js
CHANGED
|
@@ -17,6 +17,7 @@ const trust_audit_1 = require("./trust-audit");
|
|
|
17
17
|
const collaboration_1 = require("./collaboration");
|
|
18
18
|
const evidence_grounding_1 = require("./evidence-grounding");
|
|
19
19
|
const verifier_1 = require("./verifier");
|
|
20
|
+
const compare_1 = require("./compare");
|
|
20
21
|
class CommitGateError extends Error {
|
|
21
22
|
structured;
|
|
22
23
|
feedbackId;
|
|
@@ -37,7 +38,7 @@ function commitState(run, input) {
|
|
|
37
38
|
throw recordCommitGateFailure(run, options, gate);
|
|
38
39
|
}
|
|
39
40
|
node_fs_1.default.mkdirSync(run.paths.commitsDir, { recursive: true });
|
|
40
|
-
const id = createCommitId();
|
|
41
|
+
const id = createCommitId(run);
|
|
41
42
|
const snapshotPath = node_path_1.default.join(run.paths.commitsDir, `${id}.json`);
|
|
42
43
|
const audit = gate.verifierGated
|
|
43
44
|
? (0, trust_audit_1.recordTrustAuditEvent)(run, {
|
|
@@ -440,7 +441,7 @@ function recordCommitNode(run, commit, options, gate) {
|
|
|
440
441
|
function recordCommitGateFailure(run, options, gate) {
|
|
441
442
|
const first = gate.errors[0] || error("commit-gate-blocked", "Verifier-gated commit blocked");
|
|
442
443
|
const node = (0, state_node_1.recordNodeError)((0, state_node_1.createStateNode)({
|
|
443
|
-
id: `${run.id}:commit-gate-failed:${
|
|
444
|
+
id: `${run.id}:commit-gate-failed:${gateFailureSeq(run)}`,
|
|
444
445
|
kind: "error",
|
|
445
446
|
status: "pending",
|
|
446
447
|
loopStage: "checkpoint",
|
|
@@ -511,7 +512,7 @@ function resolveLinkedVerifier(requested, linked, errors, ownerKind, ownerId) {
|
|
|
511
512
|
function latestSelectionForCandidate(run, candidateId) {
|
|
512
513
|
return [...(run.candidateSelections || [])]
|
|
513
514
|
.filter((selection) => selection.candidateId === candidateId)
|
|
514
|
-
.sort((left, right) => right.selectedAt
|
|
515
|
+
.sort((left, right) => (0, compare_1.compareBytes)(right.selectedAt, left.selectedAt))[0];
|
|
515
516
|
}
|
|
516
517
|
function findSelection(run, selectionId) {
|
|
517
518
|
return (run.candidateSelections || []).find((selection) => selection.id === selectionId);
|
|
@@ -552,9 +553,22 @@ function error(code, message, options = {}) {
|
|
|
552
553
|
...options
|
|
553
554
|
};
|
|
554
555
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
556
|
+
// Deterministic commit id (FreeBSD-audit L12/L13): the commit's POSITION in the
|
|
557
|
+
// run's append-only commit log, not a wall-clock stamp + PRNG suffix. Re-running
|
|
558
|
+
// the same workflow mints byte-identical commit ids, so snapshot/replay digests
|
|
559
|
+
// match. The sequence is unique within a run (commits only ever append), and the
|
|
560
|
+
// commitState caller writes the snapshot under this id before pushing the commit.
|
|
561
|
+
function createCommitId(run) {
|
|
562
|
+
const seq = (run.commits || []).length + 1;
|
|
563
|
+
return `state-${String(seq).padStart(4, "0")}`;
|
|
564
|
+
}
|
|
565
|
+
// Deterministic suffix for a blocked-commit node id. Counts the commit-gate-failed
|
|
566
|
+
// nodes already recorded on the run and returns the next position, so repeated
|
|
567
|
+
// gate failures in one run stay collision-free and replay-stable.
|
|
568
|
+
function gateFailureSeq(run) {
|
|
569
|
+
const marker = ":commit-gate-failed:";
|
|
570
|
+
const seq = (run.nodes || []).filter((node) => node.id.includes(marker)).length + 1;
|
|
571
|
+
return String(seq).padStart(4, "0");
|
|
558
572
|
}
|
|
559
573
|
function readGitHead(cwd) {
|
|
560
574
|
try {
|
package/dist/compare.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compareBytes = compareBytes;
|
|
4
|
+
// Locale-INDEPENDENT total order for strings (FreeBSD-audit L12 determinism).
|
|
5
|
+
//
|
|
6
|
+
// `String.localeCompare` is host/locale-sensitive: two hosts can order the same
|
|
7
|
+
// byte-identical strings differently. That is fine for human-facing display, but
|
|
8
|
+
// FATAL when the sorted order feeds a sha256 digest, a tombstone/hash chain, or a
|
|
9
|
+
// stable-persisted projection (index.json, messages.jsonl, an export manifest):
|
|
10
|
+
// the same content would then serialize/hash differently across hosts, breaking
|
|
11
|
+
// CW's cross-host reproducibility and replay-determinism guarantees.
|
|
12
|
+
//
|
|
13
|
+
// Use compareBytes() for any ordering that flows into a hash, an export, a
|
|
14
|
+
// persisted projection, or a commit/replay-bearing decision. Pure display sorts
|
|
15
|
+
// may keep localeCompare.
|
|
16
|
+
function compareBytes(a, b) {
|
|
17
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
18
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.statusToNodeStatus = statusToNodeStatus;
|
|
4
|
+
exports.decisionStatus = decisionStatus;
|
|
5
|
+
exports.auditDecision = auditDecision;
|
|
6
|
+
exports.sourceForAuthor = sourceForAuthor;
|
|
7
|
+
function statusToNodeStatus(status) {
|
|
8
|
+
switch (status) {
|
|
9
|
+
case "active":
|
|
10
|
+
case "open":
|
|
11
|
+
return "running";
|
|
12
|
+
case "resolved":
|
|
13
|
+
case "superseded":
|
|
14
|
+
return "completed";
|
|
15
|
+
case "conflicting":
|
|
16
|
+
return "blocked";
|
|
17
|
+
case "rejected":
|
|
18
|
+
return "rejected";
|
|
19
|
+
default:
|
|
20
|
+
return "completed";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function decisionStatus(outcome) {
|
|
24
|
+
if (outcome === "conflicting" || outcome === "blocked")
|
|
25
|
+
return "conflicting";
|
|
26
|
+
if (outcome === "rejected")
|
|
27
|
+
return "rejected";
|
|
28
|
+
if (outcome === "superseded")
|
|
29
|
+
return "superseded";
|
|
30
|
+
return "active";
|
|
31
|
+
}
|
|
32
|
+
function auditDecision(outcome) {
|
|
33
|
+
if (outcome === "rejected")
|
|
34
|
+
return "rejected";
|
|
35
|
+
if (outcome === "blocked" || outcome === "conflicting")
|
|
36
|
+
return "failed";
|
|
37
|
+
return "accepted";
|
|
38
|
+
}
|
|
39
|
+
function sourceForAuthor(author) {
|
|
40
|
+
if (author.kind === "runtime" || author.kind === "coordinator")
|
|
41
|
+
return "runtime-derived";
|
|
42
|
+
if (author.kind === "worker" || author.kind === "verifier")
|
|
43
|
+
return "cw-validated";
|
|
44
|
+
return "operator-recorded";
|
|
45
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.boardPaths = boardPaths;
|
|
7
|
+
exports.blackboardRoot = blackboardRoot;
|
|
8
|
+
exports.messagesPath = messagesPath;
|
|
9
|
+
exports.recordPath = recordPath;
|
|
10
|
+
// Filesystem path derivation for the coordinator/blackboard layer
|
|
11
|
+
// (FreeBSD-audit R-carve). Carved out of coordinator.ts so the module no longer
|
|
12
|
+
// bundles the per-run path computation alongside the stateful blackboard
|
|
13
|
+
// operations. Re-exported from coordinator.ts to keep the public surface
|
|
14
|
+
// byte-identical.
|
|
15
|
+
//
|
|
16
|
+
// BEHAVIOR-PRESERVING — pure code movement, zero logic change. Each function is a
|
|
17
|
+
// function of a WorkflowRun's paths only: it reads run.paths and joins names; it
|
|
18
|
+
// never mutates run, never touches the blackboard state, never writes the disk.
|
|
19
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
20
|
+
const state_1 = require("../state");
|
|
21
|
+
function boardPaths(run) {
|
|
22
|
+
const root = blackboardRoot(run);
|
|
23
|
+
return {
|
|
24
|
+
root,
|
|
25
|
+
index: node_path_1.default.join(root, "index.json"),
|
|
26
|
+
messages: messagesPath(run),
|
|
27
|
+
topicsDir: node_path_1.default.join(root, "topics"),
|
|
28
|
+
contextsDir: node_path_1.default.join(root, "contexts"),
|
|
29
|
+
artifactsDir: node_path_1.default.join(root, "artifacts"),
|
|
30
|
+
snapshotsDir: node_path_1.default.join(root, "snapshots"),
|
|
31
|
+
decisionsDir: node_path_1.default.join(root, "decisions")
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function blackboardRoot(run) {
|
|
35
|
+
return run.paths.blackboardDir || node_path_1.default.join(run.paths.runDir, "blackboard");
|
|
36
|
+
}
|
|
37
|
+
function messagesPath(run) {
|
|
38
|
+
return node_path_1.default.join(blackboardRoot(run), "messages.jsonl");
|
|
39
|
+
}
|
|
40
|
+
function recordPath(run, kind, id) {
|
|
41
|
+
return node_path_1.default.join(blackboardRoot(run), kind, `${(0, state_1.safeFileName)(id)}.json`);
|
|
42
|
+
}
|