cool-workflow 0.1.79 → 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 +51 -3
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +64 -0
- package/apps/architecture-review-fast/workflow.js +153 -0
- 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 +132 -17
- package/dist/capability-registry.js +138 -168
- package/dist/cli.js +97 -98
- 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 +79 -6
- package/dist/error-feedback.js +8 -4
- package/dist/evidence-reasoning.js +3 -3
- 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 +73 -421
- package/dist/mcp-server.js +79 -183
- 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/lifecycle-operations.js +2 -1
- package/dist/orchestrator/report.js +8 -0
- package/dist/orchestrator.js +26 -9
- package/dist/reclamation.js +26 -21
- package/dist/run-export.js +494 -25
- 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 +89 -597
- 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 +165 -304
- 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 +71 -0
- package/docs/canonical-workflow-apps.7.md +37 -0
- package/docs/cli-mcp-parity.7.md +16 -0
- package/docs/contract-migration-tooling.7.md +6 -0
- package/docs/control-plane-scheduling.7.md +6 -0
- package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
- package/docs/durable-state-and-locking.7.md +8 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
- package/docs/execution-backends.7.md +6 -0
- package/docs/index.md +2 -0
- package/docs/launch/demo.tape +28 -0
- package/docs/launch/launch-kit.md +96 -17
- package/docs/launch/pre-launch-checklist.md +53 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +8 -0
- package/docs/multi-agent-eval-replay-harness.7.md +6 -0
- package/docs/multi-agent-operator-ux.7.md +6 -0
- package/docs/multi-agent-trust-policy-audit.7.md +27 -0
- package/docs/node-snapshot-diff-replay.7.md +6 -0
- package/docs/observability-cost-accounting.7.md +6 -0
- package/docs/project-index.md +27 -6
- package/docs/real-execution-backends.7.md +6 -0
- package/docs/release-and-migration.7.md +8 -0
- package/docs/release-tooling.7.md +6 -0
- package/docs/routines.md +23 -0
- package/docs/run-registry-control-plane.7.md +89 -2
- package/docs/run-retention-reclamation.7.md +8 -0
- package/docs/source-context-profiles.7.md +119 -0
- package/docs/state-explosion-management.7.md +13 -0
- package/docs/team-collaboration.7.md +6 -0
- package/docs/trust-model.md +267 -0
- package/docs/unix-principles.md +49 -1
- package/docs/vendor-manifest-loadability.7.md +43 -0
- package/docs/web-desktop-workbench.7.md +6 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +142 -0
- package/package.json +4 -1
- package/scripts/agents/builtin-templates.json +7 -0
- package/scripts/agents/claude-p-agent.js +129 -43
- package/scripts/architecture-review-fast.js +362 -0
- package/scripts/bump-version.js +5 -10
- package/scripts/canonical-apps-list.js +64 -0
- package/scripts/canonical-apps.js +36 -4
- package/scripts/coverage-gate.js +211 -0
- 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/source-context.js +291 -0
- package/scripts/version-sync-check.js +5 -7
- package/skills/ci-triage/SKILL.md +50 -0
- package/skills/ci-triage/agents/openai.yaml +4 -0
- package/skills/cool-workflow/SKILL.md +4 -1
- package/skills/deploy-check/SKILL.md +55 -0
- package/skills/deploy-check/agents/openai.yaml +4 -0
- package/skills/design-qa/SKILL.md +49 -0
- package/skills/design-qa/agents/openai.yaml +4 -0
- package/skills/pr-review/SKILL.md +45 -0
- package/skills/pr-review/agents/openai.yaml +4 -0
- package/dist/capability-dispatcher.js +0 -86
package/dist/worker-isolation.js
CHANGED
|
@@ -4,7 +4,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.WORKER_ISOLATION_SCHEMA_VERSION = void 0;
|
|
7
|
-
exports.createWorkerIsolation = createWorkerIsolation;
|
|
8
7
|
exports.allocateWorkerScope = allocateWorkerScope;
|
|
9
8
|
exports.writeWorkerManifest = writeWorkerManifest;
|
|
10
9
|
exports.syncWorkerScopeFromTask = syncWorkerScopeFromTask;
|
|
@@ -33,21 +32,9 @@ const multi_agent_1 = require("./multi-agent");
|
|
|
33
32
|
const telemetry_attestation_1 = require("./telemetry-attestation");
|
|
34
33
|
const telemetry_ledger_1 = require("./telemetry-ledger");
|
|
35
34
|
const coordinator_1 = require("./coordinator");
|
|
35
|
+
const helpers_1 = require("./worker-isolation/helpers");
|
|
36
|
+
const paths_1 = require("./worker-isolation/paths");
|
|
36
37
|
exports.WORKER_ISOLATION_SCHEMA_VERSION = 1;
|
|
37
|
-
const WORKER_SCOPE_FILE = "worker.json";
|
|
38
|
-
const WORKER_MANIFEST_FILE = "manifest.json";
|
|
39
|
-
function createWorkerIsolation(options = {}) {
|
|
40
|
-
return {
|
|
41
|
-
allocateWorkerScope: (run, task, allocateOptions) => allocateWorkerScope(run, task, { ...options, ...allocateOptions }),
|
|
42
|
-
writeWorkerManifest,
|
|
43
|
-
listWorkerScopes: (run, listOptions) => listWorkerScopes(run, listOptions),
|
|
44
|
-
getWorkerScope,
|
|
45
|
-
recordWorkerOutput,
|
|
46
|
-
recordWorkerFailure,
|
|
47
|
-
validateWorkerBoundary,
|
|
48
|
-
summarizeWorkers
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
38
|
function allocateWorkerScope(run, task, options = {}) {
|
|
52
39
|
ensureWorkerState(run);
|
|
53
40
|
const existing = task.workerId ? getWorkerScope(run, task.workerId) : undefined;
|
|
@@ -64,7 +51,7 @@ function allocateWorkerScope(run, task, options = {}) {
|
|
|
64
51
|
return existing;
|
|
65
52
|
}
|
|
66
53
|
const now = new Date().toISOString();
|
|
67
|
-
const workerId = options.workerId || createWorkerId(run, task.id);
|
|
54
|
+
const workerId = options.workerId || (0, paths_1.createWorkerId)(run, task.id);
|
|
68
55
|
const workerDir = node_path_1.default.join(workerRoot(run), (0, state_1.safeFileName)(workerId));
|
|
69
56
|
const inputPath = node_path_1.default.join(workerDir, "input.md");
|
|
70
57
|
const resultPath = node_path_1.default.join(workerDir, "result.md");
|
|
@@ -82,7 +69,10 @@ function allocateWorkerScope(run, task, options = {}) {
|
|
|
82
69
|
extraReadPaths: options.policy?.readPaths || [],
|
|
83
70
|
extraWritePaths: [...(options.policy?.writePaths || []), ...(options.policy?.allowedPaths || [])],
|
|
84
71
|
allowArtifacts: options.policy?.allowArtifacts,
|
|
85
|
-
allowLogs: options.policy?.allowLogs
|
|
72
|
+
allowLogs: options.policy?.allowLogs,
|
|
73
|
+
// H7: persisted custom profile definitions so a custom logical id resolves
|
|
74
|
+
// against THIS worker's context (worker-specific path tokens bind correctly).
|
|
75
|
+
customProfiles: run.customSandboxProfiles
|
|
86
76
|
});
|
|
87
77
|
const allowedPaths = (0, sandbox_profile_1.effectiveSandboxWritePaths)(sandboxPolicy);
|
|
88
78
|
(0, sandbox_profile_1.upsertRunSandboxPolicy)(run, sandboxPolicy);
|
|
@@ -123,7 +113,7 @@ function allocateWorkerScope(run, task, options = {}) {
|
|
|
123
113
|
feedbackIds: [],
|
|
124
114
|
errors: [],
|
|
125
115
|
multiAgent: options.multiAgent,
|
|
126
|
-
metadata: compactMetadata({
|
|
116
|
+
metadata: (0, helpers_1.compactMetadata)({
|
|
127
117
|
...options.metadata,
|
|
128
118
|
multiAgent: options.multiAgent,
|
|
129
119
|
phase: task.phase,
|
|
@@ -165,7 +155,7 @@ function allocateWorkerScope(run, task, options = {}) {
|
|
|
165
155
|
});
|
|
166
156
|
}
|
|
167
157
|
task.workerId = scope.id;
|
|
168
|
-
task.workerManifestPath = manifestPath(scope);
|
|
158
|
+
task.workerManifestPath = (0, paths_1.manifestPath)(scope);
|
|
169
159
|
task.sandboxProfileId = sandboxPolicy.id;
|
|
170
160
|
task.sandboxPolicy = sandboxPolicy;
|
|
171
161
|
task.backendId = backendId;
|
|
@@ -180,8 +170,8 @@ function writeWorkerManifest(run, scope) {
|
|
|
180
170
|
const task = run.tasks.find((candidate) => candidate.id === scope.taskId);
|
|
181
171
|
const sandboxPolicy = scope.sandboxPolicy || sandboxPolicyForBoundary(run, scope);
|
|
182
172
|
const sandboxProfileId = scope.sandboxProfileId || sandboxPolicy.id;
|
|
183
|
-
const scopePath = workerScopePath(scope);
|
|
184
|
-
const workerManifestPath = manifestPath(scope);
|
|
173
|
+
const scopePath = (0, paths_1.workerScopePath)(scope);
|
|
174
|
+
const workerManifestPath = (0, paths_1.manifestPath)(scope);
|
|
185
175
|
const manifest = {
|
|
186
176
|
schemaVersion: exports.WORKER_ISOLATION_SCHEMA_VERSION,
|
|
187
177
|
id: scope.id,
|
|
@@ -257,7 +247,7 @@ function syncWorkerScopeFromTask(run, workerId) {
|
|
|
257
247
|
...scope,
|
|
258
248
|
updatedAt: new Date().toISOString(),
|
|
259
249
|
multiAgent: task.multiAgent,
|
|
260
|
-
metadata: compactMetadata({
|
|
250
|
+
metadata: (0, helpers_1.compactMetadata)({
|
|
261
251
|
...(scope.metadata || {}),
|
|
262
252
|
multiAgent: task.multiAgent
|
|
263
253
|
})
|
|
@@ -267,7 +257,7 @@ function syncWorkerScopeFromTask(run, workerId) {
|
|
|
267
257
|
function listWorkerScopes(run, options = {}) {
|
|
268
258
|
ensureWorkerState(run);
|
|
269
259
|
const scopes = loadWorkerScopesFromDisk(run);
|
|
270
|
-
run.workers = mergeScopes(run.workers || [], scopes);
|
|
260
|
+
run.workers = (0, helpers_1.mergeScopes)(run.workers || [], scopes);
|
|
271
261
|
const listed = run.workers || [];
|
|
272
262
|
return options.status ? listed.filter((scope) => scope.status === options.status) : listed;
|
|
273
263
|
}
|
|
@@ -276,7 +266,7 @@ function getWorkerScope(run, workerId) {
|
|
|
276
266
|
const existing = (run.workers || []).find((scope) => scope.id === workerId);
|
|
277
267
|
if (existing)
|
|
278
268
|
return existing;
|
|
279
|
-
const file = node_path_1.default.join(workerRoot(run), (0, state_1.safeFileName)(workerId), WORKER_SCOPE_FILE);
|
|
269
|
+
const file = node_path_1.default.join(workerRoot(run), (0, state_1.safeFileName)(workerId), paths_1.WORKER_SCOPE_FILE);
|
|
280
270
|
if (!node_fs_1.default.existsSync(file))
|
|
281
271
|
return undefined;
|
|
282
272
|
const scope = JSON.parse(node_fs_1.default.readFileSync(file, "utf8"));
|
|
@@ -302,7 +292,7 @@ function recordWorkerOutput(run, workerId, resultPath, options = {}) {
|
|
|
302
292
|
throw new Error(violation.message);
|
|
303
293
|
}
|
|
304
294
|
if (!node_fs_1.default.existsSync(absoluteResultPath)) {
|
|
305
|
-
const error = structuredError("worker-result-missing", `Worker result file does not exist: ${absoluteResultPath}`, {
|
|
295
|
+
const error = (0, helpers_1.structuredError)("worker-result-missing", `Worker result file does not exist: ${absoluteResultPath}`, {
|
|
306
296
|
path: absoluteResultPath,
|
|
307
297
|
retryable: true
|
|
308
298
|
});
|
|
@@ -321,7 +311,7 @@ function recordWorkerOutput(run, workerId, resultPath, options = {}) {
|
|
|
321
311
|
const baseDirs = Array.from(new Set([run.cwd, process.cwd(), scope.workerDir, run.paths.runDir].filter(Boolean)));
|
|
322
312
|
const unresolved = (0, evidence_grounding_1.unresolvedFileEvidence)(parsedResult.evidence, baseDirs);
|
|
323
313
|
if (unresolved.length) {
|
|
324
|
-
const error = structuredError("worker-evidence-unresolvable", `Worker ${workerId} result cites file evidence that does not resolve on disk: ${unresolved.join(", ")}`, { path: absoluteResultPath, retryable: false });
|
|
314
|
+
const error = (0, helpers_1.structuredError)("worker-evidence-unresolvable", `Worker ${workerId} result cites file evidence that does not resolve on disk: ${unresolved.join(", ")}`, { path: absoluteResultPath, retryable: false });
|
|
325
315
|
recordWorkerFailure(run, workerId, error, { ...options, persist: options.persist });
|
|
326
316
|
throw new Error(error.message);
|
|
327
317
|
}
|
|
@@ -345,7 +335,7 @@ function recordWorkerOutput(run, workerId, resultPath, options = {}) {
|
|
|
345
335
|
// it instead of recording unverifiable usage. Default behavior is unchanged
|
|
346
336
|
// (flag-and-surface). Non-agent hops carry no verdict and are never blocked.
|
|
347
337
|
if (options.requireAttestedTelemetry && telemetry && telemetry.status !== "attested") {
|
|
348
|
-
const error = structuredError("telemetry-unattested-blocked", `Worker ${workerId} telemetry is ${telemetry.status} (${telemetry.reason || "unverified"}) and require-attested-telemetry is enabled — refusing to accept a hop whose usage cannot be cryptographically verified`, { path: absoluteResultPath, retryable: false });
|
|
338
|
+
const error = (0, helpers_1.structuredError)("telemetry-unattested-blocked", `Worker ${workerId} telemetry is ${telemetry.status} (${telemetry.reason || "unverified"}) and require-attested-telemetry is enabled — refusing to accept a hop whose usage cannot be cryptographically verified`, { path: absoluteResultPath, retryable: false });
|
|
349
339
|
recordWorkerFailure(run, workerId, error, { ...options, persist: options.persist });
|
|
350
340
|
throw new Error(error.message);
|
|
351
341
|
}
|
|
@@ -581,7 +571,7 @@ function recordWorkerFailure(run, workerId, error, options = {}) {
|
|
|
581
571
|
status: "pending",
|
|
582
572
|
loopStage: "adjust",
|
|
583
573
|
inputs: { workerId, taskId: task.id, dispatchId: scope.dispatchId },
|
|
584
|
-
artifacts: workerArtifacts(scope),
|
|
574
|
+
artifacts: (0, paths_1.workerArtifacts)(scope),
|
|
585
575
|
parents: task.stateNodeId ? [task.stateNodeId] : [],
|
|
586
576
|
contractId: pipeline_contract_1.DEFAULT_PIPELINE_CONTRACT_ID,
|
|
587
577
|
metadata: { workerId, taskId: task.id, dispatchId: scope.dispatchId, workerDir: scope.workerDir, sandboxProfileId: scope.sandboxProfileId }
|
|
@@ -636,7 +626,7 @@ function recordWorkerFailure(run, workerId, error, options = {}) {
|
|
|
636
626
|
updatedAt: new Date().toISOString(),
|
|
637
627
|
status: structured.code === "worker-boundary-violation" || structured.code.startsWith("sandbox-") ? "rejected" : "failed",
|
|
638
628
|
retryCount: typeof options.retryCount === "number" ? options.retryCount : scope.retryCount,
|
|
639
|
-
feedbackIds: unique([...(scope.feedbackIds || []), feedback.id]),
|
|
629
|
+
feedbackIds: (0, helpers_1.unique)([...(scope.feedbackIds || []), feedback.id]),
|
|
640
630
|
errors: [...(scope.errors || []), structured]
|
|
641
631
|
});
|
|
642
632
|
if (options.persist !== false)
|
|
@@ -649,7 +639,7 @@ function recordWorkerRetryAttempt(run, workerId, attempts, reason, options = {})
|
|
|
649
639
|
...scope,
|
|
650
640
|
updatedAt: new Date().toISOString(),
|
|
651
641
|
retryCount: attempts,
|
|
652
|
-
metadata: compactMetadata({
|
|
642
|
+
metadata: (0, helpers_1.compactMetadata)({
|
|
653
643
|
...scope.metadata,
|
|
654
644
|
agentDelegationAttempts: attempts,
|
|
655
645
|
agentDelegationLastFailure: reason
|
|
@@ -668,8 +658,8 @@ function summarizeWorkers(run) {
|
|
|
668
658
|
const workers = listWorkerScopes(run);
|
|
669
659
|
return {
|
|
670
660
|
total: workers.length,
|
|
671
|
-
byStatus: countBy(workers, (scope) => scope.status),
|
|
672
|
-
manifestPaths: workers.map(manifestPath),
|
|
661
|
+
byStatus: (0, helpers_1.countBy)(workers, (scope) => scope.status),
|
|
662
|
+
manifestPaths: workers.map(paths_1.manifestPath),
|
|
673
663
|
failed: workers
|
|
674
664
|
.filter((scope) => scope.status === "failed" || scope.status === "rejected")
|
|
675
665
|
.map((scope) => ({ id: scope.id, status: scope.status, feedbackIds: scope.feedbackIds || [] }))
|
|
@@ -705,15 +695,9 @@ function reclaimOrphans(run, now) {
|
|
|
705
695
|
}
|
|
706
696
|
if (orphans.length) {
|
|
707
697
|
writeWorkerIndex(run);
|
|
708
|
-
saveWorkerCheckpoint(run);
|
|
709
698
|
}
|
|
710
699
|
return { runId: run.id, reclaimed: orphans.length, orphans };
|
|
711
700
|
}
|
|
712
|
-
function saveWorkerCheckpoint(run) {
|
|
713
|
-
// Durable write via atomic temp+rename (same contract as saveCheckpoint)
|
|
714
|
-
// For worker index, the atomic write in writeWorkerIndex already handles it.
|
|
715
|
-
// This is a no-op wrapper that signals the checkpoint boundary.
|
|
716
|
-
}
|
|
717
701
|
function ensureWorkerState(run) {
|
|
718
702
|
run.paths.workersDir = run.paths.workersDir || node_path_1.default.join(run.paths.runDir, "workers");
|
|
719
703
|
node_fs_1.default.mkdirSync(run.paths.workersDir, { recursive: true });
|
|
@@ -771,7 +755,7 @@ function updateWorkerScope(run, scope) {
|
|
|
771
755
|
return updated;
|
|
772
756
|
}
|
|
773
757
|
function writeWorkerScope(scope) {
|
|
774
|
-
(0, state_1.writeJson)(workerScopePath(scope), scope);
|
|
758
|
+
(0, state_1.writeJson)((0, paths_1.workerScopePath)(scope), scope);
|
|
775
759
|
}
|
|
776
760
|
function writeWorkerIndex(run) {
|
|
777
761
|
ensureWorkerState(run);
|
|
@@ -784,7 +768,7 @@ function writeWorkerIndex(run) {
|
|
|
784
768
|
dispatchId: scope.dispatchId,
|
|
785
769
|
status: scope.status,
|
|
786
770
|
workerDir: scope.workerDir,
|
|
787
|
-
manifestPath: manifestPath(scope),
|
|
771
|
+
manifestPath: (0, paths_1.manifestPath)(scope),
|
|
788
772
|
resultPath: scope.resultPath,
|
|
789
773
|
sandboxProfileId: scope.sandboxProfileId,
|
|
790
774
|
backendId: scope.backendId,
|
|
@@ -800,7 +784,7 @@ function loadWorkerScopesFromDisk(run) {
|
|
|
800
784
|
return node_fs_1.default
|
|
801
785
|
.readdirSync(workerRoot(run), { withFileTypes: true })
|
|
802
786
|
.filter((entry) => entry.isDirectory())
|
|
803
|
-
.map((entry) => node_path_1.default.join(workerRoot(run), entry.name, WORKER_SCOPE_FILE))
|
|
787
|
+
.map((entry) => node_path_1.default.join(workerRoot(run), entry.name, paths_1.WORKER_SCOPE_FILE))
|
|
804
788
|
.filter((file) => node_fs_1.default.existsSync(file))
|
|
805
789
|
.map((file) => JSON.parse(node_fs_1.default.readFileSync(file, "utf8")));
|
|
806
790
|
}
|
|
@@ -823,6 +807,12 @@ function sandboxPolicyForBoundary(run, scope, options = {}) {
|
|
|
823
807
|
if (scope.sandboxPolicy && !options.policy && !options.sandboxProfileId)
|
|
824
808
|
return scope.sandboxPolicy;
|
|
825
809
|
const profileId = options.sandboxProfileId || options.policy?.sandboxProfileId || scope.sandboxProfileId || sandbox_profile_1.DEFAULT_SANDBOX_PROFILE_ID;
|
|
810
|
+
// H7: when the scope.sandboxPolicy snapshot is LOST, this re-resolves the policy
|
|
811
|
+
// by its logical profileId against the WORKER's paths (scope.workerDir etc.). For
|
|
812
|
+
// a CUSTOM profile the bundled lookup would throw not-found; threading
|
|
813
|
+
// run.customSandboxProfiles lets resolveSandboxProfileById re-resolve the persisted
|
|
814
|
+
// DEFINITION here — re-enforcing the same policy with worker-correct path tokens
|
|
815
|
+
// (NOT the dispatch-time paths), so a legitimate worker write is not falsely denied.
|
|
826
816
|
return (0, sandbox_profile_1.sandboxPolicyForWorker)(profileId, {
|
|
827
817
|
cwd: run.cwd,
|
|
828
818
|
runDir: run.paths.runDir,
|
|
@@ -838,7 +828,8 @@ function sandboxPolicyForBoundary(run, scope, options = {}) {
|
|
|
838
828
|
...(!scope.sandboxPolicy ? scope.allowedPaths || [] : [])
|
|
839
829
|
],
|
|
840
830
|
allowArtifacts: options.policy?.allowArtifacts,
|
|
841
|
-
allowLogs: options.policy?.allowLogs
|
|
831
|
+
allowLogs: options.policy?.allowLogs,
|
|
832
|
+
customProfiles: run.customSandboxProfiles
|
|
842
833
|
});
|
|
843
834
|
}
|
|
844
835
|
function blackboardManifest(run, scope) {
|
|
@@ -927,7 +918,7 @@ function blackboardLinkage(run, scope) {
|
|
|
927
918
|
const role = scope.multiAgent?.roleId ? run.multiAgent?.roles.find((entry) => entry.id === scope.multiAgent?.roleId) : undefined;
|
|
928
919
|
const multiAgentRun = scope.multiAgent?.runId ? run.multiAgent?.runs.find((entry) => entry.id === scope.multiAgent?.runId) : undefined;
|
|
929
920
|
const blackboardId = membership?.blackboardId || group?.blackboardId || role?.blackboardId || multiAgentRun?.blackboardId;
|
|
930
|
-
const topicIds = unique([
|
|
921
|
+
const topicIds = (0, helpers_1.unique)([
|
|
931
922
|
...(membership?.topicIds || []),
|
|
932
923
|
...(group?.topicIds || []),
|
|
933
924
|
...(role?.topicIds || []),
|
|
@@ -935,94 +926,27 @@ function blackboardLinkage(run, scope) {
|
|
|
935
926
|
]);
|
|
936
927
|
return { blackboardId, topicIds };
|
|
937
928
|
}
|
|
938
|
-
function manifestPath(scope) {
|
|
939
|
-
return node_path_1.default.join(scope.workerDir, WORKER_MANIFEST_FILE);
|
|
940
|
-
}
|
|
941
|
-
function workerScopePath(scope) {
|
|
942
|
-
return node_path_1.default.join(scope.workerDir, WORKER_SCOPE_FILE);
|
|
943
|
-
}
|
|
944
|
-
// Deterministic worker id (v0.1.40 self-audit P2): a wall-clock stamp + Math.random()
|
|
945
|
-
// made every dispatch mint a different id, so audit references were not reproducible
|
|
946
|
-
// across re-runs of the same inputs. The id is now derived from the task plus a
|
|
947
|
-
// per-task sequence (count of worker scopes already allocated for that task + 1),
|
|
948
|
-
// so re-running the same workflow yields byte-identical worker ids while retries of
|
|
949
|
-
// the SAME task still get a fresh, unique id. (workerId is excluded from the
|
|
950
|
-
// snapshot source fingerprint, so this does not change replay digests.)
|
|
951
|
-
function createWorkerId(run, taskId) {
|
|
952
|
-
const prefix = `worker-${(0, state_1.safeFileName)(taskId)}-`;
|
|
953
|
-
const seq = (run.workers || []).filter((scope) => scope.id.startsWith(prefix)).length + 1;
|
|
954
|
-
return `${prefix}${String(seq).padStart(4, "0")}`;
|
|
955
|
-
}
|
|
956
|
-
function workerArtifacts(scope) {
|
|
957
|
-
return [
|
|
958
|
-
{ id: "worker", kind: "json", path: workerScopePath(scope) },
|
|
959
|
-
{ id: "worker-manifest", kind: "json", path: manifestPath(scope) },
|
|
960
|
-
{ id: "worker-input", kind: "markdown", path: scope.inputPath }
|
|
961
|
-
];
|
|
962
|
-
}
|
|
963
929
|
function normalizeWorkerError(error, scope, options) {
|
|
964
|
-
if (isBoundaryViolation(error)) {
|
|
965
|
-
return structuredError(error.code, error.message, {
|
|
930
|
+
if ((0, helpers_1.isBoundaryViolation)(error)) {
|
|
931
|
+
return (0, helpers_1.structuredError)(error.code, error.message, {
|
|
966
932
|
path: error.path,
|
|
967
933
|
retryable: false,
|
|
968
934
|
details: { allowedPaths: error.allowedPaths, workerId: scope.id, taskId: scope.taskId, sandboxProfileId: scope.sandboxProfileId }
|
|
969
935
|
});
|
|
970
936
|
}
|
|
971
|
-
if (isStateNodeError(error)) {
|
|
937
|
+
if ((0, helpers_1.isStateNodeError)(error)) {
|
|
972
938
|
return {
|
|
973
939
|
...error,
|
|
974
940
|
at: error.at || new Date().toISOString(),
|
|
975
941
|
path: options.path || error.path,
|
|
976
942
|
retryable: options.retryable ?? error.retryable ?? false,
|
|
977
|
-
details: compactMetadata({ ...(error.details || {}), workerId: scope.id, taskId: scope.taskId })
|
|
943
|
+
details: (0, helpers_1.compactMetadata)({ ...(error.details || {}), workerId: scope.id, taskId: scope.taskId })
|
|
978
944
|
};
|
|
979
945
|
}
|
|
980
946
|
const message = error instanceof Error ? error.message : String(error);
|
|
981
|
-
return structuredError(options.code || "worker-runtime-error", message, {
|
|
947
|
+
return (0, helpers_1.structuredError)(options.code || "worker-runtime-error", message, {
|
|
982
948
|
path: options.path,
|
|
983
949
|
retryable: options.retryable ?? false,
|
|
984
950
|
details: { workerId: scope.id, taskId: scope.taskId }
|
|
985
951
|
});
|
|
986
952
|
}
|
|
987
|
-
function structuredError(code, message, options = {}) {
|
|
988
|
-
return {
|
|
989
|
-
code,
|
|
990
|
-
message,
|
|
991
|
-
at: new Date().toISOString(),
|
|
992
|
-
path: options.path,
|
|
993
|
-
retryable: options.retryable,
|
|
994
|
-
details: options.details
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
function isBoundaryViolation(value) {
|
|
998
|
-
return Boolean(value && typeof value === "object" && "allowedPaths" in value && "message" in value);
|
|
999
|
-
}
|
|
1000
|
-
function isStateNodeError(value) {
|
|
1001
|
-
return Boolean(value && typeof value === "object" && "code" in value && "message" in value);
|
|
1002
|
-
}
|
|
1003
|
-
function mergeScopes(left, right) {
|
|
1004
|
-
const merged = [...left];
|
|
1005
|
-
for (const scope of right) {
|
|
1006
|
-
const index = merged.findIndex((candidate) => candidate.id === scope.id);
|
|
1007
|
-
if (index >= 0)
|
|
1008
|
-
merged[index] = scope;
|
|
1009
|
-
else
|
|
1010
|
-
merged.push(scope);
|
|
1011
|
-
}
|
|
1012
|
-
return merged;
|
|
1013
|
-
}
|
|
1014
|
-
function unique(values) {
|
|
1015
|
-
return Array.from(new Set(values.filter(Boolean)));
|
|
1016
|
-
}
|
|
1017
|
-
function compactMetadata(value) {
|
|
1018
|
-
const entries = Object.entries(value).filter(([, entry]) => entry !== undefined);
|
|
1019
|
-
return entries.length ? Object.fromEntries(entries) : undefined;
|
|
1020
|
-
}
|
|
1021
|
-
function countBy(items, key) {
|
|
1022
|
-
const counts = {};
|
|
1023
|
-
for (const item of items) {
|
|
1024
|
-
const value = key(item);
|
|
1025
|
-
counts[value] = (counts[value] || 0) + 1;
|
|
1026
|
-
}
|
|
1027
|
-
return counts;
|
|
1028
|
-
}
|
|
@@ -131,14 +131,77 @@ node dist/cli.js backend probe agent --json # ready iff configured, else un
|
|
|
131
131
|
node dist/cli.js run architecture-review --drive --repo /path/to/repo --question "Is the design sound?"
|
|
132
132
|
node dist/cli.js run architecture-review --drive --once --repo /path/to/repo --question "..." # one step
|
|
133
133
|
node dist/cli.js run drive <run-id> --json # read-only preview of the next step
|
|
134
|
+
|
|
135
|
+
# quickstart --resume: a guided stop-then-resume a newcomer can WITNESS in <5 min
|
|
136
|
+
node dist/cli.js quickstart --resume --repo /path/to/repo --question "..." # advances ONE step, prints a continue line
|
|
137
|
+
node dist/cli.js quickstart --run <run-id> --resume # continues that run to completion
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`quickstart --resume` with no `--run` drives a single step and prints a
|
|
141
|
+
copy-pasteable `cw quickstart --run <id> --resume` continue line; rerun it with the
|
|
142
|
+
`--run <id>` to finish. The continuing invocation echoes `resumedFrom: <id>`. Bare
|
|
143
|
+
`quickstart` (no `--resume`) is unchanged — it drives straight to completion.
|
|
144
|
+
|
|
145
|
+
For faster first results, use the opt-in fast app instead of changing the full
|
|
146
|
+
review contract:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
node scripts/architecture-review-fast.js --repo /path/to/repo --question "Is the design sound?" --fast-model gpt-5.5-high --strong-model gpt-5.5-extra-high --metrics --schedule-full
|
|
134
150
|
```
|
|
135
151
|
|
|
152
|
+
`architecture-review-fast` has six workers: two Map and two Assess workers in
|
|
153
|
+
parallel, then sequential Verify and Verdict workers. The original
|
|
154
|
+
`architecture-review` app remains the full 14-worker review and is the right
|
|
155
|
+
target for background routines when a deep audit can finish outside the user's
|
|
156
|
+
foreground wait.
|
|
157
|
+
|
|
158
|
+
The model flags are policy, not attestation: they set task-level `{{model}}`
|
|
159
|
+
hints for the delegated agent process. The recorded model still comes only from
|
|
160
|
+
the agent-reported output.
|
|
161
|
+
|
|
162
|
+
The wrapper computes the source-context digest and supplies it to the fast app.
|
|
163
|
+
For external repositories, the documented no-profile command creates a repo-local
|
|
164
|
+
default `repo` profile over common tracked text surfaces. If the selected profile
|
|
165
|
+
exports zero records, the wrapper refuses rather than handing the app an empty
|
|
166
|
+
context digest.
|
|
167
|
+
The two Map workers opt in to result caching keyed by source-context digest plus
|
|
168
|
+
prompt digest. The two Assess workers also opt in, but their cache key includes
|
|
169
|
+
the completed previous-phase result digests so stale Map outputs do not satisfy
|
|
170
|
+
an Assess cache hit. A cache hit still passes through `recordWorkerOutput`
|
|
171
|
+
validation; a corrupt cached result parks/fails closed rather than spawning a
|
|
172
|
+
silent fallback.
|
|
173
|
+
|
|
174
|
+
`--metrics` is diagnostic and opt-in. It adds elapsed milliseconds, step counts,
|
|
175
|
+
agent-spawn counts, and `result-cache` hit counts to the wrapper JSON payload;
|
|
176
|
+
without it, the wrapper's default output shape stays unchanged.
|
|
177
|
+
|
|
136
178
|
`{{manifest}}`, `{{input}}`, `{{result}}`, `{{workerDir}}`, `{{model}}`, and
|
|
137
179
|
`{{prompt}}` are substituted into DISCRETE argv elements (never a shell-interpreted
|
|
138
180
|
string). Each verb is declared once in `capability-registry.ts`, so `cw <cmd>
|
|
139
181
|
--json` is byte-identical to the matching `cw_<tool>` MCP tool for the read-only
|
|
140
182
|
preview/config-show verbs.
|
|
141
183
|
|
|
184
|
+
## Live output — opt-in stderr passthrough (Unix-clean)
|
|
185
|
+
|
|
186
|
+
A drive can show the agent's activity live, without touching the evidence
|
|
187
|
+
contract, when the operator opts in with `CW_AGENT_STREAM=1`:
|
|
188
|
+
|
|
189
|
+
- **Default stays buffered.** Without `CW_AGENT_STREAM=1`, the bundled wrapper
|
|
190
|
+
preserves the legacy `--output-format json` path and forwards claude's JSON
|
|
191
|
+
stdout verbatim after writing `result.md`.
|
|
192
|
+
- **The opt-in wrapper renders; stderr only.** With `CW_AGENT_STREAM=1`, the
|
|
193
|
+
bundled wrapper runs claude in `--output-format stream-json` and renders a
|
|
194
|
+
concise human trace (tool uses, assistant text, per-turn summaries) to its
|
|
195
|
+
**stderr** — diagnostics, never data. It reconstructs the single
|
|
196
|
+
`{model, usage, result}` object for stdout only on that opt-in path.
|
|
197
|
+
- **Core forwards, never parses.** `runAgentProcess` passes the agent child's
|
|
198
|
+
stderr straight through to the operator's terminal (`stdio` inherit) only when
|
|
199
|
+
`CW_AGENT_STREAM=1`, CW's own stderr is a TTY, and `CW_NO_STREAM` is not set.
|
|
200
|
+
Piped / CI runs stay silent (the Rule of Silence). Vendor-specific rendering
|
|
201
|
+
lives in the wrapper (policy), not the kernel (mechanism).
|
|
202
|
+
- **Determinism intact.** The backend evidence triple hashes stdout only, so
|
|
203
|
+
the live stderr stream never affects recorded evidence or replay.
|
|
204
|
+
|
|
142
205
|
## Compatibility
|
|
143
206
|
|
|
144
207
|
Agent Delegation Drive is introduced in CW v0.1.38. Adding the `agent` row leaves
|
|
@@ -190,3 +253,11 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
190
253
|
0.1.78
|
|
191
254
|
|
|
192
255
|
0.1.79
|
|
256
|
+
|
|
257
|
+
## Fast Architecture Review (v0.1.80)
|
|
258
|
+
|
|
259
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
260
|
+
|
|
261
|
+
## Resumable Drive & Resume Routing (v0.1.81)
|
|
262
|
+
|
|
263
|
+
Adds `run resume <id> --drive/--once` alongside `quickstart --resume`: a stopped pipeline resumes in-place, advancing to completion (`--drive`) or one deterministic step (`--once`) over the same plan->dispatch->agent-fulfill->accept->commit lifecycle, echoing `resumedFrom: <id>`. Fixes the `run resume --drive` CLI routing so the drive flag reaches the resumed run instead of being read as an app name. Replay determinism and the agent evidence triple are unchanged.
|
|
@@ -28,6 +28,43 @@ node scripts/cw.js plan architecture-review \
|
|
|
28
28
|
--focus "runtime"
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
`architecture-review-fast`
|
|
32
|
+
|
|
33
|
+
Run a shorter architecture review for a fast first result. The app keeps the
|
|
34
|
+
full `architecture-review` contract available under its original id, but uses two
|
|
35
|
+
parallel Map workers, two parallel Assess workers, one verifier, and one verdict
|
|
36
|
+
worker. Operators can optionally provide a pinned JSONL source context and route
|
|
37
|
+
mapping/assessment work to a faster model while reserving stronger models for
|
|
38
|
+
verification and synthesis.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node scripts/architecture-review-fast.js \
|
|
42
|
+
--repo /path/to/repo \
|
|
43
|
+
--question "Is this architecture sound?" \
|
|
44
|
+
--fast-model gpt-5.5-high \
|
|
45
|
+
--strong-model gpt-5.5-extra-high \
|
|
46
|
+
--metrics \
|
|
47
|
+
--schedule-full
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The wrapper prepares one cached JSONL source context, passes its sha256 digest to
|
|
51
|
+
the fast app, runs `quickstart architecture-review-fast`, and optionally creates
|
|
52
|
+
a one-shot background schedule for the full `architecture-review` app. When run
|
|
53
|
+
against an external repo without `--profile` or `--profile-file`, it writes a
|
|
54
|
+
small repo-local `repo` profile covering common tracked text surfaces such as
|
|
55
|
+
README/package metadata, `src/`, `lib/`, `apps/`, `scripts/`, docs, and tests.
|
|
56
|
+
If the selected profile exports zero records, the wrapper fails closed instead of
|
|
57
|
+
passing an empty context digest to the app.
|
|
58
|
+
`--fast-model` and `--strong-model` are userland policy flags; internally they
|
|
59
|
+
set the same task-level hints as `CW_ARCHITECTURE_REVIEW_FAST_MODEL` and
|
|
60
|
+
`CW_ARCHITECTURE_REVIEW_STRONG_MODEL`.
|
|
61
|
+
`--metrics` is opt-in; when present the wrapper adds elapsed-time, worker-step,
|
|
62
|
+
agent-spawn, and result-cache-hit counts to the JSON payload so operators can
|
|
63
|
+
measure foreground wait reductions without changing the default output shape.
|
|
64
|
+
|
|
65
|
+
For long full reviews, use the existing routine or schedule surfaces to run
|
|
66
|
+
`architecture-review` in the background after the fast report has returned.
|
|
67
|
+
|
|
31
68
|
`pr-review-fix-ci`
|
|
32
69
|
|
|
33
70
|
Review a pull request or branch, inspect CI failures, diagnose actionable
|
package/docs/cli-mcp-parity.7.md
CHANGED
|
@@ -39,6 +39,14 @@ A new runtime capability is added once, in the registry, against one core entry.
|
|
|
39
39
|
The CLI command and the MCP tool are then two policies over that one mechanism —
|
|
40
40
|
which is exactly what the parity gate checks.
|
|
41
41
|
|
|
42
|
+
The MCP tool list is also being collapsed toward that single source. The first
|
|
43
|
+
read-only inspection group (`operator.status`, `graph`, `operator.report`,
|
|
44
|
+
worker/candidate/feedback/commit summaries, and the basic multi-agent inspection
|
|
45
|
+
views) derives its MCP tool name and description directly from the capability
|
|
46
|
+
registry; `mcp-server.ts` still owns the MCP input schema for those tools. This
|
|
47
|
+
keeps the public `tools/list` output unchanged while removing one duplicate
|
|
48
|
+
description table at a time.
|
|
49
|
+
|
|
42
50
|
## Human vs Machine Contract
|
|
43
51
|
|
|
44
52
|
The two surfaces have different contracts and must not interfere:
|
|
@@ -373,3 +381,11 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
373
381
|
0.1.78
|
|
374
382
|
|
|
375
383
|
0.1.79
|
|
384
|
+
|
|
385
|
+
## Fast Architecture Review (v0.1.80)
|
|
386
|
+
|
|
387
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
388
|
+
|
|
389
|
+
## Re-Prove Verbs on Both Surfaces (v0.1.81)
|
|
390
|
+
|
|
391
|
+
v0.1.81 grows the parity surface with two new both-surface, fail-closed verbs declared once in the capability registry: `cw audit verify` / `cw_audit_verify` re-proves the trust-audit chain and exits non-zero on any unverified or corrupt chain, and `cw run inspect-archive` / `cw_run_inspect_archive` is a read-only archive integrity check. Each `cw <cmd> --json` is schema-identical to its `cw_<tool>` and validated by the same parity gate.
|
|
@@ -123,3 +123,9 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
123
123
|
0.1.78
|
|
124
124
|
|
|
125
125
|
0.1.79
|
|
126
|
+
|
|
127
|
+
## Fast Architecture Review (v0.1.80)
|
|
128
|
+
|
|
129
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
130
|
+
|
|
131
|
+
_No changes to the contract-migration subsystem in v0.1.81._
|
|
@@ -110,3 +110,9 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
110
110
|
0.1.78
|
|
111
111
|
|
|
112
112
|
0.1.79
|
|
113
|
+
|
|
114
|
+
## Fast Architecture Review (v0.1.80)
|
|
115
|
+
|
|
116
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
117
|
+
|
|
118
|
+
_No changes to the control-plane scheduling surface in v0.1.81._
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Dogfood: real `builtin:claude` agent + `run resume --drive` (2026-06-14)
|
|
2
|
+
|
|
3
|
+
A live dogfood run with a REAL external agent (`CW_AGENT_COMMAND=builtin:claude`, the
|
|
4
|
+
bundled read-only claude wrapper). The model ran in the agent's own process; CW
|
|
5
|
+
spawned it and recorded the attested output — CW holds no API key and imports no
|
|
6
|
+
model SDK. This run had two purposes and delivered both: it confirmed the real-agent
|
|
7
|
+
delegation path works end to end, and — because it exercised the **CLI** rather than
|
|
8
|
+
the unit-test function path — it **caught a real shipped bug** in `run resume --drive`.
|
|
9
|
+
|
|
10
|
+
## What ran
|
|
11
|
+
|
|
12
|
+
- `cw run architecture-review --drive --once --repo <tmp> --question "…"` with a real
|
|
13
|
+
`builtin:claude` agent: **1 worker completed** end-to-end with zero hand-written
|
|
14
|
+
result.md — the worker's `result.md` was produced by real claude, passed the
|
|
15
|
+
evidence-gated acceptance, and a `report.md` (7.5 KB, "# Architecture Review …")
|
|
16
|
+
+ 3 state commits were written. The real-agent path (spawn → attested output →
|
|
17
|
+
evidence gate → commit) works.
|
|
18
|
+
- Run: `architecture-review-20260614T104416Z-upkor2`, status `in-progress` (1/14)
|
|
19
|
+
after the single `--once` step.
|
|
20
|
+
|
|
21
|
+
## The bug it caught (and the fix)
|
|
22
|
+
|
|
23
|
+
Resuming the partway run with `cw run resume <id> --drive` failed:
|
|
24
|
+
`cw: Workflow app not found: resume`. The `run` command's early `--drive` branch
|
|
25
|
+
(the `cw run <app> --drive` one-command form) intercepted the invocation *before* the
|
|
26
|
+
subcommand switch, so the `resume` keyword was misread as an app name and never
|
|
27
|
+
reached the `runResume` continuation shipped in #155.
|
|
28
|
+
|
|
29
|
+
The A1 unit smoke (`run-resume-drive-smoke`) had tested `runResume()` **directly**, so
|
|
30
|
+
it never exercised the CLI dispatch — only a real CLI run surfaced it. Fixed by
|
|
31
|
+
guarding the early app-drive route so a leading run-registry subcommand keyword
|
|
32
|
+
(resume/show/export/…) falls through to the switch; `run-resume-drive-smoke` now drives
|
|
33
|
+
`cw run resume <id> --drive` through the actual CLI and asserts it routes to the verb,
|
|
34
|
+
plus a regression guard that `run <app> --drive` still routes to the app drive.
|
|
35
|
+
|
|
36
|
+
## Takeaway
|
|
37
|
+
|
|
38
|
+
Unit tests that call the capability function directly can miss CLI-dispatch bugs.
|
|
39
|
+
Every both-surface verb that adds a flag wants at least one test through the real CLI
|
|
40
|
+
argv path, not just the exported function.
|
|
@@ -107,3 +107,11 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
107
107
|
0.1.78
|
|
108
108
|
|
|
109
109
|
0.1.79
|
|
110
|
+
|
|
111
|
+
## Fast Architecture Review (v0.1.80)
|
|
112
|
+
|
|
113
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
114
|
+
|
|
115
|
+
## Deterministic Tombstone Hash (v0.1.81)
|
|
116
|
+
|
|
117
|
+
The reclamation tombstone's freed-manifest is now path-sorted before it feeds `tombstoneHash`, so the same freed set always yields the same hash regardless of filesystem enumeration order. This removes a non-determinism from the write-ahead chain (v0.1.39/v0.1.40), keeping the per-run tombstone hash-chain replayable and stable across hosts. Atomicity, locking, and the durable re-point seam are unchanged. v0.1.81 also adds import-time refusal (`CW_REQUIRE_ARCHIVE_INTEGRITY=1`) and restore-time trust-audit re-proving — see run-registry-control-plane(7).
|
|
@@ -270,3 +270,9 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
270
270
|
0.1.78
|
|
271
271
|
|
|
272
272
|
0.1.79
|
|
273
|
+
|
|
274
|
+
## Fast Architecture Review (v0.1.80)
|
|
275
|
+
|
|
276
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
277
|
+
|
|
278
|
+
_No changes to the Evidence Adoption Reasoning Chain surface in v0.1.81. The v0.1.81 trust-audit `computeEventHash` fix hardens the underlying audit records this chain links to by reference, but the derived reasoning view, its commands, and its eval gates are unchanged._
|
|
@@ -300,3 +300,9 @@ Migration DAG with reversible edges (v0.1.45), capability auto-discovery (v0.1.4
|
|
|
300
300
|
0.1.78
|
|
301
301
|
|
|
302
302
|
0.1.79
|
|
303
|
+
|
|
304
|
+
## Fast Architecture Review (v0.1.80)
|
|
305
|
+
|
|
306
|
+
Adds the opt-in fast architecture-review lane: scoped JSONL source contexts, diff-aware exports, reusable Map and Assess results, measurable wrapper metrics, actionable background full-review handoff, and userland model policy flags for routing fast/strong workers without changing the full review contract.
|
|
307
|
+
|
|
308
|
+
_No changes to the execution-backends surface in v0.1.81._
|
package/docs/index.md
CHANGED
|
@@ -7,6 +7,7 @@ Read these in order when you are new to CW:
|
|
|
7
7
|
3. [Workflow App framework](workflow-app-framework.7.md) - userland app manifests, entrypoints, compatibility, and validation.
|
|
8
8
|
4. [Sandbox Profiles](sandbox-profiles.7.md) - named worker policy contracts for read/write/execute/network/env handling.
|
|
9
9
|
5. [Security / Trust Hardening](security-trust-hardening.7.md) - audit records, provenance, sandbox attestations, and acceptance rationale.
|
|
10
|
+
- [Trust Model & Limitations](trust-model.md) - what the ed25519 + hash-chain tamper-evidence proves and, honestly, what it does **not** (the single-keyholder ceiling). Read this before relying on a green verdict.
|
|
10
11
|
6. [Multi-Agent Runtime Core](multi-agent-runtime-core.7.md) - first-class MultiAgentRun, roles, groups, memberships, fanout, fanin, and lifecycle state.
|
|
11
12
|
7. [Coordinator / Blackboard](coordinator-blackboard.7.md) - shared topics, messages, context frames, artifact refs, snapshots, decisions, conflicts, and fanin evidence.
|
|
12
13
|
8. [Multi-Agent Topologies](multi-agent-topologies.7.md) - official map-reduce, debate, and judge-panel recipes built on multi-agent and blackboard records.
|
|
@@ -35,6 +36,7 @@ Read these in order when you are new to CW:
|
|
|
35
36
|
31. [Agent Delegation Drive](agent-delegation-drive.7.md) - the `agent` backend delegates each worker to an EXTERNAL agent process (claude/codex/HTTP endpoint) and `run --drive` auto-advances plan→dispatch→fulfill→accept→commit; the model runs in the agent's process, never in CW. Two-layer evidence, operator-vs-attested model, fail-closed park, replay without re-spawn.
|
|
36
37
|
32. [Run Retention & Provable Reclamation](run-retention-reclamation.7.md) - tiered, append-only, cryptographically-verifiable disk reclamation over the v0.1.28 archive overlay: seal the audit skeleton, free the reconstructable/scratch bulk, and prove it via a hash-chained tombstone; `gc plan|run|verify`, write-ahead + fail-closed, explicit capability downgrade.
|
|
37
38
|
33. [Durable State & Locking](durable-state-and-locking.7.md) - atomic (temp→rename) writes for every authoritative store with fsync-durability for the audit-essential ones, plus a portable stale-stealing file lock serializing the cross-process read-modify-write stores (home queue, archive overlay, reclamation chain); closes the prior verdict's non-atomic/unlocked P1.
|
|
39
|
+
34. [Source Context Profiles](source-context-profiles.7.md) - opt-in JSONL source exports for AI context slimming, with profile policy in manifest data and manifest records proving every included or omitted tracked file.
|
|
38
40
|
|
|
39
41
|
CW is the base system. Workflow apps are userland. Release and migration rules
|
|
40
42
|
must preserve that line: stable contracts, explicit compatibility checks, and
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# VHS tape — records the `cw demo tamper` proof to a GIF for the README hero.
|
|
2
|
+
#
|
|
3
|
+
# Reproducible, deterministic capture (no manual screen-recording). Install VHS
|
|
4
|
+
# (https://github.com/charmbracelet/vhs), then from the repo root:
|
|
5
|
+
#
|
|
6
|
+
# vhs plugins/cool-workflow/docs/launch/demo.tape
|
|
7
|
+
#
|
|
8
|
+
# Output: docs/launch/demo-tamper.gif. Then in the root README, replace the
|
|
9
|
+
# fenced demo output block under "See it in 30 seconds" with:
|
|
10
|
+
# 
|
|
11
|
+
|
|
12
|
+
Output plugins/cool-workflow/docs/launch/demo-tamper.gif
|
|
13
|
+
|
|
14
|
+
Set FontSize 15
|
|
15
|
+
Set Width 1180
|
|
16
|
+
Set Height 760
|
|
17
|
+
Set Padding 18
|
|
18
|
+
Set Theme "Dracula"
|
|
19
|
+
Set Framerate 24
|
|
20
|
+
Set PlaybackSpeed 1.0
|
|
21
|
+
|
|
22
|
+
# Use the published package so the GIF reflects exactly what a new user runs.
|
|
23
|
+
Type "npx cool-workflow demo tamper"
|
|
24
|
+
Sleep 600ms
|
|
25
|
+
Enter
|
|
26
|
+
|
|
27
|
+
# Allow npx fetch + the demo to run and print the verdict.
|
|
28
|
+
Sleep 14s
|