cool-workflow 0.1.89 → 0.1.91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +42 -1
- 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/capability-core.js +151 -9
- package/dist/capability-registry.js +6 -0
- package/dist/cli/command-surface.js +143 -6
- package/dist/cli.js +26 -1
- package/dist/clones.js +162 -0
- package/dist/drive.js +37 -2
- package/dist/mcp/tool-call.js +4 -0
- package/dist/mcp/tool-definitions.js +5 -0
- package/dist/orchestrator/report.js +6 -0
- package/dist/orchestrator.js +15 -4
- package/dist/remote-source.js +444 -0
- package/dist/reporter.js +67 -0
- package/dist/term.js +127 -9
- package/dist/version.js +1 -1
- package/docs/agent-delegation-drive.7.md +41 -22
- package/docs/cli-mcp-parity.7.md +9 -2
- package/docs/contract-migration-tooling.7.md +4 -0
- package/docs/control-plane-scheduling.7.md +4 -0
- 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/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 +15 -4
- package/docs/real-execution-backends.7.md +4 -0
- package/docs/release-and-migration.7.md +4 -0
- package/docs/release-tooling.7.md +4 -0
- package/docs/remote-source-review.7.md +88 -0
- package/docs/run-registry-control-plane.7.md +4 -0
- package/docs/run-retention-reclamation.7.md +4 -0
- package/docs/state-explosion-management.7.md +4 -0
- package/docs/team-collaboration.7.md +4 -0
- package/docs/web-desktop-workbench.7.md +4 -0
- package/manifest/plugin.manifest.json +1 -1
- package/manifest/source-context-profiles.json +1 -1
- package/package.json +1 -1
- package/scripts/agents/agent-adapter-core.js +137 -3
- package/scripts/agents/claude-p-agent.js +24 -15
- package/scripts/agents/codex-agent.js +11 -8
- package/scripts/agents/gemini-agent.js +11 -8
- package/scripts/agents/opencode-agent.js +11 -8
- package/scripts/canonical-apps.js +4 -4
- package/scripts/dogfood-release.js +1 -1
- package/scripts/golden-path.js +4 -4
package/dist/term.js
CHANGED
|
@@ -16,10 +16,29 @@ exports.cyan = cyan;
|
|
|
16
16
|
exports.doctorGlyph = doctorGlyph;
|
|
17
17
|
exports.cwLabel = cwLabel;
|
|
18
18
|
exports.indent = indent;
|
|
19
|
+
exports.nextHint = nextHint;
|
|
20
|
+
exports.tryHint = tryHint;
|
|
21
|
+
exports.sectionHeader = sectionHeader;
|
|
22
|
+
exports.phaseProgressLine = phaseProgressLine;
|
|
23
|
+
exports.formatDuration = formatDuration;
|
|
19
24
|
exports.printSuccessSummary = printSuccessSummary;
|
|
25
|
+
exports.stripAnsi = stripAnsi;
|
|
26
|
+
exports.visibleWidth = visibleWidth;
|
|
27
|
+
exports.truncate = truncate;
|
|
28
|
+
exports.formatFindingsSummary = formatFindingsSummary;
|
|
20
29
|
function isTTY(stream = process.stderr) {
|
|
21
30
|
return Boolean(stream.isTTY);
|
|
22
31
|
}
|
|
32
|
+
/** Whether to emit ANSI color on a stream, honoring the de-facto env standards:
|
|
33
|
+
* NO_COLOR / CW_NO_COLOR (any non-empty value) disable; FORCE_COLOR (non-"0") forces on
|
|
34
|
+
* even when piped; otherwise fall back to isTTY. The `--no-color` flag sets CW_NO_COLOR. */
|
|
35
|
+
function colorEnabled(stream, env = process.env) {
|
|
36
|
+
if ((env.NO_COLOR ?? "") !== "" || (env.CW_NO_COLOR ?? "") !== "")
|
|
37
|
+
return false;
|
|
38
|
+
if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== "" && env.FORCE_COLOR !== "0")
|
|
39
|
+
return true;
|
|
40
|
+
return isTTY(stream);
|
|
41
|
+
}
|
|
23
42
|
// ---- ansi codes ----
|
|
24
43
|
const ansi = {
|
|
25
44
|
reset: "\x1b[0m",
|
|
@@ -32,7 +51,7 @@ const ansi = {
|
|
|
32
51
|
};
|
|
33
52
|
// ---- styled text ----
|
|
34
53
|
function style(code, text, stream) {
|
|
35
|
-
if (!
|
|
54
|
+
if (!colorEnabled(stream))
|
|
36
55
|
return text;
|
|
37
56
|
return `${code}${text}${ansi.reset}`;
|
|
38
57
|
}
|
|
@@ -74,20 +93,119 @@ function indent(text, spaces = 2) {
|
|
|
74
93
|
const prefix = " ".repeat(spaces);
|
|
75
94
|
return text.split("\n").map((line) => `${prefix}${line}`).join("\n");
|
|
76
95
|
}
|
|
77
|
-
/**
|
|
78
|
-
|
|
96
|
+
/** A `Next: <cmd>` hint line (the command stays plain so it is copy-pasteable). */
|
|
97
|
+
function nextHint(cmd, stream) {
|
|
98
|
+
return `${dim("Next:", stream)} ${cmd}`;
|
|
99
|
+
}
|
|
100
|
+
/** A `Try: <cmd>` recovery hint (brew-style; the command stays plain to copy). */
|
|
101
|
+
function tryHint(cmd, stream) {
|
|
102
|
+
return `${dim("Try:", stream)} ${cmd}`;
|
|
103
|
+
}
|
|
104
|
+
/** A `==> Title` section header (brew-style). */
|
|
105
|
+
function sectionHeader(title, stream) {
|
|
106
|
+
return `${bold("==>", stream)} ${title}`;
|
|
107
|
+
}
|
|
108
|
+
/** A phase-progress line: `==> Map ✓ (6/6)` / `==> Assess … (3/6)`. Parallel phases
|
|
109
|
+
* use ⇉, sequential use …; a finished phase uses a green ✓. */
|
|
110
|
+
function phaseProgressLine(name, done, total, mode, stream) {
|
|
111
|
+
const complete = total > 0 && done >= total;
|
|
112
|
+
const glyph = complete ? green("✓", stream) : (mode === "parallel" ? "⇉" : "…");
|
|
113
|
+
const count = total > 0 ? ` (${done}/${total})` : "";
|
|
114
|
+
return `${sectionHeader(name, stream)} ${glyph}${count}`;
|
|
115
|
+
}
|
|
116
|
+
/** Format a DURATION in ms as `850ms` / `5.2s` / `1m02s`. Pure (no clock) — the
|
|
117
|
+
* caller measures elapsed via process.hrtime, so this never reads wall-clock time. */
|
|
118
|
+
function formatDuration(ms) {
|
|
119
|
+
if (ms < 1000)
|
|
120
|
+
return `${Math.max(0, Math.round(ms))}ms`;
|
|
121
|
+
const s = Math.round(ms / 100) / 10;
|
|
122
|
+
if (s < 60)
|
|
123
|
+
return `${s}s`;
|
|
124
|
+
const m = Math.floor(s / 60);
|
|
125
|
+
const rem = Math.round(s % 60);
|
|
126
|
+
return `${m}m${String(rem).padStart(2, "0")}s`;
|
|
127
|
+
}
|
|
128
|
+
/** Print a success summary to stderr (TTY-gated). Shows the report path, a one-line
|
|
129
|
+
* status (with N/N worker counts when known), and a copy-pasteable next/recovery
|
|
130
|
+
* command. Pipe-friendly: silent when stderr is not a TTY, so it never pollutes
|
|
131
|
+
* piped/`--json` stdout. A non-complete run with no agent configured gets a brew-style
|
|
132
|
+
* `Try: cw doctor` recovery line; otherwise `Next: cw status <id>` to inspect. */
|
|
79
133
|
function printSuccessSummary(fields, stream) {
|
|
80
134
|
if (!isTTY(stream))
|
|
81
135
|
return;
|
|
82
136
|
const s = stream || process.stderr;
|
|
83
|
-
|
|
137
|
+
const counts = (typeof fields.completedWorkers === "number" && typeof fields.plannedWorkers === "number")
|
|
138
|
+
? ` — ${fields.completedWorkers}/${fields.plannedWorkers}` : "";
|
|
139
|
+
s.write(`\n${green("✓", s)} Report: ${fields.reportPath}\n`);
|
|
84
140
|
if (fields.status === "complete") {
|
|
85
|
-
s.write(`
|
|
86
|
-
|
|
87
|
-
s.write(` Bundle: cw report bundle ${fields.runId}\n`);
|
|
88
|
-
}
|
|
141
|
+
s.write(` ${green("✓", s)} Status: complete${counts}\n`);
|
|
142
|
+
s.write(` ${nextHint(`cw report ${fields.runId} --show`, s)}\n`);
|
|
89
143
|
}
|
|
90
144
|
else {
|
|
91
|
-
s.write(` ${yellow("!")} Status: ${fields.status}
|
|
145
|
+
s.write(` ${yellow("!", s)} Status: ${fields.status}${counts}\n`);
|
|
146
|
+
// No agent backend is the #1 first-run blocker — point at the one command that
|
|
147
|
+
// diagnoses and prints the fix, brew-style. Otherwise inspect the run's state.
|
|
148
|
+
if (fields.agentConfigured === false)
|
|
149
|
+
s.write(` ${tryHint("cw doctor", s)}\n`);
|
|
150
|
+
else
|
|
151
|
+
s.write(` ${nextHint(`cw status ${fields.runId}`, s)}\n`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// ---- width-aware truncation (zero-dep) ----
|
|
155
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
156
|
+
/** Strip ANSI SGR codes (for measuring visible width). */
|
|
157
|
+
function stripAnsi(text) {
|
|
158
|
+
return text.replace(ANSI_RE, "");
|
|
159
|
+
}
|
|
160
|
+
/** Visible width of a string, ignoring ANSI. Counts each code point as width 1 — a known
|
|
161
|
+
* minor caveat for wide (CJK/emoji) glyphs, acceptable for one-line status truncation. */
|
|
162
|
+
function visibleWidth(text) {
|
|
163
|
+
return [...stripAnsi(text)].length;
|
|
164
|
+
}
|
|
165
|
+
/** Truncate a (possibly styled) string to `maxWidth` visible columns, appending `…` when cut.
|
|
166
|
+
* Operates on the PLAIN text (callers truncate before styling), so no ANSI is split. */
|
|
167
|
+
function truncate(text, maxWidth) {
|
|
168
|
+
if (maxWidth <= 0)
|
|
169
|
+
return "";
|
|
170
|
+
const chars = [...stripAnsi(text)];
|
|
171
|
+
if (chars.length <= maxWidth)
|
|
172
|
+
return text;
|
|
173
|
+
if (maxWidth === 1)
|
|
174
|
+
return "…";
|
|
175
|
+
return `${chars.slice(0, maxWidth - 1).join("")}…`;
|
|
176
|
+
}
|
|
177
|
+
// ---- findings summary table (end-of-run, compact) ----
|
|
178
|
+
/** Severity order for sorting + counting (most severe first). */
|
|
179
|
+
const SEVERITY_ORDER = ["P0", "P1", "P2", "P3", "none"];
|
|
180
|
+
/** Render a compact findings summary assembled from the run's `cw:result` blocks: a one-line
|
|
181
|
+
* count headline (e.g. `Findings: 3 — 2×P1, 1×P2`) plus a small id/severity/class table. This
|
|
182
|
+
* is the end-of-run summary — NOT the full prose (that stays in report.md + the transcript).
|
|
183
|
+
* Returns "" when there are no findings (caller prints nothing). */
|
|
184
|
+
function formatFindingsSummary(findings, stream) {
|
|
185
|
+
if (!findings.length)
|
|
186
|
+
return "";
|
|
187
|
+
const bySev = new Map();
|
|
188
|
+
for (const f of findings)
|
|
189
|
+
bySev.set(f.severity || "none", (bySev.get(f.severity || "none") || 0) + 1);
|
|
190
|
+
const order = (s) => {
|
|
191
|
+
const i = SEVERITY_ORDER.indexOf(s);
|
|
192
|
+
return i === -1 ? SEVERITY_ORDER.length : i;
|
|
193
|
+
};
|
|
194
|
+
const counts = [...bySev.entries()]
|
|
195
|
+
.sort((a, b) => order(a[0]) - order(b[0]))
|
|
196
|
+
.map(([sev, n]) => `${n}×${sev}`)
|
|
197
|
+
.join(", ");
|
|
198
|
+
const rows = [...findings].sort((a, b) => order(a.severity) - order(b.severity));
|
|
199
|
+
const sevW = Math.max(8, ...rows.map((r) => (r.severity || "none").length));
|
|
200
|
+
const clsW = Math.max(5, ...rows.map((r) => (r.classification || "unknown").length));
|
|
201
|
+
const lines = [
|
|
202
|
+
`${bold("Findings:", stream)} ${findings.length} — ${counts}`,
|
|
203
|
+
dim(` ${"SEVERITY".padEnd(sevW)} ${"CLASS".padEnd(clsW)} ID`, stream)
|
|
204
|
+
];
|
|
205
|
+
for (const r of rows) {
|
|
206
|
+
const sev = (r.severity || "none").padEnd(sevW);
|
|
207
|
+
const cls = (r.classification || "unknown").padEnd(clsW);
|
|
208
|
+
lines.push(` ${sev} ${cls} ${truncate(r.id || "(unnamed)", 60)}`);
|
|
92
209
|
}
|
|
210
|
+
return lines.join("\n");
|
|
93
211
|
}
|
package/dist/version.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION = exports.LEGACY_RUN_STATE_SCHEMA_VERSION = exports.CURRENT_RUN_STATE_SCHEMA_VERSION = exports.WORKFLOW_APP_SCHEMA_VERSION = exports.CURRENT_COOL_WORKFLOW_VERSION = void 0;
|
|
4
|
-
exports.CURRENT_COOL_WORKFLOW_VERSION = "0.1.
|
|
4
|
+
exports.CURRENT_COOL_WORKFLOW_VERSION = "0.1.91";
|
|
5
5
|
exports.WORKFLOW_APP_SCHEMA_VERSION = 1;
|
|
6
6
|
exports.CURRENT_RUN_STATE_SCHEMA_VERSION = 1;
|
|
7
7
|
exports.LEGACY_RUN_STATE_SCHEMA_VERSION = 0;
|
|
@@ -198,28 +198,43 @@ string). Each verb is declared once in `capability-registry.ts`, so `cw <cmd>
|
|
|
198
198
|
--json` is byte-identical to the matching `cw_<tool>` MCP tool for the read-only
|
|
199
199
|
preview/config-show verbs.
|
|
200
200
|
|
|
201
|
-
## Live output —
|
|
202
|
-
|
|
203
|
-
A drive
|
|
204
|
-
contract
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
the
|
|
201
|
+
## Live output — a calm live view, on stderr, Unix-clean
|
|
202
|
+
|
|
203
|
+
A drive shows the agent's activity live without ever touching the evidence
|
|
204
|
+
contract. The async per-vendor wrapper owns the live region (it parses
|
|
205
|
+
`--output-format stream-json` and its event loop is free); cw renders the calm
|
|
206
|
+
orchestration between agents plus the end-of-run summary. **Everything goes to
|
|
207
|
+
stderr — stdout stays the byte-exact data channel** (the `cw:result` fence, the
|
|
208
|
+
wrapper's `{model, usage, result}` JSON, cw's `--json` payload), so a pipe is
|
|
209
|
+
never polluted.
|
|
210
|
+
|
|
211
|
+
- **Interactive (TTY).** The wrapper renders ONE in-place status line: a Braille
|
|
212
|
+
spinner + the current action + elapsed (e.g. `⠹ Read app.js 1.2s`). Tool calls
|
|
213
|
+
fold to a single line each — spinning while running, then resolving to
|
|
214
|
+
`✓ Read app.js (0.3s)` / `✗ Bash (1.1s)` (dimmed, args width-truncated). The
|
|
215
|
+
cursor is hidden while the spinner runs and **ALWAYS restored** on exit /
|
|
216
|
+
Ctrl-C / SIGTERM (Ctrl-C exits non-zero, leaving a clean terminal).
|
|
217
|
+
- **Non-TTY stays SILENT by default** (the Rule of Silence). `CW_AGENT_STREAM=1`
|
|
218
|
+
opts a CI/piped run into a **plain append-only** trace (`→ …` / `✓ … (Xs)`
|
|
219
|
+
lines, zero ANSI/cursor bytes) for debuggability — mirroring `CW_DRIVE_PROGRESS=1`.
|
|
220
|
+
- **Verbosity.** Default is compact: the current action + folded tool lines, with
|
|
221
|
+
the model's narration/reasoning HIDDEN. `--verbose` (sets `CW_VERBOSE=1`)
|
|
222
|
+
surfaces the full narration inline; `--full` (sets `CW_OUTPUT=full`) implies
|
|
223
|
+
verbose AND prints the report inline at run end.
|
|
224
|
+
- **Transcript always on disk.** Regardless of verbosity — even when the screen
|
|
225
|
+
view is silent or compact — the wrapper writes the COMPLETE narration + tool I/O
|
|
226
|
+
to `transcript.md` next to that worker's `result.md`. The end-of-run summary
|
|
227
|
+
prints the run dir where the transcripts live, so nothing is ever lost to a
|
|
228
|
+
compact view.
|
|
229
|
+
- **Color control.** `NO_COLOR` / `CW_NO_COLOR` (the `--no-color` flag sets the
|
|
230
|
+
latter) disable ANSI; `FORCE_COLOR` forces it even when piped; otherwise color
|
|
231
|
+
follows isTTY. Honored identically by cw (`term.ts`) and every wrapper.
|
|
232
|
+
- **End-of-run summary (cw side).** A COMPACT findings table — id / severity /
|
|
233
|
+
classification + counts, re-parsed from each completed worker's `cw:result` —
|
|
234
|
+
plus the report path, status, and run dir. NOT the full prose (that stays in
|
|
235
|
+
`report.md` + the transcript); `--full` also prints the report inline.
|
|
236
|
+
- **Determinism intact.** The backend evidence triple hashes stdout only, so the
|
|
237
|
+
live stderr view never changes recorded evidence or replay.
|
|
223
238
|
|
|
224
239
|
The built-in templates are:
|
|
225
240
|
|
|
@@ -317,3 +332,7 @@ Orchestration-parity for the agent drive: `run --drive --incremental` step-level
|
|
|
317
332
|
## 0.1.89 (v0.1.89)
|
|
318
333
|
|
|
319
334
|
The one-command `cw -q` headline now routes the question and defaults the repo to the caller cwd before driving the agent; the delegation contract, drive, and accept path are unchanged.
|
|
335
|
+
|
|
336
|
+
0.1.90
|
|
337
|
+
|
|
338
|
+
0.1.91
|
package/docs/cli-mcp-parity.7.md
CHANGED
|
@@ -82,7 +82,7 @@ relationship. `identical` means `cw <cmd> --json` is equal to the `cw_<tool>`
|
|
|
82
82
|
payload; `projected` means a declared divergence with a reason; `cli-only` marks
|
|
83
83
|
a surface-specific capability with a recorded reason. The matrix is
|
|
84
84
|
<!-- gen:parity:count -->
|
|
85
|
-
machine-complete by design:
|
|
85
|
+
machine-complete by design: 201 capabilities, 188 MCP tools.
|
|
86
86
|
<!-- /gen:parity:count -->
|
|
87
87
|
|
|
88
88
|
<!-- gen:parity:table -->
|
|
@@ -272,6 +272,8 @@ machine-complete by design: 199 capabilities, 186 MCP tools.
|
|
|
272
272
|
| `gc.plan` | `cw gc plan` | `cw_gc_plan` | `gcPlan` | both | identical |
|
|
273
273
|
| `gc.run` | `cw gc run` | `cw_gc_run` | `gcRun` | both | projected |
|
|
274
274
|
| `gc.verify` | `cw gc verify` | `cw_gc_verify` | `gcVerify` | both | identical |
|
|
275
|
+
| `clones.list` | `cw clones list` | `cw_clones_list` | `listClones` | both | identical |
|
|
276
|
+
| `clones.gc` | `cw clones gc` | `cw_clones_gc` | `gcClones` | both | projected |
|
|
275
277
|
| `telemetry.verify` | `cw telemetry verify` | `cw_telemetry_verify` | `telemetryVerify` | both | identical |
|
|
276
278
|
| `demo.tamper` | `cw demo tamper` | `—` | `demoTamper` | cli-only | cli-only |
|
|
277
279
|
| `demo.bundle` | `cw demo bundle` | `—` | `demoBundle` | cli-only | cli-only |
|
|
@@ -319,12 +321,13 @@ carry a recorded reason in the registry.
|
|
|
319
321
|
<!-- /gen:parity:cliOnly -->
|
|
320
322
|
|
|
321
323
|
<!-- gen:parity:projected -->
|
|
322
|
-
|
|
324
|
+
Six capabilities are payload-divergent on purpose (`projected`):
|
|
323
325
|
|
|
324
326
|
- `commit` — Both surfaces route through the single core entry runner.commit. The CLI emits the raw StateCommitResult for scripting (commit.id, commit.evidence, commit.gate, commit.acceptanceRationale); cw_commit emits the operator commit envelope (commitId, verifierGated, checkpoint, evidenceCount, snapshotPath, nextActions, plus the raw result under `commit`). Declared projection via capability-core.commitEnvelope, not drift.
|
|
325
327
|
- `backend.agent.config.set` — Mutating: persists $CW_HOME/agent-config.json (secret-stripped) before returning the effective config; both surfaces perform the same write — it is a surface-mutating verb, not a read probe.
|
|
326
328
|
- `run.drive.step` — Mutating: advances the run by spawning the external agent per worker and recording attested output — not a read probe. CLI (--drive/--step) and MCP route through the same drive() core.
|
|
327
329
|
- `gc.run` — Mutating: frees disk and appends a tombstone; both surfaces perform the identical transaction but the payload reports now-derived bytesFreed/tombstone.
|
|
330
|
+
- `clones.gc` — Mutating: removes cache directories and reports now-derived freedBytes/removed; both surfaces perform the identical reclamation.
|
|
328
331
|
- `workbench.serve` — Both surfaces route through the single core entry buildWorkbenchServeDescriptor and return the IDENTICAL serve descriptor under `cw workbench serve --json`/`--once` and `cw_workbench_serve`. They diverge only in side effect, not payload: the CLI's default `cw workbench serve` (no --once) additionally STARTS the blocking localhost host (like `schedule daemon`), which an MCP stdio host cannot do, so cw_workbench_serve only ever returns the descriptor. Declared divergence, not drift.
|
|
329
332
|
<!-- /gen:parity:projected -->
|
|
330
333
|
|
|
@@ -521,3 +524,7 @@ CLI surface simplified to 6 commands with agent stderr streaming on by default a
|
|
|
521
524
|
## 0.1.89 (v0.1.89)
|
|
522
525
|
|
|
523
526
|
CLI golden-path fixes: `cw -q "…"` routes the question (was read as an app id → "Workflow app not found"), auto-detects the cwd as the repo (run anywhere, no `--repo`), and `cw help` wraps its command list with a trailing newline; the CLI↔MCP parity contract and the help-token parser are unchanged.
|
|
527
|
+
|
|
528
|
+
0.1.90
|
|
529
|
+
|
|
530
|
+
0.1.91
|
|
@@ -299,3 +299,7 @@ The host-facing surface tracks the CLI simplification to 6 commands (streaming o
|
|
|
299
299
|
## 0.1.89 (v0.1.89)
|
|
300
300
|
|
|
301
301
|
The host-facing surface tracks the CLI golden-path fixes (`cw -q` routing + repo auto-detect + clean help); the multi-agent verbs and their MCP-tool mirrors are unchanged.
|
|
302
|
+
|
|
303
|
+
0.1.90
|
|
304
|
+
|
|
305
|
+
0.1.91
|
package/docs/project-index.md
CHANGED
|
@@ -5,11 +5,11 @@ Generated from the current repository code on 2026-06-21 by `npm run sync:projec
|
|
|
5
5
|
## Snapshot
|
|
6
6
|
|
|
7
7
|
- Package: `cool-workflow`
|
|
8
|
-
- Version: `0.1.
|
|
9
|
-
- Source modules: `
|
|
8
|
+
- Version: `0.1.91`
|
|
9
|
+
- Source modules: `68`
|
|
10
10
|
- Workflow apps: `7`
|
|
11
|
-
- Docs: `
|
|
12
|
-
- Smoke tests: `
|
|
11
|
+
- Docs: `53`
|
|
12
|
+
- Smoke tests: `137`
|
|
13
13
|
- Repository: https://github.com/coo1white/cool-workflow
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
@@ -83,6 +83,7 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
83
83
|
- [agent-config.ts](../src/agent-config.ts)
|
|
84
84
|
- [capability-core.ts](../src/capability-core.ts)
|
|
85
85
|
- [capability-registry.ts](../src/capability-registry.ts)
|
|
86
|
+
- [clones.ts](../src/clones.ts)
|
|
86
87
|
- [collaboration.ts](../src/collaboration.ts)
|
|
87
88
|
- [compare.ts](../src/compare.ts)
|
|
88
89
|
- [contract-migration.ts](../src/contract-migration.ts)
|
|
@@ -102,6 +103,8 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
102
103
|
- [observability.ts](../src/observability.ts)
|
|
103
104
|
- [onramp.ts](../src/onramp.ts)
|
|
104
105
|
- [reclamation.ts](../src/reclamation.ts)
|
|
106
|
+
- [remote-source.ts](../src/remote-source.ts)
|
|
107
|
+
- [reporter.ts](../src/reporter.ts)
|
|
105
108
|
- [result-normalize.ts](../src/result-normalize.ts)
|
|
106
109
|
- [run-export.ts](../src/run-export.ts)
|
|
107
110
|
- [run-registry.ts](../src/run-registry.ts)
|
|
@@ -166,6 +169,7 @@ multi-agent host -> topology -> blackboard/coordinator
|
|
|
166
169
|
- [Release And Migration Discipline](release-and-migration.7.md)
|
|
167
170
|
- [Cool Workflow Release History](release-history.md)
|
|
168
171
|
- [Release Tooling](release-tooling.7.md)
|
|
172
|
+
- [Remote-Source Review (`--link`)](remote-source-review.7.md)
|
|
169
173
|
- [Verifiable Report Bundle](report-verifiable-bundle.7.md)
|
|
170
174
|
- [Routines](routines.md)
|
|
171
175
|
- [Run Registry / Control Plane](run-registry-control-plane.7.md)
|
|
@@ -203,9 +207,14 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
203
207
|
- [candidate-scoring-smoke.js](../test/candidate-scoring-smoke.js)
|
|
204
208
|
- [canonical-workflow-apps-smoke.js](../test/canonical-workflow-apps-smoke.js)
|
|
205
209
|
- [claude-p-agent-wrapper-smoke.js](../test/claude-p-agent-wrapper-smoke.js)
|
|
210
|
+
- [cli-arg-parsing-smoke.js](../test/cli-arg-parsing-smoke.js)
|
|
206
211
|
- [cli-command-surface-smoke.js](../test/cli-command-surface-smoke.js)
|
|
207
212
|
- [cli-jsonmode-parity-smoke.js](../test/cli-jsonmode-parity-smoke.js)
|
|
208
213
|
- [cli-mcp-parity-smoke.js](../test/cli-mcp-parity-smoke.js)
|
|
214
|
+
- [cli-progress-summary-smoke.js](../test/cli-progress-summary-smoke.js)
|
|
215
|
+
- [cli-recoverable-errors-smoke.js](../test/cli-recoverable-errors-smoke.js)
|
|
216
|
+
- [cli-render-smoke.js](../test/cli-render-smoke.js)
|
|
217
|
+
- [clones-gc-smoke.js](../test/clones-gc-smoke.js)
|
|
209
218
|
- [codex-agent-wrapper-smoke.js](../test/codex-agent-wrapper-smoke.js)
|
|
210
219
|
- [concurrency-default-smoke.js](../test/concurrency-default-smoke.js)
|
|
211
220
|
- [concurrent-failure-semantics-smoke.js](../test/concurrent-failure-semantics-smoke.js)
|
|
@@ -272,6 +281,8 @@ Smoke tests mirror the public contracts. The high-signal suites are:
|
|
|
272
281
|
- [release-flow-smoke.js](../test/release-flow-smoke.js)
|
|
273
282
|
- [release-gate-smoke.js](../test/release-gate-smoke.js)
|
|
274
283
|
- [release-tooling-smoke.js](../test/release-tooling-smoke.js)
|
|
284
|
+
- [remote-link-archive-smoke.js](../test/remote-link-archive-smoke.js)
|
|
285
|
+
- [remote-link-git-smoke.js](../test/remote-link-git-smoke.js)
|
|
275
286
|
- [report-bundle-smoke.js](../test/report-bundle-smoke.js)
|
|
276
287
|
- [report-verify-bundle-smoke.js](../test/report-verify-bundle-smoke.js)
|
|
277
288
|
- [result-normalize-smoke.js](../test/result-normalize-smoke.js)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Remote-Source Review (`--link`)
|
|
2
|
+
|
|
3
|
+
CW v0.1.91 lets you point a review at **any repository on the internet** instead
|
|
4
|
+
of only a local path: `cw -q "what are the risks?" --link <url>`. CW materializes
|
|
5
|
+
the remote into a local checkout and runs the **existing** review pipeline against
|
|
6
|
+
it — identical downstream to reviewing a folder. A URL passed to `-dir`/`--repo`
|
|
7
|
+
is auto-detected, so `--link <url>` and `-dir <url>` are equivalent.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cw -q "What are the risks?" --link https://github.com/owner/repo
|
|
11
|
+
cw -q "What are the risks?" --link git@gitlab.com:owner/repo.git --ref v1.2.0
|
|
12
|
+
cw -q "What are the risks?" --link https://github.com/owner/repo/archive/refs/heads/main.tar.gz
|
|
13
|
+
cw -q "..." --link <url> --check # validate the URL + tooling WITHOUT fetching
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Sources
|
|
17
|
+
|
|
18
|
+
- **Git repositories**, any host: `https://`, `http://`, `ssh://`, `git://`, the
|
|
19
|
+
scp-style `git@host:owner/repo`, and `file://`. Cloned shallow (`--depth 1
|
|
20
|
+
--single-branch`); `--ref <branch|tag>` selects a ref. `commit` is the resolved
|
|
21
|
+
`HEAD` SHA.
|
|
22
|
+
- **Downloadable archives**: `.tar.gz` / `.tgz` / `.tar` / `.zip` (e.g. a GitHub
|
|
23
|
+
"Download ZIP" / codeload tarball). Fetched, extracted, and `git init`-snapshotted
|
|
24
|
+
into a local repo so the git-tracked source-context reader works unchanged.
|
|
25
|
+
`commit` is the **sha256 of the downloaded bytes** (a content address — there is
|
|
26
|
+
no git SHA).
|
|
27
|
+
|
|
28
|
+
## The red line — materialize source, do not internalize execution
|
|
29
|
+
|
|
30
|
+
`--link` only materializes the **source** to review. CW still **DELEGATES** worker
|
|
31
|
+
execution to the operator's configured agent backend (`claude -p`, `codex exec`, an
|
|
32
|
+
HTTP endpoint) exactly as a local review does; it never executes a model itself.
|
|
33
|
+
Cloning is non-deterministic network I/O, so it happens in the **capability layer**
|
|
34
|
+
(before `plan`), never in the replay-deterministic orchestrator core — which only
|
|
35
|
+
ever sees the resulting local path.
|
|
36
|
+
|
|
37
|
+
## Provenance — where the code came from, tamper-evidently
|
|
38
|
+
|
|
39
|
+
The sanitized origin rides through three surfaces:
|
|
40
|
+
|
|
41
|
+
- `run.inputs` → a `- Source: <url>@<commit>` line in `report.md`.
|
|
42
|
+
- the `--json` result's `remote { url, commit, kind, ref, cached }`.
|
|
43
|
+
- a hash-chained `source.clone` / `source.download` **trust-audit event** that
|
|
44
|
+
`cw audit verify <run-id>` re-proves — editing the recorded origin is detectable.
|
|
45
|
+
|
|
46
|
+
Credentials in a URL (`https://user:token@host/…`) are stripped before the URL is
|
|
47
|
+
used as a cache key, printed, persisted, or recorded; the raw URL reaches only a
|
|
48
|
+
single `git` argv element. Git/download diagnostics are credential-redacted before
|
|
49
|
+
they are ever surfaced.
|
|
50
|
+
|
|
51
|
+
## Fail closed
|
|
52
|
+
|
|
53
|
+
A bad URL, a blocked scheme, a network failure, or a credential-less private repo
|
|
54
|
+
produces an **explicit error and a non-zero exit** — never a fabricated review,
|
|
55
|
+
never a hang on an auth prompt (`GIT_TERMINAL_PROMPT=0`). Hardening:
|
|
56
|
+
|
|
57
|
+
- **Scheme allowlist** (https/http/ssh/git/file); `ext::`/`fd::` transport helpers
|
|
58
|
+
and `-`-leading option-injection are rejected; the URL is always a separate argv
|
|
59
|
+
element (never a shell string); repo hooks are disabled (`-c core.hooksPath=`).
|
|
60
|
+
- **Archive extraction** validates the entry listing for `..`/absolute traversal
|
|
61
|
+
BEFORE extracting, **rejects symlink/non-regular entries** (walked with `lstat`),
|
|
62
|
+
and bounds the decompression bomb by **declared** uncompressed size (gzip ISIZE /
|
|
63
|
+
`unzip -l`) before extracting and **actual** size (1 GiB) after.
|
|
64
|
+
- **SSRF**: http(s) redirects are followed manually and each hop is re-validated
|
|
65
|
+
(http(s) scheme + no private/loopback/link-local host) before connecting — a
|
|
66
|
+
public URL cannot redirect CW into an internal service.
|
|
67
|
+
|
|
68
|
+
## Cache — `cw clones`
|
|
69
|
+
|
|
70
|
+
Checkouts are cached, content-addressed, under
|
|
71
|
+
`~/.local/state/cool-workflow/clones/<hash>/` (honoring `CW_HOME`/`XDG_STATE_HOME`)
|
|
72
|
+
and reused on the next question; `--refresh` re-fetches. Manage the cache:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
cw clones list # origin url, kind, commit, age, bytes
|
|
76
|
+
cw clones gc --older-than-days 30 # reclaim checkouts older than N days
|
|
77
|
+
cw clones gc --all # reclaim everything
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`cw clones gc` deletes only paths it has proven are inside the clones cache (fail
|
|
81
|
+
closed). Both verbs have MCP peers (`cw_clones_list`, `cw_clones_gc`) with
|
|
82
|
+
byte-identical payloads.
|
|
83
|
+
|
|
84
|
+
## Determinism note
|
|
85
|
+
|
|
86
|
+
The cache is keyed on the URL (+ref), not on content: if a URL's content changes
|
|
87
|
+
upstream, the cached checkout is reused until `--refresh` (mirroring how a git
|
|
88
|
+
clone pins its resolved `HEAD`). Use `--refresh` to re-fetch the latest.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"_comment": "SINGLE SOURCE OF TRUTH for every vendor manifest. Edit THIS file, then run `npm run gen:manifests`. Do NOT hand-edit the generated vendor manifests (.claude-plugin/, .codex-plugin/, .agents/, .mcp.json) — `npm run gen:manifests -- --check` (run by release:check) will fail if they drift from this source.",
|
|
3
3
|
"identity": {
|
|
4
4
|
"name": "cool-workflow",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.91",
|
|
6
6
|
"license": "BSD-2-Clause",
|
|
7
7
|
"homepage": "https://github.com/coo1white/cool-workflow",
|
|
8
8
|
"author": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"runtime": {
|
|
27
27
|
"description": "Runtime-kernel source context for state, orchestration, scheduling, execution, and shared types.",
|
|
28
|
-
"maxLines":
|
|
28
|
+
"maxLines": 48000,
|
|
29
29
|
"include": [
|
|
30
30
|
"plugins/cool-workflow/src/**",
|
|
31
31
|
"plugins/cool-workflow/package.json",
|