cclaw-cli 6.14.4 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +0 -2
  2. package/dist/artifact-linter/brainstorm.js +1 -1
  3. package/dist/artifact-linter/design.js +2 -2
  4. package/dist/artifact-linter/findings-dedup.js +1 -1
  5. package/dist/artifact-linter/plan.js +6 -6
  6. package/dist/artifact-linter/review-army.d.ts +1 -1
  7. package/dist/artifact-linter/review-army.js +1 -1
  8. package/dist/artifact-linter/scope.js +6 -6
  9. package/dist/artifact-linter/shared.d.ts +37 -73
  10. package/dist/artifact-linter/shared.js +30 -37
  11. package/dist/artifact-linter/spec.js +1 -1
  12. package/dist/artifact-linter/tdd.d.ts +20 -33
  13. package/dist/artifact-linter/tdd.js +89 -639
  14. package/dist/artifact-linter.js +11 -32
  15. package/dist/cli.js +1 -1
  16. package/dist/config.js +1 -1
  17. package/dist/constants.js +1 -1
  18. package/dist/content/core-agents.d.ts +8 -26
  19. package/dist/content/core-agents.js +48 -94
  20. package/dist/content/examples.d.ts +1 -1
  21. package/dist/content/examples.js +4 -4
  22. package/dist/content/hooks.js +62 -149
  23. package/dist/content/idea.js +2 -2
  24. package/dist/content/iron-laws.js +1 -1
  25. package/dist/content/node-hooks.js +2 -2
  26. package/dist/content/skills-elicitation.js +2 -2
  27. package/dist/content/skills.d.ts +4 -6
  28. package/dist/content/skills.js +14 -53
  29. package/dist/content/stage-schema.d.ts +3 -3
  30. package/dist/content/stage-schema.js +8 -46
  31. package/dist/content/stages/brainstorm.js +5 -5
  32. package/dist/content/stages/plan.js +2 -2
  33. package/dist/content/stages/review.js +1 -1
  34. package/dist/content/stages/schema-types.d.ts +1 -1
  35. package/dist/content/stages/scope.js +1 -1
  36. package/dist/content/stages/spec.js +2 -2
  37. package/dist/content/stages/tdd.js +43 -108
  38. package/dist/content/start-command.js +3 -3
  39. package/dist/content/subagent-context-skills.js +5 -3
  40. package/dist/content/subagents.js +13 -74
  41. package/dist/content/templates.d.ts +6 -6
  42. package/dist/content/templates.js +23 -24
  43. package/dist/content/utility-skills.d.ts +1 -1
  44. package/dist/content/utility-skills.js +1 -1
  45. package/dist/delegation.d.ts +79 -139
  46. package/dist/delegation.js +83 -215
  47. package/dist/early-loop.js +1 -1
  48. package/dist/flow-state.d.ts +24 -129
  49. package/dist/flow-state.js +5 -30
  50. package/dist/gate-evidence.d.ts +2 -7
  51. package/dist/gate-evidence.js +2 -59
  52. package/dist/harness-adapters.d.ts +1 -1
  53. package/dist/harness-adapters.js +11 -10
  54. package/dist/install.js +28 -460
  55. package/dist/internal/advance-stage/advance.d.ts +5 -5
  56. package/dist/internal/advance-stage/advance.js +9 -24
  57. package/dist/internal/advance-stage/parsers.d.ts +1 -1
  58. package/dist/internal/advance-stage/review-loop.d.ts +1 -1
  59. package/dist/internal/advance-stage/review-loop.js +3 -3
  60. package/dist/internal/advance-stage/start-flow.js +1 -3
  61. package/dist/internal/advance-stage.js +4 -23
  62. package/dist/internal/cohesion-contract-stub.d.ts +8 -13
  63. package/dist/internal/cohesion-contract-stub.js +18 -24
  64. package/dist/internal/flow-state-repair.d.ts +1 -1
  65. package/dist/internal/plan-split-waves.d.ts +18 -21
  66. package/dist/internal/plan-split-waves.js +16 -19
  67. package/dist/internal/wave-status.d.ts +3 -6
  68. package/dist/internal/wave-status.js +5 -27
  69. package/dist/policy.js +1 -1
  70. package/dist/run-persistence.js +10 -44
  71. package/dist/runtime/run-hook.mjs +3 -3
  72. package/dist/track-heuristics.js +1 -1
  73. package/dist/types.d.ts +2 -2
  74. package/package.json +1 -1
  75. package/dist/integration-fanin.d.ts +0 -44
  76. package/dist/integration-fanin.js +0 -180
  77. package/dist/internal/set-checkpoint-mode.d.ts +0 -16
  78. package/dist/internal/set-checkpoint-mode.js +0 -72
  79. package/dist/internal/set-integration-overseer-mode.d.ts +0 -14
  80. package/dist/internal/set-integration-overseer-mode.js +0 -69
  81. package/dist/internal/set-worktree-mode.d.ts +0 -10
  82. package/dist/internal/set-worktree-mode.js +0 -28
  83. package/dist/worktree-manager.d.ts +0 -50
  84. package/dist/worktree-manager.js +0 -136
  85. package/dist/worktree-types.d.ts +0 -36
  86. package/dist/worktree-types.js +0 -6
package/dist/install.js CHANGED
@@ -25,16 +25,16 @@ import { LANGUAGE_RULE_PACK_DIR, LEGACY_LANGUAGE_RULE_PACK_FOLDERS } from "./con
25
25
  import { RESEARCH_PLAYBOOKS } from "./content/research-playbooks.js";
26
26
  import { SUBAGENT_CONTEXT_SKILLS } from "./content/subagent-context-skills.js";
27
27
  import { CCLAW_AGENTS } from "./content/core-agents.js";
28
- import { createInitialFlowState, effectiveWorktreeExecutionMode } from "./flow-state.js";
28
+ import { createInitialFlowState } from "./flow-state.js";
29
29
  import { ensureDir, exists, writeFileSafe } from "./fs-utils.js";
30
- import { ManagedResourceSession, setActiveManagedResourceSession } from "./managed-resources.js";
30
+ import { ManagedResourceSession, readManagedResourceManifest, setActiveManagedResourceSession } from "./managed-resources.js";
31
31
  import { ensureGitignore, removeGitignorePatterns } from "./gitignore.js";
32
32
  import { HARNESS_ADAPTERS, harnessShimFileNames, harnessShimSkillNames, syncHarnessShims, removeCclawFromAgentsMd } from "./harness-adapters.js";
33
33
  import { validateHookDocument } from "./hook-schema.js";
34
34
  import { detectHarnesses } from "./init-detect.js";
35
35
  import { classifyCodexHooksFlag, codexConfigPath, readCodexConfig } from "./codex-feature-flag.js";
36
- import { CorruptFlowStateError, ensureRunSystem, readFlowState, writeFlowState } from "./runs.js";
37
- import { PLAN_SPLIT_DEFAULT_WAVE_SIZE, buildParallelExecutionPlanSection, formatNextParallelWaveSyncHint, mergeParallelWaveDefinitions, parseParallelExecutionPlanWaves, parseWavePlanDirectory, planArtifactLacksV613ParallelMetadata, upsertParallelExecutionPlanSection } from "./internal/plan-split-waves.js";
36
+ import { CorruptFlowStateError, ensureRunSystem } from "./runs.js";
37
+ import { formatNextParallelWaveSyncHint, mergeParallelWaveDefinitions, parseParallelExecutionPlanWaves, parseWavePlanDirectory } from "./internal/plan-split-waves.js";
38
38
  import { FLOW_STAGES } from "./types.js";
39
39
  const OPENCODE_PLUGIN_REL_PATH = ".opencode/plugins/cclaw-plugin.mjs";
40
40
  const CURSOR_RULE_REL_PATH = ".cursor/rules/cclaw-workflow.mdc";
@@ -125,7 +125,10 @@ const DEPRECATED_AGENT_FILES = [
125
125
  "learnings-researcher.md",
126
126
  "framework-docs-researcher.md",
127
127
  "best-practices-researcher.md",
128
- "git-history-analyzer.md"
128
+ "git-history-analyzer.md",
129
+ "test-author.md",
130
+ "slice-implementer.md",
131
+ "slice-documenter.md"
129
132
  ];
130
133
  const DEPRECATED_COMMAND_FILES = [
131
134
  "learn.md",
@@ -165,16 +168,12 @@ const DEPRECATED_STATE_FILES = [
165
168
  "context-mode.json",
166
169
  "session-digest.md",
167
170
  "context-warnings.jsonl",
168
- // Runtime Honesty 6.9.0 removed the per-run TDD cycle JSONL: gate evidence
169
- // now reads cycle phase progression directly from the artifact table.
170
171
  "tdd-cycle-log.jsonl"
171
172
  ];
172
- // v6.11.0 (R5): files under `<runtime>/artifacts/` that previous releases
173
- // generated and v6.11.0 removed. `cclaw-cli sync` deletes each so existing
173
+ // Files under `<runtime>/artifacts/` that older releases generated and
174
+ // the current release removes. `cclaw-cli sync` deletes each so existing
174
175
  // installs lose the obsolete sidecar without requiring manual cleanup.
175
176
  const DEPRECATED_ARTIFACT_FILES = [
176
- // v6.10.0 sidecar — replaced in v6.11.0 by phase events in
177
- // delegation-events.jsonl + auto-rendered tables in 06-tdd.md.
178
177
  "06-tdd-slices.jsonl"
179
178
  ];
180
179
  const DEPRECATED_HOOK_FILES = [
@@ -207,10 +206,10 @@ async function resolveGitHooksDir(projectRoot) {
207
206
  return null;
208
207
  }
209
208
  }
210
- // Legacy cleanup: prior versions installed Node-based git pre-commit/pre-push relays
211
- // under .git/hooks/* and a runtime tree at .cclaw/hooks/git/. Runtime Honesty 6.9.0
212
- // removed managed git hooks entirely; the cleanup below stays so existing installs
213
- // shed the leftover files on next sync/uninstall.
209
+ // Older versions installed Node-based git pre-commit/pre-push relays under
210
+ // `.git/hooks/*` and a runtime tree at `.cclaw/hooks/git/`. cclaw no longer
211
+ // manages git hooks; the cleanup below stays so existing installs shed the
212
+ // leftover files on next sync/uninstall.
214
213
  const LEGACY_GIT_HOOK_MANAGED_MARKER = "cclaw-managed-git-hook";
215
214
  const LEGACY_GIT_HOOK_RUNTIME_REL_DIR = `${RUNTIME_ROOT}/hooks/git`;
216
215
  async function cleanupLegacyManagedGitHookRelays(projectRoot) {
@@ -257,10 +256,12 @@ async function writeWavePlansScaffold(projectRoot) {
257
256
  }
258
257
  async function writeSkills(projectRoot, config) {
259
258
  void config;
259
+ const manifest = await readManagedResourceManifest(projectRoot).catch(() => null);
260
+ const packageVersion = manifest?.packageVersion ?? null;
260
261
  const skillTrack = "standard";
261
262
  for (const stage of FLOW_STAGES) {
262
263
  const folder = stageSkillFolder(stage);
263
- await writeFileSafe(runtimePath(projectRoot, "skills", folder, "SKILL.md"), stageSkillMarkdown(stage, skillTrack));
264
+ await writeFileSafe(runtimePath(projectRoot, "skills", folder, "SKILL.md"), stageSkillMarkdown(stage, skillTrack, packageVersion));
264
265
  }
265
266
  // Utility skills (not flow stages)
266
267
  await writeFileSafe(runtimePath(projectRoot, "skills", "learnings", "SKILL.md"), learnSkillMarkdown());
@@ -285,7 +286,6 @@ async function writeSkills(projectRoot, config) {
285
286
  for (const [folderName, markdown] of Object.entries(SUBAGENT_CONTEXT_SKILLS)) {
286
287
  await writeFileSafe(runtimePath(projectRoot, "skills", folderName, "SKILL.md"), markdown);
287
288
  }
288
- // Wave 21: language packs are no longer materialized from config.
289
289
  await fs.rm(runtimePath(projectRoot, ...LANGUAGE_RULE_PACK_DIR), { recursive: true, force: true });
290
290
  for (const legacyFolder of LEGACY_LANGUAGE_RULE_PACK_FOLDERS) {
291
291
  const legacyPath = runtimePath(projectRoot, "skills", legacyFolder);
@@ -735,13 +735,12 @@ async function writeHooks(projectRoot, config) {
735
735
  await writeMergedHookJson(projectRoot, path.join(cursorDir, "hooks.json"), cursorHooksJson());
736
736
  }
737
737
  else if (harness === "codex") {
738
- // Codex CLI v0.114 (Mar 2026) supports lifecycle hooks at
739
- // `.codex/hooks.json`, gated behind the `[features] codex_hooks = true`
740
- // flag in `~/.codex/config.toml`. cclaw always writes the file so
741
- // the moment the flag flips on, the cclaw hooks start firing. See
742
- // `codexHooksJsonWithObservation` for the Bash-only caveat on
743
- // PreToolUse/PostToolUse. If the feature flag is off, hooks remain
744
- // inert until the user enables codex_hooks in ~/.codex/config.toml.
738
+ // Codex CLI lifecycle hooks live at `.codex/hooks.json`, gated by
739
+ // `[features] codex_hooks = true` in `~/.codex/config.toml`. cclaw
740
+ // always writes the file so the moment the flag flips on, cclaw
741
+ // hooks start firing. PreToolUse/PostToolUse remain Bash-only on
742
+ // Codex; if the feature flag is off, hooks stay inert until the
743
+ // user enables `codex_hooks` in `~/.codex/config.toml`.
745
744
  const codexDir = path.join(projectRoot, ".codex");
746
745
  await ensureDir(codexDir);
747
746
  await writeMergedHookJson(projectRoot, path.join(codexDir, "hooks.json"), codexHooksJson());
@@ -784,10 +783,6 @@ async function writeCursorWorkflowRule(projectRoot, harnesses) {
784
783
  }
785
784
  async function syncDisabledHarnessArtifacts(projectRoot, harnesses) {
786
785
  const enabled = new Set(harnesses);
787
- // v0.40.0: `.codex/hooks.json` is back on the managed list now that
788
- // Codex CLI actually consumes it (v0.114+, Mar 2026). Legacy
789
- // `.codex/commands/` cleanup still happens unconditionally from
790
- // `cleanupLegacyCodexSurfaces` inside `syncHarnessShims`.
791
786
  const managedHookFiles = [
792
787
  { harness: "claude", hookPath: path.join(projectRoot, ".claude/hooks/hooks.json") },
793
788
  { harness: "cursor", hookPath: path.join(projectRoot, ".cursor/hooks.json") },
@@ -836,414 +831,6 @@ async function writeState(projectRoot, config, forceReset = false) {
836
831
  const state = createInitialFlowState({ track: "standard" });
837
832
  await writeFileSafe(statePath, `${JSON.stringify(state, null, 2)}\n`, { mode: 0o600 });
838
833
  }
839
- /**
840
- * v6.12.0 — TDD auto-cutover sync. When sync detects a legacy `06-tdd.md`
841
- * (no auto-render markers) carrying observable slice activity (e.g. `S-N`
842
- * referenced ≥3 times in slice-section bodies), insert the v6.11.0 marker
843
- * skeleton + a one-line cutover banner and stamp the highest legacy slice
844
- * id into `flow-state.json::tddCutoverSliceId`. Idempotent: re-running sync
845
- * is byte-stable once markers are present.
846
- *
847
- * Design notes:
848
- * - Best-effort: read failures, missing flow-state, or unparseable JSON
849
- * all short-circuit silently. We never throw inside sync for migration
850
- * bookkeeping.
851
- * - We use `writeFlowState({ allowReset: true })` so we don't trip
852
- * `validateFlowTransition` (the only field we mutate is the new
853
- * additive `tddCutoverSliceId`; transition rules don't apply).
854
- * - The banner mirrors the language in the `## Per-Slice Ritual`
855
- * skill section so a reader of `06-tdd.md` who hasn't seen v6.12.0
856
- * understands the contract change.
857
- */
858
- async function applyTddCutoverIfNeeded(projectRoot) {
859
- const tddArtifactPath = runtimePath(projectRoot, "artifacts", "06-tdd.md");
860
- let existing;
861
- try {
862
- existing = await fs.readFile(tddArtifactPath, "utf8");
863
- }
864
- catch {
865
- return;
866
- }
867
- if (existing.includes("<!-- auto-start: tdd-slice-summary -->")) {
868
- return;
869
- }
870
- const sliceMatches = [...existing.matchAll(/\bS-(\d+)\b/gu)];
871
- if (sliceMatches.length < 3) {
872
- return;
873
- }
874
- let maxSliceNum = 0;
875
- for (const match of sliceMatches) {
876
- const n = Number.parseInt(match[1], 10);
877
- if (Number.isFinite(n) && n > maxSliceNum) {
878
- maxSliceNum = n;
879
- }
880
- }
881
- if (maxSliceNum <= 0) {
882
- return;
883
- }
884
- const cutoverSliceId = `S-${maxSliceNum}`;
885
- const banner = [
886
- `<!-- v6.12.0 cutover: slices S-1..${cutoverSliceId} use legacy per-slice tables.`,
887
- ` New slices (S-${maxSliceNum + 1}+) use phase events + tdd-slices/<id>.md.`,
888
- " Controller MUST NOT add new rows to legacy sections. -->"
889
- ].join("\n");
890
- const slicesIndexBlock = [
891
- "<!-- auto-start: slices-index -->",
892
- "## Slices Index",
893
- "",
894
- "_Auto-rendered from `tdd-slices/S-*.md` once slice-documenter or controller writes per-slice files. Do not edit by hand._",
895
- "<!-- auto-end: slices-index -->"
896
- ].join("\n");
897
- const summaryBlock = [
898
- "<!-- auto-start: tdd-slice-summary -->",
899
- "<!-- auto-end: tdd-slice-summary -->"
900
- ].join("\n");
901
- let nextRaw;
902
- if (existing.startsWith("---\n")) {
903
- const fmEnd = existing.indexOf("\n---", 4);
904
- if (fmEnd >= 0) {
905
- const fmClose = fmEnd + 4;
906
- const head = existing.slice(0, fmClose);
907
- const tail = existing.slice(fmClose);
908
- nextRaw = `${head}\n\n${banner}\n\n${slicesIndexBlock}\n\n${summaryBlock}\n${tail}`;
909
- }
910
- else {
911
- nextRaw = `${banner}\n\n${slicesIndexBlock}\n\n${summaryBlock}\n\n${existing}`;
912
- }
913
- }
914
- else {
915
- nextRaw = `${banner}\n\n${slicesIndexBlock}\n\n${summaryBlock}\n\n${existing}`;
916
- }
917
- await writeFileSafe(tddArtifactPath, nextRaw);
918
- const slicesDir = runtimePath(projectRoot, "artifacts", "tdd-slices");
919
- await ensureDir(slicesDir);
920
- const flowStatePath = runtimePath(projectRoot, "state", "flow-state.json");
921
- let flowStateRaw;
922
- try {
923
- flowStateRaw = await fs.readFile(flowStatePath, "utf8");
924
- }
925
- catch {
926
- return;
927
- }
928
- let parsed;
929
- try {
930
- parsed = JSON.parse(flowStateRaw);
931
- }
932
- catch {
933
- return;
934
- }
935
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
936
- return;
937
- }
938
- const obj = parsed;
939
- if (typeof obj.tddCutoverSliceId === "string" && obj.tddCutoverSliceId.length > 0) {
940
- return;
941
- }
942
- // v6.14.3 — refresh the SHA256 sidecar by writing through
943
- // `writeFlowState`. The previous direct `writeFileSafe` invocation
944
- // left the sidecar stale, so the very next guarded hook on a synced
945
- // legacy project rejected its own `tddCutoverSliceId` stamp.
946
- try {
947
- const state = await readFlowState(projectRoot);
948
- await writeFlowState(projectRoot, { ...state, tddCutoverSliceId: cutoverSliceId }, {
949
- allowReset: true,
950
- writerSubsystem: "sync-v6.12-tdd-cutover-stamp"
951
- });
952
- }
953
- catch {
954
- // Best-effort: corrupt/missing state is handled elsewhere on sync.
955
- }
956
- }
957
- const V613_LEGACY_PLAN_BANNER = "<!-- legacy-continuation: predates v6.13 parallel metadata. New units MAY add dependsOn/claimedPaths/parallelizable; existing units treated as best-effort serial. -->";
958
- /**
959
- * v6.13.0 — when `05-plan.md` lacks parallel-metadata bullets on any
960
- * implementation unit, stamp `flow-state.json::legacyContinuation`, insert
961
- * a banner + managed Parallel Execution Plan stub, and keep behavior idempotent.
962
- */
963
- async function applyPlanLegacyContinuationIfNeeded(projectRoot) {
964
- const planArtifactPath = runtimePath(projectRoot, "artifacts", "05-plan.md");
965
- let existingPlan;
966
- try {
967
- existingPlan = await fs.readFile(planArtifactPath, "utf8");
968
- }
969
- catch {
970
- return;
971
- }
972
- if (!planArtifactLacksV613ParallelMetadata(existingPlan)) {
973
- return;
974
- }
975
- let nextPlan = existingPlan;
976
- if (!nextPlan.includes("legacy-continuation: predates v6.13")) {
977
- if (nextPlan.startsWith("---\n")) {
978
- const fmEnd = nextPlan.indexOf("\n---", 4);
979
- if (fmEnd >= 0) {
980
- const fmClose = fmEnd + 4;
981
- const head = nextPlan.slice(0, fmClose);
982
- const tail = nextPlan.slice(fmClose);
983
- nextPlan = `${head}\n\n${V613_LEGACY_PLAN_BANNER}\n${tail}`;
984
- }
985
- else {
986
- nextPlan = `${V613_LEGACY_PLAN_BANNER}\n\n${nextPlan}`;
987
- }
988
- }
989
- else {
990
- nextPlan = `${V613_LEGACY_PLAN_BANNER}\n\n${nextPlan}`;
991
- }
992
- }
993
- const parallelStub = buildParallelExecutionPlanSection([], PLAN_SPLIT_DEFAULT_WAVE_SIZE);
994
- if (!nextPlan.includes("<!-- parallel-exec-managed-start -->")) {
995
- nextPlan = upsertParallelExecutionPlanSection(nextPlan, parallelStub);
996
- }
997
- if (nextPlan !== existingPlan) {
998
- await writeFileSafe(planArtifactPath, nextPlan);
999
- }
1000
- const flowStatePath = runtimePath(projectRoot, "state", "flow-state.json");
1001
- if (!(await exists(flowStatePath))) {
1002
- return;
1003
- }
1004
- try {
1005
- const state = await readFlowState(projectRoot);
1006
- if (state.legacyContinuation === true) {
1007
- return;
1008
- }
1009
- await writeFlowState(projectRoot, { ...state, legacyContinuation: true }, {
1010
- allowReset: true,
1011
- writerSubsystem: "plan-legacy-continuation-sync"
1012
- });
1013
- }
1014
- catch {
1015
- // Best-effort: corrupt/missing state is handled elsewhere on sync.
1016
- }
1017
- }
1018
- /**
1019
- * v6.14.0 — set stream-style defaults on `cclaw-cli sync` and print a
1020
- * one-line hint when defaults change.
1021
- *
1022
- * v6.14.2 update — flip the legacyContinuation defaults from
1023
- * `global-red`/`always` to `per-slice`/`conditional`. Rationale: hox-shape
1024
- * projects ran into S-17 misroutes precisely because the default
1025
- * preserved the v6.12 wave barrier even after the project itself had
1026
- * moved to stream-mode. Existing flow-state values are NEVER overwritten
1027
- * — operators who want to pin `global-red`/`always` may set them
1028
- * explicitly via `cclaw-cli internal set-checkpoint-mode global-red` and
1029
- * `set-integration-overseer-mode always`.
1030
- *
1031
- * Strategy:
1032
- *
1033
- * - When `legacyContinuation: true` and `tddCheckpointMode` is unset,
1034
- * default to `tddCheckpointMode: "per-slice"` (v6.14.2 — was
1035
- * `global-red` in v6.14.0/v6.14.1).
1036
- * - When `legacyContinuation: true` and `integrationOverseerMode` is
1037
- * unset, default to `integrationOverseerMode: "conditional"` (v6.14.2
1038
- * — was `always` in v6.14.0/v6.14.1).
1039
- * - When `legacyContinuation` is NOT true (new / standard projects) and
1040
- * neither field is set, default to `tddCheckpointMode: "per-slice"`,
1041
- * `integrationOverseerMode: "conditional"`. Also default
1042
- * `worktreeExecutionMode: "worktree-first"` if unset.
1043
- *
1044
- * Returns a one-line hint string (or `null` if nothing changed) so callers
1045
- * can print it through the standard sync hint surface.
1046
- */
1047
- async function applyV614DefaultsIfNeeded(projectRoot) {
1048
- // Defensive read — match `applyTddCutoverIfNeeded`'s pattern (raw +
1049
- // JSON.parse) so corrupt state is left untouched for the downstream
1050
- // fail-fast check in `materializeRuntime` (which expects to see the
1051
- // CorruptFlowStateError surfaced via `ensureRunSystem`). Calling
1052
- // `readFlowState` directly would quarantine the corrupt file and hide
1053
- // the failure from the caller.
1054
- const flowStatePath = runtimePath(projectRoot, "state", "flow-state.json");
1055
- let flowStateRaw;
1056
- try {
1057
- flowStateRaw = await fs.readFile(flowStatePath, "utf8");
1058
- }
1059
- catch {
1060
- return null;
1061
- }
1062
- let parsed;
1063
- try {
1064
- parsed = JSON.parse(flowStateRaw);
1065
- }
1066
- catch {
1067
- return null;
1068
- }
1069
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1070
- return null;
1071
- }
1072
- const obj = parsed;
1073
- const updates = {};
1074
- const summary = [];
1075
- const tddCheckpointModeSet = obj.tddCheckpointMode === "per-slice" || obj.tddCheckpointMode === "global-red";
1076
- const integrationOverseerModeSet = obj.integrationOverseerMode === "conditional" || obj.integrationOverseerMode === "always";
1077
- const worktreeExecutionModeSet = obj.worktreeExecutionMode === "worktree-first" || obj.worktreeExecutionMode === "single-tree";
1078
- const legacyContinuation = obj.legacyContinuation === true;
1079
- if (legacyContinuation) {
1080
- if (!tddCheckpointModeSet) {
1081
- updates.tddCheckpointMode = "per-slice";
1082
- summary.push("tddCheckpointMode=per-slice (legacyContinuation, v6.14.2 default flip)");
1083
- }
1084
- if (!integrationOverseerModeSet) {
1085
- updates.integrationOverseerMode = "conditional";
1086
- summary.push("integrationOverseerMode=conditional (legacyContinuation, v6.14.2 default flip)");
1087
- }
1088
- }
1089
- else {
1090
- if (!tddCheckpointModeSet) {
1091
- updates.tddCheckpointMode = "per-slice";
1092
- summary.push("tddCheckpointMode=per-slice");
1093
- }
1094
- if (!integrationOverseerModeSet) {
1095
- updates.integrationOverseerMode = "conditional";
1096
- summary.push("integrationOverseerMode=conditional");
1097
- }
1098
- if (!worktreeExecutionModeSet) {
1099
- updates.worktreeExecutionMode = "worktree-first";
1100
- summary.push("worktreeExecutionMode=worktree-first");
1101
- }
1102
- }
1103
- if (summary.length === 0) {
1104
- return null;
1105
- }
1106
- // v6.14.3 — refresh the SHA256 sidecar in lockstep so guarded reads
1107
- // (verify-current-state, advance-stage, etc.) don't trip a guard
1108
- // mismatch immediately after `cclaw-cli sync`/`upgrade` writes the
1109
- // v6.14.2 stream-style defaults.
1110
- try {
1111
- const state = await readFlowState(projectRoot);
1112
- await writeFlowState(projectRoot, { ...state, ...updates }, {
1113
- allowReset: true,
1114
- writerSubsystem: "sync-v6.14.2-stream-defaults"
1115
- });
1116
- }
1117
- catch {
1118
- return null;
1119
- }
1120
- return `v6.14.2 stream-style defaults applied: ${summary.join(", ")}. To opt out, run cclaw-cli internal set-checkpoint-mode global-red --reason="..." and/or cclaw-cli internal set-integration-overseer-mode always --reason="...".`;
1121
- }
1122
- /**
1123
- * v6.14.2 — auto-stamp `tddWorktreeCutoverSliceId` for legacyContinuation
1124
- * projects in worktree-first mode that haven't yet recorded a boundary.
1125
- *
1126
- * Detection ("any-metadata" rule): scan the active run's
1127
- * `slice-implementer` rows. The boundary is the highest `S-N` whose
1128
- * rows for the active run lack ALL of `claimToken`, `ownerLaneId`, and
1129
- * `leasedUntil`. When no such slice exists (every slice carries at
1130
- * least one worktree field), fall back to `tddCutoverSliceId` so the
1131
- * v6.12 cutover marker still confers exemption.
1132
- *
1133
- * Idempotent: when the field is already set, returns null without
1134
- * writing. Best-effort: read failures, missing ledger, or unparseable
1135
- * rows all short-circuit silently — the existing flow-state.json is
1136
- * never corrupted.
1137
- *
1138
- * Returns a one-line hint string (or `null` if nothing changed).
1139
- */
1140
- async function applyV6142WorktreeCutoverIfNeeded(projectRoot) {
1141
- const flowStatePath = runtimePath(projectRoot, "state", "flow-state.json");
1142
- let flowStateRaw;
1143
- try {
1144
- flowStateRaw = await fs.readFile(flowStatePath, "utf8");
1145
- }
1146
- catch {
1147
- return null;
1148
- }
1149
- let parsed;
1150
- try {
1151
- parsed = JSON.parse(flowStateRaw);
1152
- }
1153
- catch {
1154
- return null;
1155
- }
1156
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1157
- return null;
1158
- }
1159
- const obj = parsed;
1160
- if (obj.legacyContinuation !== true)
1161
- return null;
1162
- if (obj.worktreeExecutionMode !== "worktree-first")
1163
- return null;
1164
- if (typeof obj.tddWorktreeCutoverSliceId === "string" &&
1165
- obj.tddWorktreeCutoverSliceId.trim().length > 0) {
1166
- return null;
1167
- }
1168
- const ledgerPath = runtimePath(projectRoot, "state", "delegation-log.json");
1169
- const activeRunId = typeof obj.activeRunId === "string" ? obj.activeRunId : "";
1170
- let ledgerRaw;
1171
- try {
1172
- ledgerRaw = await fs.readFile(ledgerPath, "utf8");
1173
- }
1174
- catch {
1175
- ledgerRaw = "";
1176
- }
1177
- let ledgerParsed = null;
1178
- if (ledgerRaw.length > 0) {
1179
- try {
1180
- ledgerParsed = JSON.parse(ledgerRaw);
1181
- }
1182
- catch {
1183
- ledgerParsed = null;
1184
- }
1185
- }
1186
- const entries = ledgerParsed &&
1187
- typeof ledgerParsed === "object" &&
1188
- !Array.isArray(ledgerParsed) &&
1189
- Array.isArray(ledgerParsed.entries)
1190
- ? ledgerParsed.entries
1191
- : [];
1192
- let boundary = -1;
1193
- for (const entry of entries) {
1194
- if (entry.agent !== "slice-implementer")
1195
- continue;
1196
- if (entry.status !== "completed")
1197
- continue;
1198
- if (typeof entry.sliceId !== "string")
1199
- continue;
1200
- if (activeRunId && entry.runId && entry.runId !== activeRunId)
1201
- continue;
1202
- const tok = typeof entry.claimToken === "string" ? entry.claimToken.trim() : "";
1203
- const lane = typeof entry.ownerLaneId === "string" ? entry.ownerLaneId.trim() : "";
1204
- const lease = typeof entry.leasedUntil === "string" ? entry.leasedUntil.trim() : "";
1205
- if (tok.length > 0 || lane.length > 0 || lease.length > 0)
1206
- continue;
1207
- const m = /^S-(\d+)$/u.exec(entry.sliceId);
1208
- if (!m)
1209
- continue;
1210
- const n = Number.parseInt(m[1], 10);
1211
- if (!Number.isFinite(n))
1212
- continue;
1213
- if (n > boundary)
1214
- boundary = n;
1215
- }
1216
- let stamped = null;
1217
- if (boundary >= 0) {
1218
- stamped = `S-${boundary}`;
1219
- }
1220
- else if (typeof obj.tddCutoverSliceId === "string" &&
1221
- /^S-\d+$/u.test(obj.tddCutoverSliceId)) {
1222
- stamped = obj.tddCutoverSliceId;
1223
- }
1224
- if (!stamped)
1225
- return null;
1226
- // v6.14.3 — go through `writeFlowState` so the SHA256 sidecar
1227
- // (`.cclaw/.flow-state.guard.json`) is refreshed in lockstep with
1228
- // the on-disk flow-state.json. The previous v6.14.2 implementation
1229
- // wrote the field via `writeFileSafe` directly, which left the
1230
- // sidecar pointing at the pre-stamp digest; the next guarded hook
1231
- // (e.g. `cclaw internal verify-current-state`) then failed with
1232
- // `flow-state guard mismatch` and demanded a manual repair.
1233
- try {
1234
- const state = await readFlowState(projectRoot);
1235
- await writeFlowState(projectRoot, { ...state, tddWorktreeCutoverSliceId: stamped }, {
1236
- allowReset: true,
1237
- writerSubsystem: "sync-v6.14.2-worktree-cutover-stamp"
1238
- });
1239
- }
1240
- catch {
1241
- return null;
1242
- }
1243
- return (`v6.14.2 stamped tddWorktreeCutoverSliceId=${stamped}; closed slices ≤ ${stamped} ` +
1244
- "are exempt from worktree-first findings under legacyContinuation. " +
1245
- "Edit .cclaw/state/flow-state.json to override (advisory).");
1246
- }
1247
834
  async function cleanLegacyArtifacts(projectRoot) {
1248
835
  for (const legacyFolder of DEPRECATED_UTILITY_SKILL_FOLDERS) {
1249
836
  await removeBestEffort(runtimePath(projectRoot, "skills", legacyFolder), true);
@@ -1381,9 +968,6 @@ async function maybeLogParallelWaveDispatchHint(projectRoot) {
1381
968
  if (!(await exists(flowPath)))
1382
969
  return;
1383
970
  try {
1384
- const state = await readFlowState(projectRoot);
1385
- if (effectiveWorktreeExecutionMode(state) !== "worktree-first")
1386
- return;
1387
971
  const planPath = runtimePath(projectRoot, "artifacts", "05-plan.md");
1388
972
  if (!(await exists(planPath)))
1389
973
  return;
@@ -1416,18 +1000,6 @@ async function materializeRuntime(projectRoot, config, forceStateReset, operatio
1416
1000
  writeRulebook(projectRoot)
1417
1001
  ]);
1418
1002
  await writeState(projectRoot, config, forceStateReset);
1419
- if (operation === "sync" || operation === "upgrade") {
1420
- await applyTddCutoverIfNeeded(projectRoot);
1421
- await applyPlanLegacyContinuationIfNeeded(projectRoot);
1422
- const v614Hint = await applyV614DefaultsIfNeeded(projectRoot);
1423
- if (v614Hint) {
1424
- process.stdout.write(`cclaw: ${v614Hint}\n`);
1425
- }
1426
- const v6142Hint = await applyV6142WorktreeCutoverIfNeeded(projectRoot);
1427
- if (v6142Hint) {
1428
- process.stdout.write(`cclaw: ${v6142Hint}\n`);
1429
- }
1430
- }
1431
1003
  try {
1432
1004
  await ensureRunSystem(projectRoot, { createIfMissing: false });
1433
1005
  }
@@ -1481,7 +1053,6 @@ export async function initCclaw(options) {
1481
1053
  throw new Error("Select at least one harness.");
1482
1054
  }
1483
1055
  const config = createDefaultConfig(options.harnesses, options.track);
1484
- // Wave 21: config is always minimal and harness-only.
1485
1056
  await writeConfig(options.projectRoot, config, { mode: "minimal" });
1486
1057
  // Init should scaffold runtime surfaces but leave flow-state creation to the
1487
1058
  // first managed start-flow invocation.
@@ -1701,14 +1272,11 @@ export async function uninstallCclaw(projectRoot) {
1701
1272
  // directory not present
1702
1273
  }
1703
1274
  }
1704
- // Codex shim location history:
1705
- // - < v0.39.0: `.codex/commands/cc*.md` (never consumed by Codex CLI)
1706
- // - v0.39.0 / v0.39.1: `.agents/skills/cclaw-cc*/SKILL.md`
1707
- // - ≥ v0.40.0: `.agents/skills/cc*/SKILL.md` (matches Codex's `/use cc`
1708
- // prompt verbatim)
1709
- // Remove all three legacy layouts on uninstall so orphans can't linger.
1710
- // We only touch cclaw-owned folder names — other tools share
1711
- // `.agents/skills/` with us.
1275
+ // Codex shims live at `.agents/skills/cc*/SKILL.md`, matching Codex's
1276
+ // `/use cc` prompt verbatim. Older layouts (`.codex/commands/cc*.md` and
1277
+ // `.agents/skills/cclaw-cc*/SKILL.md`) are purged on uninstall so orphans
1278
+ // can't linger. We only touch cclaw-owned folder names — other tools
1279
+ // share `.agents/skills/` with us.
1712
1280
  const codexSkillsRoot = path.join(projectRoot, ".agents/skills");
1713
1281
  try {
1714
1282
  const entries = await fs.readdir(codexSkillsRoot);
@@ -19,7 +19,7 @@ interface InternalValidationReport {
19
19
  corruptEventLines: number[];
20
20
  staleWorkers: string[];
21
21
  expectedMode: string;
22
- /** Wave 24: true when mandatoryAgentsFor returned [] for the run's track / taskClass. */
22
+ /** True when mandatoryAgentsFor returned [] for the run's track / taskClass. */
23
23
  skippedByTrack: boolean;
24
24
  };
25
25
  gates: {
@@ -35,23 +35,23 @@ interface InternalValidationReport {
35
35
  };
36
36
  }
37
37
  /**
38
- * Wave 24 entry point — auto-hydrate evidence for an auto-hydratable
38
+ * entry point — auto-hydrate evidence for an auto-hydratable
39
39
  * gate that the agent already included in --passed but for which they
40
40
  * forgot to provide --evidence-json. Returns silently when no
41
41
  * hydration is possible (no auto-hydratable gate, no artifact, no
42
42
  * envelope, etc.).
43
43
  *
44
- * Wave 25 (v6.1.0) layered `tryAutoHydrateAndSelectReviewLoopGate` on
44
+ * layered `tryAutoHydrateAndSelectReviewLoopGate` on
45
45
  * top of this so the gate is also auto-included in selectedGateIds
46
46
  * when the artifact yields a valid envelope. Together the two helpers
47
- * remove the contradiction the user reported in Wave 24:
47
+ * remove the contradiction:
48
48
  * - "omit this gate from --evidence-json so stage-complete can
49
49
  * auto-hydrate it" → "missing --evidence-json entries for passed
50
50
  * gates: design_diagram_freshness".
51
51
  */
52
52
  export declare function hydrateReviewLoopEvidenceFromArtifact(projectRoot: string, stage: FlowStage, track: FlowState["track"], selectedGateIds: string[], evidenceByGate: Record<string, string>): Promise<void>;
53
53
  /**
54
- * Wave 25 (v6.1.0) — auto-include an auto-hydratable review-loop gate
54
+ * auto-include an auto-hydratable review-loop gate
55
55
  * in `selectedGateIds` when:
56
56
  * - The stage has an auto-hydratable gate registered via
57
57
  * `AUTO_REVIEW_LOOP_GATE_BY_STAGE` (currently `design`).