work-kit-cli 0.2.8 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/README.md +24 -13
  2. package/cli/src/commands/bootstrap.test.ts +40 -0
  3. package/cli/src/commands/bootstrap.ts +77 -13
  4. package/cli/src/commands/cancel.ts +1 -16
  5. package/cli/src/commands/complete.ts +92 -98
  6. package/cli/src/commands/completions.ts +2 -2
  7. package/cli/src/commands/doctor.ts +1 -1
  8. package/cli/src/commands/extract.ts +217 -0
  9. package/cli/src/commands/init.test.ts +50 -0
  10. package/cli/src/commands/init.ts +70 -35
  11. package/cli/src/commands/learn.test.ts +217 -0
  12. package/cli/src/commands/learn.ts +104 -0
  13. package/cli/src/commands/loopback.ts +8 -11
  14. package/cli/src/commands/next.ts +93 -60
  15. package/cli/src/commands/observe.ts +16 -21
  16. package/cli/src/commands/pause-resume.test.ts +142 -0
  17. package/cli/src/commands/pause.ts +34 -0
  18. package/cli/src/commands/report.ts +217 -0
  19. package/cli/src/commands/resume.ts +126 -0
  20. package/cli/src/commands/setup.ts +280 -0
  21. package/cli/src/commands/status.ts +8 -6
  22. package/cli/src/commands/uninstall.ts +8 -3
  23. package/cli/src/commands/workflow.ts +43 -33
  24. package/cli/src/config/agent-map.ts +9 -9
  25. package/cli/src/config/constants.ts +54 -0
  26. package/cli/src/config/loopback-routes.ts +13 -13
  27. package/cli/src/config/model-routing.test.ts +190 -0
  28. package/cli/src/config/model-routing.ts +208 -0
  29. package/cli/src/config/project-config.test.ts +127 -0
  30. package/cli/src/config/project-config.ts +106 -0
  31. package/cli/src/config/{phases.ts → workflow.ts} +40 -23
  32. package/cli/src/context/prompt-builder.ts +10 -9
  33. package/cli/src/index.ts +130 -9
  34. package/cli/src/observer/data.ts +196 -65
  35. package/cli/src/observer/renderer.ts +127 -107
  36. package/cli/src/observer/watcher.ts +28 -16
  37. package/cli/src/state/helpers.test.ts +28 -28
  38. package/cli/src/state/helpers.ts +37 -25
  39. package/cli/src/state/schema.ts +135 -45
  40. package/cli/src/state/store.ts +127 -7
  41. package/cli/src/state/validators.test.ts +13 -13
  42. package/cli/src/state/validators.ts +3 -4
  43. package/cli/src/utils/colors.ts +2 -0
  44. package/cli/src/utils/fs.ts +13 -0
  45. package/cli/src/utils/json.ts +20 -0
  46. package/cli/src/utils/knowledge.ts +471 -0
  47. package/cli/src/utils/time.ts +27 -0
  48. package/cli/src/{engine → workflow}/loopbacks.test.ts +2 -2
  49. package/cli/src/workflow/loopbacks.ts +42 -0
  50. package/cli/src/workflow/parallel.ts +64 -0
  51. package/cli/src/workflow/transitions.test.ts +129 -0
  52. package/cli/src/{engine → workflow}/transitions.ts +18 -22
  53. package/package.json +2 -2
  54. package/skills/auto-kit/SKILL.md +44 -27
  55. package/skills/cancel-kit/SKILL.md +4 -4
  56. package/skills/full-kit/SKILL.md +45 -28
  57. package/skills/pause-kit/SKILL.md +25 -0
  58. package/skills/resume-kit/SKILL.md +64 -0
  59. package/skills/wk-bootstrap/SKILL.md +11 -5
  60. package/skills/wk-build/SKILL.md +12 -11
  61. package/skills/wk-build/{stages → steps}/commit.md +1 -1
  62. package/skills/wk-build/{stages → steps}/core.md +3 -3
  63. package/skills/wk-build/{stages → steps}/integration.md +2 -2
  64. package/skills/wk-build/{stages → steps}/migration.md +1 -1
  65. package/skills/wk-build/{stages → steps}/red.md +1 -1
  66. package/skills/wk-build/{stages → steps}/refactor.md +1 -1
  67. package/skills/wk-build/{stages → steps}/setup.md +1 -1
  68. package/skills/wk-build/{stages → steps}/ui.md +1 -1
  69. package/skills/wk-deploy/SKILL.md +7 -6
  70. package/skills/wk-deploy/{stages → steps}/merge.md +1 -1
  71. package/skills/wk-deploy/{stages → steps}/monitor.md +1 -1
  72. package/skills/wk-deploy/{stages → steps}/remediate.md +1 -1
  73. package/skills/wk-plan/SKILL.md +15 -14
  74. package/skills/wk-plan/{stages → steps}/architecture.md +1 -1
  75. package/skills/wk-plan/{stages → steps}/audit.md +2 -2
  76. package/skills/wk-plan/{stages → steps}/blueprint.md +2 -2
  77. package/skills/wk-plan/{stages → steps}/clarify.md +1 -1
  78. package/skills/wk-plan/{stages → steps}/investigate.md +1 -1
  79. package/skills/wk-plan/{stages → steps}/scope.md +1 -1
  80. package/skills/wk-plan/{stages → steps}/sketch.md +1 -1
  81. package/skills/wk-plan/{stages → steps}/ux-flow.md +1 -1
  82. package/skills/wk-review/SKILL.md +11 -10
  83. package/skills/wk-review/{stages → steps}/compliance.md +1 -1
  84. package/skills/wk-review/{stages → steps}/handoff.md +2 -2
  85. package/skills/wk-review/{stages → steps}/performance.md +1 -1
  86. package/skills/wk-review/{stages → steps}/security.md +1 -1
  87. package/skills/wk-review/{stages → steps}/self-review.md +1 -1
  88. package/skills/wk-test/SKILL.md +9 -8
  89. package/skills/wk-test/steps/e2e.md +56 -0
  90. package/skills/wk-test/{stages → steps}/validate.md +1 -1
  91. package/skills/wk-test/{stages → steps}/verify.md +1 -1
  92. package/skills/wk-wrap-up/SKILL.md +19 -5
  93. package/skills/wk-wrap-up/steps/knowledge.md +76 -0
  94. package/skills/wk-wrap-up/steps/summary.md +86 -0
  95. package/cli/src/engine/loopbacks.ts +0 -32
  96. package/cli/src/engine/parallel.ts +0 -60
  97. package/cli/src/engine/transitions.test.ts +0 -129
  98. package/skills/wk-test/stages/e2e.md +0 -53
  99. /package/cli/src/{engine/phases.ts → workflow/gates.ts} +0 -0
@@ -1,13 +1,13 @@
1
1
  ---
2
2
  name: test
3
- description: "Run the Test phase — 3 sub-stages: Verify, E2E, Validate."
3
+ description: "Run the Test phase — 3 steps: Verify, E2E, Validate."
4
4
  user-invocable: false
5
5
  allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent
6
6
  ---
7
7
 
8
8
  You are the **QA Lead**. Validate the implementation against the Blueprint and acceptance criteria.
9
9
 
10
- ## Sub-stages (in order)
10
+ ## Steps (in order)
11
11
 
12
12
  1. **Verify** — Run existing test suite, check for regressions
13
13
  2. **E2E** — Test user flows end-to-end
@@ -15,11 +15,11 @@ You are the **QA Lead**. Validate the implementation against the Blueprint and a
15
15
 
16
16
  ## Execution
17
17
 
18
- For each sub-stage:
19
- 1. Read the sub-stage file (e.g., `.claude/skills/wk-test/stages/verify.md`)
18
+ For each step:
19
+ 1. Read the step file (e.g., `.claude/skills/wk-test/steps/verify.md`)
20
20
  2. Follow its instructions
21
21
  3. Update `.work-kit/state.md` with outputs
22
- 4. Proceed to next sub-stage
22
+ 4. Proceed to next step
23
23
 
24
24
  ## Key Principle
25
25
 
@@ -27,10 +27,11 @@ For each sub-stage:
27
27
 
28
28
  ## Recording
29
29
 
30
- Throughout every sub-stage, update the shared state.md sections:
30
+ Throughout every step, update the shared state.md sections:
31
31
 
32
32
  - **`## Criteria`** — Check off criteria as they're verified. Add evidence inline: `- [x] <criterion> — verified by <test name / screenshot / manual check>`.
33
33
  - **`## Decisions`** — If you discover a criterion is untestable or needs reinterpretation, record the decision and why.
34
+ - **`## Observations`** — Whenever you notice a fragile area, a missing test pattern, or feedback about the test phase itself, append: `- [lesson|convention|risk|workflow] text` (workflow tag may include `:phase/step`). At `wrap-up/knowledge` these are routed to `.work-kit-knowledge/` so future sessions benefit.
34
35
 
35
36
  The criteria checklist is copied directly into the final work-kit log. Make it accurate.
36
37
 
@@ -51,7 +52,7 @@ Agent: Verify ──┐
51
52
  Agent: E2E ──┘
52
53
  ```
53
54
 
54
- Each sub-agent reads the same Context Input sections and writes its own `### Test: <sub-stage>` section to state.md.
55
+ Each sub-agent reads the same Context Input sections and writes its own `### Test: <step>` section to state.md.
55
56
 
56
57
  ## Boundaries
57
58
 
@@ -74,7 +75,7 @@ Each sub-agent reads the same Context Input sections and writes its own `### Tes
74
75
 
75
76
  ## Final Output
76
77
 
77
- After all sub-stages are done, append a `### Test: Final` section to state.md. This is what **Review agents read**.
78
+ After all steps are done, append a `### Test: Final` section to state.md. This is what **Review agents read**.
78
79
 
79
80
  ```markdown
80
81
  ### Test: Final
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: "Test step: Test user flows end-to-end."
3
+ ---
4
+
5
+ # E2E
6
+
7
+ **Role:** End-to-End Tester
8
+ **Goal:** Test the feature as a user would experience it.
9
+
10
+ ## Instructions
11
+
12
+ 1. **Verify Playwright is installed.** Run `npx playwright --version`. If it fails or `@playwright/test` is missing from `package.json`, STOP and tell the user to run `work-kit setup` (which installs Playwright + Chromium and scaffolds a config).
13
+ 2. Review the UX Flow from the Plan phase.
14
+ 3. For each user flow defined:
15
+ - Write a Playwright test under the project's configured `testDir` (see `playwright.config.*`).
16
+ - Test the happy path.
17
+ - Test key edge cases (empty state, error state, boundary values).
18
+ 4. Run the tests with `npx playwright test`. All flows must pass before marking this step done.
19
+ 5. Capture screenshots at key states using Playwright's `page.screenshot()` or the `--trace on` flag.
20
+ 6. Focus on the most important flows — don't test every permutation.
21
+
22
+ ## Output (append to state.md)
23
+
24
+ ```markdown
25
+ ### Test: E2E
26
+
27
+ **Verdict:** pass | fail
28
+ **Tests Written:**
29
+ - `<test file>`: <flow description>
30
+
31
+ **Flows Verified:**
32
+ - <flow 1>: pass | fail (<details>)
33
+ - <flow 2>: pass | fail (<details>)
34
+
35
+ **Screenshots:**
36
+ - <description>: <path or "not applicable">
37
+
38
+ **Notes:**
39
+ - <edge cases tested, issues found>
40
+ ```
41
+
42
+ ## Rules
43
+
44
+ - Playwright is the required E2E framework. Manual verification does NOT satisfy this step.
45
+ - If Playwright is missing, halt and direct the user to `work-kit setup` — do not fall back to curl, manual steps, or another framework.
46
+ - Focus on user-visible behavior, not internal implementation.
47
+ - Screenshots are evidence — capture them for key states.
48
+ - If a flow fails, fix the implementation (not the test) unless the test expectation is wrong.
49
+
50
+ ## Anti-Rationalization
51
+
52
+ | Excuse | Reality |
53
+ |--------|---------|
54
+ | "Manual verification counts as E2E testing" | It does not. The E2E step requires automated Playwright tests. If Playwright is unavailable, halt and ask the user to run `work-kit setup`. |
55
+ | "Unit tests already cover this flow" | Unit tests mock boundaries. E2E tests verify the real flow across boundaries — database, API, UI. A function can pass its unit test and still fail in the real pipeline. |
56
+ | "E2E tests are slow and fragile, not worth the effort" | Slow tests that catch real bugs are more valuable than fast tests that miss them. Write focused E2E tests for critical paths, not exhaustive ones for every edge case. |
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Test sub-stage: Verify every acceptance criterion is satisfied with evidence."
2
+ description: "Test step: Verify every acceptance criterion is satisfied with evidence."
3
3
  ---
4
4
 
5
5
  # Validate
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: "Test sub-stage: Run existing test suite, check for regressions."
2
+ description: "Test step: Run existing test suite, check for regressions."
3
3
  ---
4
4
 
5
5
  # Verify
@@ -10,18 +10,32 @@ allowed-tools: Bash, Read, Write, Edit, Glob, Grep
10
10
  **Role:** Work Historian
11
11
  **Goal:** Produce a concise, useful summary of what was built and why — then clean up.
12
12
 
13
- ## Instructions
13
+ This phase has **two steps** (in order):
14
+
15
+ 1. **`wrap-up/summary`** — distill state.md into a useful summary for future developers. See `.claude/skills/wk-wrap-up/steps/summary.md`.
16
+ 2. **`wrap-up/knowledge`** — harvest learnings from this session into the project's `.work-kit-knowledge/` files so the next session benefits. See `.claude/skills/wk-wrap-up/steps/knowledge.md`.
17
+
18
+ The summary you write goes into `.work-kit/summary.md`; the CLI archives it into `.work-kit-tracker/archive/<slug>-<date>/` when you call `work-kit complete wrap-up/summary --outcome done`. After summary completes, the `knowledge` step runs `work-kit extract` and (optionally) one or more `work-kit learn` calls.
14
19
 
15
- > **Note:** The CLI automatically archives `state.md`, `tracker.json`, and a placeholder `summary.md` into `.work-kit-tracker/archive/<slug>-<date>/` when the last sub-stage completes. It also appends a row to `.work-kit-tracker/index.md`. Your job is to **replace the placeholder summary.md** with a real distilled summary.
20
+ ## Instructions
16
21
 
22
+ ### Step 1: summary
17
23
  1. **Read the full `.work-kit/state.md`** — every phase output from Plan through the last completed phase
18
24
  2. **Synthesize the summary** — not a copy-paste of state, but a distilled record that a future developer (or agent) would find useful
19
- 3. **Overwrite the summary file** at `.work-kit-tracker/archive/<slug>-<date>/summary.md` on the **main branch** (not the worktree)
20
- 4. **Ask the user** if they want the worktree and branch removed
25
+ 3. **Write `.work-kit/summary.md`** in the format described in the step file
26
+ 4. **Run** `work-kit complete wrap-up/summary --outcome done`
27
+
28
+ ### Step 2: knowledge
29
+ 5. **Run `work-kit extract`** — mechanically routes Observations / Decisions / Deviations / loopbacks into `.work-kit-knowledge/` files
30
+ 6. **Review the summary you just wrote** for subjective additions the parser would miss. For each, call `work-kit learn --type <lesson|convention|risk|workflow> --text "..."`.
31
+ 7. **Run** `work-kit complete wrap-up/knowledge --outcome done`
32
+
33
+ ### Cleanup
34
+ 8. **Ask the user** if they want the worktree and branch removed
21
35
 
22
36
  ## Summary File Format
23
37
 
24
- Overwrite `.work-kit-tracker/archive/<slug>-<date>/summary.md`:
38
+ Overwrite `.work-kit/summary.md`:
25
39
 
26
40
  ```markdown
27
41
  ---
@@ -0,0 +1,76 @@
1
+ # Step: Knowledge
2
+
3
+ **Phase:** Wrap-up
4
+ **Role:** Knowledge Harvester
5
+ **Goal:** Route this session's learnings into the project's `.work-kit-knowledge/` files so the next session — and the next developer — starts smarter.
6
+
7
+ ## When this step runs
8
+
9
+ After `wrap-up/summary`. By now you've just re-read the full `state.md` and distilled it into a summary, so your working memory of this session is at its peak. This is the right moment to capture observations the parser would miss.
10
+
11
+ ## Workflow
12
+
13
+ 1. **Run mechanical extraction:**
14
+ ```bash
15
+ work-kit extract
16
+ ```
17
+ This parses `.work-kit/state.md` and `.work-kit/tracker.json` and routes entries to `.work-kit-knowledge/{lessons,conventions,risks,workflow}.md`. It pulls from:
18
+ - `## Observations` typed bullets (`- [lesson|convention|risk|workflow] text`)
19
+ - `## Decisions` → conventions
20
+ - `## Deviations` → workflow feedback
21
+ - `tracker.json.loopbacks[]` → workflow feedback
22
+ - Skipped/failed steps → workflow feedback
23
+
24
+ The output JSON tells you how many entries were `written` vs `duplicates`. Re-running is idempotent.
25
+
26
+ 2. **Read your `.work-kit/summary.md`** (the one you just wrote). For each non-obvious thing in it that the parser would NOT have captured automatically, call `work-kit learn`:
27
+
28
+ ```bash
29
+ work-kit learn --type lesson --text "Discovered that the test fixtures must be reset between Playwright suites, otherwise auth state leaks."
30
+ work-kit learn --type risk --text "src/payment/webhook.ts has no integration test coverage for retries."
31
+ work-kit learn --type convention --text "All new API endpoints must register a Zod schema in src/schemas/."
32
+ work-kit learn --type workflow --text "The wk-test/e2e step doesn't tell agents to start the dev server before running Playwright."
33
+ ```
34
+
35
+ Each call appends one entry to the appropriate `.md` file under a lockfile, with secret redaction applied automatically.
36
+
37
+ 3. **Mark the step complete:**
38
+ ```bash
39
+ work-kit complete wrap-up/knowledge --outcome done
40
+ ```
41
+
42
+ ## What goes where
43
+
44
+ | Type | File | What belongs here |
45
+ |---|---|---|
46
+ | `lesson` | lessons.md | Project-specific learnings — facts about *this* codebase. |
47
+ | `convention` | conventions.md | Codified rules this project follows. Future sessions should respect these. |
48
+ | `risk` | risks.md | Fragile or dangerous areas. Touch with care. |
49
+ | `workflow` | workflow.md | Feedback about the work-kit kit itself — skill quality, step skips, loopbacks, failure modes. **Mined manually across projects to improve work-kit upstream.** |
50
+
51
+ ## Boundaries
52
+
53
+ ### Always
54
+ - Run `work-kit extract` first, then add manual `learn` calls.
55
+ - Keep `learn --text` entries to one sentence — they're for humans skimming a list.
56
+ - Use `workflow` type only for feedback about the work-kit *itself*, not for project facts.
57
+
58
+ ### Never
59
+ - Edit the `## Manual` section of any knowledge file. That's human-curated and tooling never touches it.
60
+ - Use `workflow.md` for project-specific facts. Use `lessons.md` instead.
61
+ - Paste large code blocks, file contents, or stack traces into `--text`. Distill into one sentence.
62
+ - Skip extraction. Even if you have nothing to add manually, `work-kit extract` still routes loopbacks and deviations.
63
+
64
+ ### Failure mode
65
+ - Non-fatal. If extract or learn fails, the summary step has already succeeded — the session isn't lost. Report the error to the user; they can retry manually or run `work-kit complete wrap-up/knowledge --outcome done` anyway.
66
+
67
+ ## Output
68
+
69
+ No file output for this step — entries land in `.work-kit-knowledge/*.md`. Optionally append a one-line note to `.work-kit/state.md` describing what you captured, e.g.:
70
+
71
+ ```markdown
72
+ ### Wrap-up: Knowledge
73
+
74
+ **Extracted:** 4 entries (2 conventions, 1 risk, 1 workflow)
75
+ **Manual additions:** 2 lessons, 1 workflow feedback
76
+ ```
@@ -0,0 +1,86 @@
1
+ # Step: Summary
2
+
3
+ **Phase:** Wrap-up
4
+ **Role:** Work Historian
5
+ **Goal:** Distill the full state.md into a useful summary for future developers, then clean up.
6
+
7
+ ## Workflow
8
+
9
+ The CLI archives `state.md`, `tracker.json`, and (if you wrote one) `summary.md` into
10
+ `.work-kit-tracker/archive/<slug>-<date>/` automatically when the wrap-up step completes.
11
+ It also appends a row to `.work-kit-tracker/index.md`.
12
+
13
+ **Your job:** write a real `summary.md` to `.work-kit/summary.md` *before* calling
14
+ `work-kit complete wrap-up/summary`. The CLI will pick it up and place it in the archive.
15
+
16
+ ## Instructions
17
+
18
+ 1. **Read the full `.work-kit/state.md`** — every phase output from Plan through Deploy.
19
+ 2. **Synthesize the summary** — not a copy-paste; a distillation a future developer can use.
20
+ 3. **Write `.work-kit/summary.md`** with the format below.
21
+ 4. **Run** `work-kit complete wrap-up/summary --outcome done`.
22
+ 5. **Ask the user** if they want the worktree and feature branch removed (use `work-kit cancel` only if no merge happened; otherwise prefer `git worktree remove`).
23
+
24
+ ## Summary File Format
25
+
26
+ Write to `.work-kit/summary.md`:
27
+
28
+ ```markdown
29
+ ---
30
+ slug: <slug>
31
+ branch: feature/<slug>
32
+ pr: <#number or n/a>
33
+ started: <YYYY-MM-DD>
34
+ completed: <YYYY-MM-DD>
35
+ status: <completed | partial | rolled-back>
36
+ ---
37
+
38
+ ## Summary
39
+ <2-3 sentences: what was built, why it was needed, and the end state>
40
+
41
+ ## Criteria
42
+ <copy the final criteria checklist from state.md — checked and unchecked>
43
+
44
+ ## Key Decisions
45
+ <only the non-obvious ones — decisions where the alternative was reasonable>
46
+ - <decision>: <what was chosen> — <why, in one line>
47
+
48
+ ## Deviations from Plan
49
+ <anything that changed between Blueprint and final implementation — skip if none>
50
+ - <what changed and why>
51
+ ```
52
+
53
+ ## Include vs. Exclude
54
+
55
+ **Include:**
56
+ - Decisions where you chose between real alternatives
57
+ - Deviations from the Blueprint (and why)
58
+ - Anything a future developer would need to understand the "why" behind the code
59
+ - Criteria status — what was met, what wasn't
60
+
61
+ **Exclude:**
62
+ - Artifact lists (files, PRs, migrations) — derivable from git
63
+ - Routine implementation details ("created file X, modified file Y")
64
+ - Full phase outputs — distill, don't dump
65
+ - Internal process notes ("ran tests 3 times before they passed")
66
+
67
+ ## Boundaries
68
+
69
+ ### Always
70
+ - Read the full state.md before writing the summary
71
+ - Include every non-obvious decision in Key Decisions
72
+ - Include every deviation from the Blueprint in Deviations
73
+
74
+ ### Never
75
+ - Copy-paste full phase outputs into the summary
76
+ - Skip the criteria checklist
77
+
78
+ ## After Completion
79
+
80
+ When you call `work-kit complete wrap-up/summary --outcome done`, the CLI:
81
+
82
+ 1. Creates `.work-kit-tracker/archive/<slug>-<date>/`
83
+ 2. Copies `state.md`, `tracker.json`, and `summary.md` into it
84
+ 3. Appends a row to `.work-kit-tracker/index.md`
85
+
86
+ You may then commit the archive to the main branch and remove the worktree.
@@ -1,32 +0,0 @@
1
- import { PhaseName, Location } from "../state/schema.js";
2
- import { LOOPBACK_ROUTES } from "../config/loopback-routes.js";
3
-
4
- interface LoopbackResult {
5
- to: Location;
6
- reason: string;
7
- }
8
-
9
- /**
10
- * Check if completing a sub-stage with a given outcome should trigger a loop-back.
11
- */
12
- export function checkLoopback(
13
- phase: PhaseName,
14
- subStage: string,
15
- outcome?: string
16
- ): LoopbackResult | null {
17
- if (!outcome) return null;
18
-
19
- const route = LOOPBACK_ROUTES.find(
20
- (r) =>
21
- r.from.phase === phase &&
22
- r.from.subStage === subStage &&
23
- r.triggerOutcome === outcome
24
- );
25
-
26
- if (!route) return null;
27
-
28
- return {
29
- to: route.to,
30
- reason: route.reason,
31
- };
32
- }
@@ -1,60 +0,0 @@
1
- import type { PhaseName, WorkKitState } from "../state/schema.js";
2
-
3
- /**
4
- * Defines which sub-stages run in parallel and which runs sequentially after.
5
- */
6
- export interface ParallelGroup {
7
- parallel: string[]; // sub-stages that run concurrently
8
- thenSequential?: string; // sub-stage that runs after all parallel complete
9
- }
10
-
11
- /**
12
- * Parallel group definitions per phase.
13
- */
14
- const PARALLEL_GROUPS: Record<string, ParallelGroup> = {
15
- test: {
16
- parallel: ["verify", "e2e"],
17
- thenSequential: "validate",
18
- },
19
- review: {
20
- parallel: ["self-review", "security", "performance", "compliance"],
21
- thenSequential: "handoff",
22
- },
23
- };
24
-
25
- /**
26
- * Check if a sub-stage triggers a parallel group.
27
- * Triggers on any parallel member that is the first non-skipped one in the group.
28
- * Returns null if the sub-stage is not a parallel trigger or the group doesn't apply.
29
- */
30
- export function getParallelGroup(phase: PhaseName, subStage: string, state?: WorkKitState): ParallelGroup | null {
31
- const group = PARALLEL_GROUPS[phase];
32
- if (!group) return null;
33
-
34
- if (!group.parallel.includes(subStage)) return null;
35
-
36
- // Find the first non-skipped parallel member
37
- if (state) {
38
- const phaseState = state.phases[phase];
39
- const firstActive = group.parallel.find((ss) => {
40
- const ssState = phaseState?.subStages[ss];
41
- return ssState && ssState.status !== "skipped" && ssState.status !== "completed";
42
- });
43
- // Only trigger if this sub-stage is the first active parallel member
44
- if (firstActive !== subStage) return null;
45
- } else {
46
- // No state provided — fall back to first-member trigger
47
- if (group.parallel[0] !== subStage) return null;
48
- }
49
-
50
- return group;
51
- }
52
-
53
- /**
54
- * Check if a sub-stage is a parallel member (part of a group, not necessarily trigger).
55
- */
56
- export function isParallelMember(phase: PhaseName, subStage: string): boolean {
57
- const group = PARALLEL_GROUPS[phase];
58
- if (!group) return false;
59
- return group.parallel.includes(subStage);
60
- }
@@ -1,129 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import * as assert from "node:assert/strict";
3
- import { nextSubStageInPhase, isPhaseComplete, determineNextStep } from "./transitions.js";
4
- import type { WorkKitState, PhaseName, PhaseState, SubStageState } from "../state/schema.js";
5
- import { PHASE_NAMES, SUBSTAGES_BY_PHASE } from "../state/schema.js";
6
-
7
- function makeState(): WorkKitState {
8
- const phases = {} as Record<PhaseName, PhaseState>;
9
- for (const phase of PHASE_NAMES) {
10
- const subStages: Record<string, SubStageState> = {};
11
- for (const ss of SUBSTAGES_BY_PHASE[phase]) {
12
- subStages[ss] = { status: "pending" };
13
- }
14
- phases[phase] = { status: "pending", subStages };
15
- }
16
- return {
17
- version: 1,
18
- slug: "test",
19
- branch: "feature/test",
20
- started: "2026-01-01",
21
- mode: "full-kit",
22
- status: "in-progress",
23
- currentPhase: "plan",
24
- currentSubStage: "clarify",
25
- phases,
26
- loopbacks: [],
27
- metadata: { worktreeRoot: "/tmp/test", mainRepoRoot: "/tmp/test" },
28
- };
29
- }
30
-
31
- describe("nextSubStageInPhase", () => {
32
- it("returns first pending sub-stage", () => {
33
- const state = makeState();
34
- const result = nextSubStageInPhase(state, "plan");
35
- assert.equal(result, "clarify");
36
- });
37
-
38
- it("returns null when all complete or skipped", () => {
39
- const state = makeState();
40
- for (const ss of Object.values(state.phases.plan.subStages)) {
41
- ss.status = "completed";
42
- }
43
- const result = nextSubStageInPhase(state, "plan");
44
- assert.equal(result, null);
45
- });
46
-
47
- it("skips completed sub-stages and returns next pending", () => {
48
- const state = makeState();
49
- state.phases.plan.subStages.clarify.status = "completed";
50
- state.phases.plan.subStages.investigate.status = "completed";
51
- const result = nextSubStageInPhase(state, "plan");
52
- assert.equal(result, "sketch");
53
- });
54
- });
55
-
56
- describe("isPhaseComplete", () => {
57
- it("returns true when all complete or skipped", () => {
58
- const state = makeState();
59
- for (const ss of Object.values(state.phases.plan.subStages)) {
60
- ss.status = "completed";
61
- }
62
- assert.equal(isPhaseComplete(state, "plan"), true);
63
- });
64
-
65
- it("returns true with mix of completed and skipped", () => {
66
- const state = makeState();
67
- let first = true;
68
- for (const ss of Object.values(state.phases.plan.subStages)) {
69
- ss.status = first ? "skipped" : "completed";
70
- first = false;
71
- }
72
- assert.equal(isPhaseComplete(state, "plan"), true);
73
- });
74
-
75
- it("returns false when some sub-stages are pending", () => {
76
- const state = makeState();
77
- assert.equal(isPhaseComplete(state, "plan"), false);
78
- });
79
- });
80
-
81
- describe("determineNextStep", () => {
82
- it("returns complete when state is completed", () => {
83
- const state = makeState();
84
- state.status = "completed";
85
- const step = determineNextStep(state);
86
- assert.equal(step.type, "complete");
87
- });
88
-
89
- it("returns phase-boundary when no current phase", () => {
90
- const state = makeState();
91
- state.currentPhase = null;
92
- const step = determineNextStep(state);
93
- assert.equal(step.type, "phase-boundary");
94
- assert.equal(step.phase, "plan");
95
- });
96
-
97
- it("returns sub-stage for current phase with pending work", () => {
98
- const state = makeState();
99
- state.currentPhase = "plan";
100
- state.phases.plan.status = "in-progress";
101
- const step = determineNextStep(state);
102
- assert.equal(step.type, "sub-stage");
103
- assert.equal(step.phase, "plan");
104
- assert.equal(step.subStage, "clarify");
105
- });
106
-
107
- it("auto-proceeds to next phase by default when current phase is complete", () => {
108
- const state = makeState();
109
- state.currentPhase = "plan";
110
- for (const ss of Object.values(state.phases.plan.subStages)) {
111
- ss.status = "completed";
112
- }
113
- const step = determineNextStep(state);
114
- assert.equal(step.type, "phase-boundary");
115
- assert.equal(step.phase, "build");
116
- });
117
-
118
- it("returns wait-for-user when gated and current phase is complete", () => {
119
- const state = makeState();
120
- state.gated = true;
121
- state.currentPhase = "plan";
122
- for (const ss of Object.values(state.phases.plan.subStages)) {
123
- ss.status = "completed";
124
- }
125
- const step = determineNextStep(state);
126
- assert.equal(step.type, "wait-for-user");
127
- assert.equal(step.phase, "build");
128
- });
129
- });
@@ -1,53 +0,0 @@
1
- ---
2
- description: "Test sub-stage: Test user flows end-to-end."
3
- ---
4
-
5
- # E2E
6
-
7
- **Role:** End-to-End Tester
8
- **Goal:** Test the feature as a user would experience it.
9
-
10
- ## Instructions
11
-
12
- 1. Review the UX Flow from the Plan phase
13
- 2. For each user flow defined:
14
- - Write an E2E test (Playwright, Cypress, or manual verification)
15
- - Test the happy path
16
- - Test key edge cases (empty state, error state, boundary values)
17
- 3. Take screenshots at key states if the test framework supports it
18
- 4. Focus on the most important flows — don't test every permutation
19
-
20
- ## Output (append to state.md)
21
-
22
- ```markdown
23
- ### Test: E2E
24
-
25
- **Verdict:** pass | fail
26
- **Tests Written:**
27
- - `<test file>`: <flow description>
28
-
29
- **Flows Verified:**
30
- - <flow 1>: pass | fail (<details>)
31
- - <flow 2>: pass | fail (<details>)
32
-
33
- **Screenshots:**
34
- - <description>: <path or "not applicable">
35
-
36
- **Notes:**
37
- - <edge cases tested, issues found>
38
- ```
39
-
40
- ## Rules
41
-
42
- - If the project has no E2E framework, test manually and document the steps
43
- - Focus on user-visible behavior, not internal implementation
44
- - Screenshots are evidence — capture them for key states
45
- - If a flow fails, fix the implementation (not the test) unless the test expectation is wrong
46
-
47
- ## Anti-Rationalization
48
-
49
- | Excuse | Reality |
50
- |--------|---------|
51
- | "Manual verification counts as E2E testing" | Manual verification is not repeatable, not documented, and not run in CI. If you cannot automate it, at minimum document the exact manual steps with expected results. |
52
- | "Unit tests already cover this flow" | Unit tests mock boundaries. E2E tests verify the real flow across boundaries — database, API, UI. A function can pass its unit test and still fail in the real pipeline. |
53
- | "E2E tests are slow and fragile, not worth the effort" | Slow tests that catch real bugs are more valuable than fast tests that miss them. Write focused E2E tests for critical paths, not exhaustive ones for every edge case. |
File without changes