@printpractical/cruze 0.0.13 → 0.0.15

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 (308) 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/install.js +1 -0
  7. package/dist/adapters/inbound/cli/commands/review.js +2 -9
  8. package/dist/adapters/inbound/cli/commands/status.js +16 -63
  9. package/dist/adapters/inbound/cli/commands.js +10 -37
  10. package/dist/adapters/inbound/cli/parse_command.js +0 -54
  11. package/dist/adapters/outbound/git_repository.js +2 -71
  12. package/dist/app/ports/repository.js +0 -12
  13. package/dist/app/project_context.js +15 -25
  14. package/dist/app/use_cases/approve_document.js +29 -0
  15. package/dist/app/use_cases/check_code.js +21 -56
  16. package/dist/app/use_cases/install_skills.js +7 -1
  17. package/dist/app/use_cases/new_document.js +25 -0
  18. package/dist/app/use_cases/project_status.js +43 -67
  19. package/dist/app/use_cases/run_review.js +11 -30
  20. package/dist/app/use_cases/validate_project.js +8 -5
  21. package/dist/domain/approvals.js +51 -0
  22. package/dist/domain/check/check_source.js +3 -32
  23. package/dist/domain/check/imports.js +3 -3
  24. package/dist/domain/check/rust_imports.js +25 -3
  25. package/dist/domain/config.js +8 -84
  26. package/dist/domain/hashing.js +16 -30
  27. package/dist/domain/ids.js +13 -27
  28. package/dist/domain/next_step.js +41 -0
  29. package/dist/domain/project/features.js +71 -0
  30. package/dist/domain/project/layout.js +11 -27
  31. package/dist/domain/project/project_docs.js +48 -0
  32. package/dist/domain/project/release.js +30 -0
  33. package/dist/domain/scaffold.js +0 -1
  34. package/dist/domain/skill_budget.js +4 -4
  35. package/dist/domain/trace.js +8 -25
  36. package/dist/domain/validation/document_rules.js +65 -0
  37. package/dist/domain/validation/release_rules.js +45 -0
  38. package/dist/domain/validation/review_rules.js +21 -0
  39. package/dist/domain/validation/validate_project.js +20 -27
  40. package/dist/domain/versions/cruze_version.js +3 -9
  41. package/dist/main.js +1 -1
  42. package/package.json +1 -1
  43. package/skills/asking/SKILL.md +51 -0
  44. package/skills/behavioural-testing/SKILL.md +14 -16
  45. package/skills/behavioural-testing/examples.md +1 -2
  46. package/skills/behavioural-testing/fakes.md +2 -2
  47. package/skills/build/SKILL.md +34 -38
  48. package/skills/dependency-approval/SKILL.md +34 -31
  49. package/skills/envision/SKILL.md +23 -18
  50. package/skills/envision/architecture.md +16 -0
  51. package/skills/envision/breakdown.md +14 -0
  52. package/skills/envision/possibilities.md +6 -7
  53. package/skills/fix/SKILL.md +34 -0
  54. package/skills/formats/SKILL.md +39 -87
  55. package/skills/formats/config.md +47 -0
  56. package/skills/formats/templates/architecture.md +18 -74
  57. package/skills/formats/templates/feature.md +18 -34
  58. package/skills/formats/templates/vision.md +15 -27
  59. package/skills/hexagonal-design/SKILL.md +11 -11
  60. package/skills/hexagonal-design/contracts.md +3 -3
  61. package/skills/hexagonal-design/fundamentals.md +1 -1
  62. package/skills/hexagonal-design/languages/cpp.md +1 -1
  63. package/skills/hexagonal-design/languages/rust.md +1 -1
  64. package/skills/hexagonal-design/languages/swift.md +2 -2
  65. package/skills/hexagonal-design/runtime.md +2 -2
  66. package/skills/research/SKILL.md +4 -4
  67. package/skills/research/evaluation.md +1 -1
  68. package/skills/review/SKILL.md +27 -0
  69. package/skills/roles/SKILL.md +8 -59
  70. package/skills/roles/code-reviewer.md +22 -32
  71. package/skills/roles/researcher.md +3 -3
  72. package/skills/shape/SKILL.md +37 -0
  73. package/skills/shape/self-check.md +12 -0
  74. package/src/adapters/inbound/cli/cli_context.ts +0 -27
  75. package/src/adapters/inbound/cli/commands/code.ts +5 -18
  76. package/src/adapters/inbound/cli/commands/documents.ts +11 -37
  77. package/src/adapters/inbound/cli/commands/init.ts +1 -1
  78. package/src/adapters/inbound/cli/commands/install.ts +1 -0
  79. package/src/adapters/inbound/cli/commands/review.ts +2 -9
  80. package/src/adapters/inbound/cli/commands/status.ts +16 -63
  81. package/src/adapters/inbound/cli/commands.ts +10 -37
  82. package/src/adapters/inbound/cli/parse_command.ts +0 -54
  83. package/src/adapters/outbound/git_repository.ts +2 -71
  84. package/src/app/ports/repository.ts +0 -12
  85. package/src/app/project_context.ts +15 -25
  86. package/src/app/use_cases/approve_document.ts +29 -0
  87. package/src/app/use_cases/check_code.ts +21 -56
  88. package/src/app/use_cases/install_skills.ts +7 -1
  89. package/src/app/use_cases/new_document.ts +25 -0
  90. package/src/app/use_cases/project_status.ts +49 -73
  91. package/src/app/use_cases/run_review.ts +11 -30
  92. package/src/app/use_cases/validate_project.ts +8 -5
  93. package/src/domain/approvals.ts +51 -0
  94. package/src/domain/check/check_source.ts +3 -32
  95. package/src/domain/check/imports.ts +3 -3
  96. package/src/domain/check/rust_imports.ts +25 -3
  97. package/src/domain/config.ts +9 -85
  98. package/src/domain/hashing.ts +16 -30
  99. package/src/domain/ids.ts +13 -27
  100. package/src/domain/next_step.ts +41 -0
  101. package/src/domain/project/features.ts +71 -0
  102. package/src/domain/project/layout.ts +11 -27
  103. package/src/domain/project/project_docs.ts +48 -0
  104. package/src/domain/project/release.ts +30 -0
  105. package/src/domain/scaffold.ts +0 -1
  106. package/src/domain/skill_budget.ts +4 -4
  107. package/src/domain/trace.ts +8 -25
  108. package/src/domain/validation/document_rules.ts +65 -0
  109. package/src/domain/validation/release_rules.ts +45 -0
  110. package/src/domain/validation/review_rules.ts +21 -0
  111. package/src/domain/validation/validate_project.ts +21 -28
  112. package/src/domain/versions/cruze_version.ts +3 -9
  113. package/src/main.ts +1 -1
  114. package/templates/init/AGENTS.md +4 -12
  115. package/templates/init/ci.yml +3 -3
  116. package/templates/init/config.yaml +8 -17
  117. package/templates/init/review/claude.yaml +2 -2
  118. package/dist/adapters/inbound/cli/argument_files.js +0 -29
  119. package/dist/adapters/inbound/cli/commands/diff.js +0 -23
  120. package/dist/adapters/inbound/cli/commands/journal.js +0 -32
  121. package/dist/adapters/inbound/cli/commands/progress.js +0 -55
  122. package/dist/adapters/inbound/cli/commands/realign.js +0 -28
  123. package/dist/adapters/inbound/cli/commands/show.js +0 -96
  124. package/dist/app/use_cases/abandon_work.js +0 -42
  125. package/dist/app/use_cases/approve_artifact.js +0 -197
  126. package/dist/app/use_cases/journal_events.js +0 -64
  127. package/dist/app/use_cases/land_change.js +0 -134
  128. package/dist/app/use_cases/new_project_doc.js +0 -48
  129. package/dist/app/use_cases/new_work_item.js +0 -75
  130. package/dist/app/use_cases/realign_done.js +0 -45
  131. package/dist/app/use_cases/realign_status.js +0 -106
  132. package/dist/app/use_cases/record_progress.js +0 -118
  133. package/dist/app/use_cases/show_elements.js +0 -18
  134. package/dist/app/use_cases/show_notes.js +0 -11
  135. package/dist/app/use_cases/show_scope.js +0 -51
  136. package/dist/app/use_cases/upstream_diff.js +0 -55
  137. package/dist/domain/approvals/agent_approval.js +0 -68
  138. package/dist/domain/approvals/evaluate.js +0 -36
  139. package/dist/domain/approvals/fingerprint.js +0 -52
  140. package/dist/domain/approvals/rebase.js +0 -39
  141. package/dist/domain/approvals/records.js +0 -50
  142. package/dist/domain/approvals/upstream_text.js +0 -36
  143. package/dist/domain/architecture_sections.js +0 -23
  144. package/dist/domain/check/decision_comments.js +0 -38
  145. package/dist/domain/decision_citations.js +0 -62
  146. package/dist/domain/edits/agents_file.js +0 -58
  147. package/dist/domain/edits/managed_tables.js +0 -60
  148. package/dist/domain/edits/progress_block.js +0 -33
  149. package/dist/domain/edits/status_lines.js +0 -52
  150. package/dist/domain/elements.js +0 -126
  151. package/dist/domain/journal.js +0 -109
  152. package/dist/domain/land/bookkeeping.js +0 -54
  153. package/dist/domain/land/merge_plan.js +0 -137
  154. package/dist/domain/land/text_ops.js +0 -66
  155. package/dist/domain/line_diff.js +0 -56
  156. package/dist/domain/project/artifact_ref.js +0 -42
  157. package/dist/domain/project/deltas.js +0 -49
  158. package/dist/domain/project/element_lookup.js +0 -124
  159. package/dist/domain/project/living_model.js +0 -55
  160. package/dist/domain/project/new_items.js +0 -48
  161. package/dist/domain/project/notes.js +0 -74
  162. package/dist/domain/project/plan_parts.js +0 -111
  163. package/dist/domain/project/progress.js +0 -43
  164. package/dist/domain/project/project_view.js +0 -72
  165. package/dist/domain/project/roadmap.js +0 -43
  166. package/dist/domain/project/scope_view.js +0 -134
  167. package/dist/domain/project/work_items.js +0 -68
  168. package/dist/domain/status/next_step.js +0 -181
  169. package/dist/domain/status/pending_rethink.js +0 -22
  170. package/dist/domain/status/verification.js +0 -29
  171. package/dist/domain/status/work_status.js +0 -125
  172. package/dist/domain/validation/decision_rules.js +0 -76
  173. package/dist/domain/validation/delta_rules.js +0 -81
  174. package/dist/domain/validation/element_rules.js +0 -104
  175. package/dist/domain/validation/future_rules.js +0 -40
  176. package/dist/domain/validation/living_rules.js +0 -99
  177. package/dist/domain/validation/plan_rules.js +0 -124
  178. package/dist/domain/validation/project_rules.js +0 -115
  179. package/dist/domain/validation/size_rules.js +0 -45
  180. package/dist/domain/validation/vision_rules.js +0 -41
  181. package/dist/domain/validation/work_item_rules.js +0 -175
  182. package/dist/domain/versions/realign_notes.js +0 -72
  183. package/dist/domain/versions/rule_versions.js +0 -29
  184. package/dist/domain/versions/scheduled_exceptions.js +0 -41
  185. package/skills/about/SKILL.md +0 -21
  186. package/skills/architect/SKILL.md +0 -49
  187. package/skills/architect/feature.md +0 -40
  188. package/skills/architect/project.md +0 -71
  189. package/skills/architect/tweak.md +0 -22
  190. package/skills/architect/walkthrough.md +0 -35
  191. package/skills/domain-language/SKILL.md +0 -37
  192. package/skills/envision/feature.md +0 -25
  193. package/skills/envision/intake.md +0 -28
  194. package/skills/envision/project.md +0 -24
  195. package/skills/explore/SKILL.md +0 -39
  196. package/skills/formats/reference/architecture.md +0 -84
  197. package/skills/formats/reference/config.md +0 -80
  198. package/skills/formats/reference/durable-docs.md +0 -74
  199. package/skills/formats/reference/specs.md +0 -65
  200. package/skills/formats/reference/work-items.md +0 -100
  201. package/skills/formats/templates/adr.md +0 -7
  202. package/skills/formats/templates/change.md +0 -29
  203. package/skills/formats/templates/glossary.md +0 -8
  204. package/skills/formats/templates/roadmap.md +0 -32
  205. package/skills/formats/templates/spec.md +0 -11
  206. package/skills/formats/templates/standalone-change.md +0 -46
  207. package/skills/grilling/SKILL.md +0 -90
  208. package/skills/grilling/illustrating.md +0 -38
  209. package/skills/improve/SKILL.md +0 -51
  210. package/skills/land/SKILL.md +0 -48
  211. package/skills/next/SKILL.md +0 -31
  212. package/skills/plan/SKILL.md +0 -62
  213. package/skills/plan/tasks.md +0 -35
  214. package/skills/plan/test-plan.md +0 -14
  215. package/skills/realign/SKILL.md +0 -37
  216. package/skills/realign/notes/0.0.10.md +0 -131
  217. package/skills/realign/notes/0.0.11.md +0 -15
  218. package/skills/realign/notes/0.0.12.md +0 -31
  219. package/skills/realign/notes/0.0.13.md +0 -11
  220. package/skills/realign/notes/0.0.2.md +0 -69
  221. package/skills/realign/notes/0.0.3.md +0 -11
  222. package/skills/realign/notes/0.0.4.md +0 -27
  223. package/skills/realign/notes/0.0.5.md +0 -38
  224. package/skills/realign/notes/0.0.6.md +0 -44
  225. package/skills/realign/notes/0.0.7.md +0 -11
  226. package/skills/realign/notes/0.0.8.md +0 -97
  227. package/skills/realign/notes/0.0.9.md +0 -59
  228. package/skills/realign/notes.md +0 -40
  229. package/skills/rethink/SKILL.md +0 -62
  230. package/skills/rethink/levels.md +0 -54
  231. package/skills/roadmap/SKILL.md +0 -54
  232. package/skills/roles/auditor.md +0 -35
  233. package/skills/roles/design-reviewer.md +0 -43
  234. package/skills/roles/design-rubric.md +0 -41
  235. package/skills/roles/plan-rubric.md +0 -11
  236. package/skills/roles/surveyor.md +0 -41
  237. package/skills/roles/verifier.md +0 -42
  238. package/skills/triage/SKILL.md +0 -37
  239. package/skills/verify/SKILL.md +0 -45
  240. package/skills/verify/manual-test.md +0 -23
  241. package/src/adapters/inbound/cli/argument_files.ts +0 -29
  242. package/src/adapters/inbound/cli/commands/diff.ts +0 -23
  243. package/src/adapters/inbound/cli/commands/journal.ts +0 -32
  244. package/src/adapters/inbound/cli/commands/progress.ts +0 -55
  245. package/src/adapters/inbound/cli/commands/realign.ts +0 -28
  246. package/src/adapters/inbound/cli/commands/show.ts +0 -96
  247. package/src/app/use_cases/abandon_work.ts +0 -42
  248. package/src/app/use_cases/approve_artifact.ts +0 -197
  249. package/src/app/use_cases/journal_events.ts +0 -64
  250. package/src/app/use_cases/land_change.ts +0 -134
  251. package/src/app/use_cases/new_project_doc.ts +0 -48
  252. package/src/app/use_cases/new_work_item.ts +0 -75
  253. package/src/app/use_cases/realign_done.ts +0 -45
  254. package/src/app/use_cases/realign_status.ts +0 -106
  255. package/src/app/use_cases/record_progress.ts +0 -118
  256. package/src/app/use_cases/show_elements.ts +0 -18
  257. package/src/app/use_cases/show_notes.ts +0 -11
  258. package/src/app/use_cases/show_scope.ts +0 -51
  259. package/src/app/use_cases/upstream_diff.ts +0 -55
  260. package/src/domain/approvals/agent_approval.ts +0 -68
  261. package/src/domain/approvals/evaluate.ts +0 -36
  262. package/src/domain/approvals/fingerprint.ts +0 -52
  263. package/src/domain/approvals/rebase.ts +0 -39
  264. package/src/domain/approvals/records.ts +0 -50
  265. package/src/domain/approvals/upstream_text.ts +0 -36
  266. package/src/domain/architecture_sections.ts +0 -23
  267. package/src/domain/check/decision_comments.ts +0 -38
  268. package/src/domain/decision_citations.ts +0 -62
  269. package/src/domain/edits/agents_file.ts +0 -58
  270. package/src/domain/edits/managed_tables.ts +0 -60
  271. package/src/domain/edits/progress_block.ts +0 -33
  272. package/src/domain/edits/status_lines.ts +0 -52
  273. package/src/domain/elements.ts +0 -126
  274. package/src/domain/journal.ts +0 -109
  275. package/src/domain/land/bookkeeping.ts +0 -54
  276. package/src/domain/land/merge_plan.ts +0 -137
  277. package/src/domain/land/text_ops.ts +0 -66
  278. package/src/domain/line_diff.ts +0 -56
  279. package/src/domain/project/artifact_ref.ts +0 -42
  280. package/src/domain/project/deltas.ts +0 -49
  281. package/src/domain/project/element_lookup.ts +0 -124
  282. package/src/domain/project/living_model.ts +0 -55
  283. package/src/domain/project/new_items.ts +0 -48
  284. package/src/domain/project/notes.ts +0 -74
  285. package/src/domain/project/plan_parts.ts +0 -111
  286. package/src/domain/project/progress.ts +0 -43
  287. package/src/domain/project/project_view.ts +0 -72
  288. package/src/domain/project/roadmap.ts +0 -43
  289. package/src/domain/project/scope_view.ts +0 -134
  290. package/src/domain/project/work_items.ts +0 -68
  291. package/src/domain/status/next_step.ts +0 -181
  292. package/src/domain/status/pending_rethink.ts +0 -22
  293. package/src/domain/status/verification.ts +0 -29
  294. package/src/domain/status/work_status.ts +0 -125
  295. package/src/domain/validation/decision_rules.ts +0 -76
  296. package/src/domain/validation/delta_rules.ts +0 -81
  297. package/src/domain/validation/element_rules.ts +0 -104
  298. package/src/domain/validation/future_rules.ts +0 -40
  299. package/src/domain/validation/living_rules.ts +0 -99
  300. package/src/domain/validation/plan_rules.ts +0 -124
  301. package/src/domain/validation/project_rules.ts +0 -115
  302. package/src/domain/validation/size_rules.ts +0 -45
  303. package/src/domain/validation/vision_rules.ts +0 -41
  304. package/src/domain/validation/work_item_rules.ts +0 -175
  305. package/src/domain/versions/realign_notes.ts +0 -72
  306. package/src/domain/versions/rule_versions.ts +0 -29
  307. package/src/domain/versions/scheduled_exceptions.ts +0 -41
  308. package/templates/init/gitattributes +0 -2
@@ -36,15 +36,9 @@ export function versionSkew(cli: string, recorded: string | undefined): VersionS
36
36
  * after `version:`, so the file's comments and layout survive.
37
37
  */
38
38
  export function withRecordedVersion(configText: string, version: string): string {
39
- return withVersionLine(configText, "cruze", version);
40
- }
41
-
42
- /** The config text with a top-level version key, such as `cruze:` or `standards:`, set in place. */
43
- export function withVersionLine(configText: string, key: "cruze" | "standards", version: string): string {
44
- const line = `${key}: ${JSON.stringify(version)}`;
45
- const existing = new RegExp(`^${key}:.*$`, "m");
46
- if (existing.test(configText)) return configText.replace(existing, line);
47
- const anchor = key === "standards" ? /^cruze:.*$/m.exec(configText) ?? /^version:.*$/m.exec(configText) : /^version:.*$/m.exec(configText);
39
+ const line = `cruze: ${JSON.stringify(version)}`;
40
+ if (/^cruze:.*$/m.test(configText)) return configText.replace(/^cruze:.*$/m, line);
41
+ const anchor = /^version:.*$/m.exec(configText);
48
42
  if (anchor === null) return `${line}\n${configText}`;
49
43
  const end = anchor.index + anchor[0].length;
50
44
  return `${configText.slice(0, end)}\n${line}${configText.slice(end)}`;
package/src/main.ts CHANGED
@@ -10,7 +10,7 @@ import { ProcessAgentRunner } from "./adapters/outbound/process_agent_runner.ts"
10
10
  import { SystemClock } from "./adapters/outbound/system_clock.ts";
11
11
  import { DefaultAnswerPrompter, TerminalPrompter } from "./adapters/outbound/terminal_prompter.ts";
12
12
 
13
- // A reader that stops early, such as `cruze journal list | head`, closes the pipe; that is not an error worth a stack trace.
13
+ // A reader that stops early, such as `cruze status --text | head`, closes the pipe; that is not an error worth a stack trace.
14
14
  process.stdout.on("error", (error: NodeJS.ErrnoException) => {
15
15
  if (error.code === "EPIPE") process.exit(0);
16
16
  throw error;
@@ -1,28 +1,20 @@
1
1
  # {{project_name}}
2
2
 
3
- Instructions for coding agents working in this repository. Cruze keeps the managed sections current as changes land; edit everything else freely.
3
+ Instructions for coding agents working in this repository.
4
4
 
5
5
  ## Workflow
6
6
 
7
- This project uses [Cruze](https://github.com/PrintPractical/cruze) for spec-driven development. Durable documents live in `docs/`: vision, glossary, architecture, ADRs, specs and roadmap. Work in progress lives in `.cruze/`. Before changing code, read the design the change builds with `cruze show <change>`, once it exists. Each Cruze step runs in a new session, so its context holds what the step reads and nothing else. The Cruze skills run the `cruze` command; when it is missing, install it as https://github.com/PrintPractical/cruze#quick-start describes.
7
+ This project uses [Cruze](https://github.com/PrintPractical/cruze). `docs/vision.md` says what the product is for and which features the release holds; `docs/architecture.md` maps its ports, adapters and runtime; each `docs/features/<slug>.md` holds one feature's behaviour, public API and stack sketch, approved by the user before it is built. Run `cruze next` to see what comes next. The Cruze skills run the `cruze` command; when it is missing, install it as https://github.com/PrintPractical/cruze#quick-start describes.
8
8
 
9
9
  ## Commands
10
10
 
11
- <!-- cruze:managed -->
12
- No build or test commands yet. `cruze land` fills this in when the foundation change lands.
13
- <!-- /cruze:managed -->
11
+ No build or test commands yet. The foundation feature fills this in.
14
12
 
15
13
  ## Layout
16
14
 
17
- <!-- cruze:managed -->
18
- Not defined yet. `cruze land` fills this in from the module map in `docs/architecture.md`.
19
- <!-- /cruze:managed -->
15
+ Not defined yet. The foundation feature fills this in from `docs/architecture.md`.
20
16
 
21
17
  ## Conventions
22
18
 
23
19
  - Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/).
24
20
  - Record notable changes under `[Unreleased]` in `CHANGELOG.md`.
25
-
26
- ## Known pitfalls
27
-
28
- None recorded yet. `land` adds a line here when the same review finding or defect about this project's code happens twice.
@@ -13,11 +13,11 @@ jobs:
13
13
  - uses: actions/setup-node@v5
14
14
  with:
15
15
  node-version: 22
16
- # The foundation change adds the language's format, lint, build and
17
- # test steps here, from `commands:` in .cruze/config.yaml.
16
+ # The foundation feature adds the language's format, lint, build and
17
+ # test steps here, with a coverage gate.
18
18
  - name: Documents match the Cruze formats
19
19
  run: npx --yes --package={{cruze_package}} cruze validate
20
20
  - name: Layer rules and file budgets
21
21
  run: npx --yes --package={{cruze_package}} cruze check --ci
22
22
  - name: Every built scenario has a test
23
- run: npx --yes --package={{cruze_package}} cruze trace --all
23
+ run: npx --yes --package={{cruze_package}} cruze trace
@@ -1,33 +1,24 @@
1
1
  # Cruze project configuration, created by cruze {{cruze_version}}.
2
- # The format is described in .agents/skills/cruze-formats/reference/config.md.
3
- version: 1
2
+ # The format is described in .agents/skills/cruze-formats/config.md.
3
+ version: 2
4
4
  # The Cruze whose skills this project installed. `cruze install` keeps it current.
5
5
  cruze: "{{cruze_version}}"
6
- # The Cruze whose expectations the code meets. `realign` moves it forward.
7
- standards: "{{cruze_version}}"
8
6
  project: {{project_name_quoted}}
9
7
 
10
- # Where work items are tracked. V1 supports markdown in the repository only.
11
- tracker: markdown
12
-
13
- # Source files `cruze check` inspects, and files `cruze trace` searches for
14
- # scenario IDs. Project-scope architecture design sets these.
8
+ # Source files `cruze check` inspects, and test files `cruze trace` searches
9
+ # for scenario IDs. The foundation feature sets these.
15
10
  source: []
16
11
  tests: []
17
12
 
18
- # Budgets enforced by `cruze check`: a backstop against a file that has
19
- # outgrown one responsibility, not a size to design to. List a file under
20
- # exceptions, with a reason, to allow it past a budget.
13
+ # Budgets `cruze check` warns on: a backstop against a file that has outgrown
14
+ # one responsibility, not a size to design to. List a file under exceptions,
15
+ # with a reason, to allow it past a budget.
21
16
  check:
22
17
  max_lines: 600
23
18
  max_types: 12
24
19
  exceptions: []
25
20
 
26
- # Layer rules, written by project-scope architecture design from the module map.
21
+ # Layer rules from docs/architecture.md: which layer may import which.
27
22
  layers: []
28
23
 
29
- # The project's commands, by name, such as `test: cargo test`. The
30
- # foundation change fills them in; `cruze land` copies them into AGENTS.md.
31
- commands: {}
32
-
33
24
  {{review_setting}}
@@ -1,7 +1,7 @@
1
1
  # How `cruze review` starts an agent in a fresh context to run a role, with the
2
2
  # prompt on standard input. This lets Claude Code read the project and run git
3
- # and cruze. The verifier runs the system, so add the project's build and run
4
- # commands, such as "Bash(cargo:*)". Without review.command, your agent runs each
3
+ # and cruze. To let the reviewer run the tests, add the project's test
4
+ # command, such as "Bash(cargo test:*)". Without review.command, your agent runs each
5
5
  # role in a helper of its own.
6
6
  review:
7
7
  command: ["claude", "-p", "--allowedTools", "Read Grep Glob Bash(git diff:*) Bash(git log:*) Bash(git show:*) Bash(cruze:*)"]
@@ -1,29 +0,0 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import { dirname, resolve } from "node:path";
3
- import { UsageError } from "./cli_context.js";
4
-
5
- // Files a person or agent names on the command line, such as a scratch file of review blockers or
6
- // the path for an exported bundle. They may be anywhere, unlike project files, and relative paths
7
- // resolve against the working directory.
8
-
9
- export async function readArgumentFile(path ) {
10
- try {
11
- return await readFile(resolve(path), "utf8");
12
- } catch (error) {
13
- throw new UsageError(`cannot read ${path}: ${reason(error)}`);
14
- }
15
- }
16
-
17
- export async function writeArgumentFile(path , text ) {
18
- try {
19
- await mkdir(dirname(resolve(path)), { recursive: true });
20
- await writeFile(resolve(path), text, "utf8");
21
- } catch (error) {
22
- throw new UsageError(`cannot write ${path}: ${reason(error)}`);
23
- }
24
- }
25
-
26
- function reason(error ) {
27
- if (error instanceof Error && "code" in error && typeof error.code === "string") return error.code;
28
- return error instanceof Error ? error.message : String(error);
29
- }
@@ -1,23 +0,0 @@
1
- import { upstreamDiff, } from "../../../../app/use_cases/upstream_diff.js";
2
- import { requireArgs, } from "../cli_context.js";
3
-
4
- export async function runDiff(context , args ) {
5
- requireArgs(args, ["ref"]);
6
- const report = await upstreamDiff(context, args[0] ?? "");
7
- return { json: report, human: render(report) };
8
- }
9
-
10
- function render(report ) {
11
- const lines = [`${report.artifact}: ${report.state}`];
12
- if (report.changes.length === 0) lines.push("Nothing it cites changed since its approval.");
13
- for (const change of report.changes) {
14
- lines.push("", `${change.key}${change.path === undefined ? "" : ` in ${change.path}`}:`);
15
- lines.push(...(change.diff ?? [change.note ?? ""]).map((line) => ` ${line}`));
16
- }
17
- if (report.rebase.length > 0) {
18
- lines.push("", `Its delta changes ${report.rebase.join(", ")}: rewrite the delta to keep the new text, then approve with ${report.rebase.map((id) => `--rebase ${id}`).join(" ")}.`);
19
- } else if (report.ref !== undefined && report.state === "upstream-changed") {
20
- lines.push("", `No rebase needed. When the work still holds against this, re-stamp it with cruze approve ${report.ref} --restamp-unchanged.`);
21
- }
22
- return lines.join("\n");
23
- }
@@ -1,32 +0,0 @@
1
- import { exportFeedback, listEvents, recordEvent } from "../../../../app/use_cases/journal_events.js";
2
- import { writeArgumentFile } from "../argument_files.js";
3
- import { UsageError, requireArgs, } from "../cli_context.js";
4
-
5
- export async function runJournal(context , args , options ) {
6
- requireArgs(args, ["add|list"]);
7
- if (args[0] === "add") {
8
- requireArgs(args, ["add", "event"]);
9
- const fields = Object.fromEntries(options.set.map((pair) => {
10
- const at = pair.indexOf("=");
11
- if (at < 1) throw new UsageError(`--set takes key=value, not "${pair}"`);
12
- return [pair.slice(0, at), pair.slice(at + 1)];
13
- }));
14
- const entry = await recordEvent(context, args[1] ?? "", fields, options.item);
15
- return { json: entry, human: `Recorded ${entry.event}.` };
16
- }
17
- if (args[0] === "list") {
18
- const entries = await listEvents(context, options.event, options.item, options.all);
19
- return { json: entries, human: entries.map((e) => `${e.at} ${e.event} ${JSON.stringify({ ...e, at: undefined, event: undefined, by: undefined })}`).join("\n") || "No entries." };
20
- }
21
- throw new UsageError(`cruze journal takes add or list, not "${args[0]}"`);
22
- }
23
-
24
- export async function runFeedback(context , args , options ) {
25
- if (args[0] !== "export") throw new UsageError("usage: cruze feedback export [--out <file>] [--no-redact]");
26
- const bundle = await exportFeedback(context, options.redact);
27
- if (options.out !== undefined) {
28
- await writeArgumentFile(options.out, `${JSON.stringify(bundle, null, 2)}\n`);
29
- return { json: { out: options.out, entries: bundle.entries.length }, human: `Wrote ${bundle.entries.length} entries to ${options.out}.` };
30
- }
31
- return { json: bundle, human: `${bundle.entries.length} journal entries${bundle.redacted ? ", redacted" : ""}.` };
32
- }
@@ -1,55 +0,0 @@
1
- import { addFutureFeature, completeTask, dropFutureFeature, updateFeatureSummary, pruneRoadmap, recordDeviation, reopenTask } from "../../../../app/use_cases/record_progress.js";
2
- import { abandonWork } from "../../../../app/use_cases/abandon_work.js";
3
- import { UsageError, requireArgs, requireOption, } from "../cli_context.js";
4
-
5
- export async function runTask(context , args , options ) {
6
- requireArgs(args, ["done|deviation|reopen", "task"]);
7
- const change = options.change === undefined ? {} : { change: options.change };
8
- if (args[0] === "done") {
9
- const report = await completeTask(context, args[1] ?? "", { ...change, ...(options.commit === undefined ? {} : { commit: options.commit }) });
10
- return { json: report, human: `${report.task} done in ${report.change} (${report.done}/${report.total}).` };
11
- }
12
- if (args[0] === "deviation") {
13
- requireArgs(args, ["deviation", "task", "text"]);
14
- const report = await recordDeviation(context, args[1] ?? "", args.slice(2).join(" "), change);
15
- return { json: report, human: `Recorded a deviation on ${report.task} in ${report.change}.` };
16
- }
17
- if (args[0] === "reopen") {
18
- requireArgs(args, ["reopen", "task", "reason"]);
19
- const report = await reopenTask(context, args[1] ?? "", args.slice(2).join(" "), change);
20
- return { json: report, human: `Reopened ${report.task} in ${report.change}.` };
21
- }
22
- throw new UsageError(`cruze task takes done, deviation or reopen, not "${args[0]}"`);
23
- }
24
-
25
- export async function runFeatures(context , args , options ) {
26
- requireArgs(args, ["add|update|drop", "slug"]);
27
- if (args[0] === "add") {
28
- const goals = (options.goals ?? "").split(",").map((g) => g.trim()).filter((g) => g !== "");
29
- const report = await addFutureFeature(context, args[1] ?? "", requireOption(options.summary, "--summary"), goals);
30
- return { json: report, human: `Added ${report.feature} to the future list.` };
31
- }
32
- if (args[0] === "update") {
33
- const report = await updateFeatureSummary(context, args[1] ?? "", requireOption(options.summary, "--summary"));
34
- return { json: report, human: `Updated the summary of ${report.feature} on the ${report.list === "Future" ? "future" : "implemented"} list.` };
35
- }
36
- if (args[0] === "drop") {
37
- const report = await dropFutureFeature(context, args[1] ?? "", requireOption(options.reason, "--reason"));
38
- return { json: report, human: `Dropped ${report.feature} from the future list.` };
39
- }
40
- throw new UsageError(`cruze features takes add, update or drop, not "${args[0]}"`);
41
- }
42
-
43
- export async function runRoadmap(context , args ) {
44
- requireArgs(args, ["prune"]);
45
- if (args[0] !== "prune") throw new UsageError(`cruze roadmap takes prune, not "${args[0]}"`);
46
- const report = await pruneRoadmap(context);
47
- return { json: report, human: report.removed.length === 0 ? "No landed items to clear." : `Cleared ${report.removed.join(", ")} from the roadmap status.` };
48
- }
49
-
50
- export async function runAbandon(context , args , options ) {
51
- requireArgs(args, ["ref"]);
52
- const report = await abandonWork(context, args[0] ?? "", requireOption(options.reason, "--reason"));
53
- const back = report.futureList === undefined ? "" : ` ${report.futureList} is back on the future list.`;
54
- return { json: report, human: `Abandoned ${report.ref}; archived to ${report.archivedTo}.${back}` };
55
- }
@@ -1,28 +0,0 @@
1
- import { realignDone } from "../../../../app/use_cases/realign_done.js";
2
- import { realignStatus } from "../../../../app/use_cases/realign_status.js";
3
- import { UsageError, requireArgs, } from "../cli_context.js";
4
-
5
- export async function runRealign(context , args , options ) {
6
- requireArgs(args, ["status|done"]);
7
- if (args[0] === "status") {
8
- const report = await realignStatus(context, { full: options.full });
9
- const lines = [`Code meets Cruze ${report.standards}; the installed skills are ${report.target}${report.full ? " (full audit)" : ""}.`];
10
- for (const note of report.notes) {
11
- const open = note.findings.filter((f) => !f.waived);
12
- const how = note.detect !== undefined ? `${open.length} open finding(s) from ${note.detect}` : `for the auditor: ${note.ask ?? ""}`;
13
- lines.push(`${note.version} ${note.id}: ${note.title} (${how})`);
14
- for (const f of open) lines.push(` ${f.path}${f.line === undefined ? "" : `:${f.line}`} ${f.message}`);
15
- }
16
- if (report.newWorkOnly.length > 0) lines.push(`New work only, nothing to move: ${report.newWorkOnly.join(", ")}`);
17
- if (report.notes.length === 0) lines.push("Nothing to realign.");
18
- return { json: report, human: lines.join("\n") };
19
- }
20
- if (args[0] === "done") {
21
- const report = await realignDone(context, options.change === undefined ? {} : { change: options.change });
22
- const lines = [report.from === report.to ? `The code already meets Cruze ${report.to}.` : `The code now meets Cruze ${report.to}, up from ${report.from}.`];
23
- if (report.scheduled !== undefined) lines.push(`${report.scheduled} fixes the rest.`);
24
- if (report.excepted.length > 0) lines.push(`Listed under check.exceptions until it lands: ${report.excepted.join(", ")}`);
25
- return { json: report, human: lines.join("\n") };
26
- }
27
- throw new UsageError(`cruze realign takes status or done, not "${args[0]}"`);
28
- }
@@ -1,96 +0,0 @@
1
- import { showElements, showIndex } from "../../../../app/use_cases/show_elements.js";
2
- import { showNotes } from "../../../../app/use_cases/show_notes.js";
3
-
4
- import { showScope, } from "../../../../app/use_cases/show_scope.js";
5
- import { isId } from "../../../../domain/ids.js";
6
-
7
-
8
- import { UsageError, requireArgs, } from "../cli_context.js";
9
-
10
- export async function runShow(context , args , options ) {
11
- if (options.notes) {
12
- if (args.length > 1 || options.index) throw new UsageError("--notes takes at most one target: project, a step, a feature slug or a context");
13
- const report = await showNotes(context, args[0]);
14
- return { json: report, human: "target" in report ? renderNotesFor(report).join("\n").trimEnd() : renderNotes(report.notes) };
15
- }
16
- if (options.index) {
17
- if (args.length > 1) throw new UsageError("--index takes at most one context or capability");
18
- const index = await showIndex(context, args[0]);
19
- return { json: index, human: renderIndex(index) };
20
- }
21
- requireArgs(args, ["ref"]);
22
- if (args.every(isId)) {
23
- const report = await showElements(context, args);
24
- return { json: report, human: blocks(report.elements).join("\n").trimEnd() };
25
- }
26
- if (args.length > 1) throw new UsageError("show takes one feature or change, or one or more element IDs");
27
- const report = await showScope(context, args[0] ?? "");
28
- return { json: report, human: render(report) };
29
- }
30
-
31
- /** The index as a list an agent scans for what exists, before fetching bodies with `cruze show <ID>`. */
32
- function renderIndex(index ) {
33
- const { architecture, specs } = index.words;
34
- const lines = [`# Elements`, "", `docs/architecture.md holds ${architecture} words, and docs/specs/ ${specs}. Read an element's body with \`cruze show <ID>\`.`];
35
- let source = "";
36
- for (const entry of [...index.entries].sort((a, b) => Number(a.addedBy !== undefined) - Number(b.addedBy !== undefined))) {
37
- const heading = entry.addedBy === undefined ? entry.source : "In flight, not yet merged";
38
- if (heading !== source) lines.push("", `## ${heading}`, "");
39
- source = heading;
40
- const facts = [
41
- entry.status,
42
- entry.place,
43
- entry.scenarios === undefined ? undefined : `${entry.scenarios} scenarios`,
44
- entry.addedBy === undefined ? undefined : `added by ${entry.addedBy}`,
45
- entry.changedBy.length === 0 ? undefined : `changed by ${entry.changedBy.join(", ")}`,
46
- ].filter((f) => f !== undefined);
47
- lines.push(`- ${entry.id}: ${entry.title}${facts.length === 0 ? "" : ` (${facts.join("; ")})`}`);
48
- }
49
- return lines.join("\n");
50
- }
51
-
52
- /** The scope as a document an agent reads in place of the living docs. */
53
- function render(report ) {
54
- const lines = [`# ${report.ref}${report.feature === undefined ? "" : ` (feature ${report.feature})`}`, ""];
55
- lines.push("## Elements", "", ...blocks(report.elements), "## Scenarios", "", ...blocks(report.scenarios));
56
- lines.push("## Cited, not shown", "");
57
- lines.push(...(report.cited.length === 0 ? ["None."] : report.cited.map((c) => `- ${c.id}: ${c.title} (${c.source})`)), "");
58
- if (report.feature === undefined) lines.push("## Settled decisions", "", ...(report.decisions.length === 0 ? ["None."] : report.decisions), "");
59
- else {
60
- lines.push("## Settled decisions of the feature", "", ...(report.decisions.length === 0 ? ["None."] : report.decisions), "");
61
- lines.push("## Settled decisions of the change", "", ...(report.changeDecisions.length === 0 ? ["None."] : report.changeDecisions), "");
62
- }
63
- lines.push("## Dispositions", "");
64
- lines.push(...(report.dispositions.length === 0 ? ["None."] : report.dispositions.map((d) => `- [${d.disposition}, ${d.review}] ${d.finding}: ${d.reason}`)), "");
65
- if (report.references.length > 0) lines.push("## References", "", ...report.references.map((r) => `- \`${r.path}\`: ${r.use}`), "");
66
- lines.push(...renderNotesFor(report.notes));
67
- if (report.missing.length > 0) lines.push("## Missing", "", ...report.missing.map((id) => `- ${id} is defined nowhere`), "");
68
- return lines.join("\n").trimEnd();
69
- }
70
-
71
- function blocks(elements ) {
72
- if (elements.length === 0) return ["None.", ""];
73
- return elements.flatMap((element) => [`<!-- ${element.source} -->`, ...element.body.join("\n").trimEnd().split("\n"), ""]);
74
- }
75
-
76
- /** The notes about a piece of work and the parts of the user's input handed to it; nothing when there are none. */
77
- function renderNotesFor(found ) {
78
- if (found.notes.length === 0 && found.handoffs.length === 0) return [];
79
- return [
80
- "## Notes",
81
- "",
82
- ...found.notes.map((n) => `- \`${n.path}\`: ${n.title}${n.kind === undefined ? "" : ` (${n.kind})`}`),
83
- ...found.handoffs.map((h) => `- ${h.part}, from ${h.source} (${h.status}, handed off in \`${h.note}\`)`),
84
- "",
85
- ];
86
- }
87
-
88
- function renderNotes(notes ) {
89
- if (notes.length === 0) return "No notes.";
90
- return notes
91
- .flatMap((n) => [
92
- `- \`${n.path}\`: ${n.title} (${n.kind ?? "no kind"}; about ${n.about.length === 0 ? "nothing named" : n.about.join(", ")})`,
93
- ...n.handoff.map((h) => ` - ${h.part} goes to ${h.goesTo} (${h.status})`),
94
- ])
95
- .join("\n");
96
- }
@@ -1,42 +0,0 @@
1
- import { CruzeError } from "../../domain/cruze_error.js";
2
- import { readRows, upsertRow } from "../../domain/edits/managed_tables.js";
3
- import { resolveArtifact } from "../../domain/project/artifact_ref.js";
4
- import { PATHS } from "../../domain/project/layout.js";
5
- import { appendJournal, loadView, } from "../project_context.js";
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
- /**
15
- * Stops a feature or standalone change for good: archives its folder with the reason, marks it
16
- * abandoned on the roadmap, and puts a feature back on the future list. Changes that already
17
- * landed stay in the living docs.
18
- */
19
- export async function abandonWork(deps , ref , reason ) {
20
- if (reason.trim() === "") throw new CruzeError("missing-reason", "abandoning work needs a reason");
21
- const view = await loadView(deps.files);
22
- const { item } = resolveArtifact(view, ref);
23
- if (item === undefined || item.archived) throw new CruzeError("not-found", `"${ref}" is not an active feature or standalone change`);
24
- if (item.kind === "change") throw new CruzeError("not-abandonable", `${item.ref} belongs to a feature; remove it from the feature's Changes table through rethink instead`);
25
-
26
- const slug = typeof item.doc.frontmatter?.["roadmap"] === "string" ? item.doc.frontmatter["roadmap"] : undefined;
27
- const roadmap = view.snapshot.get(PATHS.roadmap);
28
- if (slug !== undefined && roadmap !== undefined && roadmap.includes("## Status")) {
29
- await deps.files.writeText(PATHS.roadmap, upsertRow(roadmap, "Status", [slug, item.folderName, "abandoned"]));
30
- }
31
- const report = { ref: item.ref, archivedTo: `${PATHS.archiveDir}/${item.folderName}` };
32
- const vision = view.snapshot.get(PATHS.vision);
33
- if (item.kind === "feature" && slug !== undefined && vision !== undefined && vision.includes("### Future")) {
34
- if (!readRows(vision, "Future").some((row) => row[0] === slug)) {
35
- await deps.files.writeText(PATHS.vision, upsertRow(vision, "Future", [slug, String(item.doc.frontmatter?.["title"] ?? slug), ""]));
36
- }
37
- report.futureList = slug;
38
- }
39
- await appendJournal(deps, item.folder, "abandon", { item: item.ref, reason: reason.trim() });
40
- await deps.files.move(item.folder, report.archivedTo);
41
- return report;
42
- }