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 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) and `01-brainstorm.md` through `08-ship.md`
203
- (plus `09-retro.md` at automatic closeout see below).
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 can emit entries to `knowledge.jsonl` not only retro. Strict
257
- JSONL schema keeps it machine-queryable.
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` and then closes out the feature through a
283
- guided three-step sequence:
284
-
285
- 1. **Retro** drafts `09-retro.md` from flow artifacts and the delegation
286
- log; you review and accept.
287
- 2. **Compound pass** promotes repeated knowledge entries (frequency ≥ 2,
288
- maturity = stable) into first-class rules or skills.
289
- 3. **Archive** moves artifacts to `.cclaw/runs/YYYY-MM-DD-<slug>/` and
290
- resets `flow-state.json`.
291
-
292
- Retro is not optional archive is gated on retro completion so you can't
293
- silently lose the learning pass.
294
-
295
- > **Coming next:** cclaw will chain these three steps automatically from
296
- > `ship` (one structured `edit`/`accept`/`skip` ask, resumable if the
297
- > session ends). Tracked as the v0.32 closeout-automation wave.
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, InitProfile } from "./types.js";
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, parseProfile };
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, INIT_PROFILES } from "./types.js";
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, createProfileConfig } from "./config.js";
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 <command> [flags]
41
- cclaw --help | -h
42
- cclaw --version | -v
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: --profile=<id> Pre-fill defaults. One of: minimal | standard | full. Default: standard.
47
- --harnesses=<list> Comma list of harnesses (claude,cursor,opencode,codex). Overrides the profile default.
48
- --track=<id> Flow track for new runs (standard | medium | quick). Overrides the profile default.
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 init --harnesses=claude,cursor
108
- cclaw doctor --reconcile-gates
109
- cclaw archive --name=payments-revamp
110
- cclaw eval --dry-run
111
- cclaw eval --stage=brainstorm --schema-only
112
- cclaw eval --judge --mode=fixture --stage=brainstorm
113
- cclaw eval --judge --mode=agent --stage=spec
114
- cclaw eval --mode=workflow --judge
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 { profile, track, harnesses };
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
- profile: prompted.profile,
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.stderr.write(usage());
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 = effectiveProfile
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 profileNote = effectiveProfile ? ` profile=${effectiveProfile}` : "";
824
- const trackNote = effectiveTrack ? ` track=${effectiveTrack}` : "";
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, parseProfile };
961
+ export { parseArgs, parseHarnesses, parseTrack };
package/dist/config.d.ts CHANGED
@@ -1,15 +1,5 @@
1
- import type { FlowTrack, HarnessId, InitProfile, LanguageRulePack, VibyConfig } from "./types.js";
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
- Archive the active cclaw run from inside the harness flow (agent-first finish).
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
- This command removes the user-facing CLI gap: users can stay in \`/cc-*\` flow and
21
- finish with \`/cc-ops archive\` after ship + retro are complete.
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 a shipped run when retro is still incomplete.
26
- - Do not manually move files between \`${activeArtifactsPath()}\` and \`${runsPath()}\`.
27
- - Use the archive runtime so state snapshots + manifest stay consistent.
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>] [--skip-retro --retro-reason=<text>]\`
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. If ship is complete and \`retro.completedAt\` is absent:
37
- - block with explicit instruction: run \`/cc-ops retro\` first.
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
- - optional override: \`--skip-retro --retro-reason=<text>\`
42
- 4. Execute archive command in project root.
43
- 5. Surface result:
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 (brainstorm/spec depending on track default),
46
- - knowledge curation hint when threshold exceeded.
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: "Archive the active cclaw run from harness flow and reset runtime safely."
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 archive
74
- runtime command so state snapshots and manifest generation stay atomic.
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
- - confirm whether ship is completed,
80
- - check \`retro.completedAt\` for post-ship runs.
81
- 2. If ship complete and retro incomplete -> stop and direct user to \`/cc-ops retro\`.
82
- 3. Build shell command:
83
- - \`npx cclaw archive\`
84
- - append \`--name=<slug>\` when provided
85
- - append \`--skip-retro --retro-reason=<text>\` only when user explicitly requests skip
86
- 4. Run command from repo root.
87
- 5. Relay key lines from output:
88
- - archive destination under \`${runsPath()}\`
89
- - flow reset confirmation
90
- - knowledge curation recommendation
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
  }