@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.
- package/README.md +61 -118
- package/dist/adapters/inbound/cli/cli_context.js +0 -27
- package/dist/adapters/inbound/cli/commands/code.js +5 -18
- package/dist/adapters/inbound/cli/commands/documents.js +11 -37
- package/dist/adapters/inbound/cli/commands/init.js +1 -1
- package/dist/adapters/inbound/cli/commands/install.js +1 -0
- package/dist/adapters/inbound/cli/commands/review.js +2 -9
- package/dist/adapters/inbound/cli/commands/status.js +16 -63
- package/dist/adapters/inbound/cli/commands.js +10 -37
- package/dist/adapters/inbound/cli/parse_command.js +0 -54
- package/dist/adapters/outbound/git_repository.js +2 -71
- package/dist/app/ports/repository.js +0 -12
- package/dist/app/project_context.js +15 -25
- package/dist/app/use_cases/approve_document.js +29 -0
- package/dist/app/use_cases/check_code.js +21 -56
- package/dist/app/use_cases/install_skills.js +7 -1
- package/dist/app/use_cases/new_document.js +25 -0
- package/dist/app/use_cases/project_status.js +43 -67
- package/dist/app/use_cases/run_review.js +11 -30
- package/dist/app/use_cases/validate_project.js +8 -5
- package/dist/domain/approvals.js +51 -0
- package/dist/domain/check/check_source.js +3 -32
- package/dist/domain/check/imports.js +3 -3
- package/dist/domain/check/rust_imports.js +25 -3
- package/dist/domain/config.js +8 -84
- package/dist/domain/hashing.js +16 -30
- package/dist/domain/ids.js +13 -27
- package/dist/domain/next_step.js +41 -0
- package/dist/domain/project/features.js +71 -0
- package/dist/domain/project/layout.js +11 -27
- package/dist/domain/project/project_docs.js +48 -0
- package/dist/domain/project/release.js +30 -0
- package/dist/domain/scaffold.js +0 -1
- package/dist/domain/skill_budget.js +4 -4
- package/dist/domain/trace.js +8 -25
- package/dist/domain/validation/document_rules.js +65 -0
- package/dist/domain/validation/release_rules.js +45 -0
- package/dist/domain/validation/review_rules.js +21 -0
- package/dist/domain/validation/validate_project.js +20 -27
- package/dist/domain/versions/cruze_version.js +3 -9
- package/dist/main.js +1 -1
- package/package.json +1 -1
- package/skills/asking/SKILL.md +51 -0
- package/skills/behavioural-testing/SKILL.md +14 -16
- package/skills/behavioural-testing/examples.md +1 -2
- package/skills/behavioural-testing/fakes.md +2 -2
- package/skills/build/SKILL.md +34 -38
- package/skills/dependency-approval/SKILL.md +34 -31
- package/skills/envision/SKILL.md +23 -18
- package/skills/envision/architecture.md +16 -0
- package/skills/envision/breakdown.md +14 -0
- package/skills/envision/possibilities.md +6 -7
- package/skills/fix/SKILL.md +34 -0
- package/skills/formats/SKILL.md +39 -87
- package/skills/formats/config.md +47 -0
- package/skills/formats/templates/architecture.md +18 -74
- package/skills/formats/templates/feature.md +18 -34
- package/skills/formats/templates/vision.md +15 -27
- package/skills/hexagonal-design/SKILL.md +11 -11
- package/skills/hexagonal-design/contracts.md +3 -3
- package/skills/hexagonal-design/fundamentals.md +1 -1
- package/skills/hexagonal-design/languages/cpp.md +1 -1
- package/skills/hexagonal-design/languages/rust.md +1 -1
- package/skills/hexagonal-design/languages/swift.md +2 -2
- package/skills/hexagonal-design/runtime.md +2 -2
- package/skills/research/SKILL.md +4 -4
- package/skills/research/evaluation.md +1 -1
- package/skills/review/SKILL.md +27 -0
- package/skills/roles/SKILL.md +8 -59
- package/skills/roles/code-reviewer.md +22 -32
- package/skills/roles/researcher.md +3 -3
- package/skills/shape/SKILL.md +37 -0
- package/skills/shape/self-check.md +12 -0
- package/src/adapters/inbound/cli/cli_context.ts +0 -27
- package/src/adapters/inbound/cli/commands/code.ts +5 -18
- package/src/adapters/inbound/cli/commands/documents.ts +11 -37
- package/src/adapters/inbound/cli/commands/init.ts +1 -1
- package/src/adapters/inbound/cli/commands/install.ts +1 -0
- package/src/adapters/inbound/cli/commands/review.ts +2 -9
- package/src/adapters/inbound/cli/commands/status.ts +16 -63
- package/src/adapters/inbound/cli/commands.ts +10 -37
- package/src/adapters/inbound/cli/parse_command.ts +0 -54
- package/src/adapters/outbound/git_repository.ts +2 -71
- package/src/app/ports/repository.ts +0 -12
- package/src/app/project_context.ts +15 -25
- package/src/app/use_cases/approve_document.ts +29 -0
- package/src/app/use_cases/check_code.ts +21 -56
- package/src/app/use_cases/install_skills.ts +7 -1
- package/src/app/use_cases/new_document.ts +25 -0
- package/src/app/use_cases/project_status.ts +49 -73
- package/src/app/use_cases/run_review.ts +11 -30
- package/src/app/use_cases/validate_project.ts +8 -5
- package/src/domain/approvals.ts +51 -0
- package/src/domain/check/check_source.ts +3 -32
- package/src/domain/check/imports.ts +3 -3
- package/src/domain/check/rust_imports.ts +25 -3
- package/src/domain/config.ts +9 -85
- package/src/domain/hashing.ts +16 -30
- package/src/domain/ids.ts +13 -27
- package/src/domain/next_step.ts +41 -0
- package/src/domain/project/features.ts +71 -0
- package/src/domain/project/layout.ts +11 -27
- package/src/domain/project/project_docs.ts +48 -0
- package/src/domain/project/release.ts +30 -0
- package/src/domain/scaffold.ts +0 -1
- package/src/domain/skill_budget.ts +4 -4
- package/src/domain/trace.ts +8 -25
- package/src/domain/validation/document_rules.ts +65 -0
- package/src/domain/validation/release_rules.ts +45 -0
- package/src/domain/validation/review_rules.ts +21 -0
- package/src/domain/validation/validate_project.ts +21 -28
- package/src/domain/versions/cruze_version.ts +3 -9
- package/src/main.ts +1 -1
- package/templates/init/AGENTS.md +4 -12
- package/templates/init/ci.yml +3 -3
- package/templates/init/config.yaml +8 -17
- package/templates/init/review/claude.yaml +2 -2
- package/dist/adapters/inbound/cli/argument_files.js +0 -29
- package/dist/adapters/inbound/cli/commands/diff.js +0 -23
- package/dist/adapters/inbound/cli/commands/journal.js +0 -32
- package/dist/adapters/inbound/cli/commands/progress.js +0 -55
- package/dist/adapters/inbound/cli/commands/realign.js +0 -28
- package/dist/adapters/inbound/cli/commands/show.js +0 -96
- package/dist/app/use_cases/abandon_work.js +0 -42
- package/dist/app/use_cases/approve_artifact.js +0 -197
- package/dist/app/use_cases/journal_events.js +0 -64
- package/dist/app/use_cases/land_change.js +0 -134
- package/dist/app/use_cases/new_project_doc.js +0 -48
- package/dist/app/use_cases/new_work_item.js +0 -75
- package/dist/app/use_cases/realign_done.js +0 -45
- package/dist/app/use_cases/realign_status.js +0 -106
- package/dist/app/use_cases/record_progress.js +0 -118
- package/dist/app/use_cases/show_elements.js +0 -18
- package/dist/app/use_cases/show_notes.js +0 -11
- package/dist/app/use_cases/show_scope.js +0 -51
- package/dist/app/use_cases/upstream_diff.js +0 -55
- package/dist/domain/approvals/agent_approval.js +0 -68
- package/dist/domain/approvals/evaluate.js +0 -36
- package/dist/domain/approvals/fingerprint.js +0 -52
- package/dist/domain/approvals/rebase.js +0 -39
- package/dist/domain/approvals/records.js +0 -50
- package/dist/domain/approvals/upstream_text.js +0 -36
- package/dist/domain/architecture_sections.js +0 -23
- package/dist/domain/check/decision_comments.js +0 -38
- package/dist/domain/decision_citations.js +0 -62
- package/dist/domain/edits/agents_file.js +0 -58
- package/dist/domain/edits/managed_tables.js +0 -60
- package/dist/domain/edits/progress_block.js +0 -33
- package/dist/domain/edits/status_lines.js +0 -52
- package/dist/domain/elements.js +0 -126
- package/dist/domain/journal.js +0 -109
- package/dist/domain/land/bookkeeping.js +0 -54
- package/dist/domain/land/merge_plan.js +0 -137
- package/dist/domain/land/text_ops.js +0 -66
- package/dist/domain/line_diff.js +0 -56
- package/dist/domain/project/artifact_ref.js +0 -42
- package/dist/domain/project/deltas.js +0 -49
- package/dist/domain/project/element_lookup.js +0 -124
- package/dist/domain/project/living_model.js +0 -55
- package/dist/domain/project/new_items.js +0 -48
- package/dist/domain/project/notes.js +0 -74
- package/dist/domain/project/plan_parts.js +0 -111
- package/dist/domain/project/progress.js +0 -43
- package/dist/domain/project/project_view.js +0 -72
- package/dist/domain/project/roadmap.js +0 -43
- package/dist/domain/project/scope_view.js +0 -134
- package/dist/domain/project/work_items.js +0 -68
- package/dist/domain/status/next_step.js +0 -181
- package/dist/domain/status/pending_rethink.js +0 -22
- package/dist/domain/status/verification.js +0 -29
- package/dist/domain/status/work_status.js +0 -125
- package/dist/domain/validation/decision_rules.js +0 -76
- package/dist/domain/validation/delta_rules.js +0 -81
- package/dist/domain/validation/element_rules.js +0 -104
- package/dist/domain/validation/future_rules.js +0 -40
- package/dist/domain/validation/living_rules.js +0 -99
- package/dist/domain/validation/plan_rules.js +0 -124
- package/dist/domain/validation/project_rules.js +0 -115
- package/dist/domain/validation/size_rules.js +0 -45
- package/dist/domain/validation/vision_rules.js +0 -41
- package/dist/domain/validation/work_item_rules.js +0 -175
- package/dist/domain/versions/realign_notes.js +0 -72
- package/dist/domain/versions/rule_versions.js +0 -29
- package/dist/domain/versions/scheduled_exceptions.js +0 -41
- package/skills/about/SKILL.md +0 -21
- package/skills/architect/SKILL.md +0 -49
- package/skills/architect/feature.md +0 -40
- package/skills/architect/project.md +0 -71
- package/skills/architect/tweak.md +0 -22
- package/skills/architect/walkthrough.md +0 -35
- package/skills/domain-language/SKILL.md +0 -37
- package/skills/envision/feature.md +0 -25
- package/skills/envision/intake.md +0 -28
- package/skills/envision/project.md +0 -24
- package/skills/explore/SKILL.md +0 -39
- package/skills/formats/reference/architecture.md +0 -84
- package/skills/formats/reference/config.md +0 -80
- package/skills/formats/reference/durable-docs.md +0 -74
- package/skills/formats/reference/specs.md +0 -65
- package/skills/formats/reference/work-items.md +0 -100
- package/skills/formats/templates/adr.md +0 -7
- package/skills/formats/templates/change.md +0 -29
- package/skills/formats/templates/glossary.md +0 -8
- package/skills/formats/templates/roadmap.md +0 -32
- package/skills/formats/templates/spec.md +0 -11
- package/skills/formats/templates/standalone-change.md +0 -46
- package/skills/grilling/SKILL.md +0 -90
- package/skills/grilling/illustrating.md +0 -38
- package/skills/improve/SKILL.md +0 -51
- package/skills/land/SKILL.md +0 -48
- package/skills/next/SKILL.md +0 -31
- package/skills/plan/SKILL.md +0 -62
- package/skills/plan/tasks.md +0 -35
- package/skills/plan/test-plan.md +0 -14
- package/skills/realign/SKILL.md +0 -37
- package/skills/realign/notes/0.0.10.md +0 -131
- package/skills/realign/notes/0.0.11.md +0 -15
- package/skills/realign/notes/0.0.12.md +0 -31
- package/skills/realign/notes/0.0.13.md +0 -11
- package/skills/realign/notes/0.0.2.md +0 -69
- package/skills/realign/notes/0.0.3.md +0 -11
- package/skills/realign/notes/0.0.4.md +0 -27
- package/skills/realign/notes/0.0.5.md +0 -38
- package/skills/realign/notes/0.0.6.md +0 -44
- package/skills/realign/notes/0.0.7.md +0 -11
- package/skills/realign/notes/0.0.8.md +0 -97
- package/skills/realign/notes/0.0.9.md +0 -59
- package/skills/realign/notes.md +0 -40
- package/skills/rethink/SKILL.md +0 -62
- package/skills/rethink/levels.md +0 -54
- package/skills/roadmap/SKILL.md +0 -54
- package/skills/roles/auditor.md +0 -35
- package/skills/roles/design-reviewer.md +0 -43
- package/skills/roles/design-rubric.md +0 -41
- package/skills/roles/plan-rubric.md +0 -11
- package/skills/roles/surveyor.md +0 -41
- package/skills/roles/verifier.md +0 -42
- package/skills/triage/SKILL.md +0 -37
- package/skills/verify/SKILL.md +0 -45
- package/skills/verify/manual-test.md +0 -23
- package/src/adapters/inbound/cli/argument_files.ts +0 -29
- package/src/adapters/inbound/cli/commands/diff.ts +0 -23
- package/src/adapters/inbound/cli/commands/journal.ts +0 -32
- package/src/adapters/inbound/cli/commands/progress.ts +0 -55
- package/src/adapters/inbound/cli/commands/realign.ts +0 -28
- package/src/adapters/inbound/cli/commands/show.ts +0 -96
- package/src/app/use_cases/abandon_work.ts +0 -42
- package/src/app/use_cases/approve_artifact.ts +0 -197
- package/src/app/use_cases/journal_events.ts +0 -64
- package/src/app/use_cases/land_change.ts +0 -134
- package/src/app/use_cases/new_project_doc.ts +0 -48
- package/src/app/use_cases/new_work_item.ts +0 -75
- package/src/app/use_cases/realign_done.ts +0 -45
- package/src/app/use_cases/realign_status.ts +0 -106
- package/src/app/use_cases/record_progress.ts +0 -118
- package/src/app/use_cases/show_elements.ts +0 -18
- package/src/app/use_cases/show_notes.ts +0 -11
- package/src/app/use_cases/show_scope.ts +0 -51
- package/src/app/use_cases/upstream_diff.ts +0 -55
- package/src/domain/approvals/agent_approval.ts +0 -68
- package/src/domain/approvals/evaluate.ts +0 -36
- package/src/domain/approvals/fingerprint.ts +0 -52
- package/src/domain/approvals/rebase.ts +0 -39
- package/src/domain/approvals/records.ts +0 -50
- package/src/domain/approvals/upstream_text.ts +0 -36
- package/src/domain/architecture_sections.ts +0 -23
- package/src/domain/check/decision_comments.ts +0 -38
- package/src/domain/decision_citations.ts +0 -62
- package/src/domain/edits/agents_file.ts +0 -58
- package/src/domain/edits/managed_tables.ts +0 -60
- package/src/domain/edits/progress_block.ts +0 -33
- package/src/domain/edits/status_lines.ts +0 -52
- package/src/domain/elements.ts +0 -126
- package/src/domain/journal.ts +0 -109
- package/src/domain/land/bookkeeping.ts +0 -54
- package/src/domain/land/merge_plan.ts +0 -137
- package/src/domain/land/text_ops.ts +0 -66
- package/src/domain/line_diff.ts +0 -56
- package/src/domain/project/artifact_ref.ts +0 -42
- package/src/domain/project/deltas.ts +0 -49
- package/src/domain/project/element_lookup.ts +0 -124
- package/src/domain/project/living_model.ts +0 -55
- package/src/domain/project/new_items.ts +0 -48
- package/src/domain/project/notes.ts +0 -74
- package/src/domain/project/plan_parts.ts +0 -111
- package/src/domain/project/progress.ts +0 -43
- package/src/domain/project/project_view.ts +0 -72
- package/src/domain/project/roadmap.ts +0 -43
- package/src/domain/project/scope_view.ts +0 -134
- package/src/domain/project/work_items.ts +0 -68
- package/src/domain/status/next_step.ts +0 -181
- package/src/domain/status/pending_rethink.ts +0 -22
- package/src/domain/status/verification.ts +0 -29
- package/src/domain/status/work_status.ts +0 -125
- package/src/domain/validation/decision_rules.ts +0 -76
- package/src/domain/validation/delta_rules.ts +0 -81
- package/src/domain/validation/element_rules.ts +0 -104
- package/src/domain/validation/future_rules.ts +0 -40
- package/src/domain/validation/living_rules.ts +0 -99
- package/src/domain/validation/plan_rules.ts +0 -124
- package/src/domain/validation/project_rules.ts +0 -115
- package/src/domain/validation/size_rules.ts +0 -45
- package/src/domain/validation/vision_rules.ts +0 -41
- package/src/domain/validation/work_item_rules.ts +0 -175
- package/src/domain/versions/realign_notes.ts +0 -72
- package/src/domain/versions/rule_versions.ts +0 -29
- package/src/domain/versions/scheduled_exceptions.ts +0 -41
- package/templates/init/gitattributes +0 -2
|
@@ -23,5 +23,5 @@ Gather this for each serious candidate, from the registry and the repository dur
|
|
|
23
23
|
| Component | Decision | Choice | Reason |
|
|
24
24
|
| --- | --- | --- | --- |
|
|
25
25
|
| SSH transport | adopt | `russh` <version> | Pure Rust, so no OpenSSL on macOS; maintained, Apache-2.0. `ssh2` needs libssh2. See `.cruze/notes/2026-09-25-ssh-libraries.md` |
|
|
26
|
-
| Serial line settings (`115200 8N1`) | build | | A product-specific notation of three fields that no library parses; about 30 lines to own (
|
|
26
|
+
| Serial line settings (`115200 8N1`) | build | | A product-specific notation of three fields that no library parses; about 30 lines to own (the user's decision) |
|
|
27
27
|
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cruze-review
|
|
3
|
+
description: Reviews a built feature in a fresh context for real defects, a public API that drifted from what the user approved, and scenarios without tests, fixes what it finds, and hands the user only the findings that are theirs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Review
|
|
7
|
+
|
|
8
|
+
A reviewer who never saw the build reads the code against the approved feature. It looks for what tests miss: hangs, leaks, races, data loss, failure paths, an API that drifted from what the user approved. One round, then the agent fixes and checks its own fixes. The user hears only about findings that change what they approved.
|
|
9
|
+
|
|
10
|
+
## Steps
|
|
11
|
+
|
|
12
|
+
1. **Run the code reviewer** in a fresh context, as `.agents/skills/cruze-roles/SKILL.md` says, on this feature, with the diff from where the feature's branch left `main`: `cruze review code-reviewer --feature <slug> --base <merge-base>`, where the merge base is `git merge-base main HEAD`. Done when you have its report.
|
|
13
|
+
2. **Check each finding** against the code before acting on it. Drop one whose evidence doesn't hold, and say why in one line.
|
|
14
|
+
3. **Sort them.** A finding is the user's when fixing it would change a scenario, the public API they approved, or a significant dependency. Every other finding is yours, blockers included.
|
|
15
|
+
4. **Fix yours.** Fix every blocker, and the concerns worth fixing, each with a test when it is a behaviour. Correct the documents where they no longer match the code, and show the user each change to an approved one with your report, for them to approve. Run the full suite, `cruze check --ci` and `cruze trace <slug>` again. Check your own fixes; don't run the reviewer a second time.
|
|
16
|
+
5. **Bring the user theirs,** illustrated as `.agents/skills/cruze-asking/SKILL.md` says: the problem in plain words, who meets it and how, and the change to the feature you recommend, as code or output, before and after. Their answer goes through `shape` as a change to the approved feature, then back to build.
|
|
17
|
+
6. **Report and open the pull request.** Tell the user, in a few lines:
|
|
18
|
+
- what the feature now does;
|
|
19
|
+
- how to try it: the commands to run, with what they should see;
|
|
20
|
+
- what the review found and what you fixed, counted;
|
|
21
|
+
- any finding you left, and why, each filed as an issue as `fix` says, so it isn't lost.
|
|
22
|
+
|
|
23
|
+
Add a line in the user's words under `[Unreleased]` in `CHANGELOG.md`. Update the README's status, and its usage when the feature changes what a user runs or sees, with the same commands as "how to try it". Push the branch and open a pull request, or merge as the project does. Done when the pull request is open or the branch is merged.
|
|
24
|
+
|
|
25
|
+
## Next step
|
|
26
|
+
|
|
27
|
+
`cruze next` names it: usually `shape` for the next feature.
|
package/skills/roles/SKILL.md
CHANGED
|
@@ -1,71 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cruze-roles
|
|
3
|
-
description: Prompts for Cruze's fresh-context roles
|
|
3
|
+
description: Prompts for Cruze's fresh-context roles, the code reviewer and the researcher, and how to run one. Use when a Cruze step says to run a review or research in a fresh context.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Roles
|
|
7
7
|
|
|
8
|
-
A role is a prompt with fixed inputs and a report as its only output. It runs in a fresh context, so it judges the
|
|
8
|
+
A role is a prompt with fixed inputs and a report as its only output. It runs in a fresh context, so it judges the work rather than the conversation that produced it. It never edits files.
|
|
9
9
|
|
|
10
10
|
| Role | File | Used by |
|
|
11
11
|
| --- | --- | --- |
|
|
12
|
-
|
|
|
13
|
-
|
|
|
14
|
-
| Verifier | [verifier.md](verifier.md) | verify, to run the system |
|
|
15
|
-
| Researcher | [researcher.md](researcher.md) | architect, for adopt-or-build decisions |
|
|
16
|
-
| Auditor | [auditor.md](auditor.md) | realign, to compare existing code with what a release now expects |
|
|
17
|
-
| Surveyor | [surveyor.md](surveyor.md) | improve, to find structure that departs from the standards or keeps causing friction |
|
|
12
|
+
| Code reviewer | [code-reviewer.md](code-reviewer.md) | review and fix |
|
|
13
|
+
| Researcher | [researcher.md](researcher.md) | envision, for technology choices; any step with a question that needs evidence |
|
|
18
14
|
|
|
19
15
|
## Running a role
|
|
20
16
|
|
|
21
|
-
1.
|
|
22
|
-
2.
|
|
23
|
-
3.
|
|
24
|
-
4. Take the report as it comes back
|
|
25
|
-
|
|
26
|
-
## Running a review
|
|
27
|
-
|
|
28
|
-
A review has at most two rounds. Only blockers can force the second one.
|
|
29
|
-
|
|
30
|
-
### Round 1
|
|
31
|
-
|
|
32
|
-
1. Commit the documents under review (`docs: <artifact> for design review`), so the fixes in round 2 have a diff. Then run the reviewer on the complete artifact.
|
|
33
|
-
2. Record the round: `cruze journal add review --set review=<design|plan|code> --set round=1 --set blockers=<n> --set concerns=<n> --set nits=<n>`, with the counts from the report's last line, adding `--item <ref>` for a feature or change.
|
|
34
|
-
3. **Sort the findings.** A finding is an **exception**, which the user decides, when any of these holds:
|
|
35
|
-
- Its fix changes behaviour: it adds, removes or rewrites a requirement or scenario, or changes what a person sees or does beyond what the spec says. Making the code or the plan meet a scenario as written is not a change of behaviour.
|
|
36
|
-
- Its fix changes a port, a port's `Operations` or a public contract that the approved design names.
|
|
37
|
-
- Its fix changes another decision the grilling skill leaves to the user: a context, dependency direction or a dependency.
|
|
38
|
-
- You recommend anything but `fixed`: waiving, deferring or rejecting it, or a rethink because it needs a design change. A fix through a detail amendment is an exception too.
|
|
39
|
-
- You would fix it differently from the reviewer's proposed fix.
|
|
40
|
-
|
|
41
|
-
Every other finding is yours, blockers included: you fix it as the reviewer proposes. When `review.decide` in `.cruze/config.yaml` is `all`, every finding is an exception. Nits are a count, not findings: when a report lists any, they get no disposition and you don't bring them to the user.
|
|
42
|
-
4. **Present them in one message,** written to be read cold and illustrated as `.agents/skills/cruze-grilling/illustrating.md` says. First each exception: what goes wrong, shown as the reviewer's failure scenario played out (the interaction, the code or the diagram), what the fix changes, shown before and after, and your recommended disposition and why:
|
|
43
|
-
- `fixed`: you will change the work as the finding proposes.
|
|
44
|
-
- `waived`: the finding is right, but the user accepts the risk.
|
|
45
|
-
- `deferred`: it belongs to later work. When it is future scope, add it with `cruze features add <slug> --summary <text> --goals <ids>`.
|
|
46
|
-
- `rejected`: the finding is wrong, with the reason.
|
|
47
|
-
|
|
48
|
-
A finding whose fix would change an approved element, such as one marked `Needs design change`, is never `waived`. Recommend `fixed` through a detail amendment when it qualifies, as "Detail" in `.agents/skills/cruze-rethink/levels.md` says, otherwise `rethink` at that element's level now, or `deferred` for a concern later work can carry. Once the rethink is done and the code follows it, record the finding as `fixed`. When the user wants the rethink later, record it as `rethink` instead, with `--item` naming the feature or change it amends: `cruze next` and the build gate hold that work until a rethink is recorded for it.
|
|
49
|
-
|
|
50
|
-
Then one line for each finding you are fixing yourself. When there are no exceptions, say what you are fixing and carry on without waiting. The user can object to any line until the work is approved, and that finding becomes an exception: revert its fix and let them decide it.
|
|
51
|
-
5. **Record every disposition:** `cruze journal add disposition --set finding="<rubric item>: <summary>" --set disposition=<fixed|waived|deferred|rejected|rethink> --set reason="<reason>" --set review=<design|plan|code> --set decided=<agent|user>`, with the same `--item`. Use `decided=user` for each exception, once the user decides it, and `decided=agent` for each finding you fixed yourself. The CLI refuses `decided=agent` for anything but `fixed`. A recorded disposition is never raised again.
|
|
52
|
-
6. Apply every `fixed` change, then run `cruze validate`. Done when it reports no errors.
|
|
53
|
-
7. When a finding could be caught by a tool, such as a layering, naming or size rule, tell the user which `cruze check` rule or linter setting would catch it next time.
|
|
54
|
-
|
|
55
|
-
### Round 2
|
|
56
|
-
|
|
57
|
-
Run round 2 only when a round-1 blocker was fixed. It checks only whether those blockers are fixed, and raises nothing new. You check them: in 49 recorded rounds across two projects, no reviewer re-reading a fix found a blocker still open, and the user sees every fix at the walkthrough, in the plan, or in verify's report.
|
|
58
|
-
|
|
59
|
-
1. **Check each blocker** against the diff of its fix, and run `cruze validate`. A blocker is fixed when the diff does what the proposal says and validate reports no new errors. When a fix differs from the proposal or reaches past what the finding names, say so in the message that presents it, so the user can object.
|
|
60
|
-
2. Record the round with `round=2`, the blockers still open, `concerns=0` and `checked_by=agent`.
|
|
61
|
-
3. Take any blocker still open to the user, who fixes it now, waives it or starts a rethink. There is no round 3.
|
|
62
|
-
|
|
63
|
-
Done when every finding has a journaled disposition, and every exception, and every blocker left open in round 2, has the user's decision.
|
|
64
|
-
|
|
65
|
-
## The settled ledger
|
|
66
|
-
|
|
67
|
-
Reviewers read the settled ledger so they never re-raise a decision. It consists of:
|
|
68
|
-
|
|
69
|
-
- The `## Settled decisions` of the feature or change under review.
|
|
70
|
-
- The `D<n>` lines in the `## Decisions` section of `docs/architecture.md`, and the accepted ADRs in `docs/adr/`.
|
|
71
|
-
- Earlier dispositions of the item under review, from `cruze journal list --event disposition --item <ref>`. `cruze show <ref>` includes them. Never list the whole project's: two projects' reviewers read every disposition ever recorded, about 36k tokens a time, a hundred times each.
|
|
17
|
+
1. **Start a fresh context:** a helper agent with no conversation history, where the agent can start one. Give it the role file's full text, the feature slug and the base commit, and nothing else: your opinions and your reasons for the code stay out.
|
|
18
|
+
2. **Or let the CLI start one:** `cruze review <role> --feature <slug> --base <commit>`, where the role is `code-reviewer` or `researcher`. It runs the agent configured under `review:` in `.cruze/config.yaml` and prints the role's report. When no agent is configured, or it isn't installed, it prints `status: run-in-helper` with the full prompt instead: give exactly that prompt to a helper.
|
|
19
|
+
3. **When no fresh context can run,** the code reviewer must still run fresh: tell the user, and have them run the prompt in a new session. The researcher may run in your own context, since its evidence is checkable; say that you did.
|
|
20
|
+
4. **Take the report** as it comes back, and check each finding's evidence against the files before you act on it.
|
|
@@ -1,38 +1,30 @@
|
|
|
1
1
|
# Code reviewer
|
|
2
2
|
|
|
3
|
-
You review the code
|
|
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
|
|
8
|
-
- The diff under review, from `git diff <base>` for the base commit you are given.
|
|
9
|
-
-
|
|
10
|
-
- The
|
|
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
|
+
Run the project's tests and lints, one plain command at a time, with no pipes, `&&`, `;` or redirects: an agent's allowed commands match only a plain command. When a command is refused, say so in your report.
|
|
14
|
+
|
|
16
15
|
## Rubric
|
|
17
16
|
|
|
18
17
|
Review against these items and nothing else. Each finding names one.
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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.
|
|
27
|
+
9. **Documents.** The feature's public API and stack sketch, and `docs/architecture.md` where the diff touches it, match the code: a port, operation, type, flag or claim the documents state that the code doesn't bear out, or the reverse.
|
|
36
28
|
|
|
37
29
|
## Findings
|
|
38
30
|
|
|
@@ -42,17 +34,15 @@ Each finding has this shape:
|
|
|
42
34
|
### <n>. <rubric item>: <one-line summary>
|
|
43
35
|
- Severity: blocker | concern
|
|
44
36
|
- Evidence: <path:line, quoting the code>
|
|
45
|
-
- Failure scenario: <
|
|
37
|
+
- Failure scenario: <who meets it, how, and what goes wrong>
|
|
46
38
|
- Proposed fix: <the specific change>
|
|
47
|
-
-
|
|
39
|
+
- Changes what the user approved: <the scenario or public API the fix changes, or no>
|
|
48
40
|
```
|
|
49
41
|
|
|
50
|
-
- A **blocker**
|
|
51
|
-
- Everything else is a **concern
|
|
52
|
-
- List every blocker
|
|
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>`.
|
|
42
|
+
- 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.
|
|
43
|
+
- 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.
|
|
44
|
+
- 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
45
|
|
|
56
46
|
## Report
|
|
57
47
|
|
|
58
|
-
|
|
48
|
+
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
|
|
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
|
|
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
|
|
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 =
|
|
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}]
|
|
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,
|
|
15
|
-
const report = await traceTests(context,
|
|
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
|
|
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 {
|
|
2
|
-
import {
|
|
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,
|
|
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[]
|
|
13
|
+
export async function runApprove(context: CliContext, args: string[]): Promise<CommandResult> {
|
|
15
14
|
requireArgs(args, ["document"]);
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
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
|
}
|
|
@@ -15,5 +15,6 @@ export function describeSkillInstall(report: InstallSkillsReport): string[] {
|
|
|
15
15
|
if (from !== to) lines.push(`Recorded Cruze ${to} in .cruze/config.yaml${from === undefined ? "" : `, up from ${from}`}`);
|
|
16
16
|
if (ci.repinned.length > 0) lines.push(`CI runs ${ci.repinned.join(", ")}`);
|
|
17
17
|
for (const spec of ci.unrecognised) lines.push(`CI runs ${spec}, which Cruze can't move to ${to}; update .github/workflows/ci.yml yourself`);
|
|
18
|
+
for (const note of report.notes) lines.push(`Note: ${note}`);
|
|
18
19
|
return lines;
|
|
19
20
|
}
|
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
import { runReview } from "../../../../app/use_cases/run_review.ts";
|
|
2
|
-
import {
|
|
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.
|
|
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 {
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
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
|
|
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 =
|
|
26
|
-
for (const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
35
|
-
|
|
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
|
-
|
|
56
|
-
const
|
|
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
|
-
|
|
67
|
-
|
|
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
|
}
|