cool-workflow 0.2.4 → 0.2.6
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/.gemini-plugin/mcp.json +10 -0
- package/.gemini-plugin/plugin.json +40 -0
- package/.opencode-plugin/mcp.json +10 -0
- package/.opencode-plugin/plugin.json +40 -0
- package/README.md +204 -48
- package/apps/architecture-review/app.json +1 -1
- package/apps/architecture-review-fast/app.json +1 -1
- package/apps/end-to-end-golden-path/app.json +1 -1
- package/apps/pr-review-fix-ci/app.json +1 -1
- package/apps/release-cut/app.json +1 -1
- package/apps/research-synthesis/app.json +1 -1
- package/dist/cli/dispatch.js +32 -4
- package/dist/cli/entry.js +11 -19
- package/dist/cli/global-flags.js +113 -0
- package/dist/cli/parseargv.js +7 -1
- package/dist/core/capability-data.js +337 -8
- package/dist/core/format/help.js +73 -3
- package/dist/core/format/recovery-hint.js +32 -0
- package/dist/core/multi-agent/collaboration.js +35 -6
- package/dist/core/multi-agent/runtime.js +7 -0
- package/dist/core/multi-agent/trust-policy.js +7 -1
- package/dist/core/pipeline/contract.js +7 -0
- package/dist/core/pipeline/error-feedback.js +2 -2
- package/dist/core/state/run-paths.js +3 -30
- package/dist/core/trust/evidence-grounding.js +13 -1
- package/dist/core/util/cli-args.js +22 -0
- package/dist/core/version.js +1 -1
- package/dist/mcp/dispatch.js +22 -2
- package/dist/mcp/server.js +215 -36
- package/dist/mcp/tool-process.js +181 -0
- package/dist/mcp-server.js +28 -1
- package/dist/shell/agent-config.js +11 -2
- package/dist/shell/audit-cli.js +1 -1
- package/dist/shell/commit.js +8 -2
- package/dist/shell/coordinator-io.js +73 -1
- package/dist/shell/drive.js +195 -128
- package/dist/shell/error-feedback-io.js +6 -0
- package/dist/shell/execution-backend/agent.js +201 -26
- package/dist/shell/execution-backend/container.js +44 -10
- package/dist/shell/execution-backend/local.js +33 -0
- package/dist/shell/fs-atomic.js +96 -12
- package/dist/shell/ledger-cli.js +9 -2
- package/dist/shell/metrics-cli.js +1 -1
- package/dist/shell/multi-agent-cli.js +9 -2
- package/dist/shell/multi-agent-operator-ux.js +1 -1
- package/dist/shell/observability.js +7 -4
- package/dist/shell/onramp.js +48 -5
- package/dist/shell/operator-ux.js +1 -1
- package/dist/shell/perf-trace.js +136 -0
- package/dist/shell/pipeline.js +3 -2
- package/dist/shell/reclamation-io.js +10 -9
- package/dist/shell/report-view-cli.js +2 -0
- package/dist/shell/run-export-cli.js +5 -2
- package/dist/shell/run-export.js +293 -31
- package/dist/shell/run-registry-io.js +8 -0
- package/dist/shell/run-store.js +183 -3
- package/dist/shell/scheduler-io.js +101 -10
- package/dist/shell/state-explosion-cli.js +4 -1
- package/dist/shell/telemetry-demo.js +1 -1
- package/dist/shell/telemetry-ledger-io.js +36 -24
- package/dist/shell/trust-audit.js +178 -36
- package/dist/shell/workbench-host.js +121 -10
- package/dist/shell/workbench.js +83 -6
- package/dist/shell/worker-isolation.js +1 -1
- package/dist/wiring/capability-table/basics.js +5 -0
- package/dist/wiring/capability-table/exec-backend.js +40 -22
- package/dist/wiring/capability-table/parity.js +10 -5
- package/dist/wiring/capability-table/pipeline.js +32 -0
- package/dist/wiring/capability-table/registry-core.js +26 -3
- package/dist/wiring/capability-table/reporting.js +7 -1
- package/dist/wiring/capability-table/scheduling-registry.js +8 -2
- package/dist/wiring/capability-table/trust-ledger.js +54 -12
- package/docs/agent-delegation-drive.7.md +17 -0
- package/docs/cli-mcp-parity.7.md +46 -5
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +38 -0
- package/docs/cross-agent-ledger.7.md +20 -8
- package/docs/durable-state-and-locking.7.md +4 -0
- package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
- package/docs/execution-backends.7.md +4 -0
- package/docs/fix.7.md +4 -4
- package/docs/getting-started.md +40 -32
- package/docs/index.md +17 -0
- package/docs/launch/demo.tape +4 -3
- package/docs/mcp-app-surface.7.md +27 -0
- package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
- package/docs/multi-agent-eval-replay-harness.7.md +4 -0
- package/docs/multi-agent-operator-ux.7.md +4 -0
- package/docs/node-snapshot-diff-replay.7.md +4 -0
- package/docs/observability-cost-accounting.7.md +4 -0
- package/docs/project-index.md +53 -9
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +12 -0
- package/docs/routine.7.md +22 -0
- package/docs/run-registry-control-plane.7.md +37 -9
- package/docs/run-retention-reclamation.7.md +12 -4
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/trust-audit-anchor.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +72 -2
- package/docs/workflow-app-framework.7.md +31 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +4 -3
- package/package.json +6 -3
- package/scripts/agents/agent-adapter-core.js +26 -0
- package/scripts/agents/claude-p-agent.js +4 -1
- package/scripts/agents/codex-agent.js +4 -0
- package/scripts/agents/cw-attest-wrap.js +1 -1
- package/scripts/agents/gemini-agent.js +4 -0
- package/scripts/agents/opencode-agent.js +5 -0
- package/scripts/block-unapproved-tag.js +160 -0
- package/scripts/canonical-apps.js +4 -4
- package/scripts/children/batch-delegate-child.js +72 -4
- package/scripts/children/http-batch-delegate-child.js +132 -0
- package/scripts/children/http-delegate-child.js +8 -0
- package/scripts/dogfood-release.js +2 -2
- package/scripts/fake-date-for-reproduction.js +1 -1
- package/scripts/gen-manifests.js +32 -61
- package/scripts/golden-path.js +4 -4
- package/scripts/lang-policy-check.js +82 -0
- package/scripts/parity-check.js +42 -23
- package/scripts/purity-baseline.json +0 -3
- package/scripts/purity-gate.js +16 -3
- package/scripts/release-check.js +2 -1
- package/scripts/release-flow.js +169 -41
- package/scripts/release-gate.js +208 -0
- package/scripts/release-oneclick.js +38 -7
- package/scripts/release-tags.js +47 -0
- package/scripts/schema-version-inventory.json +31 -0
- package/scripts/validate-run-state-schema.js +95 -4
- package/scripts/verdict-keygen.js +2 -2
- package/scripts/verify-bump-reproduction.js +193 -0
- package/scripts/verify-release-verdict.js +139 -0
- package/scripts/verify-verdict-signature.js +1 -1
- package/ui/workbench/app.css +50 -10
- package/ui/workbench/app.js +269 -34
- package/ui/workbench/index.html +4 -2
- package/ui/workbench/inspection.js +51 -0
- package/ui/workbench/navigation.js +44 -0
- package/docs/agent-framework.md +0 -177
- package/docs/designs/handoff-ledger.md +0 -145
- package/docs/dogfood/resume-drive-real-agent-2026-06-14.md +0 -40
- package/docs/launch/launch-kit.md +0 -195
- package/docs/launch/pre-launch-checklist.md +0 -53
- package/docs/readme-v0.1.87-full.md +0 -301
- package/docs/routines.md +0 -101
- package/docs/scheduled-tasks.md +0 -80
- package/scripts/agents/claude-p-agent.sh +0 -9
- package/scripts/block-unapproved-tag.sh +0 -75
- package/scripts/release-gate.sh +0 -94
- package/scripts/verify-bump-reproduction.sh +0 -148
- package/scripts/verify-container-selfref.js +0 -64
package/dist/shell/ledger-cli.js
CHANGED
|
@@ -188,10 +188,17 @@ function ledgerApplyCli(options) {
|
|
|
188
188
|
return (0, ledger_1.applyLedgerProposal)(parsed);
|
|
189
189
|
}
|
|
190
190
|
function ledgerListCli(options) {
|
|
191
|
-
|
|
191
|
+
// `--ledger-dir` is the preferred flag: the global CLI front door
|
|
192
|
+
// (cli/entry.ts) treats `--dir` as an alias of `--repo` for EVERY
|
|
193
|
+
// command, so `cw ledger list --dir X` made one flag mean two things.
|
|
194
|
+
// `--dir` keeps working unchanged as the legacy spelling; when both are
|
|
195
|
+
// given, `--ledger-dir` wins. Repeated flags become an array via
|
|
196
|
+
// parseArgv's append behavior, same as `--dir` always has.
|
|
197
|
+
const input = options["ledger-dir"] ?? options.dir;
|
|
198
|
+
const dirs = Array.isArray(input) ? input.map(String).filter(Boolean) : [];
|
|
192
199
|
if (dirs.length > 1)
|
|
193
200
|
return (0, ledger_io_1.unionLedgerEntries)(dirs);
|
|
194
|
-
const dir = required(dirs[0] || stringOption(
|
|
201
|
+
const dir = required(dirs[0] || stringOption(input), "--ledger-dir <ledger-directory>");
|
|
195
202
|
return (0, ledger_io_1.listLedgerEntries)(dir);
|
|
196
203
|
}
|
|
197
204
|
/** MCP-facing verify/apply take the entry OBJECT directly (not a file/
|
|
@@ -71,7 +71,7 @@ function nowOf(args) {
|
|
|
71
71
|
function metricsShowCli(runId, args) {
|
|
72
72
|
const run = (0, run_store_1.loadRunFromCwd)(runId, invocationCwd(args));
|
|
73
73
|
const policy = (0, observability_1.loadCostPolicy)(args, pluginRoot());
|
|
74
|
-
return (0, observability_1.showMetricsReport)(run, { now: nowOf(args), policy });
|
|
74
|
+
return (0, observability_1.showMetricsReport)(run, { now: nowOf(args), policy, persist: args.__cwWorkbenchReadOnlyProjection !== true });
|
|
75
75
|
}
|
|
76
76
|
/** `cw metrics summary [--scope repo|home] [--pricing ...] [--now ISO] [--limit N]`.
|
|
77
77
|
* `--limit` defaults to RunRegistry.list()'s own 50-record floor when omitted. */
|
|
@@ -113,6 +113,7 @@ exports.evalScoreCli = evalScoreCli;
|
|
|
113
113
|
exports.evalGateCli = evalGateCli;
|
|
114
114
|
exports.evalReportCli = evalReportCli;
|
|
115
115
|
const path = __importStar(require("node:path"));
|
|
116
|
+
const cli_args_1 = require("../core/util/cli-args");
|
|
116
117
|
const numeric_flag_1 = require("../core/util/numeric-flag");
|
|
117
118
|
const run_store_1 = require("./run-store");
|
|
118
119
|
const report_1 = require("./report");
|
|
@@ -139,7 +140,10 @@ function invocationCwd(args) {
|
|
|
139
140
|
return typeof args.cwd === "string" && args.cwd.trim() ? path.resolve(args.cwd) : process.cwd();
|
|
140
141
|
}
|
|
141
142
|
function loadRun(args, runId) {
|
|
142
|
-
|
|
143
|
+
const run = (0, run_store_1.loadRunFromCwd)(runId, invocationCwd(args));
|
|
144
|
+
if (args.__cwWorkbenchReadOnlyProjection === true)
|
|
145
|
+
run.__cwWorkbenchReadOnlyProjection = true;
|
|
146
|
+
return run;
|
|
143
147
|
}
|
|
144
148
|
/** Hold the run's state.json lock across the WHOLE load -> change ->
|
|
145
149
|
* persist cycle. A bare loadRun + persist pair races: two processes both
|
|
@@ -188,7 +192,10 @@ function numberArg(value) {
|
|
|
188
192
|
return Number.isFinite(parsed) ? parsed : undefined;
|
|
189
193
|
}
|
|
190
194
|
function boolArg(value) {
|
|
191
|
-
|
|
195
|
+
// parseBoolFlag reads "false"/"0"/"no"/"off" as false and throws on an
|
|
196
|
+
// unrecognized string — Boolean("false") is true, which silently
|
|
197
|
+
// ENABLED flags like `--allow-self-approval false` (fail-open).
|
|
198
|
+
return (0, cli_args_1.parseBoolFlag)(value, "flag") ?? false;
|
|
192
199
|
}
|
|
193
200
|
/** `--multi-agent-run <id>` — parseArgv keeps kebab-case option keys
|
|
194
201
|
* verbatim (no camelCase folding), so this must check the literal
|
|
@@ -91,7 +91,7 @@ function summarizeMultiAgentOperator(run) {
|
|
|
91
91
|
const topologies = (0, topology_io_1.summarizeTopologies)(run);
|
|
92
92
|
const multiAgent = (0, multi_agent_io_1.summarizeMultiAgent)(run);
|
|
93
93
|
const blackboard = (0, coordinator_io_1.summarizeBlackboard)(run);
|
|
94
|
-
const trust = (0, trust_audit_1.summarizeTrustAudit)(run);
|
|
94
|
+
const trust = (0, trust_audit_1.summarizeTrustAudit)(run, { persist: run.__cwWorkbenchReadOnlyProjection !== true });
|
|
95
95
|
const dependencies = deriveDependencies(run);
|
|
96
96
|
const failures = deriveFailures(run, dependencies);
|
|
97
97
|
const evidence = deriveEvidence(run);
|
|
@@ -453,13 +453,16 @@ function loadPersistedMetricsFingerprint(run) {
|
|
|
453
453
|
}
|
|
454
454
|
/** Derive + persist the per-run report. The RETURNED payload is pinned to
|
|
455
455
|
* `freshness: "valid"` (persistedFingerprint === itself) so `cw metrics
|
|
456
|
-
* show --json` and the MCP tool are byte-identical
|
|
457
|
-
*
|
|
456
|
+
* show --json` and the MCP tool are byte-identical. The Workbench's private
|
|
457
|
+
* projection mode keeps that established payload but does not create a
|
|
458
|
+
* derived file; NEVER touches state.json (invariant 6). */
|
|
458
459
|
function showMetricsReport(run, options) {
|
|
459
460
|
const live = deriveMetricsReport(run, { now: options.now, policy: options.policy });
|
|
460
461
|
const report = { ...live, freshness: { status: "valid", persistedFingerprint: live.sourceFingerprint, currentFingerprint: live.sourceFingerprint } };
|
|
461
|
-
|
|
462
|
-
|
|
462
|
+
if (options.persist !== false) {
|
|
463
|
+
fs.mkdirSync(metricsDir(run), { recursive: true });
|
|
464
|
+
(0, fs_atomic_1.writeJson)(metricsReportPath(run), report);
|
|
465
|
+
}
|
|
463
466
|
return report;
|
|
464
467
|
}
|
|
465
468
|
function poolRates(metric, rates) {
|
package/dist/shell/onramp.js
CHANGED
|
@@ -278,9 +278,9 @@ function resolveChangedFiles(options = {}) {
|
|
|
278
278
|
const root = gitRoot(cwd);
|
|
279
279
|
const baseRef = resolveBaseRef(root, options.changedFrom, options.env || process.env);
|
|
280
280
|
const files = new Set();
|
|
281
|
-
for (const file of
|
|
281
|
+
for (const file of gitLinesOrThrow(root, ["diff", "--name-only", baseRef, "--"]))
|
|
282
282
|
files.add(normalizeChangedPath(file));
|
|
283
|
-
for (const file of
|
|
283
|
+
for (const file of gitLinesOrThrow(root, ["ls-files", "--others", "--exclude-standard"]))
|
|
284
284
|
files.add(normalizeChangedPath(file));
|
|
285
285
|
return { baseRef, files: [...files].filter(Boolean).sort() };
|
|
286
286
|
}
|
|
@@ -406,8 +406,26 @@ function resolveBaseRef(root, changedFrom, env) {
|
|
|
406
406
|
return verifyRef(root, changedFrom);
|
|
407
407
|
if (env.CW_ONRAMP_BASE)
|
|
408
408
|
return verifyRef(root, env.CW_ONRAMP_BASE);
|
|
409
|
-
|
|
410
|
-
|
|
409
|
+
// A pull_request CI context sets GITHUB_BASE_REF, so a base ref is EXPECTED:
|
|
410
|
+
// the diff must run against the PR's own base branch. If merge-base cannot
|
|
411
|
+
// resolve there (a shallow clone that never fetched the base, a missing
|
|
412
|
+
// origin ref), we must NOT quietly degrade to HEAD -- a HEAD..HEAD diff on a
|
|
413
|
+
// clean, already-committed tree is empty, and an empty change set has no
|
|
414
|
+
// issues, so onramp:check would report ok:true on a real, unseen change (the
|
|
415
|
+
// same vacuous-pass class PR #446 closed one layer below). Fail closed.
|
|
416
|
+
if (env.GITHUB_BASE_REF) {
|
|
417
|
+
const baseBranch = `origin/${env.GITHUB_BASE_REF}`;
|
|
418
|
+
const mergeBase = gitOne(root, ["merge-base", "HEAD", baseBranch]);
|
|
419
|
+
if (mergeBase)
|
|
420
|
+
return mergeBase;
|
|
421
|
+
throw new Error(`onramp: cannot resolve a base ref -- git merge-base HEAD ${baseBranch} found no common commit (fail closed, not treated as zero changes). Fetch the base branch with a full (non-shallow) clone, or pass --changed-from / CW_ONRAMP_BASE.`);
|
|
422
|
+
}
|
|
423
|
+
// No base ref was requested (--changed-from / CW_ONRAMP_BASE) or expected
|
|
424
|
+
// (GITHUB_BASE_REF): this is the local "show my own changes" use. merge-base
|
|
425
|
+
// against origin/main narrows the diff to this branch's commits when the
|
|
426
|
+
// remote is present; with no remote we fall back to HEAD so `git diff HEAD`
|
|
427
|
+
// still surfaces the working-tree (uncommitted) changes.
|
|
428
|
+
const mergeBase = gitOne(root, ["merge-base", "HEAD", "origin/main"]);
|
|
411
429
|
if (mergeBase)
|
|
412
430
|
return mergeBase;
|
|
413
431
|
return verifyRef(root, "HEAD");
|
|
@@ -423,12 +441,37 @@ function verifyRef(root, ref) {
|
|
|
423
441
|
function gitRoot(cwd) {
|
|
424
442
|
return gitOne(node_path_1.default.resolve(cwd), ["rev-parse", "--show-toplevel"]) || node_path_1.default.resolve(cwd);
|
|
425
443
|
}
|
|
444
|
+
// Every onramp git call is a quick metadata read (rev-parse, merge-base, diff
|
|
445
|
+
// --name-only, ls-files). A finite timeout keeps a HUNG git -- a cold fsmonitor
|
|
446
|
+
// daemon, a credential prompt on a misconfigured remote -- from blocking the
|
|
447
|
+
// gate forever; 5s matches the git-metadata timeout already used in
|
|
448
|
+
// shell/commit.ts and shell/doctor.ts. On a timeout spawnSync sets
|
|
449
|
+
// `result.error` (and a null status), so gitLinesOrThrow fails closed while
|
|
450
|
+
// gitLines/gitOne fall back the same way they do for any other git failure.
|
|
451
|
+
const GIT_TIMEOUT_MS = 5000;
|
|
426
452
|
function gitLines(cwd, args) {
|
|
427
|
-
const result = (0, node_child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
|
|
453
|
+
const result = (0, node_child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: GIT_TIMEOUT_MS });
|
|
428
454
|
if (result.status !== 0)
|
|
429
455
|
return [];
|
|
430
456
|
return String(result.stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
431
457
|
}
|
|
458
|
+
/** Same as gitLines, but a failed git invocation THROWS instead of silently
|
|
459
|
+
* becoming []. resolveChangedFiles must never mistake "git could not run
|
|
460
|
+
* this diff" for "there is nothing to diff" -- that turns a transient git
|
|
461
|
+
* failure into a vacuous onramp-contract pass (a 2026-07-12 security audit
|
|
462
|
+
* finding: a broken base ref or a git error made the changed-file set
|
|
463
|
+
* empty, and an empty set has no issues, so the gate reported ok:true on a
|
|
464
|
+
* real, unseen change). Callers that WANT a soft fallback (merge-base
|
|
465
|
+
* probing, optional discovery) should keep using gitLines/gitOne. */
|
|
466
|
+
function gitLinesOrThrow(cwd, args) {
|
|
467
|
+
const result = (0, node_child_process_1.spawnSync)("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: GIT_TIMEOUT_MS });
|
|
468
|
+
if (result.error)
|
|
469
|
+
throw new Error(`onramp: git ${args.join(" ")} failed to run: ${result.error.message}`);
|
|
470
|
+
if (result.status !== 0) {
|
|
471
|
+
throw new Error(`onramp: git ${args.join(" ")} exited ${result.status} -- cannot resolve changed files (fail closed, not treated as zero changes): ${String(result.stderr || "").trim()}`);
|
|
472
|
+
}
|
|
473
|
+
return String(result.stdout || "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
474
|
+
}
|
|
432
475
|
function gitOne(cwd, args) {
|
|
433
476
|
return gitLines(cwd, args)[0] || "";
|
|
434
477
|
}
|
|
@@ -290,7 +290,7 @@ function summarizeOperatorRun(run) {
|
|
|
290
290
|
const multiAgentOperator = (0, multi_agent_operator_ux_1.summarizeMultiAgentOperator)(run);
|
|
291
291
|
const multiAgentTrust = (0, trust_policy_io_1.summarizeMultiAgentTrust)(run);
|
|
292
292
|
const blackboard = (0, coordinator_io_1.summarizeBlackboard)(run);
|
|
293
|
-
const trust = (0, trust_audit_1.summarizeTrustAudit)(run);
|
|
293
|
+
const trust = (0, trust_audit_1.summarizeTrustAudit)(run, { persist: run.__cwWorkbenchReadOnlyProjection !== true });
|
|
294
294
|
const activePhase = phases.find((p) => p.status === "running") || phases.find((p) => p.status === "pending");
|
|
295
295
|
const blockedReasons = [];
|
|
296
296
|
for (const worker of workers.workers) {
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// shell/perf-trace.ts — opt-in cold-path timing evidence for the benchmark
|
|
3
|
+
// runner. This is not a product log: it is off unless CW_BENCH_TRACE_FILE is
|
|
4
|
+
// set by scripts/bench/run.js, and it writes one JSON report when the drive
|
|
5
|
+
// process ends. Normal CLI and MCP work do not see it.
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.withPerfTraceGroup = withPerfTraceGroup;
|
|
41
|
+
exports.recordPerfDurableWrite = recordPerfDurableWrite;
|
|
42
|
+
const fs = __importStar(require("node:fs"));
|
|
43
|
+
const TRACE_FILE = process.env.CW_BENCH_TRACE_FILE || "";
|
|
44
|
+
const groups = new Map();
|
|
45
|
+
const scopes = [];
|
|
46
|
+
function enabled() {
|
|
47
|
+
return TRACE_FILE.length > 0;
|
|
48
|
+
}
|
|
49
|
+
function groupFor(name) {
|
|
50
|
+
let group = groups.get(name);
|
|
51
|
+
if (!group) {
|
|
52
|
+
group = { durationMs: 0, selfMs: 0, durableWriteCount: 0, durableWriteBytes: 0, samples: [] };
|
|
53
|
+
groups.set(name, group);
|
|
54
|
+
}
|
|
55
|
+
return group;
|
|
56
|
+
}
|
|
57
|
+
function elapsedMs(startedAt) {
|
|
58
|
+
return Number(process.hrtime.bigint() - startedAt) / 1_000_000;
|
|
59
|
+
}
|
|
60
|
+
/** Run synchronous work as one named benchmark group. Nested work is kept in
|
|
61
|
+
* the parent duration, but removed from its self time. That lets the report
|
|
62
|
+
* show dispatch work apart from its agent wait without changing call order. */
|
|
63
|
+
function withPerfTraceGroup(name, fn) {
|
|
64
|
+
if (!enabled())
|
|
65
|
+
return fn();
|
|
66
|
+
const scope = { name, startedAt: process.hrtime.bigint(), childMs: 0, durableWriteCount: 0, durableWriteBytes: 0 };
|
|
67
|
+
scopes.push(scope);
|
|
68
|
+
try {
|
|
69
|
+
return fn();
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
const ended = scopes.pop();
|
|
73
|
+
if (ended) {
|
|
74
|
+
const durationMs = elapsedMs(ended.startedAt);
|
|
75
|
+
const group = groupFor(ended.name);
|
|
76
|
+
group.durationMs += durationMs;
|
|
77
|
+
group.selfMs += Math.max(0, durationMs - ended.childMs);
|
|
78
|
+
group.durableWriteCount += ended.durableWriteCount;
|
|
79
|
+
group.durableWriteBytes += ended.durableWriteBytes;
|
|
80
|
+
group.samples.push({
|
|
81
|
+
durationMs: rounded(durationMs),
|
|
82
|
+
selfMs: rounded(Math.max(0, durationMs - ended.childMs)),
|
|
83
|
+
durableWriteCount: ended.durableWriteCount,
|
|
84
|
+
durableWriteBytes: ended.durableWriteBytes,
|
|
85
|
+
});
|
|
86
|
+
const parent = scopes[scopes.length - 1];
|
|
87
|
+
if (parent)
|
|
88
|
+
parent.childMs += durationMs;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Count a completed durable file write in the active benchmark group. */
|
|
93
|
+
function recordPerfDurableWrite(bytes) {
|
|
94
|
+
if (!enabled())
|
|
95
|
+
return;
|
|
96
|
+
const active = scopes[scopes.length - 1];
|
|
97
|
+
if (!active) {
|
|
98
|
+
const group = groupFor("other");
|
|
99
|
+
group.durableWriteCount += 1;
|
|
100
|
+
group.durableWriteBytes += bytes;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
for (const scope of scopes) {
|
|
104
|
+
scope.durableWriteCount += 1;
|
|
105
|
+
scope.durableWriteBytes += bytes;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function rounded(value) {
|
|
109
|
+
return Math.round(value * 1000) / 1000;
|
|
110
|
+
}
|
|
111
|
+
function writeTrace() {
|
|
112
|
+
if (!enabled())
|
|
113
|
+
return;
|
|
114
|
+
const value = {
|
|
115
|
+
schemaVersion: 1,
|
|
116
|
+
benchmark: "cw-cold-path",
|
|
117
|
+
groups: [...groups.entries()]
|
|
118
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
119
|
+
.map(([name, group]) => ({
|
|
120
|
+
name,
|
|
121
|
+
durationMs: rounded(group.durationMs),
|
|
122
|
+
selfMs: rounded(group.selfMs),
|
|
123
|
+
durableWriteCount: group.durableWriteCount,
|
|
124
|
+
durableWriteBytes: group.durableWriteBytes,
|
|
125
|
+
samples: group.samples,
|
|
126
|
+
})),
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
fs.writeFileSync(TRACE_FILE, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// A benchmark trace must never change the drive result or exit status.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (enabled())
|
|
136
|
+
process.once("exit", writeTrace);
|
package/dist/shell/pipeline.js
CHANGED
|
@@ -48,6 +48,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
48
48
|
exports.pureAppendRunNode = exports.writeJson = void 0;
|
|
49
49
|
exports.plan = plan;
|
|
50
50
|
const crypto = __importStar(require("node:crypto"));
|
|
51
|
+
const fs = __importStar(require("node:fs"));
|
|
51
52
|
const path = __importStar(require("node:path"));
|
|
52
53
|
const run_paths_1 = require("../core/state/run-paths");
|
|
53
54
|
const migrations_1 = require("../core/state/migrations");
|
|
@@ -147,7 +148,7 @@ function plan(app, options) {
|
|
|
147
148
|
const runId = injectedRunId || createRunId(app.workflow.id);
|
|
148
149
|
const runDir = path.join(cwd, ".cw", "runs", runId);
|
|
149
150
|
const paths = (0, run_paths_1.createRunPaths)(runDir);
|
|
150
|
-
(0,
|
|
151
|
+
(0, run_store_1.ensureRunDirs)(paths);
|
|
151
152
|
const tasks = flattenTasks(app, inputs);
|
|
152
153
|
// Stamp a real wall-clock createdAt/updatedAt at plan time (shell layer —
|
|
153
154
|
// clock reads are allowed here). The pure migration defaults a run that
|
|
@@ -207,7 +208,7 @@ function plan(app, options) {
|
|
|
207
208
|
loopStage: "interpret",
|
|
208
209
|
artifacts: [{ id: "task", kind: "markdown", path: task.taskPath }],
|
|
209
210
|
metadata: { workflowId: app.workflow.id, appId: app.id, appVersion: app.version, taskId: task.id, phase: task.phase, taskKind: task.kind, requiresEvidence: task.requiresEvidence, sandboxProfileId: task.sandboxProfileId },
|
|
210
|
-
}, { persist: false, persistNode: node_store_1.writeRunNode });
|
|
211
|
+
}, { persist: false, persistNode: node_store_1.writeRunNode, pathExists: fs.existsSync });
|
|
211
212
|
task.stateNodeId = taskResult.outputNodeId;
|
|
212
213
|
}
|
|
213
214
|
(0, report_1.writeReport)(run);
|
|
@@ -473,14 +473,15 @@ function planReclamation(run, policy = {}) {
|
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
475
|
// (3) Superseded, non-verifier-gated commit snapshots. Each commitState()
|
|
476
|
-
// call
|
|
477
|
-
//
|
|
478
|
-
// Only the run's LATEST commit and any
|
|
479
|
-
// audit-significant milestones) are
|
|
480
|
-
// "checkpoint" commit's only value is
|
|
481
|
-
// state.json (not commits/) is the
|
|
482
|
-
//
|
|
483
|
-
//
|
|
476
|
+
// call writes only the commit's own small record into commits/<id>.json
|
|
477
|
+
// (not the whole run), but these files still add up over a long run with
|
|
478
|
+
// no reclamation path today. Only the run's LATEST commit and any
|
|
479
|
+
// verifier-gated commit (the actual audit-significant milestones) are
|
|
480
|
+
// kept — an intermediate, non-gated "checkpoint" commit's only value is
|
|
481
|
+
// as a point-in-time snapshot, and state.json (not commits/) is the
|
|
482
|
+
// source of truth for resume. Treated as not reconstructable (no recipe)
|
|
483
|
+
// on purpose, kept conservative: a commit snapshot is not offered a
|
|
484
|
+
// projection path derivable from retained data.
|
|
484
485
|
let reclaimedCommitSnapshot = false;
|
|
485
486
|
if (!policy.keepCommits) {
|
|
486
487
|
const commits = run.commits || [];
|
|
@@ -663,7 +664,7 @@ function prepareFree(run, tombstone) {
|
|
|
663
664
|
for (const nodeId of repointed) {
|
|
664
665
|
try {
|
|
665
666
|
const fresh = (0, node_store_1.snapshotNode)(run, nodeId, { persist: false });
|
|
666
|
-
const { freshness } = (0, node_snapshot_1.loadNodeSnapshot)(run, fresh);
|
|
667
|
+
const { freshness } = (0, node_snapshot_1.loadNodeSnapshot)(run, fresh, fs.existsSync);
|
|
667
668
|
if (freshness === "absent") {
|
|
668
669
|
throw new ReclamationError("repoint-incomplete", `re-pointed node ${nodeId} snapshot is absent (dangling artifact)`, { nodeId });
|
|
669
670
|
}
|
|
@@ -109,6 +109,8 @@ function operatorReportText(runId, args) {
|
|
|
109
109
|
/** `cw graph <id> [--json]` / `cw operator graph`. */
|
|
110
110
|
function graphCli(runId, args) {
|
|
111
111
|
const run = (0, run_store_1.loadRunFromCwd)(runId, invocationCwd(args));
|
|
112
|
+
if (args.__cwWorkbenchReadOnlyProjection === true)
|
|
113
|
+
run.__cwWorkbenchReadOnlyProjection = true;
|
|
112
114
|
return (0, operator_ux_1.buildOperatorGraph)(run);
|
|
113
115
|
}
|
|
114
116
|
function graphText(runId, args) {
|
|
@@ -100,7 +100,10 @@ function runRestoreCli(archivePath, args) {
|
|
|
100
100
|
if (!inspect.ok) {
|
|
101
101
|
return { schemaVersion: 1, ok: false, target, inspect, imported: null, verify: null, registry: null };
|
|
102
102
|
}
|
|
103
|
-
const
|
|
103
|
+
const restored = (0, run_export_1.restoreRunAtomically)(resolvedArchive, target);
|
|
104
|
+
if (!restored.imported) {
|
|
105
|
+
return { schemaVersion: 1, ok: false, target, inspect, imported: null, verify: restored.verification, registry: null };
|
|
106
|
+
}
|
|
104
107
|
const registry = new run_registry_io_1.RunRegistry(target).refresh({ scope: "repo" });
|
|
105
|
-
return { schemaVersion: 1, ok:
|
|
108
|
+
return { schemaVersion: 1, ok: true, target, inspect, imported: restored.imported.run, verify: restored.verification, registry };
|
|
106
109
|
}
|