jettypod 4.4.115 → 4.4.118

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 (73) hide show
  1. package/.env +7 -0
  2. package/apps/dashboard/app/api/claude/[workItemId]/message/route.ts +25 -9
  3. package/apps/dashboard/app/api/claude/sessions/[sessionId]/message/route.ts +7 -3
  4. package/apps/dashboard/app/api/tests/run/stream/route.ts +13 -1
  5. package/apps/dashboard/app/api/usage/route.ts +17 -0
  6. package/apps/dashboard/app/connect-claude/page.tsx +24 -0
  7. package/apps/dashboard/app/install-claude/page.tsx +8 -6
  8. package/apps/dashboard/app/login/page.tsx +229 -0
  9. package/apps/dashboard/app/page.tsx +5 -3
  10. package/apps/dashboard/app/settings/page.tsx +2 -0
  11. package/apps/dashboard/app/subscribe/page.tsx +11 -0
  12. package/apps/dashboard/app/welcome/page.tsx +23 -0
  13. package/apps/dashboard/components/AppShell.tsx +51 -9
  14. package/apps/dashboard/components/CardMenu.tsx +14 -5
  15. package/apps/dashboard/components/ClaudePanel.tsx +65 -9
  16. package/apps/dashboard/components/ConnectClaudeScreen.tsx +223 -0
  17. package/apps/dashboard/components/DragContext.tsx +73 -64
  18. package/apps/dashboard/components/DraggableCard.tsx +6 -46
  19. package/apps/dashboard/components/GateCard.tsx +21 -0
  20. package/apps/dashboard/components/InstallClaudeScreen.tsx +132 -30
  21. package/apps/dashboard/components/KanbanBoard.tsx +173 -56
  22. package/apps/dashboard/components/PlaceholderCard.tsx +9 -19
  23. package/apps/dashboard/components/ProjectSwitcher.tsx +28 -0
  24. package/apps/dashboard/components/RealTimeKanbanWrapper.tsx +34 -3
  25. package/apps/dashboard/components/RealTimeTestsWrapper.tsx +30 -2
  26. package/apps/dashboard/components/SubscribeContent.tsx +191 -0
  27. package/apps/dashboard/components/TipCard.tsx +176 -0
  28. package/apps/dashboard/components/UpgradeBanner.tsx +29 -0
  29. package/apps/dashboard/components/WelcomeScreen.tsx +14 -4
  30. package/apps/dashboard/components/settings/AccountSection.tsx +163 -0
  31. package/apps/dashboard/contexts/ClaudeSessionContext.tsx +292 -29
  32. package/apps/dashboard/contexts/UsageContext.tsx +131 -0
  33. package/apps/dashboard/contexts/usageHelpers.js +9 -0
  34. package/apps/dashboard/electron/ipc-handlers.js +220 -114
  35. package/apps/dashboard/electron/main.js +415 -37
  36. package/apps/dashboard/electron/preload.js +23 -4
  37. package/apps/dashboard/electron/session-manager.js +141 -0
  38. package/apps/dashboard/electron-builder.config.js +3 -5
  39. package/apps/dashboard/lib/claude-process-manager.ts +6 -4
  40. package/apps/dashboard/lib/db-bridge.ts +32 -0
  41. package/apps/dashboard/lib/db.ts +159 -13
  42. package/apps/dashboard/lib/session-state-machine.ts +3 -0
  43. package/apps/dashboard/lib/session-stream-manager.ts +76 -13
  44. package/apps/dashboard/lib/tests.ts +3 -1
  45. package/apps/dashboard/next.config.js +19 -14
  46. package/apps/dashboard/package.json +3 -1
  47. package/apps/dashboard/scripts/upload-to-r2.js +89 -0
  48. package/apps/dashboard/tsconfig.tsbuildinfo +1 -0
  49. package/apps/update-server/package.json +16 -0
  50. package/apps/update-server/schema.sql +31 -0
  51. package/apps/update-server/src/index.ts +1074 -0
  52. package/apps/update-server/tsconfig.json +16 -0
  53. package/apps/update-server/wrangler.toml +35 -0
  54. package/docs/bdd-guidance.md +390 -0
  55. package/jettypod.js +5 -4
  56. package/lib/migrations/027-plan-at-creation-column.js +31 -0
  57. package/lib/migrations/028-ready-for-review-column.js +27 -0
  58. package/lib/schema.js +3 -1
  59. package/lib/seed-onboarding.js +100 -68
  60. package/lib/work-commands/index.js +43 -13
  61. package/lib/work-tracking/index.js +46 -27
  62. package/package.json +1 -1
  63. package/skills-templates/bug-mode/SKILL.md +5 -11
  64. package/skills-templates/request-routing/SKILL.md +24 -11
  65. package/skills-templates/simple-improvement/SKILL.md +35 -19
  66. package/skills-templates/stable-mode/SKILL.md +5 -6
  67. package/templates/bdd-guidance.md +139 -0
  68. package/templates/bdd-scaffolding/wait.js +18 -0
  69. package/templates/bdd-scaffolding/world.js +19 -0
  70. package/.jettypod-backup/work.db +0 -0
  71. package/apps/dashboard/app/access-code/page.tsx +0 -110
  72. package/lib/discovery-checkpoint.js +0 -123
  73. package/skills-templates/project-discovery/SKILL.md +0 -372
@@ -11,118 +11,150 @@ const ONBOARDING_EPIC = {
11
11
  description: 'Get your project set up and planned. Work through these chores one at a time — each one is a short conversation.'
12
12
  };
13
13
 
14
+ const TONE = `HOW TO RESPOND:
15
+ You are a collaborator, not an AI assistant. You're a knowledgeable partner having a real conversation.
16
+ - Do NOT open with a summary or recap of what you've been asked to do
17
+ - Do NOT list steps or outline a plan before starting
18
+ - Do NOT say "I'll help you with...", "Let me guide you through...", or "Great question!"
19
+ - Do NOT use headers, bullet lists, or formatted option blocks in your first message
20
+ - DO jump straight into conversation like a person who just sat down across the table
21
+ - DO ask one question at a time, then actually listen to the response
22
+ - DO keep responses short — a few sentences, not paragraphs
23
+ - DO respond naturally to what the user says, adapting your follow-ups accordingly`;
24
+
14
25
  const ONBOARDING_CHORES = [
15
26
  {
16
27
  title: 'Align on the user journey',
17
- description: `This is the first onboarding chore. Help the user define what their product does.
28
+ description: `${TONE}
29
+
30
+ YOUR ROLE: Help the user articulate what their product does and how people will use it.
18
31
 
19
- CLAUDE SESSION GUIDANCE:
20
- Open with: "What do users DO in this product? Walk me through the flow from opening it to getting value from it."
32
+ CONVERSATION FLOW:
21
33
 
22
- If the user isn't sure, suggest 3 different user journey options:
23
- - Journey 1: [Simple/Direct approach] with flow, pros, cons
24
- - Journey 2: [Balanced approach] with flow, pros, cons
25
- - Journey 3: [Advanced/Guided approach] with flow, pros, cons
34
+ 1. OPEN Jump straight in. Something like:
35
+ "So what are you building? Walk me through what happens when someone opens this thing up."
36
+ (Adapt to context. Be casual. No preamble.)
26
37
 
27
- Ask: "Which journey resonates? Or describe your own."
38
+ 2. LISTEN AND DIG Based on what they say, ask natural follow-ups. One at a time:
39
+ - "And then what? What happens after [thing they mentioned]?"
40
+ - "How do they find that the first time?"
41
+ - "What's the moment where it clicks — like, this is actually useful?"
42
+ Don't rush this. Let them think. Some people need 2-3 exchanges to articulate their vision.
28
43
 
29
- OUTCOME:
30
- - A clear description of the core user journey
31
- - Agreement on the main actions users take
44
+ 3. IF THEY'RE VAGUE — Don't present a formatted options list. Talk through possibilities naturally:
45
+ "I could see this going a few ways. You could do [approach A] really simple, users just [action]. Or something more like [approach B] where they [different flow]. What feels closer?"
46
+ If they're really stuck, describe 2-3 directions conversationally and ask what resonates.
32
47
 
33
- RECORD DECISION:
34
- After the user picks/describes their journey, run:
35
- jettypod work epic-implement <onboarding-epic-id> --aspect="User Journey" --decision="<chosen journey>" --rationale="<why>"
48
+ 4. CONFIRM — Once the journey is clear, reflect it back casually:
49
+ "Cool, so basically: user shows up, [does X], then [does Y], and the payoff is [Z]. That feel right?"
50
+ Wait for them to confirm or adjust.
36
51
 
37
- Then tell the user: "Got it. Close this chat and start the next chore from your backlog to continue."`
52
+ 5. RECORD After they confirm, run:
53
+ jettypod work epic-implement <onboarding-epic-id> --aspect="User Journey" --decision="<summary of chosen journey>" --rationale="<why this flow>"
54
+
55
+ 6. HAND OFF — Say something like: "Nice. Close this chat and start the next chore in your backlog to keep going."`
38
56
  },
39
57
  {
40
58
  title: 'Explore UX approaches',
41
- description: `This is the second onboarding chore. Help the user decide how the product should feel.
59
+ description: `${TONE}
60
+
61
+ YOUR ROLE: Help the user decide how their product should FEEL to use. This is about the experience, not the tech.
42
62
 
43
- CONTEXT FROM PREVIOUS CHORE:
44
- Read the user journey decision first:
63
+ CONTEXT: Read the user journey decision first:
45
64
  jettypod decisions --epic=<onboarding-epic-id>
46
65
 
47
- CLAUDE SESSION GUIDANCE:
48
- Open with: "Based on your user journey: [quote decision]. Now let's figure out how it should feel to use."
66
+ CONVERSATION FLOW:
49
67
 
50
- Present exactly 3 UX approaches (NOT tech stacks focus on the experience):
51
- - Option 1: [Simple approach] — pros, cons, what it feels like
52
- - Option 2: [Balanced approach] pros, cons, what it feels like
53
- - Option 3: [Advanced approach] — pros, cons, what it feels like
68
+ 1. OPEN Reference what they already decided and pivot naturally:
69
+ "So last time you said users would [brief journey recap]. Now I'm curious what should that actually feel like? Like, when someone [key action], are you imagining something minimal and fast, or more guided and hand-holdy?"
70
+ (Use their actual words from the decision. Don't be generic.)
54
71
 
55
- Ask: "Would you like me to create working prototypes of these?"
72
+ 2. EXPLORE THROUGH CONVERSATION Don't dump three formatted options. Talk through directions:
73
+ "One direction would be something really stripped down — [describe the feel]. That works well when [context]. But you could also go more toward [different feel] where [description]. The trade-off is [honest assessment]."
74
+ Let them react. Follow their energy.
56
75
 
57
- If yes, build quick throwaway prototypes using jettypod project prototype commands.
58
- If no, ask which option they prefer.
76
+ 3. GET SPECIFIC Once a direction emerges, push on it:
77
+ "OK so if we go that route, the main screen would probably be [description]. Does that feel right or is that too [much/little]?"
59
78
 
60
- OUTCOME:
61
- - 3 UX options compared
62
- - A winner chosen
63
- - Optionally: working prototypes tested
79
+ 4. OFFER PROTOTYPES (if it would help) — If they're torn or want to see it:
80
+ "Want me to throw together a quick prototype of that? Nothing fancy — just enough to feel it out."
81
+ If yes, use: jettypod project prototype start <approach-name>
82
+ Build a minimal throwaway prototype, then: jettypod project prototype merge
83
+ After they try it: "What did you think? Does that feel like the right direction, or should we adjust?"
64
84
 
65
- RECORD DECISION:
66
- jettypod work epic-implement <onboarding-epic-id> --aspect="UX Approach" --decision="<chosen approach>" --rationale="<why>"
85
+ 5. CONFIRM — Lock in the winner:
86
+ "Alright, so the feel is [description]. I'll record that."
67
87
 
68
- Then tell the user: "Close this chat and start the next chore from your backlog."`
88
+ 6. RECORD Run:
89
+ jettypod work epic-implement <onboarding-epic-id> --aspect="UX Approach" --decision="<chosen approach>" --rationale="<why>"
90
+
91
+ 7. HAND OFF — "Close this chat and start the next chore from your backlog."`
69
92
  },
70
93
  {
71
94
  title: 'Choose a tech stack',
72
- description: `This is the third onboarding chore. Help the user pick the right tech stack.
95
+ description: `${TONE}
96
+
97
+ YOUR ROLE: Help the user pick the right tech stack based on what they're building and how it should feel.
73
98
 
74
- CONTEXT FROM PREVIOUS CHORES:
75
- Read previous decisions first:
99
+ CONTEXT: Read previous decisions first:
76
100
  jettypod decisions --epic=<onboarding-epic-id>
77
101
 
78
- CLAUDE SESSION GUIDANCE:
79
- Open with: "You're building [journey] with a [UX approach] experience. Let's pick the tech stack."
102
+ CONVERSATION FLOW:
80
103
 
81
- Present exactly 3 tech stack options appropriate for their UX approach:
82
- - Option 1: [Stack name] pros, cons, what development will feel like
83
- - Option 2: [Stack name] — pros, cons, what development will feel like
84
- - Option 3: [Stack name] pros, cons, what development will feel like
104
+ 1. OPEN Connect the dots from previous decisions:
105
+ "You're building [journey] and you want it to feel [UX approach]. That actually narrows down the tech quite a bit."
106
+ Then lead with your honest take:
107
+ "I'd probably go with [recommendation] for this. Here's why [reason]."
108
+ (Have an opinion. Don't just present options neutrally.)
85
109
 
86
- Include "Other options considered" with brief reasons for not recommending.
110
+ 2. HAVE A REAL DISCUSSION After giving your take, open it up:
111
+ "That said — do you have a preference? Are you already comfortable with something, or is there a stack you've been wanting to try?"
112
+ Respond to what they say. If they push back, engage with it honestly:
113
+ "Yeah, [their preference] could work. The main thing you'd lose is [trade-off]. The main thing you'd gain is [benefit]. Honestly, either would be fine for this."
87
114
 
88
- OUTCOME:
89
- - 3 tech stack options compared
90
- - A winner chosen with rationale
115
+ 3. IF THEY WANT OPTIONS — Talk through 2-3 stacks conversationally, not as formatted comparison blocks:
116
+ "[Stack A] would be the fastest to get going — you'd have [benefit] out of the box. [Stack B] is more flexible but you'd need to wire up [thing] yourself. And then there's [Stack C] which is honestly overkill here unless you specifically want [thing]."
91
117
 
92
- RECORD DECISION:
93
- jettypod work epic-implement <onboarding-epic-id> --aspect="Tech Stack" --decision="<chosen stack>" --rationale="<why>"
118
+ 4. LAND ON A DECISION — Once they choose:
119
+ "Solid choice. [One sentence of genuine validation why it fits their specific project, not generic praise]."
94
120
 
95
- Then tell the user: "Close this chat and start the last onboarding chore."`
121
+ 5. RECORD Run:
122
+ jettypod work epic-implement <onboarding-epic-id> --aspect="Tech Stack" --decision="<chosen stack>" --rationale="<why>"
123
+
124
+ 6. HAND OFF — "One more chore left — close this chat and start it from your backlog."`
96
125
  },
97
126
  {
98
127
  title: 'Break the project into epics',
99
- description: `This is the final onboarding chore. Break the project into buildable phases.
128
+ description: `${TONE}
129
+
130
+ YOUR ROLE: Break the project into buildable phases (epics) based on everything they've decided.
100
131
 
101
- CONTEXT FROM PREVIOUS CHORES:
102
- Read all previous decisions first:
132
+ CONTEXT: Read all previous decisions first:
103
133
  jettypod decisions --epic=<onboarding-epic-id>
104
134
 
105
- CLAUDE SESSION GUIDANCE:
106
- Open with: "You're building [journey] as a [UX approach] experience using [tech stack]. Let's break this into phases."
135
+ CONVERSATION FLOW:
107
136
 
108
- Explain: "Epics are phase-level chunks of work. Each epic contains features things users can actually do."
137
+ 1. OPEN Bring it all together and jump straight to the breakdown:
138
+ "Alright — you're building [journey], it should feel [UX approach], and you're using [tech stack]. Let me suggest how to break this into phases."
139
+ Then just propose the epics conversationally:
140
+ "I'd start with [Epic 1] — that's the foundation, stuff like [examples]. Then [Epic 2] which covers [what]. And then [Epic 3] for [what]."
141
+ (Don't over-explain what an epic is. Keep it natural.)
109
142
 
110
- Propose 3-5 epics based on everything they've decided:
111
- - Epic 1: [Name]what it covers
112
- - Epic 2: [Name] — what it covers
113
- - Epic 3: [Name] — what it covers
143
+ 2. QUICK CONTEXT (only if needed) — If they seem unsure about the structure:
144
+ "Each of these is a phase. Inside each one we'll define specific features things users can actually do. You don't need to think about that yet though."
114
145
 
115
- Ask: "Sound right? What would you add or change?"
146
+ 3. GET FEEDBACK After proposing:
147
+ "Does that breakdown make sense? Anything you'd add, cut, or reorder?"
148
+ Adjust based on their input. Don't be precious about your proposal.
116
149
 
117
- After confirmation, create each epic:
118
- jettypod work create epic "<title>" "<description>"
150
+ 4. CREATE — Once they confirm, create each epic:
151
+ jettypod work create epic "<title>" "<description>"
152
+ Do this for each one.
119
153
 
120
- OUTCOME:
121
- - 3-5 epics created in the backlog
122
- - A recommendation for which epic to start first
154
+ 5. RECOMMEND A STARTING POINT:
155
+ "If I were you, I'd start with [Epic name] — [brief reason, like 'everything else depends on it' or 'it's the quickest win to get something real']."
123
156
 
124
- CLOSING:
125
- Tell the user: "Your project is planned! Pick an epic from the backlog and tell Claude 'Let's plan [epic name]' to start building."`
157
+ 6. CLOSE — "Your project is planned. Pick an epic from the backlog and tell Claude 'Let's plan [epic name]' to start building."`
126
158
  }
127
159
  ];
128
160
 
@@ -1902,20 +1902,50 @@ async function mergeWork(options = {}) {
1902
1902
  `Test worktrees (tests/* branches) merge BDD scenarios without completing the feature.`
1903
1903
  ));
1904
1904
  } else {
1905
- // Chore or bug worktree: mark as done
1906
- console.log(`Marking ${currentWork.type} as done...`);
1907
- const completedAt = new Date().toISOString();
1908
- await new Promise((resolve, reject) => {
1909
- db.run(
1910
- `UPDATE work_items SET status = 'done', completed_at = ? WHERE id = ?`,
1911
- [completedAt, currentWork.id],
1912
- (err) => {
1905
+ // Chore or bug worktree
1906
+ // Check if this is a standalone kanban-visible item (no parent or parent is epic)
1907
+ let isStandalone = !currentWork.parent_id;
1908
+ if (!isStandalone && currentWork.parent_id) {
1909
+ const parentItem = await new Promise((resolve, reject) => {
1910
+ db.get('SELECT type FROM work_items WHERE id = ?', [currentWork.parent_id], (err, row) => {
1913
1911
  if (err) return reject(err);
1914
- resolve();
1915
- }
1916
- );
1917
- });
1918
- console.log(`✅ ${currentWork.type.charAt(0).toUpperCase() + currentWork.type.slice(1)} #${currentWork.id} marked as done`);
1912
+ resolve(row);
1913
+ });
1914
+ });
1915
+ isStandalone = parentItem && parentItem.type === 'epic';
1916
+ }
1917
+
1918
+ if (isStandalone) {
1919
+ // Standalone item: set ready_for_review instead of marking done
1920
+ // Keep status as in_progress so it stays in the In Flight column
1921
+ // User accepts/rejects via the kanban board
1922
+ await new Promise((resolve, reject) => {
1923
+ db.run(
1924
+ `UPDATE work_items SET ready_for_review = 1 WHERE id = ?`,
1925
+ [currentWork.id],
1926
+ (err) => {
1927
+ if (err) return reject(err);
1928
+ resolve();
1929
+ }
1930
+ );
1931
+ });
1932
+ console.log(`✅ ${currentWork.type.charAt(0).toUpperCase() + currentWork.type.slice(1)} #${currentWork.id} ready for review`);
1933
+ } else {
1934
+ // Chore/bug under a feature: mark as done (feature handles the accept flow)
1935
+ console.log(`Marking ${currentWork.type} as done...`);
1936
+ const completedAt = new Date().toISOString();
1937
+ await new Promise((resolve, reject) => {
1938
+ db.run(
1939
+ `UPDATE work_items SET status = 'done', completed_at = ? WHERE id = ?`,
1940
+ [completedAt, currentWork.id],
1941
+ (err) => {
1942
+ if (err) return reject(err);
1943
+ resolve();
1944
+ }
1945
+ );
1946
+ });
1947
+ console.log(`✅ ${currentWork.type.charAt(0).toUpperCase() + currentWork.type.slice(1)} #${currentWork.id} marked as done`);
1948
+ }
1919
1949
  }
1920
1950
 
1921
1951
  // Mark worktree as merged but DON'T delete it yet
@@ -256,6 +256,22 @@ function create(type, title, description = '', parentId = null, mode = null, nee
256
256
  }
257
257
 
258
258
  function continueWithValidatedParent(epicId) {
259
+ // Read current plan from auth.json for usage tracking
260
+ let planAtCreation = null;
261
+ try {
262
+ const os = require('os');
263
+ const path = require('path');
264
+ const fs = require('fs');
265
+ const authPath = path.join(os.homedir(), 'Library', 'Application Support', 'jettypod', 'auth.json');
266
+ if (fs.existsSync(authPath)) {
267
+ const authData = JSON.parse(fs.readFileSync(authPath, 'utf8'));
268
+ planAtCreation = authData?.user?.plan || 'free';
269
+ } else {
270
+ planAtCreation = 'free';
271
+ }
272
+ } catch {
273
+ planAtCreation = 'free';
274
+ }
259
275
 
260
276
  // Only features have modes - they start with mode=NULL (no mode until implementation starts)
261
277
  // Epics, chores, and bugs don't have modes (always NULL)
@@ -282,8 +298,8 @@ function create(type, title, description = '', parentId = null, mode = null, nee
282
298
  // Set phase for features (discovery when mode=NULL, implementation when mode is set, NULL for everything else)
283
299
  const phase = type === 'feature' ? (mode ? 'implementation' : 'discovery') : null;
284
300
 
285
- const sql = `INSERT INTO work_items (type, title, description, parent_id, epic_id, mode, needs_discovery, phase, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`;
286
- db.run(sql, [type, title, description, parentId, epicId, mode, needsDiscovery ? 1 : 0, phase, 'backlog'], function(err) {
301
+ const sql = `INSERT INTO work_items (type, title, description, parent_id, epic_id, mode, needs_discovery, phase, status, plan_at_creation) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`;
302
+ db.run(sql, [type, title, description, parentId, epicId, mode, needsDiscovery ? 1 : 0, phase, 'backlog', planAtCreation], function(err) {
287
303
  if (err) {
288
304
  return reject(err);
289
305
  }
@@ -776,31 +792,19 @@ function updateStatus(id, status) {
776
792
  return resolve();
777
793
  }
778
794
 
779
- // Auto-close epics when all children are done
795
+ // Items under epics: set ready_for_review and keep in_progress for accept/reject
780
796
  if (parent.type === 'epic') {
781
- // Check if all children of this epic are done
782
- db.all(
783
- 'SELECT id, status FROM work_items WHERE parent_id = ?',
784
- [parent.id],
785
- (err, children) => {
797
+ // Set ready_for_review on the item and revert to in_progress
798
+ db.run(
799
+ 'UPDATE work_items SET ready_for_review = 1, status = ?, completed_at = NULL WHERE id = ?',
800
+ ['in_progress', item.id],
801
+ (err) => {
786
802
  if (err) {
787
- return resolve();
788
- }
789
-
790
- const allDone = children.every(child => child.status === 'done');
791
- if (allDone) {
792
- const epicCompletedAt = new Date().toISOString();
793
- db.run('UPDATE work_items SET status = ?, completed_at = ? WHERE id = ?', ['done', epicCompletedAt, parent.id], (err) => {
794
- if (err) {
795
- console.error(`Failed to auto-close epic: ${err.message}`);
796
- } else {
797
- console.log(`✓ Epic #${parent.id} also completed (all children done)`);
798
- }
799
- resolve();
800
- });
803
+ console.error(`Failed to set ready_for_review: ${err.message}`);
801
804
  } else {
802
- resolve();
805
+ console.log(`✓ Work item #${item.id} ready for review`);
803
806
  }
807
+ resolve();
804
808
  }
805
809
  );
806
810
  }
@@ -838,12 +842,12 @@ function updateStatus(id, status) {
838
842
  }
839
843
 
840
844
  if (featureComplete) {
841
- const featureCompletedAt = new Date().toISOString();
842
- db.run('UPDATE work_items SET status = ?, completed_at = ? WHERE id = ?', ['done', featureCompletedAt, parent.id], (err) => {
845
+ // Set ready_for_review instead of auto-closing — let user accept/reject
846
+ db.run('UPDATE work_items SET ready_for_review = 1 WHERE id = ?', [parent.id], (err) => {
843
847
  if (err) {
844
- console.error(`Failed to auto-close feature: ${err.message}`);
848
+ console.error(`Failed to set ready_for_review: ${err.message}`);
845
849
  } else {
846
- console.log(`✓ Feature #${parent.id} completed (all ${featureMode} mode chores done)`);
850
+ console.log(`✓ Feature #${parent.id} ready for review (all ${featureMode} mode chores done)`);
847
851
  }
848
852
  resolve();
849
853
  });
@@ -860,6 +864,21 @@ function updateStatus(id, status) {
860
864
  resolve();
861
865
  }
862
866
  });
867
+ } else if (status === 'done' && !item.parent_id) {
868
+ // Standalone item (no parent) marked done via CLI
869
+ // Set ready_for_review and revert to in_progress so user can accept/reject via kanban
870
+ db.run(
871
+ 'UPDATE work_items SET ready_for_review = 1, status = ?, completed_at = NULL WHERE id = ?',
872
+ ['in_progress', item.id],
873
+ (err) => {
874
+ if (err) {
875
+ console.error(`Failed to set ready_for_review: ${err.message}`);
876
+ } else {
877
+ console.log(`✓ Work item #${item.id} ready for review`);
878
+ }
879
+ resolve();
880
+ }
881
+ );
863
882
  } else {
864
883
  resolve();
865
884
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jettypod",
3
- "version": "4.4.115",
3
+ "version": "4.4.118",
4
4
  "description": "AI-powered development workflow manager with TDD, BDD, and automatic test generation",
5
5
  "main": "jettypod.js",
6
6
  "bin": {
@@ -342,13 +342,10 @@ jettypod work cleanup <bug-id>
342
342
 
343
343
  ---
344
344
 
345
- ### Step 5: Mark Bug as Done
345
+ ### Step 5: Completion
346
346
 
347
- **After the fix is merged, mark the bug as done:**
348
-
349
- ```bash
350
- jettypod work status <bug-id> done
351
- ```
347
+ **The merge command automatically sets the bug as ready for review.**
348
+ It will appear with accept/reject buttons on the kanban board. Do NOT call `jettypod work status <bug-id> done` — that bypasses the review gate.
352
349
 
353
350
  **Emit gate signal:**
354
351
 
@@ -387,7 +384,7 @@ Before ending bug-mode skill, ensure:
387
384
  - [ ] Fix committed with descriptive message
388
385
  - [ ] Bug merged to main
389
386
  - [ ] Worktree cleaned up
390
- - [ ] Bug marked as done
387
+ - [ ] Bug merged (review gate set automatically by merge command)
391
388
 
392
389
  ---
393
390
 
@@ -403,7 +400,4 @@ cd <main-repo> # Change to main repo
403
400
  jettypod work cleanup <bug-id> # Clean up worktree
404
401
  ```
405
402
 
406
- **Mark bug complete:**
407
- ```bash
408
- jettypod work status <bug-id> done
409
- ```
403
+ **⚠️ Do NOT mark bug as done manually — the merge command sets the review gate automatically.**
@@ -35,7 +35,7 @@ From the user's request, identify work type and complexity signals:
35
35
  | refactor, rename, move, clean up, upgrade, migrate, infrastructure | chore-planning |
36
36
  | add, build, create, implement, new feature, capability, workflow | feature-planning |
37
37
  | epic, initiative, project, roadmap, multi-feature | epic-planning |
38
- | tweak, change, update, adjust + small scope | simple-improvement |
38
+ | tweak, change, update, adjust + PURELY COSMETIC (text, color, spacing, copy only) | simple-improvement |
39
39
 
40
40
  **Complexity signals:**
41
41
  | Signal | Indicates |
@@ -46,6 +46,8 @@ From the user's request, identify work type and complexity signals:
46
46
  | Has edge cases to consider (validation, failures, states) | Higher complexity |
47
47
  | Could fail in interesting ways | Higher complexity |
48
48
  | Needs error handling design | Higher complexity |
49
+ | Adds or changes behavior (tracking, counting, filtering, sorting, state) | Higher complexity — NOT simple-improvement |
50
+ | Creates new capabilities (even small ones) | Higher complexity — NOT simple-improvement |
49
51
 
50
52
  ### Step 2: Gather Context (Silent - No Questions)
51
53
 
@@ -101,14 +103,14 @@ Are there edge cases to consider?
101
103
  │ (The speed→stable split helps: make it work, then handle edge cases)
102
104
 
103
105
 
104
- Is this substantial technical work?
105
- (Refactoring, infrastructure, migrations, multi-file changes)
106
- ├─► Yes chore-planning
106
+ Is this PURELY COSMETIC?
107
+ (Only changes text, copy, color, spacing, or static visual appearance?)
108
+ (Does NOT add/change any behavior, logic, tracking, data, or capabilities?)
109
+ ├─► Yes → simple-improvement
107
110
 
108
111
 
109
- Is this truly atomic?
110
- (No edge cases. Happy path IS the complete implementation.)
111
- └─► Yes → simple-improvement
112
+ Default chore-planning
113
+ (When in doubt, route to chore-planning, NEVER to simple-improvement)
112
114
  ```
113
115
 
114
116
  ## Route Definitions
@@ -120,7 +122,7 @@ Is this truly atomic?
120
122
  | **epic-planning** | Large initiative spanning multiple features | Break down → plan features |
121
123
  | **feature-planning** | New behavior needing UX exploration OR has edge cases worth sequencing | UX exploration → BDD → speed → stable → production |
122
124
  | **chore-planning** | Substantial technical work, clear implementation | speed → stable → production |
123
- | **simple-improvement** | Atomic change where happy path IS the complete implementation | Direct implementation |
125
+ | **simple-improvement** | PURELY COSMETIC: text, copy, color, spacing changes only. No behavior change. | Direct implementation |
124
126
 
125
127
  ## Routing Examples
126
128
 
@@ -170,11 +172,22 @@ Is this truly atomic?
170
172
  **→ simple-improvement**
171
173
  - "Change the button text from 'Submit' to 'Save'"
172
174
  - "Make the error message more descriptive"
173
- - "Add a loading spinner to the save button"
174
175
  - "Change the header color to blue"
175
- - "Add a tooltip to the settings icon"
176
+ - "Update the placeholder text in the search box"
177
+ - "Increase the font size of the title"
176
178
 
177
- *(Truly atomic: no edge cases, no error states to design, happy path IS the complete implementation)*
179
+ *(PURELY COSMETIC: only text, copy, color, spacing, or static visual changes. Zero behavior change.)*
180
+
181
+ **⚠️ NOT simple-improvement (common mistakes):**
182
+ - "Add a loading spinner to the save button" → **chore-planning** (adds behavior: state tracking, show/hide logic)
183
+ - "Add a tooltip to the settings icon" → **chore-planning** (adds behavior: hover state, positioning)
184
+ - "Track work item counts" → **feature-planning** (adds behavior: counting, state, display logic)
185
+ - "Add sorting to the list" → **feature-planning** (adds behavior: sort logic, state, UI interaction)
186
+ - "Show a count next to the tab" → **chore-planning** (adds behavior: data fetching, count computation)
187
+ - "Add a confirmation dialog" → **feature-planning** (adds behavior: modal state, user interaction, edge cases)
188
+ - "Make the sidebar collapsible" → **feature-planning** (adds behavior: toggle state, animation, persistence)
189
+
190
+ *(If it adds ANY new behavior — even "small" behavior — it is NOT a simple improvement.)*
178
191
 
179
192
  ## Stating Your Routing Decision
180
193
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: simple-improvement
3
- description: Guide implementation of simple improvements to existing functionality. Invoked by request-routing for straightforward changes like copy changes, styling tweaks, or minor behavior adjustments where the implementation is obvious. (project)
3
+ description: Guide implementation of PURELY COSMETIC changes. Invoked by request-routing ONLY for text, copy, color, and spacing changes that add zero new behavior. (project)
4
4
  ---
5
5
 
6
6
  # Simple Improvement Skill
@@ -18,24 +18,39 @@ description: Guide implementation of simple improvements to existing functionali
18
18
  └─────────────────────────────────────────────────────────────────────┘
19
19
  ```
20
20
 
21
- Lightweight workflow for basic enhancements to existing functionality. Bypasses the full speed/stable mode progression for simple changes.
21
+ Lightweight workflow for PURELY COSMETIC changes. Bypasses the full speed/stable mode progression because these changes have zero behavior impact.
22
22
 
23
23
  ## When to Use
24
24
 
25
- This skill is invoked by request-routing when work is identified as a **simple improvement**:
26
- - Copy/text changes
27
- - Styling tweaks
28
- - Minor behavior adjustments
29
- - Small bug fixes to existing functionality
25
+ This skill is invoked by request-routing ONLY for **purely cosmetic changes**:
26
+ - Text/copy changes (button labels, headings, descriptions, placeholder text)
27
+ - Color changes (background, text color, border color)
28
+ - Spacing/sizing changes (padding, margin, font size, width)
29
+ - Static visual appearance (border radius, opacity, font weight)
30
+
31
+ **The litmus test:** Could a non-developer make this change with a find-and-replace in a design tool? If yes, it's simple. If no, it's not.
30
32
 
31
33
  ## When NOT to Use
32
34
 
33
- Route back to request-routing for:
34
- - New functionality (even if small)
35
+ **If it adds or changes ANY behavior, it is NOT a simple improvement.** Route back to request-routing for:
36
+
37
+ - Adding interactive elements (tooltips, spinners, modals, collapsibles)
38
+ - Adding tracking/counting/state (counters, badges, progress indicators)
39
+ - Adding data fetching or computation
40
+ - Adding conditional logic (show/hide, enable/disable)
41
+ - Adding user interactions (hover effects with logic, drag-and-drop, sorting)
42
+ - New functionality of ANY size
35
43
  - Changes requiring new data models
36
44
  - Complex logic changes
37
45
  - Features needing error handling design
38
46
 
47
+ **Common misroutes — these are NOT simple improvements:**
48
+ - "Add a loading spinner" → has state (loading/not loading), show/hide logic
49
+ - "Show item count" → needs data query, computation, display logic
50
+ - "Add a tooltip" → hover detection, positioning, content logic
51
+ - "Make sidebar collapsible" → toggle state, persistence, animation
52
+ - "Add sorting" → sort logic, state management, UI interaction
53
+
39
54
  ---
40
55
 
41
56
  ## Instructions
@@ -71,6 +86,8 @@ Scan the user's description for these patterns:
71
86
 
72
87
  | Signal | Keywords/Patterns |
73
88
  |--------|-------------------|
89
+ | New behavior | "add", "track", "count", "show", "display", "when", "toggle", "sort", "filter" |
90
+ | State management | "loading", "spinner", "collapse", "expand", "hover", "active", "selected" |
74
91
  | New data models | "new table", "add column", "database", "schema" |
75
92
  | New API | "new endpoint", "API", "new route" |
76
93
  | Complex logic | "if/else", "conditional", "depends on", multiple "and" clauses |
@@ -78,16 +95,19 @@ Scan the user's description for these patterns:
78
95
  | Architectural changes | "refactor", "restructure", "new system" |
79
96
 
80
97
  ❌ **Route back to request-routing if ANY complexity signal detected:**
98
+ - Any new behavior (even "small" behavior like a spinner or tooltip)
99
+ - Any state management (loading, toggle, hover, selection)
81
100
  - New database tables/columns needed
82
101
  - New API endpoints required
83
102
  - Complex conditional logic
84
103
  - Multiple interconnected changes
85
104
  - Need for error handling design
86
105
 
87
- ✅ **Continue if the change is:**
106
+ ✅ **Continue ONLY if the change is:**
107
+ - Purely cosmetic (text, color, spacing, static visual appearance)
88
108
  - Single file or 2-3 related files
89
- - Modifying existing code (not creating new features)
90
- - Clear, specific scope
109
+ - Modifying existing static values (not adding logic)
110
+ - Zero new behavior, zero new state
91
111
  - No architectural decisions needed
92
112
 
93
113
  **If too complex:**
@@ -309,11 +329,8 @@ Need help? Run: git status (in worktree) to see conflict status
309
329
 
310
330
  Do NOT attempt to auto-resolve conflicts - let the user handle them manually.
311
331
 
312
- **Mark feature as done:**
313
-
314
- ```bash
315
- jettypod work status <feature-id> done
316
- ```
332
+ **The merge command automatically sets the feature as ready for review.**
333
+ 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.
317
334
 
318
335
  **Emit gate signal:**
319
336
 
@@ -367,6 +384,5 @@ jettypod work merge <chore-id> # Bash call 2
367
384
  # Cleanup
368
385
  jettypod work cleanup <chore-id>
369
386
 
370
- # Mark feature done
371
- jettypod work status <feature-id> done
387
+ # ⚠️ Do NOT mark feature done manually — merge sets the review gate automatically
372
388
  ```