jettypod 4.4.116 → 4.4.120

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 (162) hide show
  1. package/.env +7 -0
  2. package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +124 -48
  3. package/apps/dashboard/app/api/claude/[workItemId]/route.ts +171 -58
  4. package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +161 -10
  5. package/apps/dashboard/app/api/tests/run/stream/route.ts +13 -1
  6. package/apps/dashboard/app/api/usage/route.ts +17 -0
  7. package/apps/dashboard/app/api/work/[id]/route.ts +35 -0
  8. package/apps/dashboard/app/api/work/[id]/status/route.ts +43 -1
  9. package/apps/dashboard/app/connect-claude/page.tsx +24 -0
  10. package/apps/dashboard/app/decision/[id]/page.tsx +14 -14
  11. package/apps/dashboard/app/demo/gates/page.tsx +42 -42
  12. package/apps/dashboard/app/design-system/page.tsx +868 -0
  13. package/apps/dashboard/app/globals.css +6 -2
  14. package/apps/dashboard/app/install-claude/page.tsx +9 -7
  15. package/apps/dashboard/app/layout.tsx +17 -5
  16. package/apps/dashboard/app/login/page.tsx +250 -0
  17. package/apps/dashboard/app/page.tsx +11 -9
  18. package/apps/dashboard/app/settings/page.tsx +4 -2
  19. package/apps/dashboard/app/signup/page.tsx +245 -0
  20. package/apps/dashboard/app/subscribe/page.tsx +11 -0
  21. package/apps/dashboard/app/welcome/page.tsx +24 -1
  22. package/apps/dashboard/app/work/[id]/page.tsx +34 -50
  23. package/apps/dashboard/components/AppShell.tsx +95 -55
  24. package/apps/dashboard/components/CardMenu.tsx +56 -13
  25. package/apps/dashboard/components/ClaudePanel.tsx +301 -582
  26. package/apps/dashboard/components/ClaudePanelInput.tsx +23 -14
  27. package/apps/dashboard/components/ConnectClaudeScreen.tsx +210 -0
  28. package/apps/dashboard/components/CopyableId.tsx +3 -3
  29. package/apps/dashboard/components/DetailReviewActions.tsx +109 -0
  30. package/apps/dashboard/components/DragContext.tsx +75 -65
  31. package/apps/dashboard/components/DraggableCard.tsx +6 -46
  32. package/apps/dashboard/components/DropZone.tsx +2 -2
  33. package/apps/dashboard/components/EditableDetailDescription.tsx +1 -1
  34. package/apps/dashboard/components/EditableTitle.tsx +26 -6
  35. package/apps/dashboard/components/ElapsedTimer.tsx +54 -0
  36. package/apps/dashboard/components/EpicGroup.tsx +329 -0
  37. package/apps/dashboard/components/GateCard.tsx +100 -16
  38. package/apps/dashboard/components/GateChoiceCard.tsx +15 -17
  39. package/apps/dashboard/components/InstallClaudeScreen.tsx +140 -51
  40. package/apps/dashboard/components/JettyLoader.tsx +38 -0
  41. package/apps/dashboard/components/KanbanBoard.tsx +147 -766
  42. package/apps/dashboard/components/KanbanCard.tsx +506 -0
  43. package/apps/dashboard/components/LazyMarkdown.tsx +12 -0
  44. package/apps/dashboard/components/MainNav.tsx +20 -54
  45. package/apps/dashboard/components/MessageBlock.tsx +391 -0
  46. package/apps/dashboard/components/ModeStartCard.tsx +15 -15
  47. package/apps/dashboard/components/OnboardingWelcome.tsx +214 -0
  48. package/apps/dashboard/components/PlaceholderCard.tsx +11 -21
  49. package/apps/dashboard/components/ProjectSwitcher.tsx +36 -8
  50. package/apps/dashboard/components/PrototypeTimeline.tsx +25 -25
  51. package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +265 -301
  52. package/apps/dashboard/components/RealTimeTestsWrapper.tsx +97 -74
  53. package/apps/dashboard/components/ReviewFooter.tsx +141 -0
  54. package/apps/dashboard/components/SessionList.tsx +19 -18
  55. package/apps/dashboard/components/SubscribeContent.tsx +206 -0
  56. package/apps/dashboard/components/TestTree.tsx +15 -14
  57. package/apps/dashboard/components/TipCard.tsx +177 -0
  58. package/apps/dashboard/components/Toast.tsx +5 -5
  59. package/apps/dashboard/components/TypeIcon.tsx +56 -0
  60. package/apps/dashboard/components/UpgradeBanner.tsx +30 -0
  61. package/apps/dashboard/components/WaveCompletionAnimation.tsx +61 -62
  62. package/apps/dashboard/components/WelcomeScreen.tsx +25 -27
  63. package/apps/dashboard/components/WorkItemHeader.tsx +4 -4
  64. package/apps/dashboard/components/WorkItemTree.tsx +9 -28
  65. package/apps/dashboard/components/settings/AccountSection.tsx +169 -0
  66. package/apps/dashboard/components/settings/EnvVarsSection.tsx +54 -79
  67. package/apps/dashboard/components/settings/GeneralSection.tsx +26 -31
  68. package/apps/dashboard/components/settings/SettingsLayout.tsx +4 -4
  69. package/apps/dashboard/components/ui/Button.tsx +104 -0
  70. package/apps/dashboard/components/ui/Input.tsx +78 -0
  71. package/apps/dashboard/contexts/ClaudeSessionContext.tsx +408 -105
  72. package/apps/dashboard/contexts/ConnectionStatusContext.tsx +25 -4
  73. package/apps/dashboard/contexts/UsageContext.tsx +155 -0
  74. package/apps/dashboard/contexts/usageHelpers.js +9 -0
  75. package/apps/dashboard/electron/ipc-handlers.js +281 -88
  76. package/apps/dashboard/electron/main.js +691 -131
  77. package/apps/dashboard/electron/preload.js +25 -4
  78. package/apps/dashboard/electron/session-manager.js +163 -0
  79. package/apps/dashboard/electron-builder.config.js +3 -5
  80. package/apps/dashboard/hooks/useKanbanAnimation.ts +29 -0
  81. package/apps/dashboard/hooks/useKanbanUndo.ts +83 -0
  82. package/apps/dashboard/lib/backlog-parser.ts +50 -0
  83. package/apps/dashboard/lib/claude-process-manager.ts +50 -11
  84. package/apps/dashboard/lib/constants.ts +43 -0
  85. package/apps/dashboard/lib/db-bridge.ts +33 -0
  86. package/apps/dashboard/lib/db.ts +136 -20
  87. package/apps/dashboard/lib/kanban-utils.ts +70 -0
  88. package/apps/dashboard/lib/run-migrations.js +27 -2
  89. package/apps/dashboard/lib/session-state-machine.ts +3 -0
  90. package/apps/dashboard/lib/session-stream-manager.ts +144 -38
  91. package/apps/dashboard/lib/shadows.ts +7 -0
  92. package/apps/dashboard/lib/tests.ts +3 -1
  93. package/apps/dashboard/lib/utils.ts +6 -0
  94. package/apps/dashboard/next.config.js +35 -14
  95. package/apps/dashboard/package.json +6 -3
  96. package/apps/dashboard/public/bug-icon.svg +9 -0
  97. package/apps/dashboard/public/buoy-icon.svg +9 -0
  98. package/apps/dashboard/public/fonts/Satoshi-Variable.woff2 +0 -0
  99. package/apps/dashboard/public/fonts/Satoshi-VariableItalic.woff2 +0 -0
  100. package/apps/dashboard/public/in-flight-seagull.svg +9 -0
  101. package/apps/dashboard/public/jetty-icon-loading-alt.svg +11 -0
  102. package/apps/dashboard/public/jetty-icon-loading.svg +11 -0
  103. package/apps/dashboard/public/jettypod_logo.png +0 -0
  104. package/apps/dashboard/public/pier-icon.svg +14 -0
  105. package/apps/dashboard/public/star-icon.svg +9 -0
  106. package/apps/dashboard/public/wrench-icon.svg +9 -0
  107. package/apps/dashboard/scripts/upload-to-r2.js +89 -0
  108. package/apps/dashboard/scripts/ws-server.js +191 -0
  109. package/apps/dashboard/tsconfig.tsbuildinfo +1 -0
  110. package/apps/update-server/package.json +16 -0
  111. package/apps/update-server/schema.sql +31 -0
  112. package/apps/update-server/src/index.ts +1085 -0
  113. package/apps/update-server/tsconfig.json +16 -0
  114. package/apps/update-server/wrangler.toml +35 -0
  115. package/cucumber.js +9 -3
  116. package/docs/COMMAND_REFERENCE.md +34 -0
  117. package/hooks/post-checkout +32 -75
  118. package/hooks/post-merge +111 -10
  119. package/jest.setup.js +1 -0
  120. package/jettypod.js +54 -116
  121. package/lib/chore-taxonomy.js +33 -10
  122. package/lib/database.js +36 -16
  123. package/lib/db-watcher.js +1 -1
  124. package/lib/git-hooks/pre-commit +1 -1
  125. package/lib/jettypod-backup.js +27 -4
  126. package/lib/migrations/027-plan-at-creation-column.js +33 -0
  127. package/lib/migrations/028-ready-for-review-column.js +27 -0
  128. package/lib/migrations/029-remove-autoincrement.js +307 -0
  129. package/lib/migrations/029-rename-corrupted-to-cleaned.js +149 -0
  130. package/lib/migrations/index.js +47 -4
  131. package/lib/schema.js +13 -6
  132. package/lib/seed-onboarding.js +101 -69
  133. package/lib/update-command/index.js +9 -175
  134. package/lib/work-commands/index.js +129 -16
  135. package/lib/work-tracking/index.js +86 -46
  136. package/lib/worktree-diagnostics.js +16 -16
  137. package/lib/worktree-facade.js +1 -1
  138. package/lib/worktree-manager.js +8 -8
  139. package/lib/worktree-reconciler.js +5 -5
  140. package/package.json +9 -2
  141. package/scripts/ndjson-to-cucumber-json.js +152 -0
  142. package/scripts/postinstall.js +25 -0
  143. package/skills-templates/bug-mode/SKILL.md +39 -28
  144. package/skills-templates/bug-planning/SKILL.md +25 -29
  145. package/skills-templates/chore-mode/SKILL.md +131 -68
  146. package/skills-templates/chore-mode/verification.js +51 -10
  147. package/skills-templates/chore-planning/SKILL.md +47 -18
  148. package/skills-templates/epic-planning/SKILL.md +68 -48
  149. package/skills-templates/external-transition/SKILL.md +47 -47
  150. package/skills-templates/feature-planning/SKILL.md +83 -73
  151. package/skills-templates/production-mode/SKILL.md +49 -49
  152. package/skills-templates/request-routing/SKILL.md +27 -14
  153. package/skills-templates/simple-improvement/SKILL.md +68 -44
  154. package/skills-templates/speed-mode/SKILL.md +209 -128
  155. package/skills-templates/stable-mode/SKILL.md +105 -94
  156. package/templates/bdd-guidance.md +139 -0
  157. package/templates/bdd-scaffolding/wait.js +18 -0
  158. package/templates/bdd-scaffolding/world.js +19 -0
  159. package/.jettypod-backup/work.db +0 -0
  160. package/apps/dashboard/app/access-code/page.tsx +0 -110
  161. package/lib/discovery-checkpoint.js +0 -123
  162. package/skills-templates/project-discovery/SKILL.md +0 -372
@@ -18,7 +18,7 @@ description: Guide implementation of stable mode chores with comprehensive testi
18
18
  └─────────────────────────────────────────────────────────────────────┘
19
19
  ```
20
20
 
21
- ## 🛑 CRITICAL HANDOFF REQUIREMENT
21
+ ## CRITICAL HANDOFF REQUIREMENT
22
22
 
23
23
  **After completing ALL stable mode chores:**
24
24
 
@@ -30,7 +30,7 @@ description: Guide implementation of stable mode chores with comprehensive testi
30
30
  1. Set feature mode to production
31
31
  2. **IMMEDIATELY invoke production-mode using the Skill tool**
32
32
 
33
- **🛑 STOP GATE:** For external projects, DO NOT end this skill without invoking production-mode. Stable mode makes it robust - production mode makes it ready for real users at scale.
33
+ **STOP GATE:** For external projects, DO NOT end this skill without invoking production-mode. Stable mode makes it robust - production mode makes it ready for real users at scale.
34
34
 
35
35
  ---
36
36
 
@@ -40,7 +40,7 @@ Guides Claude Code through stable mode implementation with comprehensive testing
40
40
 
41
41
  When this skill is activated, you are helping implement a stable mode chore to add comprehensive testing and error handling. Follow this structured approach:
42
42
 
43
- ## 🔑 Critical Context
43
+ ## Critical Context
44
44
 
45
45
  **You are working in an isolated git worktree:**
46
46
  - `work start [chore-id]` created a dedicated worktree for this chore
@@ -52,7 +52,7 @@ When this skill is activated, you are helping implement a stable mode chore to a
52
52
 
53
53
  ---
54
54
 
55
- ## 🚨 SHELL CWD RECOVERY
55
+ ## SHELL CWD RECOVERY
56
56
 
57
57
  **If ALL bash commands start failing with "Error: Exit code 1" and no output:**
58
58
 
@@ -68,7 +68,7 @@ Your shell's working directory was likely inside a worktree that was deleted. Th
68
68
 
69
69
  ---
70
70
 
71
- ## 🛑 PRE-FLIGHT VALIDATION (REQUIRED)
71
+ ## PRE-FLIGHT VALIDATION (REQUIRED)
72
72
 
73
73
  **Before proceeding with ANY implementation, you MUST validate the worktree exists.**
74
74
 
@@ -82,17 +82,17 @@ sqlite3 .jettypod/work.db "SELECT wi.id, wi.title, wi.status, wt.worktree_path,
82
82
 
83
83
  | worktree_path | What it means | Action |
84
84
  |---------------|---------------|--------|
85
- | **Has a path** (e.g., `/path/to/.jettypod-work/...`) | Worktree exists, ready to proceed | Continue to Step 0 |
86
- | **NULL or empty** | `work start` was not called | **STOP - run `jettypod work start [chore-id]` first** |
87
- | **No rows returned** | No chore is in progress | **STOP - verify the chore exists and run `work start`** |
85
+ | **Has a path** (e.g., `/path/to/.jettypod-work/...`) | Worktree exists, ready to proceed | Continue to Step 0 |
86
+ | **NULL or empty** | `work start` was not called | **STOP - run `jettypod work start [chore-id]` first** |
87
+ | **No rows returned** | No chore is in progress | **STOP - verify the chore exists and run `work start`** |
88
88
 
89
- **🛑 STOP GATE:** If `worktree_path` is NULL or no rows returned, you MUST run `jettypod work start [chore-id]` before continuing. DO NOT proceed without a valid worktree.
89
+ **STOP GATE:** If `worktree_path` is NULL or no rows returned, you MUST run `jettypod work start [chore-id]` before continuing. DO NOT proceed without a valid worktree.
90
90
 
91
- **🚫 FORBIDDEN: Manual Git Worktree Commands**
91
+ **FORBIDDEN: Manual Git Worktree Commands**
92
92
  ```
93
- git worktree add ...
94
- git checkout -b feature/...
95
- git branch feature/...
93
+ git worktree add ...
94
+ git checkout -b feature/...
95
+ git branch feature/...
96
96
  ```
97
97
  **ALWAYS use `jettypod work start`** - it handles branch naming, path conventions, database tracking, and cleanup. Manual git commands will create orphaned worktrees that break the merge workflow.
98
98
 
@@ -109,7 +109,7 @@ sqlite3 .jettypod/work.db "SELECT wi.id, wi.title, wi.status, wt.worktree_path,
109
109
 
110
110
  ---
111
111
 
112
- ## 🔒 WORKTREE PATH LOCK
112
+ ## WORKTREE PATH LOCK
113
113
 
114
114
  **After pre-flight validation passes, capture and lock the worktree path:**
115
115
 
@@ -119,7 +119,7 @@ From the pre-flight query output, extract and store:
119
119
  **Display:**
120
120
 
121
121
  ```
122
- 🔒 WORKTREE LOCK ACTIVE
122
+ WORKTREE LOCK ACTIVE
123
123
  Path: ${WORKTREE_PATH}
124
124
 
125
125
  All file writes will use this path.
@@ -154,7 +154,7 @@ jettypod ui gate worktree-started --data='{"path":"${WORKTREE_PATH}"}'
154
154
  **User Profile:** May not know how to code - Claude Code does the implementation autonomously.
155
155
 
156
156
  <details>
157
- <summary><strong>📋 What Stable Mode Includes (click to expand)</strong></summary>
157
+ <summary><strong>What Stable Mode Includes (click to expand)</strong></summary>
158
158
 
159
159
  **Stable Mode is NOT just error handling. It includes:**
160
160
 
@@ -194,7 +194,7 @@ jettypod ui gate worktree-started --data='{"path":"${WORKTREE_PATH}"}'
194
194
 
195
195
  ---
196
196
 
197
- ## 🧪 Unit Testing in Stable Mode - True TDD
197
+ ## Unit Testing in Stable Mode - True TDD
198
198
 
199
199
  **Unit tests are written DURING implementation, not after.**
200
200
 
@@ -214,10 +214,10 @@ jettypod ui gate worktree-started --data='{"path":"${WORKTREE_PATH}"}'
214
214
  - State consistency (transaction rollback, cleanup on failure)
215
215
 
216
216
  <details>
217
- <summary><strong>📋 Unit Test Examples (click to expand)</strong></summary>
217
+ <summary><strong>Unit Test Examples (click to expand)</strong></summary>
218
218
 
219
219
  ```javascript
220
- // Stable mode unit tests (error paths and edge cases)
220
+ // Stable mode unit tests (error paths and edge cases)
221
221
  test('createUser throws ValidationError for null email', () => {
222
222
  expect(() => createUser('John', null)).toThrow(ValidationError);
223
223
  expect(() => createUser('John', null)).toThrow('Email is required');
@@ -266,7 +266,7 @@ test('getUserById returns null for non-existent user', () => {
266
266
  sqlite3 .jettypod/work.db "SELECT wi.id, wi.title, wi.parent_id, parent.title as parent_title, parent.scenario_file, wt.worktree_path, wt.branch_name FROM work_items wi LEFT JOIN work_items parent ON wi.parent_id = parent.id LEFT JOIN worktrees wt ON wi.id = wt.work_item_id WHERE wi.status = 'in_progress' AND wi.type = 'chore'"
267
267
  ```
268
268
 
269
- **🔄 WORKFLOW INTEGRATION: Start workflow tracking**
269
+ **WORKFLOW INTEGRATION: Start workflow tracking**
270
270
 
271
271
  After getting the work context, register this skill execution:
272
272
 
@@ -280,7 +280,7 @@ This validates that `speed_mode_complete` gate is passed and creates an executio
280
280
 
281
281
  ```
282
282
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
283
- 🛡️ STABLE MODE: Implementing Chore #[id]
283
+ STABLE MODE: Implementing Chore #[id]
284
284
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
285
285
 
286
286
  Chore: [title]
@@ -299,11 +299,11 @@ Analyzing stable mode BDD scenarios to determine what error handling and validat
299
299
 
300
300
  **CRITICAL:** Claude Code executes this autonomously - no user permission needed.
301
301
 
302
- **🚫 FORBIDDEN: Writing Files at This Step**
302
+ **FORBIDDEN: Writing Files at This Step**
303
303
  ```
304
- Write tool to any path
305
- Edit tool to any path
306
- Any file creation or modification
304
+ Write tool to any path
305
+ Edit tool to any path
306
+ Any file creation or modification
307
307
  ```
308
308
  **This is an ANALYSIS step.** File writes happen in Step 5.
309
309
 
@@ -331,15 +331,15 @@ sqlite3 .jettypod/work.db "SELECT wi.id, wi.title, wi.description, wi.parent_id,
331
331
  4. If no match found, list available scenarios and ask which one to implement
332
332
 
333
333
  **Handle errors gracefully:**
334
- - If no current work: "No current work found. Run: jettypod work start <chore-id>"
335
- - If no parent feature: "Current work has no parent feature."
336
- - If no scenario_file: "Feature has no scenario_file."
334
+ - If no current work: "No current work found. Run: jettypod work start <chore-id>"
335
+ - If no parent feature: "Current work has no parent feature."
336
+ - If no scenario_file: "Feature has no scenario_file."
337
337
  - If can't match chore to scenario: List available scenarios and ask user
338
338
 
339
339
  **Display to user:**
340
340
 
341
341
  ```
342
- 🧪 Stable Mode: [Feature Name]
342
+ Stable Mode: [Feature Name]
343
343
 
344
344
  Target Scenario:
345
345
  [Scenario title]
@@ -364,11 +364,11 @@ Now reviewing speed mode implementation...
364
364
 
365
365
  **CRITICAL:** Claude Code executes this autonomously - no user permission needed.
366
366
 
367
- **🚫 FORBIDDEN: Writing Files at This Step**
367
+ **FORBIDDEN: Writing Files at This Step**
368
368
  ```
369
- Write tool to any path
370
- Edit tool to any path
371
- Any file creation or modification
369
+ Write tool to any path
370
+ Edit tool to any path
371
+ Any file creation or modification
372
372
  ```
373
373
  **This is an ANALYSIS step.** File writes happen in Step 5.
374
374
 
@@ -399,14 +399,14 @@ Then use the Read tool to examine the implementation files.
399
399
  **Display analysis:**
400
400
 
401
401
  ```
402
- 📊 Code Analysis Complete
402
+ Code Analysis Complete
403
403
 
404
404
  Current Implementation:
405
405
  • Files: [list]
406
- • Success scenarios: Working (from speed mode)
407
- • Error handling: Missing [specific gaps]
408
- • Validation: Missing [specific gaps]
409
- • Edge cases: Not handled [specific gaps]
406
+ • Success scenarios: Working (from speed mode)
407
+ • Error handling: Missing [specific gaps]
408
+ • Validation: Missing [specific gaps]
409
+ • Edge cases: Not handled [specific gaps]
410
410
 
411
411
  To pass the target scenario, I need to:
412
412
  1. [Specific change]
@@ -416,7 +416,7 @@ To pass the target scenario, I need to:
416
416
  Now proposing comprehensive implementation...
417
417
  ```
418
418
 
419
- **🔄 WORKFLOW CHECKPOINT: Code analysis complete**
419
+ **WORKFLOW CHECKPOINT: Code analysis complete**
420
420
 
421
421
  ```bash
422
422
  jettypod workflow checkpoint <feature-id> --step=2
@@ -424,11 +424,11 @@ jettypod workflow checkpoint <feature-id> --step=2
424
424
 
425
425
  ### Step 3: Decide if Confirmation Needed
426
426
 
427
- **🚫 FORBIDDEN: Writing Files at This Step**
427
+ **FORBIDDEN: Writing Files at This Step**
428
428
  ```
429
- Write tool to any path
430
- Edit tool to any path
431
- Any file creation or modification
429
+ Write tool to any path
430
+ Edit tool to any path
431
+ Any file creation or modification
432
432
  ```
433
433
  **This is a DECISION step.** File writes happen in Step 5.
434
434
 
@@ -448,20 +448,20 @@ jettypod workflow checkpoint <feature-id> --step=2
448
448
 
449
449
  ### Step 3A: Propose Implementation Approach (Conditional)
450
450
 
451
- **⚡ ASYNC BOUNDARY - Only execute this if confirmation needed**
451
+ **ASYNC BOUNDARY - Only execute this if confirmation needed**
452
452
 
453
- **🚫 FORBIDDEN: Writing Files at This Step**
453
+ **FORBIDDEN: Writing Files at This Step**
454
454
  ```
455
- Write tool to any path
456
- Edit tool to any path
457
- Any file creation or modification
455
+ Write tool to any path
456
+ Edit tool to any path
457
+ Any file creation or modification
458
458
  ```
459
459
  **This is a PROPOSAL step.** File writes happen in Step 5.
460
460
 
461
461
  **Present your analysis and proposal to the user:**
462
462
 
463
463
  ```
464
- 💡 Implementation Proposal
464
+ Implementation Proposal
465
465
 
466
466
  I see multiple ways to approach this error handling. Here's what I'm thinking:
467
467
 
@@ -476,7 +476,7 @@ I see multiple ways to approach this error handling. Here's what I'm thinking:
476
476
  Sound good, or would you prefer a different approach?
477
477
  ```
478
478
 
479
- **⚡ WAIT for user confirmation or adjustments.**
479
+ **WAIT for user confirmation or adjustments.**
480
480
 
481
481
  If user adjusts: revise proposal and confirm again before proceeding.
482
482
 
@@ -484,6 +484,16 @@ If user adjusts: revise proposal and confirm again before proceeding.
484
484
 
485
485
  ---
486
486
 
487
+ ### BDD Step Definition Constraints (ENFORCED)
488
+
489
+ Before writing any step definitions, read `templates/bdd-guidance.md`. BANNED in step defs: `setTimeout`/`sleep`, module-level `let`/`var`, raw SQL, assertions in Given/When, loops/branching, self-fulfilling mocks (setting state then asserting it). Steps must be 1-5 lines calling one helper via Cucumber World (`this`). Read `features/support/helpers/` and reuse before creating.
490
+
491
+ **Scaffolding:** If `features/support/helpers/` does not exist in the project, scaffold it before writing step definitions. Copy `templates/bdd-scaffolding/wait.js` to `features/support/helpers/wait.js` and `templates/bdd-scaffolding/world.js` to `features/support/world.js`.
492
+
493
+ **Helper Reuse:** Before writing step definitions, glob `features/support/helpers/**/*.js` and read each file. Import and call existing helpers in your steps — never duplicate functionality that already exists.
494
+
495
+ ---
496
+
487
497
  ### Step 4: Establish RED Baseline
488
498
 
489
499
  **CRITICAL:** After user confirms (or skips confirmation), execute autonomously - no permission needed for code changes.
@@ -528,25 +538,25 @@ Parse the output to identify:
528
538
 
529
539
  **Display RED baseline:**
530
540
  ```
531
- 🔴 Establishing RED baseline...
541
+ Establishing RED baseline...
532
542
 
533
543
  RED Baseline: 3 of 11 steps failing (stable mode scenarios)
534
544
 
535
545
  Failing steps:
536
- Then it should throw a validation error
537
- And the error message should be "Email is required"
538
- When I provide an empty string as input
546
+ Then it should throw a validation error
547
+ And the error message should be "Email is required"
548
+ When I provide an empty string as input
539
549
 
540
550
  First error:
541
551
  Step: Then it should throw a validation error
542
552
  Error: Error: Expected function to throw but it didn't
543
553
 
544
- 🎯 Goal: Make all stable mode scenarios pass
554
+ Goal: Make all stable mode scenarios pass
545
555
 
546
556
  Now implementing...
547
557
  ```
548
558
 
549
- **🔄 WORKFLOW CHECKPOINT: RED baseline established**
559
+ **WORKFLOW CHECKPOINT: RED baseline established**
550
560
 
551
561
  ```bash
552
562
  jettypod workflow checkpoint <feature-id> --step=4
@@ -556,9 +566,9 @@ jettypod workflow checkpoint <feature-id> --step=4
556
566
 
557
567
  ### Step 5: RED→GREEN→REFACTOR Loop
558
568
 
559
- **🔒 WORKTREE PATH REQUIRED:** All file writes MUST use the `WORKTREE_PATH` captured after pre-flight validation.
569
+ **WORKTREE PATH REQUIRED:** All file writes MUST use the `WORKTREE_PATH` captured after pre-flight validation.
560
570
 
561
- **✅ NOW you may write files** - worktree is locked, approach is confirmed.
571
+ **NOW you may write files** - worktree is locked, approach is confirmed.
562
572
 
563
573
  **Emit gate signal:**
564
574
 
@@ -581,23 +591,23 @@ jettypod ui gate implementing --data='{"description":"[stable mode error handlin
581
591
  **Show progress each iteration:**
582
592
  ```
583
593
  ━━━ Iteration 3/10 ━━━
584
- 📝 Unit test: test/user.test.js - validates email format
594
+ Unit test: test/user.test.js - validates email format
585
595
  RED: Test fails - no validation exists yet
586
- ✍️ Implementation: src/user.js - added email format validation
596
+ Implementation: src/user.js - added email format validation
587
597
  GREEN: Unit test passes
588
- 🧪 Running BDD scenarios...
589
- 📊 Progress: 9/11 BDD steps passing
590
- Newly passing: Then it should throw a validation error
591
- 🔧 Next failure: And the error message should be user-friendly
598
+ Running BDD scenarios...
599
+ Progress: 9/11 BDD steps passing
600
+ Newly passing: Then it should throw a validation error
601
+ Next failure: And the error message should be user-friendly
592
602
  BDD step: Then the error message should be "Email format is invalid"
593
603
  ```
594
604
 
595
605
  **When GREEN achieved:**
596
606
  ```
597
- 🎉 GREEN: All stable mode scenarios passing!
607
+ GREEN: All stable mode scenarios passing!
598
608
  ```
599
609
 
600
- **🔄 WORKFLOW CHECKPOINT: GREEN achieved**
610
+ **WORKFLOW CHECKPOINT: GREEN achieved**
601
611
 
602
612
  ```bash
603
613
  jettypod workflow checkpoint <feature-id> --step=5
@@ -612,7 +622,7 @@ jettypod workflow checkpoint <feature-id> --step=5
612
622
  **Re-run tests after refactor** to ensure nothing broke.
613
623
 
614
624
  <details>
615
- <summary><strong>📋 TDD Loop Guidelines (click to expand)</strong></summary>
625
+ <summary><strong>TDD Loop Guidelines (click to expand)</strong></summary>
616
626
 
617
627
  **Iteration strategy:**
618
628
  - Start with first failing stable mode step
@@ -632,6 +642,8 @@ jettypod workflow checkpoint <feature-id> --step=5
632
642
 
633
643
  </details>
634
644
 
645
+ **Quality Gate:** Before committing, review every `.steps.js` file you wrote or modified. Check for banlist violations: `setTimeout`/`sleep`, module-level `let`/`var`, raw SQL, assertions in Given/When, self-fulfilling mocks, steps longer than 5 lines. Fix violations before proceeding.
646
+
635
647
  ---
636
648
 
637
649
  ### Step 6: Route After Chore Completion
@@ -654,10 +666,10 @@ sqlite3 .jettypod/work.db "SELECT id, title FROM work_items WHERE parent_id = <f
654
666
 
655
667
  ```
656
668
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
657
- 🎯 Stable Mode Chore Complete
669
+ Stable Mode Chore Complete
658
670
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
659
671
 
660
- Error handling and validation scenarios pass for this chore
672
+ Error handling and validation scenarios pass for this chore
661
673
 
662
674
  More stable mode chores remain. Starting next chore:
663
675
  #[next-chore-id]: [next-chore-title]
@@ -699,7 +711,7 @@ If the query returns no remaining chores, proceed to Step 7.
699
711
 
700
712
  ### Step 7: Complete Feature or Transition to Production Mode
701
713
 
702
- **🛑 CRITICAL: This step ONLY runs after ALL stable chores are complete.**
714
+ **CRITICAL: This step ONLY runs after ALL stable chores are complete.**
703
715
 
704
716
  **First, merge the final stable chore:**
705
717
 
@@ -741,27 +753,26 @@ sqlite3 .jettypod/work.db "SELECT project_state FROM project_config WHERE id = 1
741
753
 
742
754
  **If project_state = 'internal':**
743
755
 
744
- ```bash
745
- jettypod work status <feature-id> done
746
- ```
756
+ **The merge command automatically sets the feature as ready for review.**
757
+ It will appear with accept/reject buttons on the kanban board. Do NOT call `jettypod work status <feature-id> done` — that bypasses the review gate.
747
758
 
748
759
  **Display:**
749
760
 
750
761
  ```
751
762
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
752
- FEATURE COMPLETE!
763
+ FEATURE COMPLETE!
753
764
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
754
765
 
755
766
  Feature: #[id] [Feature Title]
756
- Status: DONE
767
+ Status: DONE
757
768
 
758
769
  What we accomplished:
759
- All BDD scenarios passing (success + error handling + edge cases)
760
- Comprehensive error handling and validation
761
- Input validation and edge case coverage
762
- State consistency and data integrity
770
+ All BDD scenarios passing (success + error handling + edge cases)
771
+ Comprehensive error handling and validation
772
+ Input validation and edge case coverage
773
+ State consistency and data integrity
763
774
 
764
- 📝 INTERNAL PROJECT - STABLE MODE IS COMPLETE
775
+ INTERNAL PROJECT - STABLE MODE IS COMPLETE
765
776
 
766
777
  This is an internal project - stable mode is the end state.
767
778
  Feature is complete and ready to use!
@@ -770,7 +781,7 @@ Note: If you later transition to external (accepting real users),
770
781
  run the external-transition skill to generate production chores.
771
782
  ```
772
783
 
773
- **🔄 WORKFLOW INTEGRATION: Complete workflow (internal project)**
784
+ **WORKFLOW INTEGRATION: Complete workflow (internal project)**
774
785
 
775
786
  ```bash
776
787
  jettypod workflow complete stable-mode <feature-id>
@@ -792,7 +803,7 @@ This marks the `stable_mode_complete` gate as passed. For internal projects, thi
792
803
 
793
804
  **If project_state = 'external':**
794
805
 
795
- **🛑 CRITICAL HANDOFF - You MUST invoke production-mode using the Skill tool.**
806
+ **CRITICAL HANDOFF - You MUST invoke production-mode using the Skill tool.**
796
807
 
797
808
  **Set feature mode to production:**
798
809
 
@@ -804,21 +815,21 @@ jettypod work set-mode <feature-id> production
804
815
 
805
816
  ```
806
817
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
807
- 🎯 Stable Mode Complete! Transitioning to Production Mode
818
+ Stable Mode Complete! Transitioning to Production Mode
808
819
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
809
820
 
810
- ⚠️ CRITICAL: This is an EXTERNAL project.
821
+ CRITICAL: This is an EXTERNAL project.
811
822
  Stable mode makes it robust - production mode makes it ready for real users.
812
823
 
813
824
  What we accomplished:
814
- All BDD scenarios passing (success + error handling + edge cases)
815
- Comprehensive error handling and validation
816
- Feature stable and ready for production hardening
825
+ All BDD scenarios passing (success + error handling + edge cases)
826
+ Comprehensive error handling and validation
827
+ Feature stable and ready for production hardening
817
828
 
818
- 🚀 Now invoking production-mode skill...
829
+ Now invoking production-mode skill...
819
830
  ```
820
831
 
821
- **🔄 WORKFLOW INTEGRATION: Complete workflow (external project)**
832
+ **WORKFLOW INTEGRATION: Complete workflow (external project)**
822
833
 
823
834
  ```bash
824
835
  jettypod workflow complete stable-mode <feature-id>
@@ -854,7 +865,7 @@ Before ending stable-mode skill, ensure:
854
865
  - [ ] Integration scenario still passes (feature remains reachable after error handling added)
855
866
  - [ ] Final chore merged to main
856
867
  - [ ] Project state checked (internal vs external)
857
- - [ ] **INTERNAL:** Feature marked as done
868
+ - [ ] **INTERNAL:** Feature merged (review gate set automatically by merge command)
858
869
  - [ ] **EXTERNAL:** Feature mode set to production AND production-mode skill invoked
859
870
 
860
871
  ---
@@ -878,17 +889,17 @@ jettypod work start <chore-id> # Create worktree and start chore
878
889
 
879
890
  **Set feature status/mode:**
880
891
  ```bash
881
- jettypod work status <feature-id> done # Mark feature complete (internal only)
882
- jettypod work set-mode <feature-id> production # Set feature to production mode
892
+ # Do NOT call `work status done` merge sets the review gate automatically
893
+ jettypod work set-mode <feature-id> production # Set feature to production mode (external only)
883
894
  ```
884
895
 
885
- **❌ DO NOT use these to complete chores:**
896
+ **DO NOT use these to complete chores:**
886
897
  - `jettypod work status <chore-id> done`
887
898
  - `jettypod work complete <id>`
888
899
 
889
900
  ---
890
901
 
891
- ## ⚠️ Important: Sequential Workflow
902
+ ## Important: Sequential Workflow
892
903
 
893
904
  **Stable mode chores MUST be completed sequentially, not in parallel.**
894
905
 
@@ -0,0 +1,139 @@
1
+ # BDD Reference for Skills
2
+
3
+ Read this before writing scenarios or step definitions. Every rule here is enforced — not advisory.
4
+
5
+ ## Scenario Formulation
6
+
7
+ **Feature files describe "what" and "why." Step definitions implement "how."**
8
+
9
+ Each scenario: one behavior, one reason to fail.
10
+
11
+ ### Rules
12
+
13
+ - **Declarative** — describe intent, not UI clicks. "When the user retries payment" not "When I click the third button."
14
+ - **Stable** — no brittle details (pixel positions, timing, CSS selectors).
15
+ - **Deterministic** — use factories with known data. Never depend on ambient/existing data.
16
+ - **No implementation leakage** — no "Given the database has..." in feature files. Use intentful language: "Given a user with an unpaid invoice."
17
+
18
+ ### Good
19
+
20
+ ```gherkin
21
+ Scenario: User can retry a failed payment
22
+ Given a user with an unpaid invoice
23
+ And the payment processor returns "insufficient_funds"
24
+ When the user retries payment with a different card
25
+ Then the invoice is marked as paid
26
+ And the user sees a receipt
27
+ ```
28
+
29
+ ### Bad
30
+
31
+ ```gherkin
32
+ Scenario: Pay invoice
33
+ Given I click the "Billing" tab
34
+ And I wait 2 seconds
35
+ And I click the third button on the page
36
+ When I type "4111111111111111" into the card field
37
+ Then I should see "Success"
38
+ ```
39
+
40
+ ## Step Definition Banlist
41
+
42
+ These are BANNED in step definitions. Not "avoid" — banned.
43
+
44
+ | Banned | Use instead |
45
+ |--------|-------------|
46
+ | `setTimeout`, `sleep`, fixed waits | `waitFor(() => condition, { timeout })` polling utility |
47
+ | Module-level `let`/`var` state | Cucumber World (`this`) for per-scenario state |
48
+ | Raw SQL (`db.run`, `db.get`) | Helper methods in `features/support/helpers/` |
49
+ | Loops and branching logic | One intentful helper call per step |
50
+ | Assertions in Given/When steps | Assertions belong in Then steps only |
51
+ | Inline selectors/click chains | Page objects or screen models |
52
+ | Setting mock state then asserting it | Tests must exercise real production code |
53
+
54
+ ### Thin Step Pattern
55
+
56
+ Steps do three things: parse parameters, call one helper, assert outcome.
57
+
58
+ ```js
59
+ // GOOD — thin step, calls helper
60
+ When('the user retries payment with a different card', async function () {
61
+ await this.billing.retryPaymentWith(this.validCard);
62
+ });
63
+
64
+ // BAD — inline implementation
65
+ When('the user retries payment with a different card', async function () {
66
+ await page.click('#billing-tab');
67
+ await page.waitForSelector('.invoice-list');
68
+ await page.click('.invoice:first-child .retry-btn');
69
+ await page.fill('#card-number', '4242424242424242');
70
+ await page.click('#submit');
71
+ await new Promise(r => setTimeout(r, 2000));
72
+ });
73
+ ```
74
+
75
+ ## Helper Layer Architecture
76
+
77
+ Step definitions must not contain domain logic, SQL, or UI interaction directly. Use this layering:
78
+
79
+ ```
80
+ Feature files (behavior — Gherkin)
81
+ └─ Step definitions (glue — thin, 1-5 lines)
82
+ └─ Helpers (features/support/helpers/)
83
+ ├─ Domain helpers (intentful operations)
84
+ ├─ API client
85
+ ├─ DB helpers (encapsulated queries)
86
+ └─ Wait utilities (polling, not sleeping)
87
+ ```
88
+
89
+ **Dependency rules:**
90
+ - Step defs call helpers. Never call drivers directly.
91
+ - Helpers call drivers (DB, API, UI).
92
+ - Feature files know nothing about implementation.
93
+
94
+ **Before writing step definitions:** Read `features/support/helpers/` for existing helpers. Reuse before creating new ones.
95
+
96
+ ## Async & External Dependencies
97
+
98
+ **Async:** Poll with timeout, never sleep.
99
+ ```js
100
+ await waitFor(() => order.status === 'COMPLETED', { timeout: 10_000 });
101
+ ```
102
+
103
+ **External services:** Stub at the boundary for most tests. Use fakes (in-memory implementations) over mocks. Mocks test call patterns ("did we call X?"); fakes test outcomes ("did the user get the result?").
104
+
105
+ **Auth flows:** Use test shortcuts (token minting, session injection). Don't make every scenario pay the login tax.
106
+
107
+ ## Test Doubles
108
+
109
+ Prefer stubs/fakes for BDD. They support behavior assertions without coupling to implementation.
110
+
111
+ Use mocks only when verifying a side effect IS the scenario's purpose (e.g., "audit event was emitted").
112
+
113
+ **BDD asserts outcomes, not internal choreography.**
114
+
115
+ ## Data Setup
116
+
117
+ Use intentful factories:
118
+ ```js
119
+ // GOOD
120
+ await this.fixtures.createUserWithUnpaidInvoice();
121
+
122
+ // BAD — implementation leakage
123
+ await db.run('INSERT INTO users...');
124
+ await db.run('INSERT INTO invoices...');
125
+ ```
126
+
127
+ Freeze time and seed randomness. Assert on meaning ("receipt exists") not raw IDs.
128
+
129
+ ## Quality Checklist
130
+
131
+ After writing tests, verify:
132
+
133
+ - [ ] Steps are 1-5 lines, each calling one helper
134
+ - [ ] No `setTimeout` or `sleep` anywhere in step definitions
135
+ - [ ] State stored on `this` (Cucumber World), not module-level variables
136
+ - [ ] No raw SQL in step definitions
137
+ - [ ] Assertions only in Then steps
138
+ - [ ] Tests exercise real production code (not asserting mock state you just set)
139
+ - [ ] Existing helpers reused, not duplicated
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Poll a condition function until it returns true, with timeout.
3
+ * Use this instead of setTimeout/sleep in step definitions.
4
+ *
5
+ * Usage:
6
+ * const { waitFor } = require('../helpers/wait');
7
+ * await waitFor(() => order.status === 'COMPLETED', { timeout: 10000 });
8
+ */
9
+ async function waitFor(conditionFn, { timeout = 5000, interval = 100 } = {}) {
10
+ const start = Date.now();
11
+ while (Date.now() - start < timeout) {
12
+ if (await conditionFn()) return;
13
+ await new Promise(r => setTimeout(r, interval));
14
+ }
15
+ throw new Error(`waitFor timed out after ${timeout}ms`);
16
+ }
17
+
18
+ module.exports = { waitFor };