cclaw-cli 0.30.0 → 0.32.0
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/README.md +45 -24
- package/dist/cli.d.ts +2 -4
- package/dist/cli.js +48 -133
- package/dist/config.d.ts +1 -11
- package/dist/config.js +0 -40
- package/dist/content/archive-command.js +58 -32
- package/dist/content/compound-command.js +79 -24
- package/dist/content/next-command.js +40 -8
- package/dist/content/protocols.js +39 -8
- package/dist/content/retro-command.js +104 -32
- package/dist/doctor.js +0 -2
- package/dist/flow-state.d.ts +31 -0
- package/dist/flow-state.js +37 -1
- package/dist/harness-adapters.js +19 -7
- package/dist/install.d.ts +3 -5
- package/dist/install.js +4 -9
- package/dist/runs.js +39 -4
- package/dist/types.d.ts +0 -12
- package/dist/types.js +0 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,7 +117,8 @@ Plus harness-specific shims:
|
|
|
117
117
|
|
|
118
118
|
`.cclaw/config.yaml` holds every tunable key (prompt guard strictness,
|
|
119
119
|
TDD enforcement, git-hook guards, language rule packs, track heuristics).
|
|
120
|
-
Edit it directly — `cclaw-cli upgrade` preserves your changes.
|
|
120
|
+
Edit it directly — `cclaw-cli upgrade` preserves your changes. Full key
|
|
121
|
+
reference: [`docs/config.md`](./docs/config.md).
|
|
121
122
|
|
|
122
123
|
---
|
|
123
124
|
|
|
@@ -199,8 +200,9 @@ cclaw has eight stages, but a single prompt rarely needs all of them.
|
|
|
199
200
|
| **standard** _(default)_ | all 8 stages | `new feature`, `refactor`, `migration`, `platform`, `schema`, `architecture` |
|
|
200
201
|
|
|
201
202
|
Each stage produces a dated artifact under `.cclaw/artifacts/`:
|
|
202
|
-
`00-idea.md` (seed)
|
|
203
|
-
|
|
203
|
+
`00-idea.md` (seed), `01-brainstorm.md` through `08-ship.md`, and
|
|
204
|
+
`09-retro.md` at automatic closeout (see
|
|
205
|
+
[Ship and closeout](#ship-and-closeout--automatic-resumable)).
|
|
204
206
|
|
|
205
207
|
### Track heuristics are configurable
|
|
206
208
|
|
|
@@ -253,8 +255,12 @@ it into ceremony:
|
|
|
253
255
|
in a single place (`.cclaw/contexts/`), so every skill speaks the same
|
|
254
256
|
dialect.
|
|
255
257
|
- **Knowledge capture throughout the flow.** Every stage completion
|
|
256
|
-
protocol
|
|
257
|
-
|
|
258
|
+
protocol emits typed entries (`rule` / `pattern` / `lesson`) to
|
|
259
|
+
`.cclaw/knowledge.jsonl` as the flow progresses — not only at retro.
|
|
260
|
+
Retro itself adds a `compound` entry, and the automatic compound pass
|
|
261
|
+
after ship promotes recurring entries (≥ 3) into first-class
|
|
262
|
+
rules/protocols/skills so the **next** run is easier. Strict JSONL
|
|
263
|
+
schema keeps the whole thing machine-queryable.
|
|
258
264
|
- **Automatic integrity checks.** Runtime health is verified on every
|
|
259
265
|
stage transition — no command you need to remember to run.
|
|
260
266
|
|
|
@@ -277,24 +283,38 @@ native subagent dispatch, such as Codex — see
|
|
|
277
283
|
|
|
278
284
|
---
|
|
279
285
|
|
|
280
|
-
## Ship and closeout
|
|
281
|
-
|
|
282
|
-
Shipping writes `08-ship.md`
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
286
|
+
## Ship and closeout — automatic, resumable
|
|
287
|
+
|
|
288
|
+
Shipping writes `08-ship.md`. `/cc-next` then automatically walks the
|
|
289
|
+
feature through a deterministic three-step closeout without extra
|
|
290
|
+
commands from you:
|
|
291
|
+
|
|
292
|
+
1. **Retro (`09-retro.md`).** cclaw drafts a retrospective from your
|
|
293
|
+
stage artifacts, the delegation log, and the knowledge entries
|
|
294
|
+
recorded during the run. It then asks exactly **one** structured
|
|
295
|
+
question:
|
|
296
|
+
- **accept** *(default)* — keep the draft, record one `compound`
|
|
297
|
+
knowledge entry, advance.
|
|
298
|
+
- **edit** — you edit `09-retro.md` in place, then `/cc-next` again.
|
|
299
|
+
- **skip** — record a one-line reason, continue (archive will
|
|
300
|
+
surface the skip in the run manifest).
|
|
301
|
+
2. **Compound pass.** If the knowledge store has clusters recurring 3+
|
|
302
|
+
times, cclaw proposes concrete lifts into rules/protocols/skills and
|
|
303
|
+
asks once: apply-all / apply-selected / skip. An empty pass advances
|
|
304
|
+
silently.
|
|
305
|
+
3. **Archive.** Moves artifacts into `.cclaw/runs/YYYY-MM-DD-<slug>/`,
|
|
306
|
+
snapshots `state/`, writes a manifest, and resets `flow-state.json`
|
|
307
|
+
to the track's initial stage.
|
|
308
|
+
|
|
309
|
+
The chain is driven by `closeout.shipSubstate` inside `flow-state.json`
|
|
310
|
+
(`retro_review` → `compound_review` → `ready_to_archive` → `archived`).
|
|
311
|
+
If your session dies mid-closeout, a new `/cc-next` resumes at the
|
|
312
|
+
exact step — retro drafts are not regenerated and no structured ask is
|
|
313
|
+
repeated silently.
|
|
314
|
+
|
|
315
|
+
You can still invoke each step manually (`/cc-ops retro`, `/cc-ops
|
|
316
|
+
compound`, `/cc-ops archive`), but for the default path you do not need
|
|
317
|
+
to: `/cc-next` is the only command.
|
|
298
318
|
|
|
299
319
|
---
|
|
300
320
|
|
|
@@ -355,7 +375,8 @@ npx cclaw-cli --version
|
|
|
355
375
|
For CI or scripted installs, `cclaw-cli init --harnesses=<list>
|
|
356
376
|
--no-interactive` is the non-interactive form. All other tunables
|
|
357
377
|
(prompt-guard strictness, TDD enforcement, language rule packs, track
|
|
358
|
-
heuristics) are set by editing `.cclaw/config.yaml` directly
|
|
378
|
+
heuristics) are set by editing `.cclaw/config.yaml` directly — see
|
|
379
|
+
[`docs/config.md`](./docs/config.md) for the full key reference.
|
|
359
380
|
|
|
360
381
|
---
|
|
361
382
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import type { FlowTrack, HarnessId
|
|
2
|
+
import type { FlowTrack, HarnessId } from "./types.js";
|
|
3
3
|
import type { EvalMode } from "./eval/types.js";
|
|
4
4
|
type CommandName = "init" | "sync" | "doctor" | "upgrade" | "uninstall" | "archive" | "eval";
|
|
5
5
|
interface ParsedArgs {
|
|
6
6
|
command?: CommandName;
|
|
7
7
|
harnesses?: HarnessId[];
|
|
8
8
|
track?: FlowTrack;
|
|
9
|
-
profile?: InitProfile;
|
|
10
9
|
dryRun?: boolean;
|
|
11
10
|
interactive?: boolean;
|
|
12
11
|
reconcileGates?: boolean;
|
|
@@ -40,6 +39,5 @@ interface ParsedArgs {
|
|
|
40
39
|
export declare function usage(): string;
|
|
41
40
|
declare function parseHarnesses(raw: string): HarnessId[];
|
|
42
41
|
declare function parseTrack(raw: string): FlowTrack;
|
|
43
|
-
declare function parseProfile(raw: string): InitProfile;
|
|
44
42
|
declare function parseArgs(argv: string[]): ParsedArgs;
|
|
45
|
-
export { parseArgs, parseHarnesses, parseTrack
|
|
43
|
+
export { parseArgs, parseHarnesses, parseTrack };
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createReadStream, realpathSync } from "node:fs";
|
|
2
|
+
import { createReadStream, existsSync, realpathSync } from "node:fs";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import fs from "node:fs/promises";
|
|
5
5
|
import process from "node:process";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { FLOW_TRACKS, HARNESS_IDS
|
|
9
|
+
import { FLOW_TRACKS, HARNESS_IDS } from "./types.js";
|
|
10
10
|
import { doctorChecks, doctorSucceeded } from "./doctor.js";
|
|
11
11
|
import { initCclaw, syncCclaw, uninstallCclaw, upgradeCclaw } from "./install.js";
|
|
12
12
|
import { error, info } from "./logger.js";
|
|
13
13
|
import { archiveRun } from "./runs.js";
|
|
14
14
|
import { CCLAW_VERSION, RUNTIME_ROOT } from "./constants.js";
|
|
15
|
-
import { createDefaultConfig
|
|
15
|
+
import { createDefaultConfig } from "./config.js";
|
|
16
16
|
import { detectHarnesses } from "./init-detect.js";
|
|
17
17
|
import { HARNESS_ADAPTERS } from "./harness-adapters.js";
|
|
18
18
|
import { runEval } from "./eval/runner.js";
|
|
@@ -21,7 +21,6 @@ import { writeBaselinesFromReport } from "./eval/baseline.js";
|
|
|
21
21
|
import { writeJsonReport, writeMarkdownReport } from "./eval/report.js";
|
|
22
22
|
import { formatDiffMarkdown, runEvalDiff } from "./eval/diff.js";
|
|
23
23
|
import { ensureRunDir, generateRunId, isRunAlive, listRuns, readRunStatus, resolveRunId, runLogPath, writeRunStatus } from "./eval/runs.js";
|
|
24
|
-
import { EVAL_MODES } from "./eval/types.js";
|
|
25
24
|
import { parseModeInput } from "./eval/mode.js";
|
|
26
25
|
import { FLOW_STAGES } from "./types.js";
|
|
27
26
|
const INSTALLER_COMMANDS = [
|
|
@@ -37,82 +36,33 @@ export function usage() {
|
|
|
37
36
|
return `cclaw - installer-first flow toolkit
|
|
38
37
|
|
|
39
38
|
Usage:
|
|
40
|
-
cclaw
|
|
41
|
-
cclaw
|
|
42
|
-
cclaw --
|
|
39
|
+
npx cclaw-cli # launch setup or print "already installed" hint
|
|
40
|
+
npx cclaw-cli <command> [flags]
|
|
41
|
+
npx cclaw-cli --help | -h
|
|
42
|
+
npx cclaw-cli --version | -v
|
|
43
43
|
|
|
44
44
|
Commands:
|
|
45
45
|
init Bootstrap .cclaw runtime, state, and harness shims in this project.
|
|
46
|
-
Flags: --
|
|
47
|
-
--
|
|
48
|
-
|
|
49
|
-
--interactive Force interactive prompts (TTY only).
|
|
50
|
-
--no-interactive Skip interactive prompts even on TTY.
|
|
51
|
-
--dry-run Print resolved config + generated surfaces without writing files.
|
|
52
|
-
sync Regenerate harness shim files from the current .cclaw config (non-destructive).
|
|
53
|
-
doctor Run health checks against the local .cclaw runtime. Exit code 2 when any error-severity check fails.
|
|
54
|
-
Flags: --reconcile-gates Recompute current-stage gate evidence before checks.
|
|
55
|
-
--json Emit machine-readable JSON output.
|
|
56
|
-
--only=<filter> Comma list of severities/check-name filters (error,warning,info,trace:,hook:...).
|
|
57
|
-
--explain Include fix + doc reference per check in text mode.
|
|
58
|
-
--quiet Print only failing checks (and totals).
|
|
59
|
-
archive Move .cclaw/artifacts into .cclaw/runs/<date>-<slug> and reset flow state.
|
|
60
|
-
Flags: --name=<feature> Feature slug (default: inferred from 00-idea.md).
|
|
61
|
-
--skip-retro Bypass mandatory retro gate (requires --retro-reason).
|
|
62
|
-
--retro-reason=<t> Reason for bypassing retro gate.
|
|
63
|
-
eval Run cclaw evals against .cclaw/evals/corpus (Phase 7: structural verifier + baselines).
|
|
64
|
-
Flags: --stage=<id> Limit to one flow stage (${FLOW_STAGES.join("|")}) for fixture/agent modes.
|
|
65
|
-
--mode=<${EVAL_MODES.join("|")}>
|
|
66
|
-
Evaluation mode:
|
|
67
|
-
fixture = verify existing artifacts with structural/rule/judge verifiers.
|
|
68
|
-
agent = LLM drafts one stage's artifact in a sandbox with tools.
|
|
69
|
-
workflow = LLM runs the full multi-stage flow (brainstorm→plan).
|
|
70
|
-
Legacy --tier=A|B|C still works (deprecated).
|
|
71
|
-
--schema-only Run only structural verifiers (default).
|
|
72
|
-
--rules Also run rule-based verifiers (keywords, regex, counts, uniqueness, traceability).
|
|
73
|
-
--judge Run the LLM judge (median-of-N) against each case's rubric. Requires CCLAW_EVAL_API_KEY; fixture mode judges an existing artifact, agent/workflow modes draft first and then judge.
|
|
74
|
-
--dry-run Validate config + corpus, print summary, do not execute.
|
|
75
|
-
--json Emit machine-readable JSON on stdout.
|
|
76
|
-
--no-write Skip writing the report to .cclaw/evals/reports/.
|
|
77
|
-
--update-baseline Overwrite baselines from the current run (requires --confirm).
|
|
78
|
-
--confirm Acknowledge --update-baseline (prevents accidental resets).
|
|
79
|
-
--quiet Silence the stderr progress logger (default: emit one
|
|
80
|
-
line per case / stage to stderr so long runs are visible).
|
|
81
|
-
--max-cost-usd=<n> Abort the run if committed USD spend crosses <n>
|
|
82
|
-
(independent from the daily cap). Also readable from
|
|
83
|
-
CCLAW_EVAL_MAX_COST_USD.
|
|
84
|
-
--compare-model=<id> Run the same corpus twice — once with the configured model
|
|
85
|
-
and once with <id> — then diff the summaries. Exit code 1
|
|
86
|
-
when the override model regressed.
|
|
87
|
-
--background Spawn the run as a detached child process, write the
|
|
88
|
-
combined output to .cclaw/evals/runs/<id>/run.log, and
|
|
89
|
-
return immediately. Attach later with
|
|
90
|
-
\`cclaw eval runs tail <id|latest>\`.
|
|
91
|
-
|
|
92
|
-
Subcommands:
|
|
93
|
-
diff <old> <new> Compare two reports under .cclaw/evals/reports/.
|
|
94
|
-
Each argument is a cclawVersion (e.g. 0.26.0), a filename,
|
|
95
|
-
or the literal "latest". Exit code 1 when the diff shows a
|
|
96
|
-
regression. Accepts --json to emit machine-readable output.
|
|
97
|
-
runs [action] [id] Inspect background runs under .cclaw/evals/runs/.
|
|
98
|
-
Actions: list (default) | status <id|latest> | tail <id|latest>.
|
|
99
|
-
upgrade Refresh generated files in .cclaw without modifying user artifacts.
|
|
46
|
+
Flags: --harnesses=<list> Comma list of harnesses (claude,cursor,opencode,codex).
|
|
47
|
+
--no-interactive Skip interactive prompts even on TTY (for CI/scripts).
|
|
48
|
+
upgrade Refresh generated files in .cclaw. Preserves your config.yaml.
|
|
100
49
|
uninstall Remove .cclaw runtime and the generated harness shim files.
|
|
50
|
+
eval Run cclaw evals. Maintainer surface — see docs/evals.md.
|
|
51
|
+
Full flag reference: \`npx cclaw-cli eval --help\` or docs/evals.md.
|
|
101
52
|
|
|
102
53
|
Global flags:
|
|
103
54
|
-h, --help Show this help message and exit 0.
|
|
104
55
|
-v, --version Print the cclaw CLI version and exit 0.
|
|
105
56
|
|
|
106
57
|
Examples:
|
|
107
|
-
cclaw
|
|
108
|
-
cclaw
|
|
109
|
-
cclaw
|
|
110
|
-
cclaw eval --dry-run
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
cclaw eval diff 0.26.0 latest
|
|
58
|
+
npx cclaw-cli
|
|
59
|
+
npx cclaw-cli init --harnesses=claude,cursor --no-interactive
|
|
60
|
+
npx cclaw-cli upgrade
|
|
61
|
+
npx cclaw-cli eval --dry-run
|
|
62
|
+
|
|
63
|
+
Everything operational (retro, archive, worktrees, doctor, learnings)
|
|
64
|
+
happens inside your harness via slash commands. The CLI is just a
|
|
65
|
+
launcher. See README.md for the four user-facing slash commands.
|
|
116
66
|
|
|
117
67
|
Docs: https://github.com/zuevrs/cclaw
|
|
118
68
|
Issues: https://github.com/zuevrs/cclaw/issues
|
|
@@ -136,13 +86,6 @@ function parseTrack(raw) {
|
|
|
136
86
|
}
|
|
137
87
|
return trimmed;
|
|
138
88
|
}
|
|
139
|
-
function parseProfile(raw) {
|
|
140
|
-
const trimmed = raw.trim();
|
|
141
|
-
if (!INIT_PROFILES.includes(trimmed)) {
|
|
142
|
-
throw new Error(`Unknown profile: ${trimmed}. Supported: ${INIT_PROFILES.join(", ")}`);
|
|
143
|
-
}
|
|
144
|
-
return trimmed;
|
|
145
|
-
}
|
|
146
89
|
function parseLegacyTier(raw) {
|
|
147
90
|
return parseModeInput(raw.toUpperCase(), {
|
|
148
91
|
source: "cli",
|
|
@@ -165,6 +108,26 @@ function parseEvalStage(raw) {
|
|
|
165
108
|
function isInitPromptAllowed(ctx) {
|
|
166
109
|
return Boolean(process.stdin.isTTY && ctx.stdout.isTTY);
|
|
167
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Print a short, friendly hint when the user runs `cclaw-cli` with no
|
|
113
|
+
* arguments. Does not read or mutate flow state — only checks whether
|
|
114
|
+
* `.cclaw/config.yaml` exists to branch between "installed" and
|
|
115
|
+
* "not-installed" messaging. Keeps exit 0 in both cases: users discover
|
|
116
|
+
* the tool through this path, not through an error.
|
|
117
|
+
*/
|
|
118
|
+
function printNoArgsHint(ctx) {
|
|
119
|
+
const installed = existsSync(path.join(ctx.cwd, RUNTIME_ROOT, "config.yaml"));
|
|
120
|
+
if (installed) {
|
|
121
|
+
ctx.stdout.write("cclaw is installed in this project. Open your harness (Claude Code, " +
|
|
122
|
+
"Cursor, OpenCode, or Codex) and type `/cc` to start.\n");
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
ctx.stdout.write("cclaw is not installed in this project yet.\n" +
|
|
126
|
+
"Run `npx cclaw-cli init` to bootstrap .cclaw and the harness shims.\n" +
|
|
127
|
+
"For help: `npx cclaw-cli --help`.\n");
|
|
128
|
+
}
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
168
131
|
function buildInitSurfacePreview(harnesses) {
|
|
169
132
|
const lines = [
|
|
170
133
|
".cclaw/config.yaml",
|
|
@@ -206,39 +169,11 @@ function buildInitSurfacePreview(harnesses) {
|
|
|
206
169
|
}
|
|
207
170
|
return lines;
|
|
208
171
|
}
|
|
209
|
-
function inferTrackDefault(profile, track) {
|
|
210
|
-
if (track)
|
|
211
|
-
return track;
|
|
212
|
-
if (!profile)
|
|
213
|
-
return "standard";
|
|
214
|
-
return createProfileConfig(profile).defaultTrack ?? "standard";
|
|
215
|
-
}
|
|
216
172
|
async function promptInitConfig(defaults, ctx) {
|
|
217
173
|
const rl = createInterface({
|
|
218
174
|
input: process.stdin,
|
|
219
175
|
output: ctx.stdout
|
|
220
176
|
});
|
|
221
|
-
const pickSingle = async (label, options, fallback) => {
|
|
222
|
-
while (true) {
|
|
223
|
-
ctx.stdout.write(`\n${label}\n`);
|
|
224
|
-
options.forEach((option, index) => {
|
|
225
|
-
const marker = option === fallback ? " (default)" : "";
|
|
226
|
-
ctx.stdout.write(` ${index + 1}) ${option}${marker}\n`);
|
|
227
|
-
});
|
|
228
|
-
const answer = (await rl.question("> ")).trim();
|
|
229
|
-
if (answer.length === 0) {
|
|
230
|
-
return fallback;
|
|
231
|
-
}
|
|
232
|
-
const numeric = Number(answer);
|
|
233
|
-
if (Number.isInteger(numeric) && numeric >= 1 && numeric <= options.length) {
|
|
234
|
-
return options[numeric - 1];
|
|
235
|
-
}
|
|
236
|
-
if (options.includes(answer)) {
|
|
237
|
-
return answer;
|
|
238
|
-
}
|
|
239
|
-
ctx.stdout.write("Invalid selection. Use option number or value.\n");
|
|
240
|
-
}
|
|
241
|
-
};
|
|
242
177
|
const pickHarnesses = async (fallback) => {
|
|
243
178
|
const fallbackText = fallback.join(",");
|
|
244
179
|
while (true) {
|
|
@@ -260,11 +195,8 @@ async function promptInitConfig(defaults, ctx) {
|
|
|
260
195
|
}
|
|
261
196
|
};
|
|
262
197
|
try {
|
|
263
|
-
const profile = await pickSingle("Select init profile:", INIT_PROFILES, defaults.profile);
|
|
264
|
-
const trackDefault = inferTrackDefault(profile, defaults.track);
|
|
265
|
-
const track = await pickSingle("Select default flow track:", FLOW_TRACKS, trackDefault);
|
|
266
198
|
const harnesses = await pickHarnesses(defaults.harnesses);
|
|
267
|
-
return {
|
|
199
|
+
return { harnesses };
|
|
268
200
|
}
|
|
269
201
|
finally {
|
|
270
202
|
rl.close();
|
|
@@ -279,13 +211,11 @@ async function resolveInitInputs(parsed, ctx) {
|
|
|
279
211
|
const promptForbidden = parsed.interactive === false;
|
|
280
212
|
const implicitPrompt = !promptForbidden &&
|
|
281
213
|
isInitPromptAllowed(ctx) &&
|
|
282
|
-
parsed.profile === undefined &&
|
|
283
214
|
parsed.track === undefined &&
|
|
284
215
|
parsed.harnesses === undefined;
|
|
285
216
|
const shouldPrompt = promptRequested || implicitPrompt;
|
|
286
217
|
if (!shouldPrompt) {
|
|
287
218
|
return {
|
|
288
|
-
profile: parsed.profile,
|
|
289
219
|
track: parsed.track,
|
|
290
220
|
harnesses: autoHarnesses,
|
|
291
221
|
detectedHarnesses
|
|
@@ -295,14 +225,11 @@ async function resolveInitInputs(parsed, ctx) {
|
|
|
295
225
|
throw new Error("Interactive init requires a TTY. Remove --interactive or run in a terminal.");
|
|
296
226
|
}
|
|
297
227
|
const defaults = {
|
|
298
|
-
profile: parsed.profile ?? "standard",
|
|
299
|
-
track: inferTrackDefault(parsed.profile, parsed.track),
|
|
300
228
|
harnesses: autoHarnesses ?? HARNESS_IDS.slice()
|
|
301
229
|
};
|
|
302
230
|
const prompted = await promptInitConfig(defaults, ctx);
|
|
303
231
|
return {
|
|
304
|
-
|
|
305
|
-
track: prompted.track,
|
|
232
|
+
track: parsed.track,
|
|
306
233
|
harnesses: prompted.harnesses,
|
|
307
234
|
detectedHarnesses
|
|
308
235
|
};
|
|
@@ -447,7 +374,6 @@ function parseArgs(argv) {
|
|
|
447
374
|
continue;
|
|
448
375
|
}
|
|
449
376
|
if (flag.startsWith("--profile=")) {
|
|
450
|
-
parsed.profile = parseProfile(flag.replace("--profile=", ""));
|
|
451
377
|
continue;
|
|
452
378
|
}
|
|
453
379
|
if (flag === "--interactive") {
|
|
@@ -780,28 +706,20 @@ async function runCommand(parsed, ctx) {
|
|
|
780
706
|
}
|
|
781
707
|
const command = parsed.command;
|
|
782
708
|
if (!command) {
|
|
783
|
-
ctx
|
|
784
|
-
return 1;
|
|
709
|
+
return printNoArgsHint(ctx);
|
|
785
710
|
}
|
|
786
711
|
if (command === "init") {
|
|
787
712
|
const resolved = await resolveInitInputs(parsed, ctx);
|
|
788
|
-
const effectiveProfile = resolved.profile;
|
|
789
713
|
const effectiveTrack = resolved.track;
|
|
790
714
|
const effectiveHarnesses = resolved.harnesses;
|
|
791
715
|
if (parsed.dryRun === true) {
|
|
792
|
-
const previewConfig =
|
|
793
|
-
? createProfileConfig(effectiveProfile, {
|
|
794
|
-
harnesses: effectiveHarnesses,
|
|
795
|
-
defaultTrack: effectiveTrack
|
|
796
|
-
})
|
|
797
|
-
: createDefaultConfig(effectiveHarnesses, effectiveTrack);
|
|
716
|
+
const previewConfig = createDefaultConfig(effectiveHarnesses, effectiveTrack);
|
|
798
717
|
const previewSurfaces = buildInitSurfacePreview(previewConfig.harnesses);
|
|
799
718
|
info(ctx, "Dry run: no files were written.");
|
|
800
719
|
if (resolved.detectedHarnesses.length > 0 && parsed.harnesses === undefined) {
|
|
801
720
|
info(ctx, `Detected harnesses from repo: ${resolved.detectedHarnesses.join(", ")}`);
|
|
802
721
|
}
|
|
803
722
|
ctx.stdout.write(`${JSON.stringify({
|
|
804
|
-
profile: effectiveProfile ?? "standard(default)",
|
|
805
723
|
track: previewConfig.defaultTrack ?? "standard",
|
|
806
724
|
harnesses: previewConfig.harnesses,
|
|
807
725
|
promptGuardMode: previewConfig.promptGuardMode,
|
|
@@ -814,16 +732,13 @@ async function runCommand(parsed, ctx) {
|
|
|
814
732
|
await initCclaw({
|
|
815
733
|
projectRoot: ctx.cwd,
|
|
816
734
|
harnesses: effectiveHarnesses,
|
|
817
|
-
track: effectiveTrack
|
|
818
|
-
profile: effectiveProfile
|
|
735
|
+
track: effectiveTrack
|
|
819
736
|
});
|
|
820
737
|
if (resolved.detectedHarnesses.length > 0 && parsed.harnesses === undefined) {
|
|
821
738
|
info(ctx, `Detected harnesses from repo: ${resolved.detectedHarnesses.join(", ")}`);
|
|
822
739
|
}
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
const suffix = profileNote || trackNote ? ` (${(profileNote + trackNote).trim()})` : "";
|
|
826
|
-
info(ctx, `Initialized .cclaw runtime and generated harness shims${suffix}`);
|
|
740
|
+
const trackNote = effectiveTrack ? ` (track=${effectiveTrack})` : "";
|
|
741
|
+
info(ctx, `Initialized .cclaw runtime and generated harness shims${trackNote}`);
|
|
827
742
|
return 0;
|
|
828
743
|
}
|
|
829
744
|
if (command === "sync") {
|
|
@@ -1043,4 +958,4 @@ function isDirectExecution() {
|
|
|
1043
958
|
if (isDirectExecution()) {
|
|
1044
959
|
void main();
|
|
1045
960
|
}
|
|
1046
|
-
export { parseArgs, parseHarnesses, parseTrack
|
|
961
|
+
export { parseArgs, parseHarnesses, parseTrack };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import type { FlowTrack, HarnessId,
|
|
1
|
+
import type { FlowTrack, HarnessId, VibyConfig } from "./types.js";
|
|
2
2
|
export declare function configPath(projectRoot: string): string;
|
|
3
3
|
export declare function createDefaultConfig(harnesses?: HarnessId[], defaultTrack?: FlowTrack): VibyConfig;
|
|
4
|
-
/**
|
|
5
|
-
* Build a VibyConfig for a named init profile. Profile defaults are applied
|
|
6
|
-
* first, then any explicit overrides (CLI flags) win. This keeps the profile
|
|
7
|
-
* contract deterministic and testable.
|
|
8
|
-
*/
|
|
9
|
-
export declare function createProfileConfig(profile: InitProfile, overrides?: {
|
|
10
|
-
harnesses?: HarnessId[];
|
|
11
|
-
defaultTrack?: FlowTrack;
|
|
12
|
-
languageRulePacks?: LanguageRulePack[];
|
|
13
|
-
}): VibyConfig;
|
|
14
4
|
export declare function readConfig(projectRoot: string): Promise<VibyConfig>;
|
|
15
5
|
export declare function writeConfig(projectRoot: string, config: VibyConfig): Promise<void>;
|
package/dist/config.js
CHANGED
|
@@ -67,46 +67,6 @@ export function createDefaultConfig(harnesses = DEFAULT_HARNESSES, defaultTrack
|
|
|
67
67
|
languageRulePacks: []
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Build a VibyConfig for a named init profile. Profile defaults are applied
|
|
72
|
-
* first, then any explicit overrides (CLI flags) win. This keeps the profile
|
|
73
|
-
* contract deterministic and testable.
|
|
74
|
-
*/
|
|
75
|
-
export function createProfileConfig(profile, overrides = {}) {
|
|
76
|
-
const base = createDefaultConfig();
|
|
77
|
-
switch (profile) {
|
|
78
|
-
case "minimal":
|
|
79
|
-
return {
|
|
80
|
-
...base,
|
|
81
|
-
harnesses: overrides.harnesses ?? ["claude"],
|
|
82
|
-
promptGuardMode: "advisory",
|
|
83
|
-
tddEnforcement: "advisory",
|
|
84
|
-
gitHookGuards: false,
|
|
85
|
-
defaultTrack: overrides.defaultTrack ?? "medium",
|
|
86
|
-
languageRulePacks: overrides.languageRulePacks ?? []
|
|
87
|
-
};
|
|
88
|
-
case "standard":
|
|
89
|
-
return {
|
|
90
|
-
...base,
|
|
91
|
-
harnesses: overrides.harnesses ?? DEFAULT_HARNESSES,
|
|
92
|
-
promptGuardMode: "advisory",
|
|
93
|
-
tddEnforcement: "advisory",
|
|
94
|
-
gitHookGuards: false,
|
|
95
|
-
defaultTrack: overrides.defaultTrack ?? "standard",
|
|
96
|
-
languageRulePacks: overrides.languageRulePacks ?? []
|
|
97
|
-
};
|
|
98
|
-
case "full":
|
|
99
|
-
return {
|
|
100
|
-
...base,
|
|
101
|
-
harnesses: overrides.harnesses ?? DEFAULT_HARNESSES,
|
|
102
|
-
promptGuardMode: "strict",
|
|
103
|
-
tddEnforcement: "strict",
|
|
104
|
-
gitHookGuards: true,
|
|
105
|
-
defaultTrack: overrides.defaultTrack ?? "standard",
|
|
106
|
-
languageRulePacks: overrides.languageRulePacks ?? [...LANGUAGE_RULE_PACKS]
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
70
|
export async function readConfig(projectRoot) {
|
|
111
71
|
const fullPath = configPath(projectRoot);
|
|
112
72
|
if (!(await exists(fullPath))) {
|
|
@@ -15,35 +15,46 @@ export function archiveCommandContract() {
|
|
|
15
15
|
|
|
16
16
|
## Purpose
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Finalize the active cclaw run: move artifacts to \`${runsPath()}/<archive-id>\`,
|
|
19
|
+
snapshot state, write a manifest, and reset runtime for the next run.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
Auto-triggered by \`/cc-next\` when \`closeout.shipSubstate === "ready_to_archive"\`.
|
|
22
|
+
Direct invocation from a harness command is supported but rarely needed.
|
|
22
23
|
|
|
23
24
|
## HARD-GATE
|
|
24
25
|
|
|
25
|
-
- Do not archive
|
|
26
|
-
- Do not
|
|
27
|
-
|
|
26
|
+
- Do not archive with \`closeout.shipSubstate !== "ready_to_archive"\`.
|
|
27
|
+
- Do not archive a shipped run when \`retro.completedAt\` is missing and
|
|
28
|
+
\`closeout.retroSkipped !== true\`.
|
|
29
|
+
- Never hand-move files between \`${activeArtifactsPath()}\` and \`${runsPath()}\`.
|
|
30
|
+
Always run the archive runtime command so the snapshot+manifest stay
|
|
31
|
+
atomic.
|
|
28
32
|
|
|
29
33
|
## Inputs
|
|
30
34
|
|
|
31
|
-
\`/cc-ops archive [--name=<slug>]
|
|
35
|
+
\`/cc-ops archive [--name=<slug>]\`
|
|
36
|
+
|
|
37
|
+
(Legacy flags \`--skip-retro --retro-reason=<text>\` still exist for CLI
|
|
38
|
+
invocations; in-harness the skip path is driven by \`closeout.retroSkipped\`
|
|
39
|
+
set during retro.)
|
|
32
40
|
|
|
33
41
|
## Algorithm
|
|
34
42
|
|
|
35
43
|
1. Read \`${flowStatePath()}\`.
|
|
36
|
-
2.
|
|
37
|
-
|
|
44
|
+
2. Verify \`closeout.shipSubstate === "ready_to_archive"\`. If not, report
|
|
45
|
+
\`closeout not ready (state=<substate>) | run: /cc-next\` and stop.
|
|
38
46
|
3. Build archive command:
|
|
39
|
-
- base: \`npx cclaw archive
|
|
40
|
-
- optional: \`--name=<slug
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
- base: \`npx cclaw archive\`,
|
|
48
|
+
- optional: \`--name=<slug>\`,
|
|
49
|
+
- legacy override: \`--skip-retro --retro-reason=<text>\` (only when user
|
|
50
|
+
explicitly wants the CLI skip path).
|
|
51
|
+
4. Execute the archive command in project root.
|
|
52
|
+
5. On success, flow-state is reset to the initial stage for the default
|
|
53
|
+
track; \`closeout.shipSubstate\` returns to \`"idle"\` on reset.
|
|
54
|
+
6. Surface:
|
|
44
55
|
- archive id/path,
|
|
45
|
-
- reset stage
|
|
46
|
-
- knowledge curation hint when
|
|
56
|
+
- reset stage,
|
|
57
|
+
- knowledge curation hint when \`activeEntryCount >= softThreshold\`.
|
|
47
58
|
|
|
48
59
|
## Output format
|
|
49
60
|
|
|
@@ -63,36 +74,51 @@ cclaw archive
|
|
|
63
74
|
export function archiveCommandSkillMarkdown() {
|
|
64
75
|
return `---
|
|
65
76
|
name: ${ARCHIVE_SKILL_NAME}
|
|
66
|
-
description: "
|
|
77
|
+
description: "Finalize the active cclaw run. Auto-triggered by /cc-next when shipSubstate=ready_to_archive."
|
|
67
78
|
---
|
|
68
79
|
|
|
69
80
|
# /cc-ops archive
|
|
70
81
|
|
|
71
82
|
## HARD-GATE
|
|
72
83
|
|
|
73
|
-
Never simulate archive by hand-editing runtime files. Always execute the
|
|
74
|
-
runtime command so state snapshots and manifest generation stay
|
|
84
|
+
Never simulate archive by hand-editing runtime files. Always execute the
|
|
85
|
+
archive runtime command so state snapshots and manifest generation stay
|
|
86
|
+
atomic. Never bypass the substate check — if retro/compound haven't
|
|
87
|
+
advanced the substate to \`ready_to_archive\`, stop and surface the
|
|
88
|
+
mismatch.
|
|
75
89
|
|
|
76
90
|
## Protocol
|
|
77
91
|
|
|
78
92
|
1. Read \`${flowStatePath()}\`:
|
|
79
|
-
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
- if \`closeout.shipSubstate !== "ready_to_archive"\`, stop and route
|
|
94
|
+
the user back to \`/cc-next\` (it will resume at the correct step),
|
|
95
|
+
- sanity-check: \`completedStages\` must include \`"ship"\`,
|
|
96
|
+
- sanity-check: \`retro.completedAt\` is set **or**
|
|
97
|
+
\`closeout.retroSkipped === true\` with a reason.
|
|
98
|
+
2. Build shell command:
|
|
99
|
+
- \`npx cclaw archive\`,
|
|
100
|
+
- append \`--name=<slug>\` when provided,
|
|
101
|
+
- append legacy \`--skip-retro --retro-reason=<text>\` only when the user
|
|
102
|
+
explicitly requests the CLI skip path (normally not needed — skip is
|
|
103
|
+
captured in \`closeout\` during retro).
|
|
104
|
+
3. Run command from repo root.
|
|
105
|
+
4. Relay key lines from output:
|
|
106
|
+
- archive destination under \`${runsPath()}\`,
|
|
107
|
+
- flow reset confirmation,
|
|
108
|
+
- knowledge curation recommendation if \`activeEntryCount >= 50\`.
|
|
109
|
+
|
|
110
|
+
## Resume semantics
|
|
111
|
+
|
|
112
|
+
Archive is idempotent on a per-run basis. If a previous session ran
|
|
113
|
+
archive successfully, the active artifacts directory is empty and
|
|
114
|
+
\`closeout.shipSubstate\` is \`"idle"\`; \`/cc-next\` will simply report
|
|
115
|
+
"Flow complete" or prompt for a new \`/cc\` input.
|
|
91
116
|
|
|
92
117
|
## Validation
|
|
93
118
|
|
|
94
|
-
- \`${runsPath()}\` contains a new archive folder.
|
|
119
|
+
- \`${runsPath()}\` contains a new archive folder for this run.
|
|
95
120
|
- \`${activeArtifactsPath()}\` is reset for the next run.
|
|
96
121
|
- \`${flowStatePath()}\` is valid JSON and points to the initial stage.
|
|
122
|
+
- \`closeout.shipSubstate === "idle"\` after reset.
|
|
97
123
|
`;
|
|
98
124
|
}
|