cclaw-cli 7.7.0 → 8.1.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.
Files changed (282) hide show
  1. package/README.md +210 -134
  2. package/dist/artifact-frontmatter.d.ts +51 -0
  3. package/dist/artifact-frontmatter.js +131 -0
  4. package/dist/artifact-paths.d.ts +7 -27
  5. package/dist/artifact-paths.js +20 -249
  6. package/dist/cancel.d.ts +16 -0
  7. package/dist/cancel.js +66 -0
  8. package/dist/cli.d.ts +2 -27
  9. package/dist/cli.js +90 -508
  10. package/dist/compound.d.ts +26 -0
  11. package/dist/compound.js +96 -0
  12. package/dist/config.d.ts +14 -51
  13. package/dist/config.js +23 -359
  14. package/dist/constants.d.ts +11 -18
  15. package/dist/constants.js +19 -106
  16. package/dist/content/antipatterns.d.ts +1 -0
  17. package/dist/content/antipatterns.js +109 -0
  18. package/dist/content/artifact-templates.d.ts +10 -0
  19. package/dist/content/artifact-templates.js +550 -0
  20. package/dist/content/cancel-command.d.ts +2 -2
  21. package/dist/content/cancel-command.js +25 -17
  22. package/dist/content/core-agents.d.ts +9 -233
  23. package/dist/content/core-agents.js +39 -766
  24. package/dist/content/decision-protocol.d.ts +1 -12
  25. package/dist/content/decision-protocol.js +27 -20
  26. package/dist/content/examples.d.ts +8 -42
  27. package/dist/content/examples.js +293 -425
  28. package/dist/content/idea-command.d.ts +2 -0
  29. package/dist/content/idea-command.js +38 -0
  30. package/dist/content/iron-laws.d.ts +4 -138
  31. package/dist/content/iron-laws.js +18 -197
  32. package/dist/content/meta-skill.d.ts +1 -3
  33. package/dist/content/meta-skill.js +57 -132
  34. package/dist/content/node-hooks.d.ts +12 -8
  35. package/dist/content/node-hooks.js +188 -838
  36. package/dist/content/recovery.d.ts +8 -0
  37. package/dist/content/recovery.js +179 -0
  38. package/dist/content/reference-patterns.d.ts +4 -13
  39. package/dist/content/reference-patterns.js +260 -389
  40. package/dist/content/research-playbooks.d.ts +8 -8
  41. package/dist/content/research-playbooks.js +108 -121
  42. package/dist/content/review-loop.d.ts +6 -192
  43. package/dist/content/review-loop.js +29 -731
  44. package/dist/content/skills.d.ts +8 -38
  45. package/dist/content/skills.js +681 -732
  46. package/dist/content/specialist-prompts/architect.d.ts +1 -0
  47. package/dist/content/specialist-prompts/architect.js +225 -0
  48. package/dist/content/specialist-prompts/brainstormer.d.ts +1 -0
  49. package/dist/content/specialist-prompts/brainstormer.js +168 -0
  50. package/dist/content/specialist-prompts/index.d.ts +2 -0
  51. package/dist/content/specialist-prompts/index.js +14 -0
  52. package/dist/content/specialist-prompts/planner.d.ts +1 -0
  53. package/dist/content/specialist-prompts/planner.js +182 -0
  54. package/dist/content/specialist-prompts/reviewer.d.ts +1 -0
  55. package/dist/content/specialist-prompts/reviewer.js +193 -0
  56. package/dist/content/specialist-prompts/security-reviewer.d.ts +1 -0
  57. package/dist/content/specialist-prompts/security-reviewer.js +133 -0
  58. package/dist/content/specialist-prompts/slice-builder.d.ts +1 -0
  59. package/dist/content/specialist-prompts/slice-builder.js +232 -0
  60. package/dist/content/stage-playbooks.d.ts +8 -0
  61. package/dist/content/stage-playbooks.js +404 -0
  62. package/dist/content/start-command.d.ts +2 -12
  63. package/dist/content/start-command.js +221 -207
  64. package/dist/flow-state.d.ts +21 -178
  65. package/dist/flow-state.js +67 -170
  66. package/dist/fs-utils.d.ts +6 -26
  67. package/dist/fs-utils.js +29 -162
  68. package/dist/gitignore.d.ts +2 -1
  69. package/dist/gitignore.js +51 -34
  70. package/dist/harness-detect.d.ts +10 -0
  71. package/dist/harness-detect.js +29 -0
  72. package/dist/install.d.ts +27 -15
  73. package/dist/install.js +230 -1342
  74. package/dist/knowledge-store.d.ts +19 -163
  75. package/dist/knowledge-store.js +56 -590
  76. package/dist/logger.d.ts +8 -3
  77. package/dist/logger.js +13 -4
  78. package/dist/orchestrator-routing.d.ts +29 -0
  79. package/dist/orchestrator-routing.js +156 -0
  80. package/dist/run-persistence.d.ts +7 -118
  81. package/dist/run-persistence.js +29 -845
  82. package/dist/runtime/run-hook.entry.d.ts +1 -3
  83. package/dist/runtime/run-hook.entry.js +19 -4
  84. package/dist/runtime/run-hook.mjs +13 -1024
  85. package/dist/types.d.ts +25 -261
  86. package/dist/types.js +8 -36
  87. package/package.json +6 -3
  88. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  89. package/dist/artifact-linter/brainstorm.js +0 -353
  90. package/dist/artifact-linter/design.d.ts +0 -18
  91. package/dist/artifact-linter/design.js +0 -444
  92. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  93. package/dist/artifact-linter/findings-dedup.js +0 -232
  94. package/dist/artifact-linter/plan.d.ts +0 -2
  95. package/dist/artifact-linter/plan.js +0 -826
  96. package/dist/artifact-linter/review-army.d.ts +0 -49
  97. package/dist/artifact-linter/review-army.js +0 -520
  98. package/dist/artifact-linter/review.d.ts +0 -2
  99. package/dist/artifact-linter/review.js +0 -113
  100. package/dist/artifact-linter/scope.d.ts +0 -2
  101. package/dist/artifact-linter/scope.js +0 -158
  102. package/dist/artifact-linter/shared.d.ts +0 -637
  103. package/dist/artifact-linter/shared.js +0 -2163
  104. package/dist/artifact-linter/ship.d.ts +0 -2
  105. package/dist/artifact-linter/ship.js +0 -250
  106. package/dist/artifact-linter/spec.d.ts +0 -2
  107. package/dist/artifact-linter/spec.js +0 -176
  108. package/dist/artifact-linter/tdd.d.ts +0 -118
  109. package/dist/artifact-linter/tdd.js +0 -1404
  110. package/dist/artifact-linter.d.ts +0 -15
  111. package/dist/artifact-linter.js +0 -517
  112. package/dist/codex-feature-flag.d.ts +0 -58
  113. package/dist/codex-feature-flag.js +0 -193
  114. package/dist/content/closeout-guidance.d.ts +0 -14
  115. package/dist/content/closeout-guidance.js +0 -44
  116. package/dist/content/diff-command.d.ts +0 -1
  117. package/dist/content/diff-command.js +0 -43
  118. package/dist/content/harness-doc.d.ts +0 -1
  119. package/dist/content/harness-doc.js +0 -65
  120. package/dist/content/hook-events.d.ts +0 -9
  121. package/dist/content/hook-events.js +0 -23
  122. package/dist/content/hook-manifest.d.ts +0 -81
  123. package/dist/content/hook-manifest.js +0 -156
  124. package/dist/content/hooks.d.ts +0 -11
  125. package/dist/content/hooks.js +0 -1972
  126. package/dist/content/idea.d.ts +0 -60
  127. package/dist/content/idea.js +0 -416
  128. package/dist/content/language-policy.d.ts +0 -2
  129. package/dist/content/language-policy.js +0 -13
  130. package/dist/content/learnings.d.ts +0 -6
  131. package/dist/content/learnings.js +0 -141
  132. package/dist/content/observe.d.ts +0 -19
  133. package/dist/content/observe.js +0 -86
  134. package/dist/content/opencode-plugin.d.ts +0 -1
  135. package/dist/content/opencode-plugin.js +0 -635
  136. package/dist/content/review-prompts.d.ts +0 -1
  137. package/dist/content/review-prompts.js +0 -104
  138. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  139. package/dist/content/runtime-shared-snippets.js +0 -80
  140. package/dist/content/session-hooks.d.ts +0 -7
  141. package/dist/content/session-hooks.js +0 -107
  142. package/dist/content/skills-elicitation.d.ts +0 -1
  143. package/dist/content/skills-elicitation.js +0 -167
  144. package/dist/content/stage-command.d.ts +0 -2
  145. package/dist/content/stage-command.js +0 -17
  146. package/dist/content/stage-schema.d.ts +0 -117
  147. package/dist/content/stage-schema.js +0 -955
  148. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  149. package/dist/content/stages/_lint-metadata/index.js +0 -97
  150. package/dist/content/stages/brainstorm.d.ts +0 -2
  151. package/dist/content/stages/brainstorm.js +0 -184
  152. package/dist/content/stages/design.d.ts +0 -2
  153. package/dist/content/stages/design.js +0 -288
  154. package/dist/content/stages/index.d.ts +0 -8
  155. package/dist/content/stages/index.js +0 -11
  156. package/dist/content/stages/plan.d.ts +0 -2
  157. package/dist/content/stages/plan.js +0 -191
  158. package/dist/content/stages/review.d.ts +0 -2
  159. package/dist/content/stages/review.js +0 -240
  160. package/dist/content/stages/schema-types.d.ts +0 -203
  161. package/dist/content/stages/schema-types.js +0 -1
  162. package/dist/content/stages/scope.d.ts +0 -2
  163. package/dist/content/stages/scope.js +0 -254
  164. package/dist/content/stages/ship.d.ts +0 -2
  165. package/dist/content/stages/ship.js +0 -159
  166. package/dist/content/stages/spec.d.ts +0 -2
  167. package/dist/content/stages/spec.js +0 -170
  168. package/dist/content/stages/tdd.d.ts +0 -4
  169. package/dist/content/stages/tdd.js +0 -273
  170. package/dist/content/state-contracts.d.ts +0 -1
  171. package/dist/content/state-contracts.js +0 -63
  172. package/dist/content/status-command.d.ts +0 -4
  173. package/dist/content/status-command.js +0 -109
  174. package/dist/content/subagent-context-skills.d.ts +0 -4
  175. package/dist/content/subagent-context-skills.js +0 -279
  176. package/dist/content/subagents.d.ts +0 -3
  177. package/dist/content/subagents.js +0 -997
  178. package/dist/content/templates.d.ts +0 -26
  179. package/dist/content/templates.js +0 -1692
  180. package/dist/content/track-render-context.d.ts +0 -18
  181. package/dist/content/track-render-context.js +0 -53
  182. package/dist/content/tree-command.d.ts +0 -1
  183. package/dist/content/tree-command.js +0 -64
  184. package/dist/content/utility-skills.d.ts +0 -30
  185. package/dist/content/utility-skills.js +0 -160
  186. package/dist/content/view-command.d.ts +0 -2
  187. package/dist/content/view-command.js +0 -92
  188. package/dist/delegation.d.ts +0 -649
  189. package/dist/delegation.js +0 -1539
  190. package/dist/early-loop.d.ts +0 -70
  191. package/dist/early-loop.js +0 -302
  192. package/dist/execution-topology.d.ts +0 -36
  193. package/dist/execution-topology.js +0 -73
  194. package/dist/gate-evidence.d.ts +0 -85
  195. package/dist/gate-evidence.js +0 -631
  196. package/dist/harness-adapters.d.ts +0 -151
  197. package/dist/harness-adapters.js +0 -756
  198. package/dist/harness-selection.d.ts +0 -31
  199. package/dist/harness-selection.js +0 -214
  200. package/dist/hook-schema.d.ts +0 -6
  201. package/dist/hook-schema.js +0 -114
  202. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  203. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  204. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  205. package/dist/init-detect.d.ts +0 -2
  206. package/dist/init-detect.js +0 -50
  207. package/dist/internal/advance-stage/advance.d.ts +0 -89
  208. package/dist/internal/advance-stage/advance.js +0 -655
  209. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  210. package/dist/internal/advance-stage/cancel-run.js +0 -19
  211. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  212. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  213. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  214. package/dist/internal/advance-stage/helpers.js +0 -145
  215. package/dist/internal/advance-stage/hook.d.ts +0 -8
  216. package/dist/internal/advance-stage/hook.js +0 -40
  217. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  218. package/dist/internal/advance-stage/parsers.js +0 -357
  219. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  220. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  221. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  222. package/dist/internal/advance-stage/review-loop.js +0 -199
  223. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  224. package/dist/internal/advance-stage/rewind.js +0 -108
  225. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  226. package/dist/internal/advance-stage/start-flow.js +0 -241
  227. package/dist/internal/advance-stage/verify.d.ts +0 -21
  228. package/dist/internal/advance-stage/verify.js +0 -185
  229. package/dist/internal/advance-stage.d.ts +0 -7
  230. package/dist/internal/advance-stage.js +0 -138
  231. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  232. package/dist/internal/cohesion-contract-stub.js +0 -148
  233. package/dist/internal/compound-readiness.d.ts +0 -23
  234. package/dist/internal/compound-readiness.js +0 -102
  235. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  236. package/dist/internal/detect-public-api-changes.js +0 -45
  237. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  238. package/dist/internal/detect-supply-chain-changes.js +0 -138
  239. package/dist/internal/early-loop-status.d.ts +0 -7
  240. package/dist/internal/early-loop-status.js +0 -93
  241. package/dist/internal/envelope-validate.d.ts +0 -7
  242. package/dist/internal/envelope-validate.js +0 -66
  243. package/dist/internal/flow-state-repair.d.ts +0 -20
  244. package/dist/internal/flow-state-repair.js +0 -104
  245. package/dist/internal/plan-split-waves.d.ts +0 -190
  246. package/dist/internal/plan-split-waves.js +0 -764
  247. package/dist/internal/runtime-integrity.d.ts +0 -7
  248. package/dist/internal/runtime-integrity.js +0 -268
  249. package/dist/internal/slice-commit.d.ts +0 -7
  250. package/dist/internal/slice-commit.js +0 -619
  251. package/dist/internal/tdd-loop-status.d.ts +0 -14
  252. package/dist/internal/tdd-loop-status.js +0 -68
  253. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  254. package/dist/internal/tdd-red-evidence.js +0 -153
  255. package/dist/internal/waiver-grant.d.ts +0 -62
  256. package/dist/internal/waiver-grant.js +0 -294
  257. package/dist/internal/wave-status.d.ts +0 -63
  258. package/dist/internal/wave-status.js +0 -450
  259. package/dist/managed-resources.d.ts +0 -53
  260. package/dist/managed-resources.js +0 -313
  261. package/dist/policy.d.ts +0 -10
  262. package/dist/policy.js +0 -167
  263. package/dist/retro-gate.d.ts +0 -9
  264. package/dist/retro-gate.js +0 -47
  265. package/dist/run-archive.d.ts +0 -61
  266. package/dist/run-archive.js +0 -391
  267. package/dist/runs.d.ts +0 -2
  268. package/dist/runs.js +0 -2
  269. package/dist/stack-detection.d.ts +0 -116
  270. package/dist/stack-detection.js +0 -489
  271. package/dist/streaming/event-stream.d.ts +0 -31
  272. package/dist/streaming/event-stream.js +0 -114
  273. package/dist/tdd-cycle.d.ts +0 -107
  274. package/dist/tdd-cycle.js +0 -289
  275. package/dist/tdd-verification-evidence.d.ts +0 -17
  276. package/dist/tdd-verification-evidence.js +0 -122
  277. package/dist/track-heuristics.d.ts +0 -27
  278. package/dist/track-heuristics.js +0 -154
  279. package/dist/util/slice-id.d.ts +0 -58
  280. package/dist/util/slice-id.js +0 -89
  281. package/dist/worktree-manager.d.ts +0 -20
  282. package/dist/worktree-manager.js +0 -108
package/dist/cli.js CHANGED
@@ -1,530 +1,112 @@
1
1
  #!/usr/bin/env node
2
- import process from "node:process";
3
- import path from "node:path";
4
- import { existsSync, realpathSync } from "node:fs";
5
- import { createInterface } from "node:readline/promises";
6
- import { fileURLToPath } from "node:url";
2
+ import { CCLAW_VERSION } from "./constants.js";
7
3
  import { initCclaw, syncCclaw, uninstallCclaw, upgradeCclaw } from "./install.js";
8
- import { error, info } from "./logger.js";
9
- import { FLOW_TRACKS, HARNESS_IDS } from "./types.js";
10
- import { ARCHIVE_DISPOSITIONS, archiveRun } from "./runs.js";
11
- import { CCLAW_VERSION, RUNTIME_ROOT } from "./constants.js";
12
- import { createDefaultConfig, readConfig } from "./config.js";
13
- import { detectHarnesses } from "./init-detect.js";
14
- import { HARNESS_ADAPTERS } from "./harness-adapters.js";
15
- import { promptHarnessSelectionChecklist } from "./harness-selection.js";
16
- export { parseHarnessSelectionAnswer } from "./harness-selection.js";
17
- import { classifyCodexHooksFlag, codexConfigPath, patchCodexHooksFlag, readCodexConfig, writeCodexConfig } from "./codex-feature-flag.js";
18
- import { runInternalCommand } from "./internal/advance-stage.js";
19
- const INSTALLER_COMMANDS = [
20
- "init",
21
- "sync",
22
- "upgrade",
23
- "uninstall",
24
- "archive",
25
- "internal"
26
- ];
27
- export function usage() {
28
- return `cclaw - installer-first flow toolkit
4
+ import { configureLogger, error as logError, info } from "./logger.js";
5
+ import { HARNESS_IDS } from "./types.js";
6
+ const HELP_BODY = `cclaw v${CCLAW_VERSION} harness installer / sync.
29
7
 
30
- Usage:
31
- npx cclaw-cli # launch setup or print "already installed" hint
32
- npx cclaw-cli <command> [flags]
33
- npx cclaw-cli --help | -h
34
- npx cclaw-cli --version | -v
8
+ Usage: cclaw <command> [options]
35
9
 
36
10
  Commands:
37
- init Bootstrap .cclaw runtime, state, and harness shims in this project.
38
- Flags: --harnesses=<list> Comma list of harnesses (claude,cursor,opencode,codex).
39
- --no-interactive Skip interactive prompts even on TTY (for CI/scripts).
40
- sync Reconcile generated runtime files with the current config.
41
- Flags: --harnesses=<list> Update configured harnesses before syncing.
42
- --interactive Pick harnesses from a numbered TTY menu.
43
- --check Verify managed hook files are byte-identical to canonical generators.
44
- upgrade Refresh generated files in .cclaw. Preserves your config.yaml.
45
- archive Archive the active run and reset flow state for the next run.
46
- Flags: --name=<slug> Override archive folder suffix.
47
- --skip-retro Skip retro gate only when runtime allows it.
48
- --retro-reason=<txt> Required rationale with --skip-retro.
49
- --disposition=<completed|cancelled|abandoned>
50
- --reason=<txt> Required for cancelled/abandoned archives.
51
- uninstall Remove .cclaw runtime and the generated harness shim files.
11
+ init Install cclaw assets in the current project.
12
+ sync Reapply cclaw assets to match the current code (idempotent).
13
+ upgrade Sync after upgrading the cclaw-cli npm package.
14
+ uninstall Remove cclaw assets from the current project.
15
+ help Show this help.
16
+ version Print the version.
52
17
 
53
- Global flags:
54
- -h, --help Show this help message and exit 0.
55
- -v, --version Print the cclaw CLI version and exit 0.
18
+ Harness selection:
19
+ - If --harness=<id>[,<id>] is passed, install for those.
20
+ - Otherwise, the existing .cclaw/config.yaml (if any) wins.
21
+ - Otherwise, cclaw auto-detects from project root markers (.claude/, .cursor/,
22
+ .opencode/, .codex/, .agents/skills/, CLAUDE.md, opencode.json).
23
+ - If nothing is detected and no flag is passed, init exits with an error.
56
24
 
57
- Examples:
58
- npx cclaw-cli
59
- npx cclaw-cli init --harnesses=claude,cursor --no-interactive
60
- npx cclaw-cli sync --interactive
61
- npx cclaw-cli sync --check
62
- npx cclaw-cli archive --name=my-run
63
- npx cclaw-cli archive --disposition=cancelled --reason="deprioritized"
64
- npx cclaw-cli upgrade
25
+ Flow control (plan / build / review / ship) lives inside the harness via the /cc command, not in this CLI. There is no \`cclaw plan\`, \`cclaw status\`, \`cclaw ship\`, or \`cclaw migrate\` — by design.
65
26
 
66
- Happy-path work happens inside your harness via /cc, /cc-idea,
67
- and /cc-cancel. Installer/support operations are init/sync/upgrade/uninstall
68
- plus explicit archive actions.
69
-
70
- Docs: https://github.com/zuevrs/cclaw
71
- Local: README.md and generated .cclaw/skills/*.md
72
- Issues: https://github.com/zuevrs/cclaw/issues
27
+ Options:
28
+ --harness=<id>[,<id>] Comma-separated list. Supported: ${HARNESS_IDS.join(", ")}.
73
29
  `;
74
- }
75
- function parseHarnesses(raw) {
76
- const requested = raw
77
- .split(",")
78
- .map((item) => item.trim())
79
- .filter(Boolean);
80
- if (requested.length === 0) {
81
- throw new Error("Select at least one harness.");
82
- }
83
- const invalid = requested.filter((item) => !HARNESS_IDS.includes(item));
84
- if (invalid.length > 0) {
85
- throw new Error(`Unknown harnesses: ${invalid.join(", ")}`);
86
- }
87
- return requested;
88
- }
89
- function parseTrack(raw) {
90
- const trimmed = raw.trim();
91
- if (!FLOW_TRACKS.includes(trimmed)) {
92
- throw new Error(`Unknown track: ${trimmed}. Supported: ${FLOW_TRACKS.join(", ")}`);
93
- }
94
- return trimmed;
95
- }
96
- function parseArchiveDisposition(raw) {
97
- const trimmed = raw.trim();
98
- if (!ARCHIVE_DISPOSITIONS.includes(trimmed)) {
99
- throw new Error(`Unknown archive disposition: ${trimmed}. Supported: ${ARCHIVE_DISPOSITIONS.join(", ")}`);
100
- }
101
- return trimmed;
102
- }
103
- function isInitPromptAllowed(ctx) {
104
- return Boolean(process.stdin.isTTY && ctx.stdout.isTTY);
105
- }
106
- /**
107
- * Print a short, friendly hint when the user runs `cclaw-cli` with no
108
- * arguments. Does not read or mutate flow state — only checks whether
109
- * `.cclaw/config.yaml` exists to branch between "installed" and
110
- * "not-installed" messaging. Keeps exit 0 in both cases: users discover
111
- * the tool through this path, not through an error.
112
- */
113
- function printNoArgsHint(ctx) {
114
- const installed = existsSync(path.join(ctx.cwd, RUNTIME_ROOT, "config.yaml"));
115
- if (installed) {
116
- ctx.stdout.write("cclaw is installed in this project. Open your harness (Claude Code, " +
117
- "Cursor, OpenCode, or Codex) and type `/cc` to start.\n");
118
- }
119
- else {
120
- ctx.stdout.write("cclaw is not installed in this project yet.\n" +
121
- "Run `npx cclaw-cli init` to bootstrap .cclaw and the harness shims.\n" +
122
- "For help: `npx cclaw-cli --help`.\n");
123
- }
124
- return 0;
125
- }
126
- function buildInitSurfacePreview(harnesses) {
127
- const lines = [
128
- ".cclaw/config.yaml",
129
- ".cclaw/commands/*.md",
130
- ".cclaw/skills/*/SKILL.md",
131
- ".cclaw/templates/*",
132
- ".cclaw/agents/*.md",
133
- ".cclaw/hooks/*",
134
- ".cclaw/rules/**",
135
- ".cclaw/archive/**",
136
- ".cclaw/artifacts/**",
137
- ".cclaw/knowledge.jsonl",
138
- ".cclaw/state/*.json|*.jsonl",
139
- "AGENTS.md (managed block)"
140
- ];
141
- for (const harness of harnesses) {
142
- const adapter = HARNESS_ADAPTERS[harness];
143
- if (adapter.shimKind === "skill") {
144
- lines.push(`${adapter.commandDir}/cc*/SKILL.md`);
145
- }
146
- else {
147
- lines.push(`${adapter.commandDir}/cc*.md`);
148
- }
149
- if (harness === "claude") {
150
- lines.push(".claude/hooks/hooks.json");
151
- }
152
- if (harness === "cursor") {
153
- lines.push(".cursor/hooks.json");
154
- lines.push(".cursor/rules/cclaw-workflow.mdc");
155
- }
156
- if (harness === "codex") {
157
- // .codex/hooks.json is managed because Codex CLI
158
- // grew a real hooks API (v0.114+, behind the `codex_hooks`
159
- // feature flag). Legacy `.codex/commands/*` is still auto-cleaned.
160
- lines.push(".codex/hooks.json (requires `codex_hooks = true` in ~/.codex/config.toml)");
161
- }
162
- if (harness === "opencode") {
163
- lines.push(".opencode/plugins/cclaw-plugin.mjs");
164
- lines.push("opencode.json(.c) plugin registration");
165
- }
166
- }
167
- return lines;
168
- }
169
- async function promptInitConfig(defaults, ctx) {
170
- const harnesses = await promptHarnessSelectionChecklist(defaults, ctx, "Initial cclaw harnesses");
171
- return { harnesses };
172
- }
173
- /**
174
- * When Codex is one of the installed harnesses, check the Codex CLI
175
- * config file for the `codex_hooks` feature flag. If it is missing or
176
- * disabled, offer to patch it in with the user's explicit consent.
177
- *
178
- * The function is deliberately advisory: it never fails init — the worst
179
- * case is that Codex runs without the hooks engine, which is exactly
180
- * how v0.39.x already shipped. We always print a resolution hint so
181
- * the user knows what to do next regardless of which branch was taken.
182
- */
183
- async function maybeEnableCodexHooksFlag(harnesses, parsed, ctx) {
184
- if (!harnesses || !harnesses.includes("codex"))
185
- return;
186
- const configPath = codexConfigPath();
187
- let existing;
188
- try {
189
- existing = await readCodexConfig(configPath);
190
- }
191
- catch (err) {
192
- ctx.stdout.write(`note: Could not read ${configPath} to check the codex_hooks flag: ` +
193
- `${err instanceof Error ? err.message : String(err)}\n`);
194
- return;
195
- }
196
- const state = classifyCodexHooksFlag(existing);
197
- if (state === "enabled") {
198
- return;
199
- }
200
- const humanState = state === "missing-file"
201
- ? "Codex config file does not exist yet"
202
- : state === "missing-section"
203
- ? "no [features] section"
204
- : state === "missing-key"
205
- ? "no codex_hooks key"
206
- : "codex_hooks is not enabled";
207
- const instructions = `To enable Codex hooks manually later, ensure ${configPath} contains:\n` +
208
- ` [features]\n codex_hooks = true\n`;
209
- if (parsed.interactive === false) {
210
- ctx.stdout.write(`note: codex_hooks feature flag is not enabled (${humanState}).\n` +
211
- ` cclaw wrote .codex/hooks.json, but Codex will ignore it until you enable the flag.\n` +
212
- ` ${instructions}`);
213
- return;
214
- }
215
- if (!isInitPromptAllowed(ctx)) {
216
- ctx.stdout.write(`note: codex_hooks feature flag is not enabled (${humanState}).\n` +
217
- ` cclaw wrote .codex/hooks.json, but Codex will ignore it until you enable the flag.\n` +
218
- ` ${instructions}`);
219
- return;
220
- }
221
- const rl = createInterface({
222
- input: process.stdin,
223
- output: ctx.stdout
224
- });
225
- try {
226
- const answer = (await rl.question(`\nCodex CLI hooks are off (${humanState}).\n` +
227
- `Enable [features] codex_hooks = true in ${configPath} now? [y/N]: `)).trim().toLowerCase();
228
- const yes = answer === "y" || answer === "yes";
229
- if (!yes) {
230
- ctx.stdout.write(`Leaving ${configPath} untouched. ${instructions}`);
231
- return;
232
- }
233
- const { updated, changed } = patchCodexHooksFlag(existing);
234
- if (!changed) {
235
- ctx.stdout.write(`codex_hooks is already enabled — no changes written.\n`);
236
- return;
237
- }
238
- try {
239
- await writeCodexConfig(configPath, updated);
240
- ctx.stdout.write(`Enabled [features] codex_hooks = true in ${configPath}.\n`);
241
- }
242
- catch (err) {
243
- ctx.stdout.write(`Could not write ${configPath}: ` +
244
- `${err instanceof Error ? err.message : String(err)}\n` +
245
- `${instructions}`);
246
- }
247
- }
248
- finally {
249
- rl.close();
250
- }
251
- }
252
- async function resolveInitInputs(parsed, ctx) {
253
- const detectedHarnesses = parsed.harnesses ? [] : await detectHarnesses(ctx.cwd);
254
- const autoHarnesses = parsed.harnesses
255
- ? parsed.harnesses
256
- : (detectedHarnesses.length > 0 ? detectedHarnesses : undefined);
257
- const promptRequested = parsed.interactive === true;
258
- const promptForbidden = parsed.interactive === false;
259
- const implicitPrompt = !promptForbidden &&
260
- isInitPromptAllowed(ctx) &&
261
- parsed.track === undefined &&
262
- parsed.harnesses === undefined;
263
- const shouldPrompt = promptRequested || implicitPrompt;
264
- if (!shouldPrompt) {
265
- return {
266
- track: parsed.track,
267
- harnesses: autoHarnesses,
268
- detectedHarnesses
269
- };
270
- }
271
- if (!isInitPromptAllowed(ctx)) {
272
- throw new Error("Interactive init requires a TTY. Remove --interactive or run in a terminal.");
273
- }
274
- const defaults = {
275
- harnesses: autoHarnesses ?? HARNESS_IDS.slice()
276
- };
277
- const prompted = await promptInitConfig({ ...defaults, detectedHarnesses }, ctx);
278
- return {
279
- track: parsed.track,
280
- harnesses: prompted.harnesses,
281
- detectedHarnesses
282
- };
283
- }
284
- async function resolveSyncInputs(parsed, ctx) {
285
- const explicitHarnesses = parsed.harnesses;
286
- if (explicitHarnesses && explicitHarnesses.length > 0) {
287
- return { harnesses: explicitHarnesses };
288
- }
289
- if (parsed.interactive !== true) {
290
- return {};
291
- }
292
- if (!isInitPromptAllowed(ctx)) {
293
- throw new Error("Interactive sync requires a TTY. Remove --interactive or run in a terminal.");
294
- }
295
- let currentHarnesses = [];
296
- try {
297
- currentHarnesses = (await readConfig(ctx.cwd)).harnesses;
298
- }
299
- catch {
300
- currentHarnesses = [];
301
- }
302
- const detectedHarnesses = await detectHarnesses(ctx.cwd);
303
- const defaults = detectedHarnesses.length > 0 ? detectedHarnesses : currentHarnesses.length > 0 ? currentHarnesses : HARNESS_IDS.slice();
304
- return {
305
- harnesses: await promptHarnessSelectionChecklist({
306
- harnesses: defaults,
307
- detectedHarnesses,
308
- currentHarnesses
309
- }, ctx, "Sync harness reconfiguration")
310
- };
311
- }
312
30
  function parseArgs(argv) {
313
- const parsed = {};
314
- const helpFlag = argv.find((arg) => arg === "--help" || arg === "-h");
315
- if (helpFlag) {
316
- parsed.showHelp = true;
317
- }
318
- const versionFlag = argv.find((arg) => arg === "--version" || arg === "-v");
319
- if (versionFlag) {
320
- parsed.showVersion = true;
321
- }
322
- const filteredArgv = argv.filter((arg) => arg !== "--help" && arg !== "-h" && arg !== "--version" && arg !== "-v");
323
- const [commandRaw, ...rest] = filteredArgv;
324
- parsed.command = INSTALLER_COMMANDS.includes(commandRaw)
325
- ? commandRaw
326
- : undefined;
327
- // Hidden maintainer surface for runtime guards/helpers. Keep raw positional
328
- // args untouched so subcommand-level parsing can evolve independently.
329
- if (parsed.command === "internal") {
330
- parsed.internalArgs = [...rest];
331
- return parsed;
332
- }
333
- const flags = rest;
334
- const isAllowedForCommand = (flag) => {
335
- if (parsed.command === "init" || parsed.command === "sync") {
336
- return flag.startsWith("--harnesses=") ||
337
- (parsed.command === "init" && flag.startsWith("--track=")) ||
338
- (parsed.command === "init" && flag.startsWith("--profile=")) ||
339
- (parsed.command === "sync" && flag === "--check") ||
340
- flag === "--interactive" ||
341
- flag === "--no-interactive" ||
342
- (parsed.command === "init" && flag === "--dry-run");
343
- }
344
- if (parsed.command === "archive") {
345
- return flag.startsWith("--name=") ||
346
- flag === "--skip-retro" ||
347
- flag.startsWith("--retro-reason=") ||
348
- flag.startsWith("--disposition=") ||
349
- flag.startsWith("--reason=");
350
- }
351
- return false;
352
- };
353
- for (const flag of flags) {
354
- if (!isAllowedForCommand(flag)) {
355
- throw new Error(`Flag ${flag} is not supported for ${parsed.command ?? "this command"}.`);
356
- }
357
- if (flag.startsWith("--harnesses=")) {
358
- parsed.harnesses = parseHarnesses(flag.replace("--harnesses=", ""));
359
- continue;
360
- }
361
- if (flag.startsWith("--track=")) {
362
- parsed.track = parseTrack(flag.replace("--track=", ""));
363
- continue;
364
- }
365
- if (flag.startsWith("--profile=")) {
366
- continue;
367
- }
368
- if (flag === "--interactive") {
369
- parsed.interactive = true;
370
- continue;
371
- }
372
- if (flag === "--no-interactive") {
373
- parsed.interactive = false;
374
- continue;
375
- }
376
- if (flag === "--dry-run") {
377
- parsed.dryRun = true;
378
- continue;
379
- }
380
- if (flag === "--check") {
381
- parsed.syncCheck = true;
382
- continue;
383
- }
384
- if (flag.startsWith("--name=")) {
385
- parsed.archiveName = flag.replace("--name=", "").trim();
386
- continue;
387
- }
388
- if (flag === "--skip-retro") {
389
- parsed.archiveSkipRetro = true;
390
- continue;
391
- }
392
- if (flag.startsWith("--retro-reason=")) {
393
- parsed.archiveSkipRetroReason = flag.replace("--retro-reason=", "").trim();
394
- continue;
31
+ const [command = "help", ...rest] = argv;
32
+ const flags = {};
33
+ let harnesses;
34
+ for (const arg of rest) {
35
+ if (arg.startsWith("--harness=")) {
36
+ const list = arg.slice("--harness=".length).split(",").map((value) => value.trim()).filter(Boolean);
37
+ const invalid = list.filter((value) => !HARNESS_IDS.includes(value));
38
+ if (invalid.length > 0) {
39
+ throw new Error(`Unknown harnesses: ${invalid.join(", ")}. Supported: ${HARNESS_IDS.join(", ")}`);
40
+ }
41
+ harnesses = list;
395
42
  }
396
- if (flag.startsWith("--disposition=")) {
397
- parsed.archiveDisposition = parseArchiveDisposition(flag.replace("--disposition=", ""));
398
- continue;
43
+ else if (arg.startsWith("--")) {
44
+ const [name, ...value] = arg.slice(2).split("=");
45
+ flags[name] = value.length === 0 ? true : value.join("=");
399
46
  }
400
- if (flag.startsWith("--reason=")) {
401
- parsed.archiveDispositionReason = flag.replace("--reason=", "").trim();
402
- continue;
47
+ else {
48
+ flags._ = arg;
403
49
  }
404
50
  }
405
- return parsed;
51
+ return { command, harnesses, flags };
406
52
  }
407
- async function runCommand(parsed, ctx) {
408
- if (parsed.showHelp) {
409
- ctx.stdout.write(usage());
410
- return 0;
411
- }
412
- if (parsed.showVersion) {
413
- ctx.stdout.write(`cclaw ${CCLAW_VERSION}\n`);
414
- return 0;
415
- }
416
- const command = parsed.command;
417
- if (!command) {
418
- return printNoArgsHint(ctx);
419
- }
420
- if (command === "internal") {
421
- return runInternalCommand(ctx.cwd, parsed.internalArgs ?? [], ctx);
422
- }
423
- if (command === "init") {
424
- const resolved = await resolveInitInputs(parsed, ctx);
425
- const effectiveTrack = resolved.track;
426
- const effectiveHarnesses = resolved.harnesses;
427
- if (parsed.dryRun === true) {
428
- const previewConfig = createDefaultConfig(effectiveHarnesses, effectiveTrack);
429
- const previewSurfaces = buildInitSurfacePreview(previewConfig.harnesses);
430
- info(ctx, "Dry run: no files were written.");
431
- if (resolved.detectedHarnesses.length > 0 && parsed.harnesses === undefined) {
432
- info(ctx, `Detected harnesses from repo: ${resolved.detectedHarnesses.join(", ")}`);
433
- }
434
- ctx.stdout.write(`${JSON.stringify({
435
- track: effectiveTrack ?? "standard",
436
- harnesses: previewConfig.harnesses,
437
- generatedSurfaces: previewSurfaces
438
- }, null, 2)}\n`);
53
+ export async function runCli(argv, context) {
54
+ configureLogger(context.stdout, context.stderr);
55
+ const args = parseArgs(argv);
56
+ switch (args.command) {
57
+ case "init": {
58
+ const result = await initCclaw({ cwd: context.cwd, harnesses: args.harnesses });
59
+ info(`[cclaw] init complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
439
60
  return 0;
440
61
  }
441
- await initCclaw({
442
- projectRoot: ctx.cwd,
443
- harnesses: effectiveHarnesses,
444
- track: effectiveTrack
445
- });
446
- if (resolved.detectedHarnesses.length > 0 && parsed.harnesses === undefined) {
447
- info(ctx, `Detected harnesses from repo: ${resolved.detectedHarnesses.join(", ")}`);
448
- }
449
- const trackNote = effectiveTrack ? ` (track=${effectiveTrack})` : "";
450
- info(ctx, `Initialized .cclaw runtime and generated harness shims${trackNote}`);
451
- info(ctx, "Config: .cclaw/config.yaml (harnesses + auto-managed version stamps).");
452
- await maybeEnableCodexHooksFlag(effectiveHarnesses, parsed, ctx);
453
- return 0;
454
- }
455
- if (command === "sync") {
456
- if (parsed.syncCheck === true) {
457
- await syncCclaw(ctx.cwd, { check: true });
458
- info(ctx, "Managed hook drift check passed (no sync required).");
62
+ case "sync": {
63
+ const result = await syncCclaw({ cwd: context.cwd, harnesses: args.harnesses });
64
+ info(`[cclaw] sync complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
459
65
  return 0;
460
66
  }
461
- const resolved = await resolveSyncInputs(parsed, ctx);
462
- await syncCclaw(ctx.cwd, { harnesses: resolved.harnesses });
463
- const harnessNote = resolved.harnesses ? ` (${resolved.harnesses.join(", ")})` : "";
464
- info(ctx, `Synchronized harness shims from current .cclaw config${harnessNote}`);
465
- return 0;
466
- }
467
- if (command === "upgrade") {
468
- await upgradeCclaw(ctx.cwd);
469
- info(ctx, "Upgraded .cclaw runtime and regenerated generated files");
470
- return 0;
471
- }
472
- if (command === "archive") {
473
- const archived = await archiveRun(ctx.cwd, parsed.archiveName, {
474
- skipRetro: parsed.archiveSkipRetro === true,
475
- skipRetroReason: parsed.archiveSkipRetroReason,
476
- disposition: parsed.archiveDisposition,
477
- dispositionReason: parsed.archiveDispositionReason
478
- });
479
- const snapshotSummary = archived.snapshottedStateFiles.length > 0
480
- ? ` Snapshotted ${archived.snapshottedStateFiles.length} state file(s) under ${archived.archivePath}/state and wrote archive-manifest.json.`
481
- : "";
482
- info(ctx, `Archived active artifacts to ${archived.archivePath} (${archived.disposition}). Flow state reset to brainstorm.${snapshotSummary}`);
483
- const k = archived.knowledge;
484
- if (k.overThreshold) {
485
- info(ctx, `Knowledge curation recommended: ${k.knowledgePath} now has ${k.activeEntryCount} active entries (soft threshold ${k.softThreshold}). Ask your harness to curate cclaw knowledge and plan a soft-archive of stale/duplicate entries to ${RUNTIME_ROOT}/knowledge.archive.jsonl.`);
486
- }
487
- else if (k.activeEntryCount > 0) {
488
- info(ctx, `Knowledge: ${k.activeEntryCount}/${k.softThreshold} active entries. Ask your harness for a cclaw knowledge curation sweep before the next run if needed.`);
67
+ case "upgrade": {
68
+ const result = await upgradeCclaw({ cwd: context.cwd, harnesses: args.harnesses });
69
+ info(`[cclaw] upgrade complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
70
+ return 0;
489
71
  }
490
- else {
491
- info(ctx, `Knowledge: 0 active entries in ${k.knowledgePath}. Capture lessons from this run through the learnings skill before they fade.`);
72
+ case "uninstall": {
73
+ await uninstallCclaw({ cwd: context.cwd });
74
+ info("[cclaw] uninstall complete.");
75
+ return 0;
492
76
  }
493
- return 0;
494
- }
495
- await uninstallCclaw(ctx.cwd);
496
- info(ctx, "Removed .cclaw runtime and generated shim files");
497
- return 0;
498
- }
499
- async function main() {
500
- const ctx = {
501
- cwd: process.cwd(),
502
- stdout: process.stdout,
503
- stderr: process.stderr
504
- };
505
- try {
506
- const parsed = parseArgs(process.argv.slice(2));
507
- const code = await runCommand(parsed, ctx);
508
- process.exitCode = code;
509
- }
510
- catch (err) {
511
- error(ctx, err instanceof Error ? err.message : "Unknown error");
512
- process.exitCode = 1;
513
- }
514
- }
515
- function isDirectExecution() {
516
- if (!process.argv[1])
517
- return false;
518
- try {
519
- const entryPath = realpathSync(path.resolve(process.argv[1]));
520
- const modulePath = realpathSync(fileURLToPath(import.meta.url));
521
- return entryPath === modulePath;
522
- }
523
- catch {
524
- return false;
525
- }
526
- }
527
- if (isDirectExecution()) {
528
- void main();
77
+ case "version":
78
+ case "--version":
79
+ case "-v":
80
+ info(CCLAW_VERSION);
81
+ return 0;
82
+ case "help":
83
+ case "--help":
84
+ case "-h":
85
+ info(HELP_BODY);
86
+ return 0;
87
+ case "plan":
88
+ case "status":
89
+ case "ship":
90
+ case "migrate":
91
+ case "build":
92
+ case "review":
93
+ logError(`[cclaw] '${args.command}' is not a CLI command in v8. Flow control happens via /cc inside your harness.`);
94
+ return 2;
95
+ default:
96
+ logError(`[cclaw] unknown command: ${args.command}`);
97
+ logError(HELP_BODY);
98
+ return 2;
99
+ }
100
+ }
101
+ const isMain = import.meta.url === `file://${process.argv[1]}`;
102
+ if (isMain) {
103
+ runCli(process.argv.slice(2), { cwd: process.cwd(), stdout: process.stdout, stderr: process.stderr })
104
+ .then((code) => {
105
+ process.exit(code);
106
+ })
107
+ .catch((err) => {
108
+ const message = err instanceof Error ? err.message : String(err);
109
+ process.stderr.write(`[cclaw] ${message}\n`);
110
+ process.exit(1);
111
+ });
529
112
  }
530
- export { parseArgs, parseArchiveDisposition, parseHarnesses, parseTrack };
@@ -0,0 +1,26 @@
1
+ import { type ArtifactStage } from "./artifact-paths.js";
2
+ import { type KnowledgeEntry } from "./knowledge-store.js";
3
+ export interface CompoundQualitySignals {
4
+ hasArchitectDecision: boolean;
5
+ reviewIterations: number;
6
+ securityFlag: boolean;
7
+ userRequestedCapture: boolean;
8
+ }
9
+ export interface CompoundRunOptions {
10
+ shipCommit: string;
11
+ signals: CompoundQualitySignals;
12
+ refines?: string | null;
13
+ notes?: string;
14
+ }
15
+ export interface CompoundRunResult {
16
+ slug: string;
17
+ shippedDir: string;
18
+ learningCaptured: boolean;
19
+ movedArtifacts: ArtifactStage[];
20
+ knowledgeEntry?: KnowledgeEntry;
21
+ }
22
+ export declare class CompoundError extends Error {
23
+ }
24
+ export declare function shouldCaptureLearning(signals: CompoundQualitySignals): boolean;
25
+ export declare function runCompoundAndShip(projectRoot: string, options: CompoundRunOptions): Promise<CompoundRunResult>;
26
+ export declare function defaultPathsToCheck(projectRoot: string): Promise<string[]>;