cclaw-cli 7.7.1 → 8.1.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 (284) hide show
  1. package/README.md +211 -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 +107 -511
  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 -768
  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 -134
  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/harness-prompt.d.ts +26 -0
  73. package/dist/harness-prompt.js +142 -0
  74. package/dist/install.d.ts +35 -15
  75. package/dist/install.js +238 -1347
  76. package/dist/knowledge-store.d.ts +19 -163
  77. package/dist/knowledge-store.js +56 -590
  78. package/dist/logger.d.ts +8 -3
  79. package/dist/logger.js +13 -4
  80. package/dist/orchestrator-routing.d.ts +29 -0
  81. package/dist/orchestrator-routing.js +156 -0
  82. package/dist/run-persistence.d.ts +7 -118
  83. package/dist/run-persistence.js +29 -845
  84. package/dist/runtime/run-hook.entry.d.ts +1 -3
  85. package/dist/runtime/run-hook.entry.js +19 -4
  86. package/dist/runtime/run-hook.mjs +13 -1024
  87. package/dist/types.d.ts +25 -261
  88. package/dist/types.js +8 -36
  89. package/package.json +6 -3
  90. package/dist/artifact-linter/brainstorm.d.ts +0 -2
  91. package/dist/artifact-linter/brainstorm.js +0 -353
  92. package/dist/artifact-linter/design.d.ts +0 -18
  93. package/dist/artifact-linter/design.js +0 -444
  94. package/dist/artifact-linter/findings-dedup.d.ts +0 -56
  95. package/dist/artifact-linter/findings-dedup.js +0 -232
  96. package/dist/artifact-linter/plan.d.ts +0 -2
  97. package/dist/artifact-linter/plan.js +0 -826
  98. package/dist/artifact-linter/review-army.d.ts +0 -49
  99. package/dist/artifact-linter/review-army.js +0 -520
  100. package/dist/artifact-linter/review.d.ts +0 -2
  101. package/dist/artifact-linter/review.js +0 -113
  102. package/dist/artifact-linter/scope.d.ts +0 -2
  103. package/dist/artifact-linter/scope.js +0 -158
  104. package/dist/artifact-linter/shared.d.ts +0 -637
  105. package/dist/artifact-linter/shared.js +0 -2163
  106. package/dist/artifact-linter/ship.d.ts +0 -2
  107. package/dist/artifact-linter/ship.js +0 -250
  108. package/dist/artifact-linter/spec.d.ts +0 -2
  109. package/dist/artifact-linter/spec.js +0 -176
  110. package/dist/artifact-linter/tdd.d.ts +0 -118
  111. package/dist/artifact-linter/tdd.js +0 -1404
  112. package/dist/artifact-linter.d.ts +0 -15
  113. package/dist/artifact-linter.js +0 -517
  114. package/dist/codex-feature-flag.d.ts +0 -58
  115. package/dist/codex-feature-flag.js +0 -193
  116. package/dist/content/closeout-guidance.d.ts +0 -14
  117. package/dist/content/closeout-guidance.js +0 -44
  118. package/dist/content/diff-command.d.ts +0 -1
  119. package/dist/content/diff-command.js +0 -43
  120. package/dist/content/harness-doc.d.ts +0 -1
  121. package/dist/content/harness-doc.js +0 -65
  122. package/dist/content/hook-events.d.ts +0 -9
  123. package/dist/content/hook-events.js +0 -23
  124. package/dist/content/hook-manifest.d.ts +0 -81
  125. package/dist/content/hook-manifest.js +0 -156
  126. package/dist/content/hooks.d.ts +0 -11
  127. package/dist/content/hooks.js +0 -1972
  128. package/dist/content/idea.d.ts +0 -60
  129. package/dist/content/idea.js +0 -416
  130. package/dist/content/language-policy.d.ts +0 -2
  131. package/dist/content/language-policy.js +0 -13
  132. package/dist/content/learnings.d.ts +0 -6
  133. package/dist/content/learnings.js +0 -141
  134. package/dist/content/observe.d.ts +0 -19
  135. package/dist/content/observe.js +0 -86
  136. package/dist/content/opencode-plugin.d.ts +0 -1
  137. package/dist/content/opencode-plugin.js +0 -635
  138. package/dist/content/review-prompts.d.ts +0 -1
  139. package/dist/content/review-prompts.js +0 -104
  140. package/dist/content/runtime-shared-snippets.d.ts +0 -8
  141. package/dist/content/runtime-shared-snippets.js +0 -80
  142. package/dist/content/session-hooks.d.ts +0 -7
  143. package/dist/content/session-hooks.js +0 -107
  144. package/dist/content/skills-elicitation.d.ts +0 -1
  145. package/dist/content/skills-elicitation.js +0 -167
  146. package/dist/content/stage-command.d.ts +0 -2
  147. package/dist/content/stage-command.js +0 -17
  148. package/dist/content/stage-schema.d.ts +0 -117
  149. package/dist/content/stage-schema.js +0 -955
  150. package/dist/content/stages/_lint-metadata/index.d.ts +0 -2
  151. package/dist/content/stages/_lint-metadata/index.js +0 -97
  152. package/dist/content/stages/brainstorm.d.ts +0 -2
  153. package/dist/content/stages/brainstorm.js +0 -184
  154. package/dist/content/stages/design.d.ts +0 -2
  155. package/dist/content/stages/design.js +0 -288
  156. package/dist/content/stages/index.d.ts +0 -8
  157. package/dist/content/stages/index.js +0 -11
  158. package/dist/content/stages/plan.d.ts +0 -2
  159. package/dist/content/stages/plan.js +0 -191
  160. package/dist/content/stages/review.d.ts +0 -2
  161. package/dist/content/stages/review.js +0 -240
  162. package/dist/content/stages/schema-types.d.ts +0 -203
  163. package/dist/content/stages/schema-types.js +0 -1
  164. package/dist/content/stages/scope.d.ts +0 -2
  165. package/dist/content/stages/scope.js +0 -254
  166. package/dist/content/stages/ship.d.ts +0 -2
  167. package/dist/content/stages/ship.js +0 -159
  168. package/dist/content/stages/spec.d.ts +0 -2
  169. package/dist/content/stages/spec.js +0 -170
  170. package/dist/content/stages/tdd.d.ts +0 -4
  171. package/dist/content/stages/tdd.js +0 -273
  172. package/dist/content/state-contracts.d.ts +0 -1
  173. package/dist/content/state-contracts.js +0 -63
  174. package/dist/content/status-command.d.ts +0 -4
  175. package/dist/content/status-command.js +0 -109
  176. package/dist/content/subagent-context-skills.d.ts +0 -4
  177. package/dist/content/subagent-context-skills.js +0 -279
  178. package/dist/content/subagents.d.ts +0 -3
  179. package/dist/content/subagents.js +0 -997
  180. package/dist/content/templates.d.ts +0 -26
  181. package/dist/content/templates.js +0 -1692
  182. package/dist/content/track-render-context.d.ts +0 -18
  183. package/dist/content/track-render-context.js +0 -53
  184. package/dist/content/tree-command.d.ts +0 -1
  185. package/dist/content/tree-command.js +0 -64
  186. package/dist/content/utility-skills.d.ts +0 -30
  187. package/dist/content/utility-skills.js +0 -160
  188. package/dist/content/view-command.d.ts +0 -2
  189. package/dist/content/view-command.js +0 -92
  190. package/dist/delegation.d.ts +0 -649
  191. package/dist/delegation.js +0 -1539
  192. package/dist/early-loop.d.ts +0 -70
  193. package/dist/early-loop.js +0 -302
  194. package/dist/execution-topology.d.ts +0 -44
  195. package/dist/execution-topology.js +0 -95
  196. package/dist/gate-evidence.d.ts +0 -85
  197. package/dist/gate-evidence.js +0 -631
  198. package/dist/harness-adapters.d.ts +0 -151
  199. package/dist/harness-adapters.js +0 -756
  200. package/dist/harness-selection.d.ts +0 -31
  201. package/dist/harness-selection.js +0 -214
  202. package/dist/hook-schema.d.ts +0 -6
  203. package/dist/hook-schema.js +0 -114
  204. package/dist/hook-schemas/claude-hooks.v1.json +0 -10
  205. package/dist/hook-schemas/codex-hooks.v1.json +0 -10
  206. package/dist/hook-schemas/cursor-hooks.v1.json +0 -13
  207. package/dist/init-detect.d.ts +0 -2
  208. package/dist/init-detect.js +0 -50
  209. package/dist/internal/advance-stage/advance.d.ts +0 -89
  210. package/dist/internal/advance-stage/advance.js +0 -655
  211. package/dist/internal/advance-stage/cancel-run.d.ts +0 -8
  212. package/dist/internal/advance-stage/cancel-run.js +0 -19
  213. package/dist/internal/advance-stage/flow-state-coercion.d.ts +0 -3
  214. package/dist/internal/advance-stage/flow-state-coercion.js +0 -81
  215. package/dist/internal/advance-stage/helpers.d.ts +0 -14
  216. package/dist/internal/advance-stage/helpers.js +0 -145
  217. package/dist/internal/advance-stage/hook.d.ts +0 -8
  218. package/dist/internal/advance-stage/hook.js +0 -40
  219. package/dist/internal/advance-stage/parsers.d.ts +0 -72
  220. package/dist/internal/advance-stage/parsers.js +0 -357
  221. package/dist/internal/advance-stage/proactive-delegation-trace.d.ts +0 -24
  222. package/dist/internal/advance-stage/proactive-delegation-trace.js +0 -56
  223. package/dist/internal/advance-stage/review-loop.d.ts +0 -16
  224. package/dist/internal/advance-stage/review-loop.js +0 -199
  225. package/dist/internal/advance-stage/rewind.d.ts +0 -14
  226. package/dist/internal/advance-stage/rewind.js +0 -108
  227. package/dist/internal/advance-stage/start-flow.d.ts +0 -13
  228. package/dist/internal/advance-stage/start-flow.js +0 -241
  229. package/dist/internal/advance-stage/verify.d.ts +0 -21
  230. package/dist/internal/advance-stage/verify.js +0 -185
  231. package/dist/internal/advance-stage.d.ts +0 -7
  232. package/dist/internal/advance-stage.js +0 -138
  233. package/dist/internal/cohesion-contract-stub.d.ts +0 -24
  234. package/dist/internal/cohesion-contract-stub.js +0 -148
  235. package/dist/internal/compound-readiness.d.ts +0 -23
  236. package/dist/internal/compound-readiness.js +0 -102
  237. package/dist/internal/detect-public-api-changes.d.ts +0 -5
  238. package/dist/internal/detect-public-api-changes.js +0 -45
  239. package/dist/internal/detect-supply-chain-changes.d.ts +0 -6
  240. package/dist/internal/detect-supply-chain-changes.js +0 -138
  241. package/dist/internal/early-loop-status.d.ts +0 -7
  242. package/dist/internal/early-loop-status.js +0 -93
  243. package/dist/internal/envelope-validate.d.ts +0 -7
  244. package/dist/internal/envelope-validate.js +0 -66
  245. package/dist/internal/flow-state-repair.d.ts +0 -20
  246. package/dist/internal/flow-state-repair.js +0 -104
  247. package/dist/internal/plan-split-waves.d.ts +0 -190
  248. package/dist/internal/plan-split-waves.js +0 -764
  249. package/dist/internal/runtime-integrity.d.ts +0 -7
  250. package/dist/internal/runtime-integrity.js +0 -268
  251. package/dist/internal/slice-commit.d.ts +0 -7
  252. package/dist/internal/slice-commit.js +0 -619
  253. package/dist/internal/tdd-loop-status.d.ts +0 -14
  254. package/dist/internal/tdd-loop-status.js +0 -68
  255. package/dist/internal/tdd-red-evidence.d.ts +0 -7
  256. package/dist/internal/tdd-red-evidence.js +0 -153
  257. package/dist/internal/waiver-grant.d.ts +0 -62
  258. package/dist/internal/waiver-grant.js +0 -294
  259. package/dist/internal/wave-status.d.ts +0 -74
  260. package/dist/internal/wave-status.js +0 -506
  261. package/dist/managed-resources.d.ts +0 -53
  262. package/dist/managed-resources.js +0 -313
  263. package/dist/policy.d.ts +0 -10
  264. package/dist/policy.js +0 -167
  265. package/dist/retro-gate.d.ts +0 -9
  266. package/dist/retro-gate.js +0 -47
  267. package/dist/run-archive.d.ts +0 -61
  268. package/dist/run-archive.js +0 -391
  269. package/dist/runs.d.ts +0 -2
  270. package/dist/runs.js +0 -2
  271. package/dist/stack-detection.d.ts +0 -116
  272. package/dist/stack-detection.js +0 -489
  273. package/dist/streaming/event-stream.d.ts +0 -31
  274. package/dist/streaming/event-stream.js +0 -114
  275. package/dist/tdd-cycle.d.ts +0 -107
  276. package/dist/tdd-cycle.js +0 -289
  277. package/dist/tdd-verification-evidence.d.ts +0 -17
  278. package/dist/tdd-verification-evidence.js +0 -122
  279. package/dist/track-heuristics.d.ts +0 -27
  280. package/dist/track-heuristics.js +0 -154
  281. package/dist/util/slice-id.d.ts +0 -58
  282. package/dist/util/slice-id.js +0 -89
  283. package/dist/worktree-manager.d.ts +0 -20
  284. package/dist/worktree-manager.js +0 -108
package/dist/cli.js CHANGED
@@ -1,530 +1,126 @@
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, in an interactive TTY, cclaw shows a checkbox picker
22
+ (auto-detected harnesses pre-selected; Up/Down · Space · Enter).
23
+ - In non-TTY (CI, npx --yes, piped input), cclaw auto-detects from project
24
+ root markers (.claude/, .cursor/, .opencode/, .codex/, .agents/skills/,
25
+ CLAUDE.md, opencode.json) and exits with an error if nothing is found.
56
26
 
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
27
+ 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
28
 
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
29
+ Options:
30
+ --harness=<id>[,<id>] Comma-separated list. Supported: ${HARNESS_IDS.join(", ")}.
73
31
  `;
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
32
  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;
395
- }
396
- if (flag.startsWith("--disposition=")) {
397
- parsed.archiveDisposition = parseArchiveDisposition(flag.replace("--disposition=", ""));
398
- continue;
399
- }
400
- if (flag.startsWith("--reason=")) {
401
- parsed.archiveDispositionReason = flag.replace("--reason=", "").trim();
402
- continue;
403
- }
404
- }
405
- return parsed;
406
- }
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(", ")}`);
33
+ const [command = "help", ...rest] = argv;
34
+ const flags = {};
35
+ let harnesses;
36
+ for (const arg of rest) {
37
+ if (arg.startsWith("--harness=")) {
38
+ const list = arg.slice("--harness=".length).split(",").map((value) => value.trim()).filter(Boolean);
39
+ const invalid = list.filter((value) => !HARNESS_IDS.includes(value));
40
+ if (invalid.length > 0) {
41
+ throw new Error(`Unknown harnesses: ${invalid.join(", ")}. Supported: ${HARNESS_IDS.join(", ")}`);
433
42
  }
434
- ctx.stdout.write(`${JSON.stringify({
435
- track: effectiveTrack ?? "standard",
436
- harnesses: previewConfig.harnesses,
437
- generatedSurfaces: previewSurfaces
438
- }, null, 2)}\n`);
439
- return 0;
43
+ harnesses = list;
440
44
  }
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(", ")}`);
45
+ else if (arg.startsWith("--")) {
46
+ const [name, ...value] = arg.slice(2).split("=");
47
+ flags[name] = value.length === 0 ? true : value.join("=");
448
48
  }
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).");
49
+ else {
50
+ flags._ = arg;
51
+ }
52
+ }
53
+ return { command, harnesses, flags };
54
+ }
55
+ export async function runCli(argv, context) {
56
+ configureLogger(context.stdout, context.stderr);
57
+ const args = parseArgs(argv);
58
+ switch (args.command) {
59
+ case "init": {
60
+ const result = await initCclaw({
61
+ cwd: context.cwd,
62
+ harnesses: args.harnesses,
63
+ interactive: true
64
+ });
65
+ info(`[cclaw] init complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
459
66
  return 0;
460
67
  }
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.`);
68
+ case "sync": {
69
+ const result = await syncCclaw({
70
+ cwd: context.cwd,
71
+ harnesses: args.harnesses,
72
+ interactive: true
73
+ });
74
+ info(`[cclaw] sync complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
75
+ return 0;
486
76
  }
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.`);
77
+ case "upgrade": {
78
+ const result = await upgradeCclaw({
79
+ cwd: context.cwd,
80
+ harnesses: args.harnesses,
81
+ interactive: true
82
+ });
83
+ info(`[cclaw] upgrade complete. Harnesses: ${result.installedHarnesses.join(", ")}`);
84
+ return 0;
489
85
  }
490
- else {
491
- info(ctx, `Knowledge: 0 active entries in ${k.knowledgePath}. Capture lessons from this run through the learnings skill before they fade.`);
86
+ case "uninstall": {
87
+ await uninstallCclaw({ cwd: context.cwd });
88
+ info("[cclaw] uninstall complete.");
89
+ return 0;
492
90
  }
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();
91
+ case "version":
92
+ case "--version":
93
+ case "-v":
94
+ info(CCLAW_VERSION);
95
+ return 0;
96
+ case "help":
97
+ case "--help":
98
+ case "-h":
99
+ info(HELP_BODY);
100
+ return 0;
101
+ case "plan":
102
+ case "status":
103
+ case "ship":
104
+ case "migrate":
105
+ case "build":
106
+ case "review":
107
+ logError(`[cclaw] '${args.command}' is not a CLI command in v8. Flow control happens via /cc inside your harness.`);
108
+ return 2;
109
+ default:
110
+ logError(`[cclaw] unknown command: ${args.command}`);
111
+ logError(HELP_BODY);
112
+ return 2;
113
+ }
114
+ }
115
+ const isMain = import.meta.url === `file://${process.argv[1]}`;
116
+ if (isMain) {
117
+ runCli(process.argv.slice(2), { cwd: process.cwd(), stdout: process.stdout, stderr: process.stderr })
118
+ .then((code) => {
119
+ process.exit(code);
120
+ })
121
+ .catch((err) => {
122
+ const message = err instanceof Error ? err.message : String(err);
123
+ process.stderr.write(`[cclaw] ${message}\n`);
124
+ process.exit(1);
125
+ });
529
126
  }
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[]>;