@printpractical/cruze 0.0.13 → 0.0.14

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 (298) hide show
  1. package/README.md +61 -118
  2. package/dist/adapters/inbound/cli/cli_context.js +0 -27
  3. package/dist/adapters/inbound/cli/commands/code.js +5 -18
  4. package/dist/adapters/inbound/cli/commands/documents.js +11 -37
  5. package/dist/adapters/inbound/cli/commands/init.js +1 -1
  6. package/dist/adapters/inbound/cli/commands/review.js +2 -9
  7. package/dist/adapters/inbound/cli/commands/status.js +16 -63
  8. package/dist/adapters/inbound/cli/commands.js +10 -37
  9. package/dist/adapters/inbound/cli/parse_command.js +0 -54
  10. package/dist/adapters/outbound/git_repository.js +2 -71
  11. package/dist/app/ports/repository.js +0 -12
  12. package/dist/app/project_context.js +15 -25
  13. package/dist/app/use_cases/approve_document.js +29 -0
  14. package/dist/app/use_cases/check_code.js +21 -56
  15. package/dist/app/use_cases/new_document.js +25 -0
  16. package/dist/app/use_cases/project_status.js +43 -67
  17. package/dist/app/use_cases/run_review.js +11 -30
  18. package/dist/app/use_cases/validate_project.js +4 -4
  19. package/dist/domain/approvals.js +51 -0
  20. package/dist/domain/check/check_source.js +2 -31
  21. package/dist/domain/config.js +8 -84
  22. package/dist/domain/hashing.js +16 -30
  23. package/dist/domain/ids.js +13 -27
  24. package/dist/domain/next_step.js +41 -0
  25. package/dist/domain/project/features.js +71 -0
  26. package/dist/domain/project/layout.js +11 -27
  27. package/dist/domain/project/project_docs.js +48 -0
  28. package/dist/domain/project/release.js +30 -0
  29. package/dist/domain/scaffold.js +0 -1
  30. package/dist/domain/skill_budget.js +4 -4
  31. package/dist/domain/trace.js +8 -25
  32. package/dist/domain/validation/document_rules.js +70 -0
  33. package/dist/domain/validation/release_rules.js +45 -0
  34. package/dist/domain/validation/validate_project.js +20 -27
  35. package/dist/domain/versions/cruze_version.js +3 -9
  36. package/dist/main.js +1 -1
  37. package/package.json +1 -1
  38. package/skills/asking/SKILL.md +51 -0
  39. package/skills/behavioural-testing/SKILL.md +14 -16
  40. package/skills/behavioural-testing/examples.md +1 -2
  41. package/skills/behavioural-testing/fakes.md +2 -2
  42. package/skills/build/SKILL.md +34 -38
  43. package/skills/dependency-approval/SKILL.md +34 -31
  44. package/skills/envision/SKILL.md +23 -18
  45. package/skills/envision/architecture.md +16 -0
  46. package/skills/envision/breakdown.md +14 -0
  47. package/skills/envision/possibilities.md +6 -7
  48. package/skills/fix/SKILL.md +34 -0
  49. package/skills/formats/SKILL.md +39 -87
  50. package/skills/formats/config.md +47 -0
  51. package/skills/formats/templates/architecture.md +18 -74
  52. package/skills/formats/templates/feature.md +18 -34
  53. package/skills/formats/templates/vision.md +15 -27
  54. package/skills/hexagonal-design/SKILL.md +11 -11
  55. package/skills/hexagonal-design/contracts.md +3 -3
  56. package/skills/hexagonal-design/fundamentals.md +1 -1
  57. package/skills/hexagonal-design/languages/cpp.md +1 -1
  58. package/skills/hexagonal-design/languages/rust.md +1 -1
  59. package/skills/hexagonal-design/languages/swift.md +2 -2
  60. package/skills/hexagonal-design/runtime.md +2 -2
  61. package/skills/research/SKILL.md +4 -4
  62. package/skills/research/evaluation.md +1 -1
  63. package/skills/review/SKILL.md +27 -0
  64. package/skills/roles/SKILL.md +8 -59
  65. package/skills/roles/code-reviewer.md +21 -32
  66. package/skills/roles/researcher.md +3 -3
  67. package/skills/shape/SKILL.md +37 -0
  68. package/skills/shape/self-check.md +12 -0
  69. package/src/adapters/inbound/cli/cli_context.ts +0 -27
  70. package/src/adapters/inbound/cli/commands/code.ts +5 -18
  71. package/src/adapters/inbound/cli/commands/documents.ts +11 -37
  72. package/src/adapters/inbound/cli/commands/init.ts +1 -1
  73. package/src/adapters/inbound/cli/commands/review.ts +2 -9
  74. package/src/adapters/inbound/cli/commands/status.ts +16 -63
  75. package/src/adapters/inbound/cli/commands.ts +10 -37
  76. package/src/adapters/inbound/cli/parse_command.ts +0 -54
  77. package/src/adapters/outbound/git_repository.ts +2 -71
  78. package/src/app/ports/repository.ts +0 -12
  79. package/src/app/project_context.ts +15 -25
  80. package/src/app/use_cases/approve_document.ts +29 -0
  81. package/src/app/use_cases/check_code.ts +21 -56
  82. package/src/app/use_cases/new_document.ts +25 -0
  83. package/src/app/use_cases/project_status.ts +49 -73
  84. package/src/app/use_cases/run_review.ts +11 -30
  85. package/src/app/use_cases/validate_project.ts +4 -4
  86. package/src/domain/approvals.ts +51 -0
  87. package/src/domain/check/check_source.ts +2 -31
  88. package/src/domain/config.ts +9 -85
  89. package/src/domain/hashing.ts +16 -30
  90. package/src/domain/ids.ts +13 -27
  91. package/src/domain/next_step.ts +41 -0
  92. package/src/domain/project/features.ts +71 -0
  93. package/src/domain/project/layout.ts +11 -27
  94. package/src/domain/project/project_docs.ts +48 -0
  95. package/src/domain/project/release.ts +30 -0
  96. package/src/domain/scaffold.ts +0 -1
  97. package/src/domain/skill_budget.ts +4 -4
  98. package/src/domain/trace.ts +8 -25
  99. package/src/domain/validation/document_rules.ts +70 -0
  100. package/src/domain/validation/release_rules.ts +45 -0
  101. package/src/domain/validation/validate_project.ts +21 -28
  102. package/src/domain/versions/cruze_version.ts +3 -9
  103. package/src/main.ts +1 -1
  104. package/templates/init/AGENTS.md +4 -12
  105. package/templates/init/ci.yml +3 -3
  106. package/templates/init/config.yaml +8 -17
  107. package/templates/init/review/claude.yaml +2 -2
  108. package/dist/adapters/inbound/cli/argument_files.js +0 -29
  109. package/dist/adapters/inbound/cli/commands/diff.js +0 -23
  110. package/dist/adapters/inbound/cli/commands/journal.js +0 -32
  111. package/dist/adapters/inbound/cli/commands/progress.js +0 -55
  112. package/dist/adapters/inbound/cli/commands/realign.js +0 -28
  113. package/dist/adapters/inbound/cli/commands/show.js +0 -96
  114. package/dist/app/use_cases/abandon_work.js +0 -42
  115. package/dist/app/use_cases/approve_artifact.js +0 -197
  116. package/dist/app/use_cases/journal_events.js +0 -64
  117. package/dist/app/use_cases/land_change.js +0 -134
  118. package/dist/app/use_cases/new_project_doc.js +0 -48
  119. package/dist/app/use_cases/new_work_item.js +0 -75
  120. package/dist/app/use_cases/realign_done.js +0 -45
  121. package/dist/app/use_cases/realign_status.js +0 -106
  122. package/dist/app/use_cases/record_progress.js +0 -118
  123. package/dist/app/use_cases/show_elements.js +0 -18
  124. package/dist/app/use_cases/show_notes.js +0 -11
  125. package/dist/app/use_cases/show_scope.js +0 -51
  126. package/dist/app/use_cases/upstream_diff.js +0 -55
  127. package/dist/domain/approvals/agent_approval.js +0 -68
  128. package/dist/domain/approvals/evaluate.js +0 -36
  129. package/dist/domain/approvals/fingerprint.js +0 -52
  130. package/dist/domain/approvals/rebase.js +0 -39
  131. package/dist/domain/approvals/records.js +0 -50
  132. package/dist/domain/approvals/upstream_text.js +0 -36
  133. package/dist/domain/architecture_sections.js +0 -23
  134. package/dist/domain/check/decision_comments.js +0 -38
  135. package/dist/domain/decision_citations.js +0 -62
  136. package/dist/domain/edits/agents_file.js +0 -58
  137. package/dist/domain/edits/managed_tables.js +0 -60
  138. package/dist/domain/edits/progress_block.js +0 -33
  139. package/dist/domain/edits/status_lines.js +0 -52
  140. package/dist/domain/elements.js +0 -126
  141. package/dist/domain/journal.js +0 -109
  142. package/dist/domain/land/bookkeeping.js +0 -54
  143. package/dist/domain/land/merge_plan.js +0 -137
  144. package/dist/domain/land/text_ops.js +0 -66
  145. package/dist/domain/line_diff.js +0 -56
  146. package/dist/domain/project/artifact_ref.js +0 -42
  147. package/dist/domain/project/deltas.js +0 -49
  148. package/dist/domain/project/element_lookup.js +0 -124
  149. package/dist/domain/project/living_model.js +0 -55
  150. package/dist/domain/project/new_items.js +0 -48
  151. package/dist/domain/project/notes.js +0 -74
  152. package/dist/domain/project/plan_parts.js +0 -111
  153. package/dist/domain/project/progress.js +0 -43
  154. package/dist/domain/project/project_view.js +0 -72
  155. package/dist/domain/project/roadmap.js +0 -43
  156. package/dist/domain/project/scope_view.js +0 -134
  157. package/dist/domain/project/work_items.js +0 -68
  158. package/dist/domain/status/next_step.js +0 -181
  159. package/dist/domain/status/pending_rethink.js +0 -22
  160. package/dist/domain/status/verification.js +0 -29
  161. package/dist/domain/status/work_status.js +0 -125
  162. package/dist/domain/validation/decision_rules.js +0 -76
  163. package/dist/domain/validation/delta_rules.js +0 -81
  164. package/dist/domain/validation/element_rules.js +0 -104
  165. package/dist/domain/validation/future_rules.js +0 -40
  166. package/dist/domain/validation/living_rules.js +0 -99
  167. package/dist/domain/validation/plan_rules.js +0 -124
  168. package/dist/domain/validation/project_rules.js +0 -115
  169. package/dist/domain/validation/size_rules.js +0 -45
  170. package/dist/domain/validation/vision_rules.js +0 -41
  171. package/dist/domain/validation/work_item_rules.js +0 -175
  172. package/dist/domain/versions/realign_notes.js +0 -72
  173. package/dist/domain/versions/rule_versions.js +0 -29
  174. package/dist/domain/versions/scheduled_exceptions.js +0 -41
  175. package/skills/about/SKILL.md +0 -21
  176. package/skills/architect/SKILL.md +0 -49
  177. package/skills/architect/feature.md +0 -40
  178. package/skills/architect/project.md +0 -71
  179. package/skills/architect/tweak.md +0 -22
  180. package/skills/architect/walkthrough.md +0 -35
  181. package/skills/domain-language/SKILL.md +0 -37
  182. package/skills/envision/feature.md +0 -25
  183. package/skills/envision/intake.md +0 -28
  184. package/skills/envision/project.md +0 -24
  185. package/skills/explore/SKILL.md +0 -39
  186. package/skills/formats/reference/architecture.md +0 -84
  187. package/skills/formats/reference/config.md +0 -80
  188. package/skills/formats/reference/durable-docs.md +0 -74
  189. package/skills/formats/reference/specs.md +0 -65
  190. package/skills/formats/reference/work-items.md +0 -100
  191. package/skills/formats/templates/adr.md +0 -7
  192. package/skills/formats/templates/change.md +0 -29
  193. package/skills/formats/templates/glossary.md +0 -8
  194. package/skills/formats/templates/roadmap.md +0 -32
  195. package/skills/formats/templates/spec.md +0 -11
  196. package/skills/formats/templates/standalone-change.md +0 -46
  197. package/skills/grilling/SKILL.md +0 -90
  198. package/skills/grilling/illustrating.md +0 -38
  199. package/skills/improve/SKILL.md +0 -51
  200. package/skills/land/SKILL.md +0 -48
  201. package/skills/next/SKILL.md +0 -31
  202. package/skills/plan/SKILL.md +0 -62
  203. package/skills/plan/tasks.md +0 -35
  204. package/skills/plan/test-plan.md +0 -14
  205. package/skills/realign/SKILL.md +0 -37
  206. package/skills/realign/notes/0.0.10.md +0 -131
  207. package/skills/realign/notes/0.0.11.md +0 -15
  208. package/skills/realign/notes/0.0.12.md +0 -31
  209. package/skills/realign/notes/0.0.13.md +0 -11
  210. package/skills/realign/notes/0.0.2.md +0 -69
  211. package/skills/realign/notes/0.0.3.md +0 -11
  212. package/skills/realign/notes/0.0.4.md +0 -27
  213. package/skills/realign/notes/0.0.5.md +0 -38
  214. package/skills/realign/notes/0.0.6.md +0 -44
  215. package/skills/realign/notes/0.0.7.md +0 -11
  216. package/skills/realign/notes/0.0.8.md +0 -97
  217. package/skills/realign/notes/0.0.9.md +0 -59
  218. package/skills/realign/notes.md +0 -40
  219. package/skills/rethink/SKILL.md +0 -62
  220. package/skills/rethink/levels.md +0 -54
  221. package/skills/roadmap/SKILL.md +0 -54
  222. package/skills/roles/auditor.md +0 -35
  223. package/skills/roles/design-reviewer.md +0 -43
  224. package/skills/roles/design-rubric.md +0 -41
  225. package/skills/roles/plan-rubric.md +0 -11
  226. package/skills/roles/surveyor.md +0 -41
  227. package/skills/roles/verifier.md +0 -42
  228. package/skills/triage/SKILL.md +0 -37
  229. package/skills/verify/SKILL.md +0 -45
  230. package/skills/verify/manual-test.md +0 -23
  231. package/src/adapters/inbound/cli/argument_files.ts +0 -29
  232. package/src/adapters/inbound/cli/commands/diff.ts +0 -23
  233. package/src/adapters/inbound/cli/commands/journal.ts +0 -32
  234. package/src/adapters/inbound/cli/commands/progress.ts +0 -55
  235. package/src/adapters/inbound/cli/commands/realign.ts +0 -28
  236. package/src/adapters/inbound/cli/commands/show.ts +0 -96
  237. package/src/app/use_cases/abandon_work.ts +0 -42
  238. package/src/app/use_cases/approve_artifact.ts +0 -197
  239. package/src/app/use_cases/journal_events.ts +0 -64
  240. package/src/app/use_cases/land_change.ts +0 -134
  241. package/src/app/use_cases/new_project_doc.ts +0 -48
  242. package/src/app/use_cases/new_work_item.ts +0 -75
  243. package/src/app/use_cases/realign_done.ts +0 -45
  244. package/src/app/use_cases/realign_status.ts +0 -106
  245. package/src/app/use_cases/record_progress.ts +0 -118
  246. package/src/app/use_cases/show_elements.ts +0 -18
  247. package/src/app/use_cases/show_notes.ts +0 -11
  248. package/src/app/use_cases/show_scope.ts +0 -51
  249. package/src/app/use_cases/upstream_diff.ts +0 -55
  250. package/src/domain/approvals/agent_approval.ts +0 -68
  251. package/src/domain/approvals/evaluate.ts +0 -36
  252. package/src/domain/approvals/fingerprint.ts +0 -52
  253. package/src/domain/approvals/rebase.ts +0 -39
  254. package/src/domain/approvals/records.ts +0 -50
  255. package/src/domain/approvals/upstream_text.ts +0 -36
  256. package/src/domain/architecture_sections.ts +0 -23
  257. package/src/domain/check/decision_comments.ts +0 -38
  258. package/src/domain/decision_citations.ts +0 -62
  259. package/src/domain/edits/agents_file.ts +0 -58
  260. package/src/domain/edits/managed_tables.ts +0 -60
  261. package/src/domain/edits/progress_block.ts +0 -33
  262. package/src/domain/edits/status_lines.ts +0 -52
  263. package/src/domain/elements.ts +0 -126
  264. package/src/domain/journal.ts +0 -109
  265. package/src/domain/land/bookkeeping.ts +0 -54
  266. package/src/domain/land/merge_plan.ts +0 -137
  267. package/src/domain/land/text_ops.ts +0 -66
  268. package/src/domain/line_diff.ts +0 -56
  269. package/src/domain/project/artifact_ref.ts +0 -42
  270. package/src/domain/project/deltas.ts +0 -49
  271. package/src/domain/project/element_lookup.ts +0 -124
  272. package/src/domain/project/living_model.ts +0 -55
  273. package/src/domain/project/new_items.ts +0 -48
  274. package/src/domain/project/notes.ts +0 -74
  275. package/src/domain/project/plan_parts.ts +0 -111
  276. package/src/domain/project/progress.ts +0 -43
  277. package/src/domain/project/project_view.ts +0 -72
  278. package/src/domain/project/roadmap.ts +0 -43
  279. package/src/domain/project/scope_view.ts +0 -134
  280. package/src/domain/project/work_items.ts +0 -68
  281. package/src/domain/status/next_step.ts +0 -181
  282. package/src/domain/status/pending_rethink.ts +0 -22
  283. package/src/domain/status/verification.ts +0 -29
  284. package/src/domain/status/work_status.ts +0 -125
  285. package/src/domain/validation/decision_rules.ts +0 -76
  286. package/src/domain/validation/delta_rules.ts +0 -81
  287. package/src/domain/validation/element_rules.ts +0 -104
  288. package/src/domain/validation/future_rules.ts +0 -40
  289. package/src/domain/validation/living_rules.ts +0 -99
  290. package/src/domain/validation/plan_rules.ts +0 -124
  291. package/src/domain/validation/project_rules.ts +0 -115
  292. package/src/domain/validation/size_rules.ts +0 -45
  293. package/src/domain/validation/vision_rules.ts +0 -41
  294. package/src/domain/validation/work_item_rules.ts +0 -175
  295. package/src/domain/versions/realign_notes.ts +0 -72
  296. package/src/domain/versions/rule_versions.ts +0 -29
  297. package/src/domain/versions/scheduled_exceptions.ts +0 -41
  298. package/templates/init/gitattributes +0 -2
@@ -1,38 +1,29 @@
1
1
  # Code reviewer
2
2
 
3
- You review the code a change adds, before it lands. You work in two lanes. The spec lane asks whether the code does what the change promised, and nothing else. The architecture lane asks whether it sits where the design put it and is built the way the project's standards require. You report findings, and you edit nothing.
3
+ You review the code of one feature before it lands, in a fresh context. You ask two things: does the code do what the user approved, and will it hold up when it runs. You report findings, and you edit nothing.
4
4
 
5
5
  ## Inputs
6
6
 
7
- - The change's `change.md`, and the output of `cruze show <ref>`: the elements it builds, the scenarios it delivers, the settled decisions and the ledger. Read an element it lists as cited only when the diff calls it, with `cruze show <ID>`.
8
- - The diff under review, from `git diff <base>` for the base commit you are given. When the base is where an earlier verify stopped, review older code only where the diff changes what it does.
9
- - The ADRs in `docs/adr/`, and the specs in `docs/specs/` for the capabilities the change touches.
10
- - The references `cruze show` lists, at the sections the change's elements cite.
11
- - The settled ledger, as `.agents/skills/cruze-roles/SKILL.md` defines it, with the output of `cruze journal list --event disposition --item <ref>`.
12
- - The deviations the change recorded, from `cruze journal list --event deviation --item <ref>`.
13
- - The output of `cruze check` and `cruze trace --change <ref>`.
7
+ - The feature file in `docs/features/`: its scenarios, public API, stack sketch and decisions. This is what the user approved.
8
+ - The diff under review, from `git diff <base>` for the base commit you are given.
9
+ - `docs/architecture.md`, at the ports, runtime and layers the diff touches.
10
+ - The output of `cruze check` and `cruze trace <slug>`.
14
11
  - The standards: `.agents/skills/cruze-hexagonal-design/SKILL.md`, its language file for the project's language when one exists, `.agents/skills/cruze-behavioural-testing/SKILL.md` and `.agents/skills/cruze-dependency-approval/SKILL.md`.
15
12
 
13
+ You may run the project's tests.
14
+
16
15
  ## Rubric
17
16
 
18
17
  Review against these items and nothing else. Each finding names one.
19
18
 
20
- ### Spec lane
21
-
22
- 1. **Scenarios.** Every scenario the change delivers is implemented, and has a test that carries its ID, drives the seam the test plan names, and takes its expected values from the scenario.
23
- 2. **Failures.** Each failure scenario produces the error it specifies and leaves the state it specifies. Wire formats, codes and behaviour that a reference governs follow the section the design cites.
24
- 3. **Scope.** The code adds no behaviour the change's scope doesn't deliver, and no public item, variant or operation that only a later change uses. Unrequested or early code is a finding, even when it looks useful or the next change needs it.
25
- 4. **Protected tests.** No behaviour, contract or smoke test for an approved scenario, port or flow was weakened, skipped or deleted without a delta that changes its subject.
26
-
27
- ### Architecture lane
28
-
29
- 5. **Placement.** Every file the diff adds or changes is where the architecture puts its owner, and matches the task's file targets or a recorded deviation.
30
- 6. **Direction.** Dependencies point inward. No technology type crosses a port. Inbound adapters hold no domain rules or workflow.
31
- 7. **Size.** No file holds two responsibilities, and none passes its budget without a recorded exception. No file was split by length alone, leaving one responsibility across files, and no code is bent to fit a budget, such as a type alias, a string where an error type belongs, types merged or a function placed away from its owner to stay under a limit.
32
- 8. **Idiom.** The code is idiomatic for the language, uses its standard tooling, and follows the language file's rules, including where tests live. Tests reuse the fixtures and harnesses in the test support module rather than redefining them. Each `expect`, `unwrap` or panic in the diff has a reason its case can't happen; one a caller, the clock or a concurrent call can reach is a finding.
33
- 9. **Libraries.** Nothing hand-writes what a mature library does without a recorded `build` decision, and every new dependency has a recorded approval. No code works around a dependency or a feature: hand-written code, a shell command or a less idiomatic construct chosen because the clean one needs a dependency is a finding.
34
- 10. **Contracts.** Each adapter honours its port's `Operations`, and each fake passes the same contract tests as the real adapter.
35
- 11. **Deviations.** Each deviation the change recorded is a choice build may make on its own: a private helper or a new file inside the owner's module, a `check.exceptions` entry, a fixture in the test support module, or two tasks swapped. A deviation that added an element, port operation or scenario, wrote a file outside the owner's module, changed an approved scenario's behaviour or its test, worked around a dependency or a feature, or settled a limit, timeout, message or error case the design doesn't give, needed a design amendment: a blocker, with `Needs design change` naming the element.
19
+ 1. **Scenarios.** Every scenario is implemented and has a test that carries its ID, drives a public seam, and takes its expected values from the scenario. Each failure scenario produces the message and leaves the state it specifies.
20
+ 2. **Public API.** What the code exposes matches the feature's public API section: names, types, errors, commands and output. Anything public it doesn't list is a finding.
21
+ 3. **Runtime.** Follow each request, message and event from its source to its consumer through every task, channel and queue. Look for what tests rarely reach: a hang, a spin, a leak of a task, handle or memory, a race, unbounded growth, a full queue holding up unrelated work, a lost result across a reconnect, shutdown that waits forever or drops work it promised to finish.
22
+ 4. **Failures.** Each external call's failure is handled as the feature and the architecture say: disks, networks, peers and user mistakes. Nothing is silently swallowed.
23
+ 5. **Ports and adapters.** Dependencies point inward and match the layers. No technology type crosses a port. Inbound adapters hold no domain rules. Each fake passes the same contract tests as its real adapter.
24
+ 6. **Tests.** No test was weakened, skipped or deleted. Tests drive behaviour through public interfaces rather than restating what a fake was told.
25
+ 7. **Idiom.** The code is idiomatic for the language and follows its language file. Each `expect`, `unwrap` or panic has a reason its case can't happen.
26
+ 8. **Libraries.** Nothing hand-writes what a mature library does, and every significant dependency is in the architecture or approved.
36
27
 
37
28
  ## Findings
38
29
 
@@ -42,17 +33,15 @@ Each finding has this shape:
42
33
  ### <n>. <rubric item>: <one-line summary>
43
34
  - Severity: blocker | concern
44
35
  - Evidence: <path:line, quoting the code>
45
- - Failure scenario: <what goes wrong, concretely, when this runs>
36
+ - Failure scenario: <who meets it, how, and what goes wrong>
46
37
  - Proposed fix: <the specific change>
47
- - Needs design change: <the approved element whose text the fix must change, such as a port's `Operations`, or `no`>
38
+ - Changes what the user approved: <the scenario or public API the fix changes, or no>
48
39
  ```
49
40
 
50
- - A **blocker** means a scenario fails or is untested, a protected test was weakened, a layering rule is broken, an unapproved dependency was added, or an adapter can't honour its port's `Operations`. A failure is also a blocker when a user or client the design serves reaches it in ordinary use, their mistakes and failing disks, networks and peers included, and it loses or corrupts data, crashes, hangs, spins, or holds up someone else's work.
51
- - Everything else is a **concern**, even when its fix needs a design change, such as a failure only hand-made input reaches that harms only its sender: in one change, such cases were the only blockers of two verifies in a row. Say who reaches the failure, and how.
52
- - List every blocker. List at most 5 concerns, or one per 5 tasks of the change when that is more, the most important first. Count the rest as nits: give only their number, never their text. Report only what would go wrong: no concerns is a valid report, and a small change usually has few.
53
- - Drop any finding that contradicts the settled ledger. The only exception is a blocker with new evidence, which you mark `New evidence:` and explain.
54
- - When a finding could be caught mechanically, add `Check: <the cruze check rule or linter setting that would catch it>`.
41
+ - A **blocker** is a scenario that fails or has no test, a public API that differs from the approved one, a broken layer rule, or a failure that someone using the product in an ordinary way reaches and that loses or corrupts data, crashes, hangs, spins, or holds up other work.
42
+ - Everything else is a **concern**. Say who reaches it and how. A failure that only deliberately malformed input reaches, and that harms only its sender, is a concern.
43
+ - List every blocker, and at most 5 concerns, the most important first. Count the rest as nits by number only. No findings is a valid report.
55
44
 
56
45
  ## Report
57
46
 
58
- Report the spec lane, then the architecture lane. End with one line: `Blockers: <n>. Concerns: <n>. Nits: <n>.` When a lane has no findings, give the evidence for its most important item.
47
+ List the findings, then end with one line: `Blockers: <n>. Concerns: <n>. Nits: <n>.`
@@ -1,10 +1,10 @@
1
1
  # Researcher
2
2
 
3
- You find out whether mature libraries already provide the components a design needs, and you answer technical questions from primary sources. You report what you found, and you edit nothing in the project.
3
+ You find out whether mature libraries already provide the components the architecture needs, and you answer technical questions from primary sources. You report what you found, and you edit nothing in the project.
4
4
 
5
5
  ## Inputs
6
6
 
7
- - The components to research. For each: the capability in one line, the requirements that matter, and the module that would own it.
7
+ - The components to research. For each: the capability in one line, and the requirements that matter.
8
8
  - Or a question, with the version it applies to.
9
9
  - The constraints section of `docs/vision.md`.
10
10
  - The project's dependency manifests and lockfiles, if they exist.
@@ -25,7 +25,7 @@ For components, report one block each:
25
25
  | <component> | adopt or build | <package and version, when adopting> | <the deciding reason> |
26
26
 
27
27
  Evidence: <the evaluation table for the serious candidates, with sources and the date checked>
28
- New dependency: yes or no
28
+ New dependency: no, yes, or significant with the reason
29
29
  Claims to verify: <each feature, flag or command the design would rely on, with where the source shows it>
30
30
  ```
31
31
 
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: cruze-shape
3
+ description: Shapes one feature with the user before it is built, writing its behaviour as scenarios, its public API as code and a sketch of how it crosses the stack, and ends with the user's approval.
4
+ ---
5
+
6
+ # Shape
7
+
8
+ Shape is where the user decides what a feature does and what it looks like from outside, before any code exists. It produces one document, `docs/features/<slug>.md`, and one approval. Everything the user would otherwise discover at the end, such as an internal type they wouldn't have chosen or a thread they didn't expect, is shown here instead.
9
+
10
+ Read `.agents/skills/cruze-asking/SKILL.md` and `.agents/skills/cruze-formats/SKILL.md`, and `.agents/skills/cruze-hexagonal-design/SKILL.md` with its language file.
11
+
12
+ ## Steps
13
+
14
+ 1. **Find the feature.** Run `cruze next`, or take the slug the user names. Read its row in the vision's Release table, `docs/architecture.md`, and the feature files of what it needs. Work on a branch named for the feature. Done when you know what the feature is for and what it builds on.
15
+ 2. **Start the document** with `cruze new feature <slug> --title "<title>"`, unless it exists.
16
+ 3. **Write the behaviour.** For the feature's intent, write the scenarios: the main case first, then each edge and each failure a user can meet, with concrete values. Each one is a Given, a When and a Then, in the user's words, with the exact message or output they see. Invent the edge cases a user would hit: empty input, a duplicate, the thing not there, the network gone, the limit reached.
17
+ 4. **Write the public API** as real code in the project's language: every public type, function, command, endpoint, message or file format this feature adds or changes, with its errors. For a command-line tool, the commands and their exact output. Write "No change." when the feature has none.
18
+ 5. **Sketch the stack.** A plain-text diagram of the main scenario crossing the stack: the inbound adapter, the use case, the domain, each port and the adapter behind it, marking what is new. Below it, one line per change to `docs/architecture.md`, such as a new port or a new runtime task, and make those changes there. Name any value the system's own components pass each other untyped or encoded, such as a JSON value, and any new thread, task or queue.
19
+ 6. **Check it yourself** against [self-check.md](self-check.md), and fix what it finds. Done when every item passes.
20
+ 7. **Ask what only the user can answer,** in at most one round, as the asking skill says. Write the answers in.
21
+ 8. **Show it.** In one message:
22
+ - what the feature does, in two sentences;
23
+ - each scenario in one line, as the user would see it;
24
+ - the public API as code;
25
+ - the stack sketch;
26
+ - the decisions you took, one line each.
27
+
28
+ End with: "Do you approve this feature, or what should change?" Apply changes, and say what moved. Done when the user approves.
29
+ 9. **Approve and commit.** Run `cruze approve <slug>`, then commit the feature file and any architecture change with a message such as `docs: shape <slug>`.
30
+
31
+ ## Changing an approved feature
32
+
33
+ Shape also runs when build finds that a scenario or the public API must change. Edit the document, show the user exactly what changed, with the before and after as code or output, and approve again. `cruze status` shows the feature as edited until then.
34
+
35
+ ## Next step
36
+
37
+ `build`, for the approved feature.
@@ -0,0 +1,12 @@
1
+ # Self-check before showing a feature
2
+
3
+ Read the feature as an implementer who never saw the conversation. Each "no" is a gap build would fill with a guess; fix it in the document.
4
+
5
+ 1. **Every failure has a scenario.** For each external call the feature makes, and each input a user gives, the scenarios say what the user sees when it fails: the message, the exit code or the screen, and what state is left behind.
6
+ 2. **Every number is written down.** Each timeout, limit, buffer size, retry count and poll interval the feature depends on has a value, in the scenario or the architecture's runtime.
7
+ 3. **Every queue says what happens when it is full.** For each channel, buffer or queue the feature adds: what a sender does when it is full, and which other work waits meanwhile. One slow peer holds up only its own work unless a decision says otherwise.
8
+ 4. **Shutdown and recovery are covered.** What happens to work in flight when the process stops, a connection drops, or a dependency comes back.
9
+ 5. **The public API is complete.** Every error a caller can meet is named in the code sketch. Nothing public exists only for a later feature.
10
+ 6. **The ports stay ports.** No technology type, such as a database row, an HTTP request or a JSON value, crosses into the domain or the use cases.
11
+ 7. **Nothing is built ahead of need.** Every type, field and operation in the sketch is used by one of this feature's scenarios. A future feature leaves room; it adds nothing now.
12
+ 8. **Each scenario can be tested** through a public interface, with the values it states.
@@ -34,36 +34,9 @@ export interface Options {
34
34
  text: boolean;
35
35
  title?: string;
36
36
  feature?: string;
37
- roadmap?: string;
38
- change?: string;
39
- commit?: string;
40
- summary?: string;
41
- goals?: string;
42
- reason?: string;
43
- set: string[];
44
- item?: string;
45
- event?: string;
46
- out?: string;
47
- redact: boolean;
48
- all: boolean;
49
- file: string[];
50
37
  ci: boolean;
51
- gate?: string;
52
- override?: string;
53
- overlap: boolean;
54
- full: boolean;
55
- replan: string[];
56
- rebase: string[];
57
- byAgent: boolean;
58
- restampUnchanged: boolean;
59
- index: boolean;
60
- notes: boolean;
61
- kind?: string;
62
- about?: string;
63
- round?: string;
64
38
  package?: string;
65
39
  base?: string;
66
- blockers?: string;
67
40
  }
68
41
 
69
42
  export type Handler = (context: CliContext, args: string[], options: Options) => Promise<CommandResult>;
@@ -1,32 +1,19 @@
1
1
  import { posix } from "node:path";
2
2
  import { checkCode, traceTests } from "../../../../app/use_cases/check_code.ts";
3
- import { landChange } from "../../../../app/use_cases/land_change.ts";
4
3
  import type { CliContext, CommandResult, Options } from "../cli_context.ts";
5
4
 
6
5
  export async function runCheck(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
7
- const files = [...options.file, ...args].map((file) => posix.normalize(posix.join(context.workingDirectory, file)));
6
+ const files = args.map((file) => posix.normalize(posix.join(context.workingDirectory, file)));
8
7
  const report = await checkCode(context, { ci: options.ci, ...(files.length === 0 ? {} : { files }) });
9
- const lines = report.findings.map((f) => `${f.severity} ${f.path}${f.line === undefined ? "" : `:${f.line}`} ${f.message} [${f.rule}]${f.pending === true ? " (pending realign)" : ""}`);
8
+ const lines = report.findings.map((f) => `${f.severity} ${f.path}${f.line === undefined ? "" : `:${f.line}`} ${f.message} [${f.rule}]`);
10
9
  lines.push(`Checked ${report.checked} file(s): ${report.passed ? "passed" : "failed"}.`);
11
10
  return { json: report, human: lines.join("\n"), failed: !report.passed };
12
11
  }
13
12
 
14
- export async function runTrace(context: CliContext, _args: string[], options: Options): Promise<CommandResult> {
15
- const report = await traceTests(context, { all: options.all, ...(options.change === undefined ? {} : { change: options.change }) });
13
+ export async function runTrace(context: CliContext, args: string[]): Promise<CommandResult> {
14
+ const report = await traceTests(context, args[0]);
16
15
  const lines = report.missing.map((id) => `missing test for ${id}`);
17
- lines.push(...report.unknown.map((u) => `${u.path}:${u.line} cites ${u.id}, which no spec or delta defines`));
16
+ lines.push(...report.unknown.map((u) => `${u.path}:${u.line} cites ${u.id}, which no feature defines`));
18
17
  lines.push(`Traced ${report.scenarios.length} scenario(s) for ${report.scope}: ${report.passed ? "passed" : "failed"}.`);
19
18
  return { json: report, human: lines.join("\n"), failed: !report.passed };
20
19
  }
21
-
22
- export async function runLand(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
23
- const report = await landChange(context, args[0], options.override === undefined ? {} : { override: options.override });
24
- const lines = [`Landed ${report.change}.`];
25
- if (report.merged.length > 0) lines.push(`Merged into the living docs: ${report.merged.join(", ")}`);
26
- if (report.built.length > 0) lines.push(`Now built: ${report.built.join(", ")}`);
27
- if (report.removed.length > 0) lines.push(`Removed: ${report.removed.join(", ")}`);
28
- if (report.restamped.length > 0) lines.push(`Re-stamped approvals: ${report.restamped.join(", ")}`);
29
- if (report.unexcepted.length > 0) lines.push(`CI checks these again, now that the change realign scheduled them in has landed: ${report.unexcepted.join(", ")}`);
30
- if (report.archivedTo !== undefined) lines.push(`Finished; archived to ${report.archivedTo}.`);
31
- return { json: report, human: lines.join("\n") };
32
- }
@@ -1,9 +1,8 @@
1
- import { approveArtifact } from "../../../../app/use_cases/approve_artifact.ts";
2
- import { PROJECT_DOC_KINDS, createNote, createProjectDoc, type ProjectDocKind } from "../../../../app/use_cases/new_project_doc.ts";
3
- import { createWorkItem, type NewKind } from "../../../../app/use_cases/new_work_item.ts";
1
+ import { approveDocument } from "../../../../app/use_cases/approve_document.ts";
2
+ import { DOCUMENT_KINDS, createDocument, type DocumentKind } from "../../../../app/use_cases/new_document.ts";
4
3
  import { validate } from "../../../../app/use_cases/validate_project.ts";
5
4
  import type { Problem } from "../../../../domain/validation/problem.ts";
6
- import { UsageError, requireArgs, requireOption, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
5
+ import { UsageError, requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
7
6
 
8
7
  export async function runValidate(context: CliContext): Promise<CommandResult> {
9
8
  const report = await validate(context);
@@ -11,44 +10,19 @@ export async function runValidate(context: CliContext): Promise<CommandResult> {
11
10
  return { json: report, human: [...report.problems.map(formatProblem), summary].join("\n"), failed: !report.valid };
12
11
  }
13
12
 
14
- export async function runApprove(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
13
+ export async function runApprove(context: CliContext, args: string[]): Promise<CommandResult> {
15
14
  requireArgs(args, ["document"]);
16
- if (options.byAgent && options.restampUnchanged) throw new UsageError("--by-agent and --restamp-unchanged are alternatives");
17
- const agent = options.byAgent ? "plan-review" : options.restampUnchanged ? "rethink" : undefined;
18
- const report = await approveArtifact(context, args[0] ?? "", { replan: options.replan, rebase: options.rebase, ...(agent === undefined ? {} : { agent }) });
19
- const lines = [`Approved ${report.artifact} (${report.hash.slice(0, 19)}), pinned to ${report.upstream.length} upstream element(s).`];
20
- if (report.basis === "plan-review") lines.push("Approved for the user: its plan review closed with no blocker open.");
21
- if (report.restamped !== undefined) lines.push(`Re-stamped for the user: its own design is unchanged, and only ${report.restamped.join(", ")} changed.`);
22
- if (report.stamped.length > 0) lines.push(`Marked ${report.stamped.length} element(s) planned.`);
23
- if (report.bound !== undefined) lines.push(`Bound the change to branch ${report.bound}.`);
24
- if (report.replanned.length > 0) lines.push(`Set back to planned: ${report.replanned.join(", ")}.`);
25
- if (report.rebased.length > 0) lines.push(`Accepted the current living text of: ${report.rebased.join(", ")}.`);
26
- return { json: report, human: lines.join("\n") };
15
+ const record = await approveDocument(context, args[0] ?? "");
16
+ return { json: record, human: `Approved ${record.path} (${record.hash.slice(0, 19)}).` };
27
17
  }
28
18
 
29
19
  export async function runNew(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
30
20
  requireArgs(args, ["kind"]);
31
- if (PROJECT_DOC_KINDS.includes(args[0] as ProjectDocKind)) {
32
- const report = await createProjectDoc(context, args[0] as ProjectDocKind);
33
- return { json: report, human: `Created ${report.path}` };
34
- }
35
- requireArgs(args, ["kind", "slug"]);
36
- if (args[0] === "note") {
37
- const report = await createNote(context, args[1] ?? "", requireOption(options.title, "--title"), requireOption(options.kind, "--kind"), requireOption(options.about, "--about"));
38
- return { json: report, human: `Created ${report.path}` };
39
- }
40
- const kind = args[0] as NewKind;
41
- if (!["feature", "change", "adr"].includes(kind)) {
42
- throw new UsageError(`cruze new takes ${PROJECT_DOC_KINDS.join(", ")}, feature, change, adr or note, not "${args[0]}"`);
43
- }
44
- const report = await createWorkItem(context, {
45
- kind,
46
- slug: args[1] ?? "",
47
- title: requireOption(options.title, "--title"),
48
- ...(options.feature === undefined ? {} : { feature: options.feature }),
49
- ...(options.roadmap === undefined ? {} : { roadmap: options.roadmap }),
50
- });
51
- return { json: report, human: `Created ${report.kind} ${report.ref} at ${report.path}` };
21
+ const kind = args[0] as DocumentKind;
22
+ if (!DOCUMENT_KINDS.includes(kind)) throw new UsageError(`cruze new takes ${DOCUMENT_KINDS.join(", ")}, not "${args[0]}"`);
23
+ if (kind === "feature") requireArgs(args, ["kind", "slug"]);
24
+ const report = await createDocument(context, kind, args[1], options.title);
25
+ return { json: report, human: `Created ${report.path}` };
52
26
  }
53
27
 
54
28
  export function formatProblem(problem: Problem): string {
@@ -18,6 +18,6 @@ export async function runInit(context: CliContext, _args: string[], options: Opt
18
18
  if (report.created.length > 0) lines.push(`Created: ${report.created.join(", ")}`);
19
19
  if (report.skipped.length > 0) lines.push(`Left untouched (already present): ${report.skipped.join(", ")}`);
20
20
  lines.push(...describeSkillInstall(report.skills));
21
- lines.push("Next: open your coding agent in this repository and ask it what Cruze can do.");
21
+ lines.push("Next: open your coding agent in this repository and ask it to envision the project, with whatever you have: a sentence, a design document, notes.");
22
22
  return { json: report, human: lines.join("\n") };
23
23
  }
@@ -1,18 +1,11 @@
1
1
  import { runReview } from "../../../../app/use_cases/run_review.ts";
2
- import { readArgumentFile } from "../argument_files.ts";
3
- import { UsageError, requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
2
+ import { requireArgs, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
4
3
 
5
4
  export async function runReviewCommand(context: CliContext, args: string[], options: Options): Promise<CommandResult> {
6
5
  requireArgs(args, ["role"]);
7
- const round = options.round === undefined ? undefined : Number(options.round);
8
- if (round !== undefined && round !== 1 && round !== 2) throw new UsageError("--round is 1 or 2");
9
- if (options.blockers !== undefined && round !== 2) throw new UsageError("--blockers goes with --round 2");
10
- const blockers = options.blockers === undefined ? undefined : await readArgumentFile(options.blockers);
11
6
  const report = await runReview(context, {
12
7
  role: args[0] ?? "",
13
- ...(options.item === undefined ? {} : { item: options.item }),
14
- ...(round === undefined ? {} : { round }),
15
- ...(blockers === undefined ? {} : { blockers }),
8
+ ...(options.feature === undefined ? {} : { item: options.feature }),
16
9
  ...(options.base === undefined ? {} : { base: options.base }),
17
10
  });
18
11
  return { json: report, human: report.status === "reported" ? report.report : `${report.instruction}\n\n${report.prompt}` };
@@ -1,71 +1,24 @@
1
- import { checkBuildGate, findOverlaps, showStatus, suggestNext } from "../../../../app/use_cases/project_status.ts";
2
- import type { ApprovalStatus } from "../../../../domain/approvals/evaluate.ts";
3
- import { UsageError, type CliContext, type CommandResult, type Options } from "../cli_context.ts";
1
+ import { showStatus, suggestNext } from "../../../../app/use_cases/project_status.ts";
2
+ import type { NextStep } from "../../../../domain/next_step.ts";
3
+ import type { CliContext, CommandResult } from "../cli_context.ts";
4
4
 
5
- export async function runStatus(context: CliContext, _args: string[], options: Options): Promise<CommandResult> {
6
- if (options.override !== undefined && options.gate === undefined) throw new UsageError("--override goes with --gate build");
7
- if (options.change !== undefined && !options.overlap) throw new UsageError("--change goes with --overlap");
8
- if (options.gate !== undefined && options.overlap) throw new UsageError("--gate and --overlap are alternatives");
9
- if (options.gate !== undefined) {
10
- if (options.gate !== "build") throw new UsageError(`unknown gate "${options.gate}"; the only gate is build`);
11
- const report = await checkBuildGate(context, options.override);
12
- const human = report.passed
13
- ? report.overridden ? `Build gate overridden and journaled:\n ${report.reasons.join("\n ")}` : "Build gate passed."
14
- : `Build gate blocked:\n ${report.reasons.join("\n ")}`;
15
- return { json: report, human, failed: !report.passed };
16
- }
17
- if (options.overlap) {
18
- const report = await findOverlaps(context, options.change);
19
- const human = report.overlaps.length === 0
20
- ? `No other branch touches what ${report.change} touches.`
21
- : report.overlaps.map((o) => `${o.branch}: ${o.item} also touches ${o.shared.join(", ")}`).join("\n");
22
- return { json: report, human };
23
- }
5
+ export async function runStatus(context: CliContext): Promise<CommandResult> {
24
6
  const report = await showStatus(context);
25
- const lines = [`Branch: ${report.branch ?? "(none)"}${report.active === undefined ? "" : `, building ${report.active}`}`];
26
- for (const doc of report.documents) lines.push(describe(doc.artifact, doc));
27
- for (const feature of report.features) {
28
- lines.push(`${describe(`feature ${feature.ref}`, feature.approval)}${pendingNote(feature.rethinkPending)}`);
29
- for (const change of feature.changes) {
30
- const name = change.ref.split("/")[1] ?? change.ref;
31
- lines.push(change.landed !== undefined ? ` ${name}: landed ${change.landed}` : ` ${describe(name, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
32
- }
7
+ const lines = report.documents.map((d) => `${d.path}: ${d.state}`);
8
+ for (const f of report.features) {
9
+ const needs = f.needs.length === 0 ? "" : `, needs ${f.needs.join(", ")}`;
10
+ const approval = f.approval === "missing" ? "" : `, ${f.approval}`;
11
+ lines.push(`${f.slug}: ${f.status}${approval}${f.scenarios === 0 ? "" : `, ${f.scenarios} scenario(s)`}${needs}${f.inRelease ? "" : " (not in the release)"}`);
33
12
  }
34
- for (const change of report.standalone) lines.push(`${describe(`change ${change.ref}`, change.approval)}, tasks ${change.tasksDone}/${change.tasksTotal}${pendingNote(change.rethinkPending)}`);
35
- const json = {
36
- ...report,
37
- documents: report.documents.map(compact),
38
- features: report.features.map((f) => ({ ...f, approval: compact(f.approval), changes: f.changes.map((c) => ({ ...c, approval: compact(c.approval) })) })),
39
- standalone: report.standalone.map((c) => ({ ...c, approval: compact(c.approval) })),
40
- };
41
- return { json, human: lines.join("\n") };
42
- }
43
-
44
- /** The state without the record's hashes: an agent reads status often, and the hashes were a third of each read. */
45
- function compact(status: ApprovalStatus): Omit<ApprovalStatus, "record"> & { approvedAt?: string; by?: string; basis?: string } {
46
- const { record, ...rest } = status;
47
- if (record === undefined) return rest;
48
- return { ...rest, approvedAt: record.approvedAt, by: record.by, ...(record.basis === undefined ? {} : { basis: record.basis }) };
49
- }
50
-
51
- function pendingNote(findings: string[] | undefined): string {
52
- return findings === undefined ? "" : `, ${findings.length} finding(s) waiting on a rethink`;
13
+ lines.push(`Next: ${describe(report.next)}`);
14
+ return { json: report, human: lines.join("\n") };
53
15
  }
54
16
 
55
- /** Every step starts a new session: one session that ran plan, build, verify and land reached 745k tokens of context. */
56
- const FRESH_SESSION = "Run it in a new session, so its context starts empty.";
57
-
58
- const BASIS: Record<string, string> = { "plan-review": " (by the agent, after its plan review)", rethink: " (re-stamped by the agent after a rethink)" };
59
-
60
- function describe(label: string, status: ApprovalStatus): string {
61
- const byAgent = status.state === "approved" ? BASIS[status.record?.basis ?? ""] ?? "" : "";
62
- const detail = status.changed.length > 0 ? ` (${status.changed.join(", ")})` : status.unjournaled === true ? " (no journal entry)" : byAgent;
63
- return `${label}: ${status.state}${detail}`;
17
+ export async function runNext(context: CliContext): Promise<CommandResult> {
18
+ const next = await suggestNext(context);
19
+ return { json: next, human: `Next: ${describe(next)}` };
64
20
  }
65
21
 
66
- export async function runNext(context: CliContext): Promise<CommandResult> {
67
- const report = await suggestNext(context);
68
- const describe = (s: { step: string; target?: string; reason: string }): string => `${s.step}${s.target === undefined ? "" : ` ${s.target}`}: ${s.reason}`;
69
- const lines = [`Next: ${describe(report.next)}`, ...report.also.map((s) => `Also: ${describe(s)}`), FRESH_SESSION];
70
- return { json: { ...report, session: FRESH_SESSION }, human: lines.join("\n") };
22
+ function describe(step: NextStep): string {
23
+ return `${step.step}${step.target === undefined ? "" : ` ${step.target}`}: ${step.reason}`;
71
24
  }
@@ -1,14 +1,9 @@
1
1
  import type { Handler } from "./cli_context.ts";
2
- import { runCheck, runLand, runTrace } from "./commands/code.ts";
3
- import { runDiff } from "./commands/diff.ts";
2
+ import { runCheck, runTrace } from "./commands/code.ts";
4
3
  import { runApprove, runNew, runValidate } from "./commands/documents.ts";
5
4
  import { runInit } from "./commands/init.ts";
6
5
  import { runInstall } from "./commands/install.ts";
7
- import { runRealign } from "./commands/realign.ts";
8
- import { runFeedback, runJournal } from "./commands/journal.ts";
9
- import { runAbandon, runFeatures, runRoadmap, runTask } from "./commands/progress.ts";
10
6
  import { runReviewCommand } from "./commands/review.ts";
11
- import { runShow } from "./commands/show.ts";
12
7
  import { runNext, runStatus } from "./commands/status.ts";
13
8
 
14
9
  /** A command, and the options it takes: one list, or one per subcommand for a command that has them. */
@@ -20,37 +15,15 @@ export interface Command {
20
15
 
21
16
  export const COMMANDS: Record<string, Command> = {
22
17
  init: { handler: runInit, options: ["name", "yes", "agent", "package"], usage: "init [--name <name>] [--yes] [--agent claude|other] [--package <npm spec>] set up this repository and install the skills" },
23
- install: { handler: runInstall, options: ["agent"], usage: "install [--agent <agent>] install or update the Cruze skills" },
24
- validate: { handler: runValidate, options: [], usage: "validate check every document against the formats" },
25
- status: { handler: runStatus, options: ["gate", "override", "overlap", "change"], usage: "status [--gate build [--override <reason>]] [--overlap [--change <ref>]]" },
26
- next: { handler: runNext, options: [], usage: "next the step to run next on this branch, and why" },
27
- diff: { handler: runDiff, options: [], usage: "diff <ref> what changed upstream of a document since its approval, and whether its delta needs a rebase" },
28
- show: {
29
- handler: runShow,
30
- options: ["index", "notes"],
31
- usage: "show <ref> | show <ID>... | show --index [<context>] | show --notes [<target>] a change's design, chosen elements, one line per element, or the notes and hand-offs for a target",
32
- },
33
- approve: {
34
- handler: runApprove,
35
- options: ["replan", "rebase", "by-agent", "restamp-unchanged"],
36
- usage: "approve <vision|architecture|roadmap|ref|path> [--replan <ID>...] [--rebase <ID>...] [--by-agent|--restamp-unchanged] record an approval of a document",
37
- },
38
- new: {
39
- handler: runNew,
40
- options: { vision: [], glossary: [], architecture: [], roadmap: [], feature: ["title", "roadmap"], change: ["title", "feature", "roadmap"], adr: ["title"], note: ["title", "kind", "about"] },
41
- usage: "new <vision|glossary|architecture|roadmap> | new <feature|change|adr> <slug> --title <title> [--feature <ref>] [--roadmap <slug>] | new note <slug> --title <title> --kind <input|intake|explore|research> --about <subjects>",
42
- },
43
- task: { handler: runTask, options: { done: ["change", "commit"], deviation: ["change"], reopen: ["change"] }, usage: "task <done|deviation|reopen> <T#> [text] [--change <ref>] [--commit <sha>]" },
44
- features: { handler: runFeatures, options: { add: ["summary", "goals"], update: ["summary"], drop: ["reason"] }, usage: "features <add|update|drop> <slug> [--summary <text>] [--goals <ids>] [--reason <text>]" },
45
- roadmap: { handler: runRoadmap, options: { prune: [] }, usage: "roadmap prune clear landed items from the roadmap status when a release closes" },
46
- journal: { handler: runJournal, options: { add: ["set", "item"], list: ["event", "item", "all"] }, usage: "journal <add <event> --set key=value... [--item <ref>]|list [--event <event>] [--item <ref>] [--all]>" },
47
- review: { handler: runReviewCommand, options: ["item", "round", "blockers", "base"], usage: "review <role> [--item <ref>] [--round 1|2 --blockers <file>] [--base <commit>] run a role in a fresh agent context" },
48
- feedback: { handler: runFeedback, options: { export: ["out", "no-redact"] }, usage: "feedback export [--out <file>] [--no-redact]" },
49
- trace: { handler: runTrace, options: ["all", "change"], usage: "trace [--all] [--change <ref>] link scenarios to the tests that prove them" },
50
- check: { handler: runCheck, options: ["file", "ci"], usage: "check [<file>...] [--ci] enforce layer rules and file budgets" },
51
- abandon: { handler: runAbandon, options: ["reason"], usage: "abandon <ref> --reason <text> archive a feature or standalone change that stops for good" },
52
- land: { handler: runLand, options: ["override"], usage: "land [<ref>] [--override <reason>] merge a verified change into the living docs" },
53
- realign: { handler: runRealign, options: { status: ["full"], done: ["change"] }, usage: "realign <status [--full]|done [--change <ref>]> what the installed Cruze expects of existing code, and recording that the code meets it" },
18
+ install: { handler: runInstall, options: ["agent"], usage: "install [--agent <agent>] install or update the Cruze skills" },
19
+ new: { handler: runNew, options: { vision: [], architecture: [], feature: ["title"] }, usage: "new vision | new architecture | new feature <slug> [--title <title>] start a document from its template" },
20
+ validate: { handler: runValidate, options: [], usage: "validate check every document against the formats" },
21
+ approve: { handler: runApprove, options: [], usage: "approve <vision|architecture|feature slug> record that the user approved a document as it reads now" },
22
+ status: { handler: runStatus, options: [], usage: "status each document's approval, each feature's progress, and the next step" },
23
+ next: { handler: runNext, options: [], usage: "next the step to run next, and why" },
24
+ trace: { handler: runTrace, options: [], usage: "trace [<feature slug>] link scenarios to the tests that carry their IDs" },
25
+ check: { handler: runCheck, options: ["ci"], usage: "check [<file>...] [--ci] enforce layer rules and file budgets" },
26
+ review: { handler: runReviewCommand, options: ["feature", "base"], usage: "review <code-reviewer|researcher> [--feature <slug>] [--base <commit>] run a role in a fresh agent context" },
54
27
  };
55
28
 
56
29
  export const USAGE = `Usage: cruze <command> [options]
@@ -28,36 +28,9 @@ export function parseCommand(argv: string[]): ParsedCommand {
28
28
  help: { type: "boolean", short: "h", default: false },
29
29
  title: { type: "string" },
30
30
  feature: { type: "string" },
31
- roadmap: { type: "string" },
32
- change: { type: "string" },
33
- commit: { type: "string" },
34
- summary: { type: "string" },
35
- goals: { type: "string" },
36
- reason: { type: "string" },
37
- set: { type: "string", multiple: true, default: [] },
38
- item: { type: "string" },
39
- event: { type: "string" },
40
- out: { type: "string" },
41
- "no-redact": { type: "boolean", default: false },
42
- all: { type: "boolean", default: false },
43
- file: { type: "string", multiple: true, default: [] },
44
31
  ci: { type: "boolean", default: false },
45
- gate: { type: "string" },
46
- override: { type: "string" },
47
- overlap: { type: "boolean", default: false },
48
- full: { type: "boolean", default: false },
49
- round: { type: "string" },
50
32
  package: { type: "string" },
51
- replan: { type: "string", multiple: true, default: [] },
52
- rebase: { type: "string", multiple: true, default: [] },
53
33
  base: { type: "string" },
54
- blockers: { type: "string" },
55
- "by-agent": { type: "boolean", default: false },
56
- "restamp-unchanged": { type: "boolean", default: false },
57
- index: { type: "boolean", default: false },
58
- notes: { type: "boolean", default: false },
59
- kind: { type: "string" },
60
- about: { type: "string" },
61
34
  },
62
35
  });
63
36
  } catch (error) {
@@ -71,39 +44,12 @@ export function parseCommand(argv: string[]): ParsedCommand {
71
44
  agent: values.agent,
72
45
  json: values.json,
73
46
  text: values.text,
74
- set: values.set,
75
- redact: !values["no-redact"],
76
- all: values.all,
77
- file: values.file,
78
47
  ci: values.ci,
79
- overlap: values.overlap,
80
- full: values.full,
81
- replan: values.replan,
82
- rebase: values.rebase,
83
- byAgent: values["by-agent"],
84
- restampUnchanged: values["restamp-unchanged"],
85
- index: values.index,
86
- notes: values.notes,
87
48
  ...optional("name", values.name),
88
49
  ...optional("title", values.title),
89
50
  ...optional("feature", values.feature),
90
- ...optional("roadmap", values.roadmap),
91
- ...optional("change", values.change),
92
- ...optional("commit", values.commit),
93
- ...optional("summary", values.summary),
94
- ...optional("goals", values.goals),
95
- ...optional("reason", values.reason),
96
- ...optional("item", values.item),
97
- ...optional("event", values.event),
98
- ...optional("out", values.out),
99
- ...optional("gate", values.gate),
100
- ...optional("override", values.override),
101
- ...optional("round", values.round),
102
51
  ...optional("package", values.package),
103
52
  ...optional("base", values.base),
104
- ...optional("blockers", values.blockers),
105
- ...optional("kind", values.kind),
106
- ...optional("about", values.about),
107
53
  };
108
54
  const given = [...new Set(tokens.flatMap((token) => (token.kind === "option" ? [token.name] : [])))];
109
55
  return { words: positionals, options, given, help: values.help, version: values.version };