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.
Files changed (131) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +51 -3
  4. package/apps/architecture-review/app.json +1 -1
  5. package/apps/architecture-review-fast/app.json +64 -0
  6. package/apps/architecture-review-fast/workflow.js +153 -0
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/agent-config.js +21 -7
  12. package/dist/candidate-scoring.js +42 -22
  13. package/dist/capability-core.js +132 -17
  14. package/dist/capability-registry.js +138 -168
  15. package/dist/cli.js +97 -98
  16. package/dist/collaboration.js +5 -6
  17. package/dist/commit.js +20 -6
  18. package/dist/compare.js +18 -0
  19. package/dist/coordinator/classify.js +45 -0
  20. package/dist/coordinator/paths.js +42 -0
  21. package/dist/coordinator/util.js +129 -0
  22. package/dist/coordinator.js +127 -300
  23. package/dist/dispatch.js +35 -0
  24. package/dist/drive.js +79 -6
  25. package/dist/error-feedback.js +8 -4
  26. package/dist/evidence-reasoning.js +3 -3
  27. package/dist/execution-backend/agent.js +331 -0
  28. package/dist/execution-backend/probes.js +96 -0
  29. package/dist/execution-backend/util.js +47 -0
  30. package/dist/execution-backend.js +73 -421
  31. package/dist/mcp-server.js +79 -183
  32. package/dist/multi-agent/graph.js +84 -0
  33. package/dist/multi-agent/helpers.js +145 -0
  34. package/dist/multi-agent/paths.js +22 -0
  35. package/dist/multi-agent-eval/format.js +194 -0
  36. package/dist/multi-agent-eval/normalize.js +51 -0
  37. package/dist/multi-agent-eval.js +39 -244
  38. package/dist/multi-agent-host.js +0 -19
  39. package/dist/multi-agent.js +125 -314
  40. package/dist/node-snapshot.js +3 -3
  41. package/dist/observability/format.js +61 -0
  42. package/dist/observability/intake.js +98 -0
  43. package/dist/observability.js +14 -160
  44. package/dist/operator-ux/format.js +364 -0
  45. package/dist/operator-ux.js +22 -363
  46. package/dist/orchestrator/lifecycle-operations.js +2 -1
  47. package/dist/orchestrator/report.js +8 -0
  48. package/dist/orchestrator.js +26 -9
  49. package/dist/reclamation.js +26 -21
  50. package/dist/run-export.js +494 -25
  51. package/dist/run-registry/derive.js +172 -0
  52. package/dist/run-registry/format.js +124 -0
  53. package/dist/run-registry/gc.js +251 -0
  54. package/dist/run-registry/policy.js +16 -0
  55. package/dist/run-registry/queue.js +116 -0
  56. package/dist/run-registry.js +89 -597
  57. package/dist/run-state-schema.js +1 -0
  58. package/dist/sandbox-profile.js +43 -2
  59. package/dist/state-explosion/format.js +159 -0
  60. package/dist/state-explosion/helpers.js +82 -0
  61. package/dist/state-explosion.js +165 -304
  62. package/dist/state-node.js +19 -4
  63. package/dist/telemetry-attestation.js +55 -0
  64. package/dist/telemetry-demo.js +15 -3
  65. package/dist/telemetry-ledger.js +60 -15
  66. package/dist/topology.js +25 -8
  67. package/dist/triggers.js +33 -14
  68. package/dist/trust-audit.js +145 -33
  69. package/dist/version.js +1 -1
  70. package/dist/worker-isolation/helpers.js +51 -0
  71. package/dist/worker-isolation/paths.js +46 -0
  72. package/dist/worker-isolation.js +39 -115
  73. package/docs/agent-delegation-drive.7.md +71 -0
  74. package/docs/canonical-workflow-apps.7.md +37 -0
  75. package/docs/cli-mcp-parity.7.md +16 -0
  76. package/docs/contract-migration-tooling.7.md +6 -0
  77. package/docs/control-plane-scheduling.7.md +6 -0
  78. package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +40 -0
  79. package/docs/durable-state-and-locking.7.md +8 -0
  80. package/docs/evidence-adoption-reasoning-chain.7.md +6 -0
  81. package/docs/execution-backends.7.md +6 -0
  82. package/docs/index.md +2 -0
  83. package/docs/launch/demo.tape +28 -0
  84. package/docs/launch/launch-kit.md +96 -17
  85. package/docs/launch/pre-launch-checklist.md +53 -0
  86. package/docs/multi-agent-cli-mcp-surface.7.md +8 -0
  87. package/docs/multi-agent-eval-replay-harness.7.md +6 -0
  88. package/docs/multi-agent-operator-ux.7.md +6 -0
  89. package/docs/multi-agent-trust-policy-audit.7.md +27 -0
  90. package/docs/node-snapshot-diff-replay.7.md +6 -0
  91. package/docs/observability-cost-accounting.7.md +6 -0
  92. package/docs/project-index.md +27 -6
  93. package/docs/real-execution-backends.7.md +6 -0
  94. package/docs/release-and-migration.7.md +8 -0
  95. package/docs/release-tooling.7.md +6 -0
  96. package/docs/routines.md +23 -0
  97. package/docs/run-registry-control-plane.7.md +89 -2
  98. package/docs/run-retention-reclamation.7.md +8 -0
  99. package/docs/source-context-profiles.7.md +119 -0
  100. package/docs/state-explosion-management.7.md +13 -0
  101. package/docs/team-collaboration.7.md +6 -0
  102. package/docs/trust-model.md +267 -0
  103. package/docs/unix-principles.md +49 -1
  104. package/docs/vendor-manifest-loadability.7.md +43 -0
  105. package/docs/web-desktop-workbench.7.md +6 -0
  106. package/manifest/plugin.manifest.json +1 -1
  107. package/manifest/source-context-profiles.json +142 -0
  108. package/package.json +4 -1
  109. package/scripts/agents/builtin-templates.json +7 -0
  110. package/scripts/agents/claude-p-agent.js +129 -43
  111. package/scripts/architecture-review-fast.js +362 -0
  112. package/scripts/bump-version.js +5 -10
  113. package/scripts/canonical-apps-list.js +64 -0
  114. package/scripts/canonical-apps.js +36 -4
  115. package/scripts/coverage-gate.js +211 -0
  116. package/scripts/dogfood-release.js +1 -1
  117. package/scripts/golden-path.js +4 -4
  118. package/scripts/parity-check.js +5 -0
  119. package/scripts/release-check.js +5 -1
  120. package/scripts/source-context.js +291 -0
  121. package/scripts/version-sync-check.js +5 -7
  122. package/skills/ci-triage/SKILL.md +50 -0
  123. package/skills/ci-triage/agents/openai.yaml +4 -0
  124. package/skills/cool-workflow/SKILL.md +4 -1
  125. package/skills/deploy-check/SKILL.md +55 -0
  126. package/skills/deploy-check/agents/openai.yaml +4 -0
  127. package/skills/design-qa/SKILL.md +49 -0
  128. package/skills/design-qa/agents/openai.yaml +4 -0
  129. package/skills/pr-review/SKILL.md +45 -0
  130. package/skills/pr-review/agents/openai.yaml +4 -0
  131. package/dist/capability-dispatcher.js +0 -86
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.BackendError = exports.SANDBOX_DIMENSIONS = exports.DEFAULT_BACKEND_ID = exports.EXECUTION_BACKEND_SCHEMA_VERSION = void 0;
29
+ exports.BackendError = exports.SANDBOX_DIMENSIONS = exports.DEFAULT_BACKEND_ID = exports.EXECUTION_BACKEND_SCHEMA_VERSION = exports.runAgentBatchOutcomes = exports.prepareAgentSpawn = exports.stripSecretArgs = exports.sha256 = void 0;
30
30
  exports.registerBackend = registerBackend;
31
31
  exports.getBackendDriver = getBackendDriver;
32
32
  exports.listBackendDescriptors = listBackendDescriptors;
@@ -39,21 +39,32 @@ exports.requiredSandboxDimensions = requiredSandboxDimensions;
39
39
  exports.attestSandbox = attestSandbox;
40
40
  exports.probeBackend = probeBackend;
41
41
  exports.runBackend = runBackend;
42
- exports.stripSecretArgs = stripSecretArgs;
43
- exports.prepareAgentSpawn = prepareAgentSpawn;
44
- exports.runAgentBatchOutcomes = runAgentBatchOutcomes;
45
42
  exports.createExecutionBackend = createExecutionBackend;
46
43
  exports.listExecutionBackends = listExecutionBackends;
47
44
  exports.backendListPayload = backendListPayload;
48
45
  exports.backendShowPayload = backendShowPayload;
49
46
  exports.backendProbePayload = backendProbePayload;
50
47
  exports.buildChildEnv = buildChildEnv;
51
- exports.sha256 = sha256;
52
48
  exports.clearProbeCache = clearProbeCache;
53
- const node_crypto_1 = __importDefault(require("node:crypto"));
54
49
  const node_fs_1 = __importDefault(require("node:fs"));
55
- const node_path_1 = __importDefault(require("node:path"));
56
50
  const node_child_process_1 = require("node:child_process");
51
+ // Pure leaf helpers — carved into ./execution-backend/util.ts (god-module carve).
52
+ // `sha256` is re-exported below to keep the public surface byte-identical.
53
+ const util_1 = require("./execution-backend/util");
54
+ // Per-backend readiness probe bodies — carved into ./execution-backend/probes.ts.
55
+ const probes_1 = require("./execution-backend/probes");
56
+ // Agent-delegation pure helpers + concurrent batch — carved into
57
+ // ./execution-backend/agent.ts. The public symbols (stripSecretArgs,
58
+ // AgentSpawnJob, prepareAgentSpawn, runAgentBatchOutcomes) are re-exported below.
59
+ const agent_1 = require("./execution-backend/agent");
60
+ // Re-export the carved public surface so every importer of "./execution-backend"
61
+ // is byte-unchanged (no public signature changed; pure code movement).
62
+ var util_2 = require("./execution-backend/util");
63
+ Object.defineProperty(exports, "sha256", { enumerable: true, get: function () { return util_2.sha256; } });
64
+ var agent_2 = require("./execution-backend/agent");
65
+ Object.defineProperty(exports, "stripSecretArgs", { enumerable: true, get: function () { return agent_2.stripSecretArgs; } });
66
+ Object.defineProperty(exports, "prepareAgentSpawn", { enumerable: true, get: function () { return agent_2.prepareAgentSpawn; } });
67
+ Object.defineProperty(exports, "runAgentBatchOutcomes", { enumerable: true, get: function () { return agent_2.runAgentBatchOutcomes; } });
57
68
  exports.EXECUTION_BACKEND_SCHEMA_VERSION = 1;
58
69
  exports.DEFAULT_BACKEND_ID = "node";
59
70
  exports.SANDBOX_DIMENSIONS = ["read", "write", "command", "network", "env"];
@@ -204,21 +215,21 @@ function getBackendDescriptor(id) {
204
215
  // — no central switch to edit. Function declarations below are hoisted, so the
205
216
  // closures resolve at call time.
206
217
  const BUILTIN_DRIVER_BEHAVIORS = {
207
- node: { spawnStyle: "direct", runtimeNote: () => "node", probe: probeNodeBackend },
218
+ node: { spawnStyle: "direct", runtimeNote: () => "node", probe: probes_1.probeNodeBackend },
208
219
  bun: {
209
220
  spawnStyle: "direct",
210
- runtimeNote: () => (hasExecutable("bun") ? "bun (node-compatible execution)" : "node-compatible (bun not installed)"),
211
- probe: probeBunBackend
221
+ runtimeNote: () => ((0, util_1.hasExecutable)("bun") ? "bun (node-compatible execution)" : "node-compatible (bun not installed)"),
222
+ probe: probes_1.probeBunBackend
212
223
  },
213
- shell: { spawnStyle: "shell", runtimeNote: () => "posix-shell", probe: probeShellBackend },
214
- container: { delegateRun: ctxDelegate(runContainer), buildHandle: containerHandle, probe: probeContainerBackend },
215
- remote: { delegateRun: ctxDelegate(runHttpDelegation), buildHandle: remoteHandle, probe: probeRemoteBackend },
216
- ci: { delegateRun: ctxDelegate(runHttpDelegation), buildHandle: ciHandle, probe: probeCiBackend },
224
+ shell: { spawnStyle: "shell", runtimeNote: () => "posix-shell", probe: probes_1.probeShellBackend },
225
+ container: { delegateRun: ctxDelegate(runContainer), buildHandle: containerHandle, probe: probes_1.probeContainerBackend },
226
+ remote: { delegateRun: ctxDelegate(runHttpDelegation), buildHandle: remoteHandle, probe: probes_1.probeRemoteBackend },
227
+ ci: { delegateRun: ctxDelegate(runHttpDelegation), buildHandle: ciHandle, probe: probes_1.probeCiBackend },
217
228
  agent: {
218
229
  delegateRun: ctxDelegate(runAgentProcess),
219
- buildHandle: agentHandle,
230
+ buildHandle: agent_1.agentHandle,
220
231
  commandlessDelegate: true,
221
- probe: probeAgentBackend
232
+ probe: probes_1.probeAgentBackend
222
233
  }
223
234
  };
224
235
  for (const spec of DRIVER_SPECS) {
@@ -254,7 +265,7 @@ function resolveBackendSelection(requested, env = process.env) {
254
265
  return { backendId: exports.DEFAULT_BACKEND_ID, source: "default" };
255
266
  }
256
267
  function backendSelectionFrom(args, env = process.env) {
257
- const requested = firstString(args.backend, args.backendId, args.executionBackend);
268
+ const requested = (0, util_1.firstString)(args.backend, args.backendId, args.executionBackend);
258
269
  return resolveBackendSelection(requested, env);
259
270
  }
260
271
  // ---------------------------------------------------------------------------
@@ -340,77 +351,6 @@ function probeBackend(id, context = {}) {
340
351
  reason: body.reason
341
352
  };
342
353
  }
343
- function probeNodeBackend() {
344
- const ok = hasExecutable("node");
345
- return {
346
- checks: [{ name: "node-runtime", ok, detail: ok ? "node on PATH" : "node not found on PATH" }],
347
- readiness: ok ? "ready" : "unavailable",
348
- reason: ok ? undefined : "node runtime not found on PATH"
349
- };
350
- }
351
- function probeShellBackend() {
352
- const ok = hasExecutable("sh") || node_fs_1.default.existsSync("/bin/sh");
353
- return {
354
- checks: [{ name: "posix-shell", ok, detail: ok ? "sh available" : "no POSIX shell found" }],
355
- readiness: ok ? "ready" : "unavailable",
356
- reason: ok ? undefined : "POSIX shell not found"
357
- };
358
- }
359
- function probeBunBackend() {
360
- const bun = hasExecutable("bun");
361
- const node = hasExecutable("node");
362
- return {
363
- checks: [
364
- { name: "bun-runtime", ok: bun, detail: bun ? "bun on PATH" : "bun not found; node-compatible fallback" },
365
- { name: "node-compatible-fallback", ok: node, detail: node ? "node on PATH" : "node not found on PATH" }
366
- ],
367
- readiness: bun || node ? "ready" : "unavailable",
368
- reason: !bun && node ? "bun not installed; executing via node-compatible runtime" : !bun && !node ? "neither bun nor node found on PATH" : undefined
369
- };
370
- }
371
- function probeContainerBackend() {
372
- const docker = hasExecutable("docker");
373
- const podman = hasExecutable("podman");
374
- return {
375
- checks: [
376
- { name: "docker", ok: docker, detail: docker ? "docker on PATH" : "docker not found" },
377
- { name: "podman", ok: podman, detail: podman ? "podman on PATH" : "podman not found" }
378
- ],
379
- readiness: docker || podman ? "ready" : "unavailable",
380
- reason: docker || podman ? undefined : "no container runtime (docker/podman) found; supply --image to delegate explicitly"
381
- };
382
- }
383
- function probeRemoteBackend() {
384
- const endpoint = (process.env.CW_REMOTE_ENDPOINT || "").trim();
385
- return {
386
- checks: [{ name: "endpoint", ok: Boolean(endpoint), detail: endpoint ? "CW_REMOTE_ENDPOINT configured" : "CW_REMOTE_ENDPOINT not set" }],
387
- readiness: endpoint ? "ready" : "unverified",
388
- reason: endpoint ? undefined : "no remote endpoint configured (set CW_REMOTE_ENDPOINT or pass --endpoint)"
389
- };
390
- }
391
- function probeCiBackend() {
392
- const endpoint = (process.env.CW_CI_ENDPOINT || "").trim();
393
- return {
394
- checks: [{ name: "ci-endpoint", ok: Boolean(endpoint), detail: endpoint ? "CW_CI_ENDPOINT configured" : "CW_CI_ENDPOINT not set" }],
395
- readiness: endpoint ? "ready" : "unverified",
396
- reason: endpoint ? undefined : "no CI job target configured (set CW_CI_ENDPOINT or pass --job)"
397
- };
398
- }
399
- function probeAgentBackend() {
400
- // Mirrors remote/ci EXACTLY: unconfigured ⇒ `unverified` (NOT a hard refusal),
401
- // configured ⇒ `ready`. "Configured" = a command-template or endpoint is set.
402
- const command = (process.env.CW_AGENT_COMMAND || "").trim();
403
- const endpoint = (process.env.CW_AGENT_ENDPOINT || "").trim();
404
- const configured = Boolean(command || endpoint);
405
- return {
406
- checks: [
407
- { name: "agent-command", ok: Boolean(command), detail: command ? "CW_AGENT_COMMAND configured" : "CW_AGENT_COMMAND not set" },
408
- { name: "agent-endpoint", ok: Boolean(endpoint), detail: endpoint ? "CW_AGENT_ENDPOINT configured" : "CW_AGENT_ENDPOINT not set" }
409
- ],
410
- readiness: configured ? "ready" : "unverified",
411
- reason: configured ? undefined : "no agent configured (set CW_AGENT_COMMAND or CW_AGENT_ENDPOINT, or pass --agent-command/--agent-endpoint)"
412
- };
413
- }
414
354
  // ---------------------------------------------------------------------------
415
355
  // The run entry. Refuses (fail closed) when the sandbox cannot be honored, the
416
356
  // command is denied by policy, or the backend is not ready. Local drivers spawn a
@@ -474,9 +414,9 @@ function executeLocal(descriptor, policy, request, label, attestation) {
474
414
  ? (0, node_child_process_1.spawnSync)([command, ...args].join(" "), { ...options, shell: true })
475
415
  : (0, node_child_process_1.spawnSync)(command, args, { ...options, shell: false });
476
416
  const exitCode = typeof result.status === "number" ? result.status : null;
477
- const spawnError = result.error ? messageOf(result.error) : undefined;
417
+ const spawnError = result.error ? (0, util_1.messageOf)(result.error) : undefined;
478
418
  const stdout = String(result.stdout || "");
479
- const digest = sha256(stdout);
419
+ const digest = (0, util_1.sha256)(stdout);
480
420
  const status = spawnError ? "failed" : exitCode === 0 ? "completed" : "failed";
481
421
  const evidence = [
482
422
  `command:${[command, ...args].join(" ")}`,
@@ -502,7 +442,7 @@ function executeLocal(descriptor, policy, request, label, attestation) {
502
442
  backendId: descriptor.id,
503
443
  locality: descriptor.locality,
504
444
  kind: descriptor.kind,
505
- attestation: { ...attestation, status: status === "completed" ? attestation.status : attestation.status, notes }
445
+ attestation: { ...attestation, status: attestation.status, notes }
506
446
  }
507
447
  };
508
448
  }
@@ -544,7 +484,7 @@ function delegate(descriptor, policy, request, label, probe) {
544
484
  * identical to executeLocal's, so evidence is byte-stable across backends. The
545
485
  * handle is recorded in provenance only. */
546
486
  function delegatedEnvelope(descriptor, label, handle, attestation, command, args, exitCode, stdout) {
547
- const digest = sha256(stdout);
487
+ const digest = (0, util_1.sha256)(stdout);
548
488
  const status = exitCode === 0 ? "completed" : "failed";
549
489
  const evidence = [
550
490
  `command:${[command, ...args].join(" ")}`,
@@ -573,7 +513,7 @@ function delegatedEnvelope(descriptor, label, handle, attestation, command, args
573
513
  * closed when no runtime is on PATH, the daemon is unreachable, or the runtime
574
514
  * itself errors (exit 125) — distinct from the command's own non-zero exit. */
575
515
  function runContainer(descriptor, policy, request, label, handle, attestation) {
576
- const runtime = hasExecutable("docker") ? "docker" : hasExecutable("podman") ? "podman" : undefined;
516
+ const runtime = (0, util_1.hasExecutable)("docker") ? "docker" : (0, util_1.hasExecutable)("podman") ? "podman" : undefined;
577
517
  if (!runtime) {
578
518
  return refusedEnvelope(descriptor, policy, label, "runtime-unavailable", "no container runtime (docker/podman) on PATH", {
579
519
  attestation
@@ -622,7 +562,7 @@ function runContainer(descriptor, policy, request, label, handle, attestation) {
622
562
  maxBuffer: 32 * 1024 * 1024
623
563
  });
624
564
  if (result.error) {
625
- return refusedEnvelope(descriptor, policy, label, "delegation-failed", `${runtime} run failed: ${messageOf(result.error)}`, {
565
+ return refusedEnvelope(descriptor, policy, label, "delegation-failed", `${runtime} run failed: ${(0, util_1.messageOf)(result.error)}`, {
626
566
  attestation
627
567
  });
628
568
  }
@@ -696,7 +636,7 @@ function runHttpDelegation(descriptor, policy, request, label, handle, attestati
696
636
  maxBuffer: 32 * 1024 * 1024
697
637
  });
698
638
  if (child.error) {
699
- return refusedEnvelope(descriptor, policy, label, "delegation-failed", `${descriptor.id} delegation failed: ${messageOf(child.error)}`, {
639
+ return refusedEnvelope(descriptor, policy, label, "delegation-failed", `${descriptor.id} delegation failed: ${(0, util_1.messageOf)(child.error)}`, {
700
640
  attestation
701
641
  });
702
642
  }
@@ -714,168 +654,31 @@ function runHttpDelegation(descriptor, policy, request, label, handle, attestati
714
654
  }
715
655
  return delegatedEnvelope(descriptor, label, handle, attestation, command, args, parsed.exitCode, String(parsed.stdout || ""));
716
656
  }
717
- /** Resolve the agent invocation from the request delegation > env. Vendor-neutral;
718
- * the durable file config is folded in by the drive layer before this point. */
719
- function resolveAgentInvocation(request) {
720
- const delegation = request.delegation || {};
721
- const envCommand = (process.env.CW_AGENT_COMMAND || "").trim();
722
- const endpoint = delegation.endpoint || (process.env.CW_AGENT_ENDPOINT || "").trim() || undefined;
723
- const model = delegation.model || (process.env.CW_AGENT_MODEL || "").trim() || undefined;
724
- // Accept the invocation via delegation (preferred) OR the top-level command/args.
725
- let binary = delegation.command || request.command || undefined;
726
- let rawArgs = delegation.args ? [...delegation.args] : request.args ? [...request.args] : [];
727
- // An env-string command ("claude -p --output-format json {{manifest}}") is split
728
- // into a binary + discrete argv template NEVER shell-interpreted.
729
- if (!binary && envCommand) {
730
- const parts = envCommand.split(/\s+/).filter(Boolean);
731
- binary = parts[0];
732
- if (!delegation.args)
733
- rawArgs = parts.slice(1);
734
- }
735
- else if (binary && !delegation.args && /\s/.test(binary)) {
736
- const parts = binary.split(/\s+/).filter(Boolean);
737
- binary = parts[0];
738
- rawArgs = parts.slice(1);
739
- }
740
- return { binary, rawArgs, endpoint, model, timeoutMs: request.timeoutMs };
741
- }
742
- const AGENT_SECRET_FLAGS = new Set(["--api-key", "--apikey", "--token", "--key", "--secret", "--password", "--auth", "--bearer"]);
743
- /** Redact secrets from recorded agent args: a value FOLLOWING a known secret flag,
744
- * an `--x-key=...` inline value, or a token that LOOKS like a credential. Never
745
- * record a raw secret in provenance/evidence. Exported so the durable config
746
- * surface strips the SAME way before persisting/showing a command template. */
747
- function stripSecretArgs(args) {
748
- const out = [];
749
- for (let i = 0; i < args.length; i++) {
750
- const arg = String(args[i]);
751
- if (AGENT_SECRET_FLAGS.has(arg.toLowerCase())) {
752
- out.push(arg);
753
- if (i + 1 < args.length) {
754
- out.push("<redacted>");
755
- i++;
756
- }
757
- continue;
758
- }
759
- const inline = arg.match(/^(--?[A-Za-z][\w-]*(?:key|token|secret|password|auth|bearer)[\w-]*)=.*/i);
760
- if (inline) {
761
- out.push(`${inline[1]}=<redacted>`);
762
- continue;
763
- }
764
- // Bare credential-looking token: a known provider prefix, or a long high-entropy
765
- // run with NO path separators (so file paths / {{...}} substitutions survive as
766
- // useful provenance). Over-redaction is safe; leaking a key is not.
767
- if (/^(sk-|ghp_|gho_|github_pat_|xox[abpr]-|Bearer\s)/.test(arg) || (arg.length >= 32 && /^[A-Za-z0-9_\-]{32,}$/.test(arg))) {
768
- out.push("<redacted>");
769
- continue;
770
- }
771
- out.push(arg);
772
- }
773
- return out;
774
- }
775
- /** Best-effort parse of the AGENT-reported model id from its stdout. SOLELY the
776
- * agent's own report — `unreported` when absent. Never CW_AGENT_MODEL. */
777
- function parseAgentReport(stdout) {
778
- const text = String(stdout || "").trim();
779
- if (!text)
780
- return {};
781
- const tryObj = (value) => {
782
- try {
783
- const parsed = JSON.parse(value);
784
- return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
785
- }
786
- catch {
787
- return undefined;
788
- }
789
- };
790
- let obj = tryObj(text);
791
- if (!obj) {
792
- const line = text
793
- .split(/\r?\n/)
794
- .reverse()
795
- .find((entry) => entry.trim().startsWith("{") && entry.trim().endsWith("}"));
796
- if (line)
797
- obj = tryObj(line.trim());
798
- }
799
- if (!obj)
800
- return {};
801
- const usage = obj.usage && typeof obj.usage === "object" ? obj.usage : undefined;
802
- let model = typeof obj.model === "string"
803
- ? obj.model
804
- : usage && typeof usage.model === "string"
805
- ? usage.model
806
- : typeof obj.modelId === "string"
807
- ? obj.modelId
808
- : undefined;
809
- // Some agents (e.g. `claude -p --output-format json`) report no top-level model;
810
- // the model id(s) appear as KEYS of a `modelUsage` object. Pick the primary model
811
- // (the one with the most input tokens). Still SOLELY the agent's own report.
812
- if (!model && obj.modelUsage && typeof obj.modelUsage === "object" && !Array.isArray(obj.modelUsage)) {
813
- const entries = Object.entries(obj.modelUsage);
814
- if (entries.length) {
815
- const tokensOf = (value) => {
816
- const record = value && typeof value === "object" ? value : {};
817
- const input = Number(record.inputTokens ?? record.input_tokens ?? 0);
818
- return Number.isFinite(input) ? input : 0;
819
- };
820
- entries.sort((left, right) => tokensOf(right[1]) - tokensOf(left[1]));
821
- model = entries[0][0];
822
- }
823
- }
824
- // Track 1: the executor's detached signature over its usage report, if it signs.
825
- // SOLELY the agent's own field — CW verifies it later against the trust key.
826
- const usageSignature = typeof obj.usageSignature === "string"
827
- ? obj.usageSignature
828
- : typeof obj.usage_signature === "string"
829
- ? obj.usage_signature
830
- : undefined;
831
- return { model, usage, usageSignature };
832
- }
833
- function agentSubstitutions(request, model) {
834
- const manifest = request.manifest;
835
- const workerDir = manifest?.workerDir || request.cwd || "";
836
- return {
837
- manifest: manifest?.manifestPath || (workerDir ? node_path_1.default.join(workerDir, "manifest.json") : ""),
838
- input: manifest?.inputPath || "",
839
- result: manifest?.resultPath || "",
840
- workerDir,
841
- model: model || "",
842
- prompt: manifest?.prompt || ""
843
- };
844
- }
845
- function substituteAgentArg(arg, subst) {
846
- return arg.replace(/\{\{(\w+)\}\}/g, (_, key) => (key in subst ? subst[key] : `{{${key}}}`));
847
- }
848
- /** Build the recorded process handle for the envelope — secret-stripped + the
849
- * agent-reported model. Same SHAPE that lands in provenance, never in evidence. */
850
- function recordedAgentHandle(binary, endpoint, recordedArgs, model, reportedModel, reportedUsage, usageSignature) {
851
- const ref = binary ? [binary, ...recordedArgs].join(" ") : endpoint || "";
852
- return {
853
- kind: "process",
854
- ref,
855
- endpoint,
856
- metadata: {
857
- mode: binary ? "command" : "endpoint",
858
- command: binary,
859
- args: recordedArgs,
860
- model,
861
- reportedModel,
862
- // Telemetry thread-back: the agent's OWN self-reported token usage (parsed
863
- // from its stdout by parseAgentReport). ATTESTED, never measured by CW —
864
- // same red-line posture as reportedModel. Lands in provenance, never in the
865
- // byte-stable evidence triple. Absent when the agent reported no usage.
866
- ...(reportedUsage ? { reportedUsage } : {}),
867
- // Track 1: the executor's detached signature over its usage report. CW
868
- // verifies it against the operator trust key at output intake.
869
- ...(usageSignature ? { usageSignature } : {})
870
- }
871
- };
872
- }
657
+ // ---------------------------------------------------------------------------
658
+ // agent the v0.1.38 delegating driver. Spawns an EXTERNAL agent process per
659
+ // worker (claude -p / codex exec / …) argv-style (shell:false), or POSTs the
660
+ // manifest to a configured HTTP agent endpoint. The agent reads the worker
661
+ // input/manifest and writes the worker's result.md out-of-process; CW captures
662
+ // the agent CHILD's command + exit + stdout digest as the canonical evidence
663
+ // triple (NEVER the result.md that is the separate recordWorkerOutput layer)
664
+ // and records the kind:process handle + agent-reported model in provenance.
665
+ //
666
+ // THE RED LINE: CW spawns the agent and records its attested output. It NEVER
667
+ // imports a model SDK, holds an API key, or constructs a model API request. Any
668
+ // API key flows from the agent's OWN inherited env; CW never reads or records it.
669
+ // The operator-chosen CW_AGENT_MODEL is interpolated into `{{model}}` as policy
670
+ // and recorded ONLY in secret-stripped args — it is NEVER the attested model id.
671
+ //
672
+ // The pure agent helpers (resolveAgentInvocation, stripSecretArgs, parseAgentReport,
673
+ // agentSubstitutions, substituteAgentArg, recordedAgentHandle, extractEndpointResult,
674
+ // agentHandle) and the concurrent batch live in ./execution-backend/agent.ts; the
675
+ // stateful runners below build the refusal/delegated envelopes and stay here.
873
676
  function runAgentProcess(descriptor, policy, request, label, handle, attestation) {
874
- const resolved = resolveAgentInvocation(request);
875
- const subst = agentSubstitutions(request, resolved.model);
677
+ const resolved = (0, agent_1.resolveAgentInvocation)(request);
678
+ const subst = (0, agent_1.agentSubstitutions)(request, resolved.model);
876
679
  if (resolved.binary) {
877
- const realArgs = resolved.rawArgs.map((arg) => substituteAgentArg(arg, subst));
878
- const recordedArgs = stripSecretArgs(realArgs);
680
+ const realArgs = resolved.rawArgs.map((arg) => (0, agent_1.substituteAgentArg)(arg, subst));
681
+ const recordedArgs = (0, agent_1.stripSecretArgs)(realArgs);
879
682
  // Spawn the agent argv-style — shell:false, never a shell-interpreted string.
880
683
  // The agent inherits the host env so ITS OWN credentials resolve; CW neither
881
684
  // reads nor records them. CW enforces only the exact argv it spawns.
@@ -887,31 +690,36 @@ function runAgentProcess(descriptor, policy, request, label, handle, attestation
887
690
  outcome = request.preparedAgentOutcome;
888
691
  }
889
692
  else {
693
+ // Live output is opt-in (POLA): stdout is always captured as data, while
694
+ // stderr is forwarded only when the operator explicitly asks for a stream
695
+ // and this process is attached to a terminal. CI/pipes stay silent.
696
+ const streamStderr = process.env.CW_AGENT_STREAM === "1" && Boolean(process.stderr.isTTY) && process.env.CW_NO_STREAM !== "1";
890
697
  const child = (0, node_child_process_1.spawnSync)(resolved.binary, realArgs, {
891
698
  cwd: request.cwd,
892
699
  env: { ...process.env },
893
700
  encoding: "utf8",
894
701
  timeout: resolved.timeoutMs || 600000,
895
702
  maxBuffer: 32 * 1024 * 1024,
896
- shell: false
703
+ shell: false,
704
+ stdio: ["ignore", "pipe", streamStderr ? "inherit" : "pipe"]
897
705
  });
898
706
  outcome = {
899
- ...(child.error ? { spawnError: messageOf(child.error) } : {}),
707
+ ...(child.error ? { spawnError: (0, util_1.messageOf)(child.error) } : {}),
900
708
  exitCode: typeof child.status === "number" ? child.status : null,
901
709
  stdout: String(child.stdout || "")
902
710
  };
903
711
  }
904
712
  if (outcome.spawnError) {
905
- const handleOut = recordedAgentHandle(resolved.binary, undefined, recordedArgs, resolved.model, "unreported");
713
+ const handleOut = (0, agent_1.recordedAgentHandle)(resolved.binary, undefined, recordedArgs, resolved.model, "unreported");
906
714
  return refusedEnvelope(descriptor, policy, label, "delegation-failed", `agent process failed to spawn: ${outcome.spawnError}`, {
907
715
  attestation: { ...attestation, handle: handleOut }
908
716
  });
909
717
  }
910
718
  const exitCode = outcome.exitCode;
911
719
  const stdout = outcome.stdout;
912
- const report = parseAgentReport(stdout);
720
+ const report = (0, agent_1.parseAgentReport)(stdout);
913
721
  const reportedModel = report.model && report.model.trim() ? report.model.trim() : "unreported";
914
- const handleOut = recordedAgentHandle(resolved.binary, undefined, recordedArgs, resolved.model, reportedModel, report.usage, report.usageSignature);
722
+ const handleOut = (0, agent_1.recordedAgentHandle)(resolved.binary, undefined, recordedArgs, resolved.model, reportedModel, report.usage, report.usageSignature);
915
723
  if (exitCode === null) {
916
724
  // No exit code (timeout/killed) ⇒ fail closed, never a fabricated completion.
917
725
  return refusedEnvelope(descriptor, policy, label, "delegation-failed", `agent process returned no exit code (timed out or killed)`, {
@@ -929,94 +737,6 @@ function runAgentProcess(descriptor, policy, request, label, handle, attestation
929
737
  attestation
930
738
  });
931
739
  }
932
- /** Resolve a request to a spawn-style batch job, or undefined when the agent is
933
- * endpoint-configured/unconfigured (those settle through the serial path). */
934
- function prepareAgentSpawn(request) {
935
- const resolved = resolveAgentInvocation(request);
936
- if (!resolved.binary)
937
- return undefined;
938
- const subst = agentSubstitutions(request, resolved.model);
939
- return {
940
- binary: resolved.binary,
941
- args: resolved.rawArgs.map((arg) => substituteAgentArg(arg, subst)),
942
- cwd: request.cwd,
943
- timeoutMs: resolved.timeoutMs || 600000
944
- };
945
- }
946
- // Reads jobs JSON on stdin, spawns ALL concurrently (shell:false, inherited env —
947
- // the agent's own credentials resolve; CW never reads them), per-job SIGTERM at
948
- // timeoutMs + SIGKILL at +5s, caps each captured stdout at 32MB, and prints the
949
- // outcome array when every job has settled. stderr is drained (a full pipe must
950
- // never wedge a child). A kill yields exitCode null — the no-exit-code refusal.
951
- const BATCH_DELEGATE_CHILD = `
952
- const { spawn } = require("node:child_process");
953
- let raw = "";
954
- process.stdin.setEncoding("utf8");
955
- process.stdin.on("data", (d) => (raw += d));
956
- process.stdin.on("end", () => {
957
- const jobs = JSON.parse(raw);
958
- if (!jobs.length) { process.stdout.write("[]"); return; }
959
- const out = new Array(jobs.length);
960
- let pending = jobs.length;
961
- const CAP = 32 * 1024 * 1024;
962
- jobs.forEach((job, i) => {
963
- let stdout = "";
964
- let settled = false;
965
- const settle = (o) => {
966
- if (settled) return;
967
- settled = true;
968
- out[i] = o;
969
- if (--pending === 0) process.stdout.write(JSON.stringify(out));
970
- };
971
- let child;
972
- try {
973
- child = spawn(job.binary, job.args, { cwd: job.cwd, env: process.env, shell: false });
974
- } catch (error) {
975
- settle({ spawnError: String((error && error.message) || error), exitCode: null, stdout: "" });
976
- return;
977
- }
978
- const term = setTimeout(() => { try { child.kill("SIGTERM"); } catch {} }, job.timeoutMs);
979
- const kill = setTimeout(() => { try { child.kill("SIGKILL"); } catch {} }, job.timeoutMs + 5000);
980
- child.stdout.on("data", (d) => { if (stdout.length < CAP) stdout += d; });
981
- child.stderr.on("data", () => {});
982
- child.on("error", (error) => {
983
- clearTimeout(term); clearTimeout(kill);
984
- settle({ spawnError: String((error && error.message) || error), exitCode: null, stdout });
985
- });
986
- child.on("close", (code) => {
987
- clearTimeout(term); clearTimeout(kill);
988
- settle({ exitCode: typeof code === "number" ? code : null, stdout });
989
- });
990
- });
991
- });
992
- `;
993
- /** Run a batch of agent spawns concurrently; outcomes index-align with jobs. The
994
- * parent backstop timeout (max job timeout + 30s) means even a wedged delegate
995
- * child cannot deadlock the drive: on any batch-level failure EVERY job settles
996
- * as a fail-closed spawn refusal — never a fabricated completion, never a hang. */
997
- function runAgentBatchOutcomes(jobs) {
998
- if (!jobs.length)
999
- return [];
1000
- const maxTimeout = Math.max(...jobs.map((job) => job.timeoutMs));
1001
- const child = (0, node_child_process_1.spawnSync)(process.execPath, ["-e", BATCH_DELEGATE_CHILD], {
1002
- input: JSON.stringify(jobs),
1003
- encoding: "utf8",
1004
- maxBuffer: 33 * 1024 * 1024 * jobs.length,
1005
- timeout: maxTimeout + 30000
1006
- });
1007
- if (!child.error && typeof child.status === "number" && child.status === 0) {
1008
- try {
1009
- const parsed = JSON.parse(String(child.stdout || ""));
1010
- if (Array.isArray(parsed) && parsed.length === jobs.length)
1011
- return parsed;
1012
- }
1013
- catch {
1014
- // fall through to the fail-closed mapping below
1015
- }
1016
- }
1017
- const reason = child.error ? messageOf(child.error) : `batch delegate exited ${child.status === null ? "without an exit code (timed out or killed)" : `with ${child.status}`}`;
1018
- return jobs.map(() => ({ spawnError: `batch delegate failed: ${reason}`, exitCode: null, stdout: "" }));
1019
- }
1020
740
  /** Agent HTTP endpoint variant — POSTs the worker manifest/prompt to a configured
1021
741
  * agent endpoint via the shared Node delegate child; if the endpoint returns a
1022
742
  * `result` body, CW writes it to the worker's result.md (the endpoint agent is the
@@ -1039,9 +759,9 @@ function runAgentEndpoint(descriptor, policy, request, label, resolved, attestat
1039
759
  timeout: resolved.timeoutMs || 600000,
1040
760
  maxBuffer: 32 * 1024 * 1024
1041
761
  });
1042
- const baseHandle = recordedAgentHandle(undefined, endpoint, [], resolved.model, "unreported");
762
+ const baseHandle = (0, agent_1.recordedAgentHandle)(undefined, endpoint, [], resolved.model, "unreported");
1043
763
  if (child.error) {
1044
- return refusedEnvelope(descriptor, policy, label, "delegation-failed", `agent endpoint delegation failed: ${messageOf(child.error)}`, {
764
+ return refusedEnvelope(descriptor, policy, label, "delegation-failed", `agent endpoint delegation failed: ${(0, util_1.messageOf)(child.error)}`, {
1045
765
  attestation: { ...attestation, handle: baseHandle }
1046
766
  });
1047
767
  }
@@ -1062,9 +782,9 @@ function runAgentEndpoint(descriptor, policy, request, label, resolved, attestat
1062
782
  const stdout = String(parsed.stdout || "");
1063
783
  // If the endpoint agent returned the result body, CW (as transport) writes it to
1064
784
  // the worker's result.md for the separate recordWorkerOutput layer to accept.
1065
- const report = parseAgentReport(stdout);
785
+ const report = (0, agent_1.parseAgentReport)(stdout);
1066
786
  if (manifest?.resultPath && report.usage === undefined) {
1067
- const body = extractEndpointResult(stdout);
787
+ const body = (0, agent_1.extractEndpointResult)(stdout);
1068
788
  if (body && !node_fs_1.default.existsSync(manifest.resultPath)) {
1069
789
  try {
1070
790
  node_fs_1.default.writeFileSync(manifest.resultPath, body, "utf8");
@@ -1075,28 +795,9 @@ function runAgentEndpoint(descriptor, policy, request, label, resolved, attestat
1075
795
  }
1076
796
  }
1077
797
  const reportedModel = report.model && report.model.trim() ? report.model.trim() : "unreported";
1078
- const handleOut = recordedAgentHandle(undefined, endpoint, [], resolved.model, reportedModel, report.usage, report.usageSignature);
798
+ const handleOut = (0, agent_1.recordedAgentHandle)(undefined, endpoint, [], resolved.model, reportedModel, report.usage, report.usageSignature);
1079
799
  return delegatedEnvelope(descriptor, label, handleOut, { ...attestation, handle: handleOut }, "agent-endpoint", [endpoint], parsed.exitCode, stdout);
1080
800
  }
1081
- function extractEndpointResult(stdout) {
1082
- const text = String(stdout || "").trim();
1083
- if (!text)
1084
- return undefined;
1085
- try {
1086
- const parsed = JSON.parse(text);
1087
- if (parsed && typeof parsed === "object") {
1088
- if (typeof parsed.result === "string")
1089
- return parsed.result;
1090
- if (typeof parsed.resultMarkdown === "string")
1091
- return parsed.resultMarkdown;
1092
- }
1093
- }
1094
- catch {
1095
- /* not JSON — treat the raw text as the result body */
1096
- return text;
1097
- }
1098
- return undefined;
1099
- }
1100
801
  function delegationHandle(descriptor, request) {
1101
802
  return getBackendDriver(descriptor.id)?.buildHandle?.(request);
1102
803
  }
@@ -1127,28 +828,6 @@ function ciHandle(request) {
1127
828
  const ref = endpoint && jobId ? `${endpoint}#${jobId}` : jobId || endpoint || "";
1128
829
  return { kind: "ci", ref, endpoint, jobId };
1129
830
  }
1130
- function agentHandle(request) {
1131
- // The agent invocation is POLICY-as-DATA, resolved flags(delegation) > env. The
1132
- // handle records ONLY secret-stripped provenance; the raw template is re-resolved
1133
- // inside runAgentProcess for substitution + spawning so no secret ever lands in
1134
- // a recorded handle/evidence entry.
1135
- const resolved = resolveAgentInvocation(request);
1136
- if (!resolved.binary && !resolved.endpoint)
1137
- return undefined;
1138
- const strippedArgs = stripSecretArgs(resolved.rawArgs);
1139
- const ref = resolved.binary ? [resolved.binary, ...strippedArgs].join(" ") : resolved.endpoint || "";
1140
- return {
1141
- kind: "process",
1142
- ref,
1143
- endpoint: resolved.endpoint,
1144
- metadata: {
1145
- mode: resolved.binary ? "command" : "endpoint",
1146
- command: resolved.binary,
1147
- args: strippedArgs,
1148
- model: resolved.model
1149
- }
1150
- };
1151
- }
1152
831
  function refusedEnvelope(descriptor, policy, label, code, reason, options = {}) {
1153
832
  const attestation = options.attestation
1154
833
  ? { ...options.attestation, status: "refused", notes: [...(options.attestation.notes || []), `refused: ${code}`] }
@@ -1237,33 +916,6 @@ function commandDenied(policy, command) {
1237
916
  function runtimeNote(descriptor) {
1238
917
  return getBackendDriver(descriptor.id)?.runtimeNote?.() ?? "node";
1239
918
  }
1240
- function hasExecutable(name) {
1241
- const dirs = (process.env.PATH || "").split(node_path_1.default.delimiter).filter(Boolean);
1242
- for (const dir of dirs) {
1243
- const candidate = node_path_1.default.join(dir, name);
1244
- try {
1245
- if (node_fs_1.default.existsSync(candidate) && node_fs_1.default.statSync(candidate).isFile())
1246
- return true;
1247
- }
1248
- catch {
1249
- // ignore unreadable PATH entries
1250
- }
1251
- }
1252
- return false;
1253
- }
1254
- function sha256(value) {
1255
- return `sha256:${node_crypto_1.default.createHash("sha256").update(value, "utf8").digest("hex")}`;
1256
- }
1257
- function firstString(...values) {
1258
- for (const value of values) {
1259
- if (typeof value === "string" && value.trim())
1260
- return value.trim();
1261
- }
1262
- return undefined;
1263
- }
1264
- function messageOf(error) {
1265
- return error instanceof Error ? error.message : String(error);
1266
- }
1267
919
  // ---- Probe cache (v0.1.60) — mechanism, not policy -----------------------
1268
920
  const _probeCache = new Map();
1269
921
  const PROBE_CACHE_TTL_MS = 60_000; // 60s