jettypod 4.4.67 → 4.4.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jettypod.js CHANGED
@@ -270,6 +270,7 @@ jettypod work create feature "<title>" --parent=<id>
270
270
  jettypod work create chore "<title>" --parent=<id>
271
271
  jettypod work start <id> # Creates worktree branch
272
272
  jettypod work merge # Merges worktree back to main
273
+ jettypod work cleanup <id> # Cleanup worktree after merge
273
274
  jettypod work tests <feature-id> # Create test worktree for BDD
274
275
  jettypod work tests merge <id> # Merge tests to main
275
276
  jettypod work status <id> cancelled
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Migration: Add 'merged' status to worktrees table
3
+ *
4
+ * Purpose: Support separating merge from cleanup - worktrees stay after merge
5
+ * until explicitly cleaned up. This prevents shell CWD corruption when merge
6
+ * is run from inside the worktree.
7
+ *
8
+ * SQLite doesn't support ALTER CONSTRAINT, so we need to recreate the table.
9
+ */
10
+
11
+ module.exports = {
12
+ id: '018-worktrees-merged-status',
13
+ description: 'Add merged status to worktrees table for separate cleanup step',
14
+
15
+ async up(db) {
16
+ return new Promise((resolve, reject) => {
17
+ db.serialize(() => {
18
+ // 1. Create new table with updated constraint
19
+ db.run(`
20
+ CREATE TABLE IF NOT EXISTS worktrees_new (
21
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
22
+ work_item_id INTEGER NOT NULL,
23
+ branch_name TEXT NOT NULL,
24
+ worktree_path TEXT NOT NULL,
25
+ status TEXT NOT NULL CHECK(status IN ('active', 'merging', 'merged', 'cleanup_pending', 'corrupted')),
26
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
27
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
28
+ FOREIGN KEY (work_item_id) REFERENCES work_items(id)
29
+ )
30
+ `, (err) => {
31
+ if (err) return reject(err);
32
+ });
33
+
34
+ // 2. Copy data from old table
35
+ db.run(`
36
+ INSERT INTO worktrees_new (id, work_item_id, branch_name, worktree_path, status, created_at, updated_at)
37
+ SELECT id, work_item_id, branch_name, worktree_path, status, created_at, updated_at
38
+ FROM worktrees
39
+ `, (err) => {
40
+ if (err) return reject(err);
41
+ });
42
+
43
+ // 3. Drop old indexes
44
+ db.run('DROP INDEX IF EXISTS idx_worktrees_work_item_id', (err) => {
45
+ if (err) return reject(err);
46
+ });
47
+
48
+ db.run('DROP INDEX IF EXISTS idx_worktrees_status', (err) => {
49
+ if (err) return reject(err);
50
+ });
51
+
52
+ // 4. Drop old table
53
+ db.run('DROP TABLE worktrees', (err) => {
54
+ if (err) return reject(err);
55
+ });
56
+
57
+ // 5. Rename new table
58
+ db.run('ALTER TABLE worktrees_new RENAME TO worktrees', (err) => {
59
+ if (err) return reject(err);
60
+ });
61
+
62
+ // 6. Recreate indexes
63
+ db.run(`
64
+ CREATE INDEX idx_worktrees_work_item_id
65
+ ON worktrees(work_item_id)
66
+ `, (err) => {
67
+ if (err) return reject(err);
68
+ });
69
+
70
+ db.run(`
71
+ CREATE INDEX idx_worktrees_status
72
+ ON worktrees(status)
73
+ `, (err) => {
74
+ if (err) return reject(err);
75
+ resolve();
76
+ });
77
+ });
78
+ });
79
+ },
80
+
81
+ async down(db) {
82
+ // Reverse migration - remove 'merged' status
83
+ // Any rows with 'merged' status will fail the constraint, so convert them first
84
+ return new Promise((resolve, reject) => {
85
+ db.serialize(() => {
86
+ // Convert any 'merged' status to 'cleanup_pending'
87
+ db.run(`UPDATE worktrees SET status = 'cleanup_pending' WHERE status = 'merged'`, (err) => {
88
+ if (err) return reject(err);
89
+ });
90
+
91
+ // Create table without 'merged' in constraint
92
+ db.run(`
93
+ CREATE TABLE IF NOT EXISTS worktrees_new (
94
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
95
+ work_item_id INTEGER NOT NULL,
96
+ branch_name TEXT NOT NULL,
97
+ worktree_path TEXT NOT NULL,
98
+ status TEXT NOT NULL CHECK(status IN ('active', 'merging', 'cleanup_pending', 'corrupted')),
99
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
100
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
101
+ FOREIGN KEY (work_item_id) REFERENCES work_items(id)
102
+ )
103
+ `, (err) => {
104
+ if (err) return reject(err);
105
+ });
106
+
107
+ db.run(`
108
+ INSERT INTO worktrees_new (id, work_item_id, branch_name, worktree_path, status, created_at, updated_at)
109
+ SELECT id, work_item_id, branch_name, worktree_path, status, created_at, updated_at
110
+ FROM worktrees
111
+ `, (err) => {
112
+ if (err) return reject(err);
113
+ });
114
+
115
+ db.run('DROP INDEX IF EXISTS idx_worktrees_work_item_id', (err) => {
116
+ if (err) return reject(err);
117
+ });
118
+
119
+ db.run('DROP INDEX IF EXISTS idx_worktrees_status', (err) => {
120
+ if (err) return reject(err);
121
+ });
122
+
123
+ db.run('DROP TABLE worktrees', (err) => {
124
+ if (err) return reject(err);
125
+ });
126
+
127
+ db.run('ALTER TABLE worktrees_new RENAME TO worktrees', (err) => {
128
+ if (err) return reject(err);
129
+ });
130
+
131
+ db.run(`
132
+ CREATE INDEX idx_worktrees_work_item_id
133
+ ON worktrees(work_item_id)
134
+ `, (err) => {
135
+ if (err) return reject(err);
136
+ });
137
+
138
+ db.run(`
139
+ CREATE INDEX idx_worktrees_status
140
+ ON worktrees(status)
141
+ `, (err) => {
142
+ if (err) return reject(err);
143
+ resolve();
144
+ });
145
+ });
146
+ });
147
+ }
148
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jettypod",
3
- "version": "4.4.67",
3
+ "version": "4.4.68",
4
4
  "description": "AI-powered development workflow manager with TDD, BDD, and automatic test generation",
5
5
  "main": "jettypod.js",
6
6
  "bin": {
@@ -19,7 +19,7 @@ When this skill is activated, you are helping discover the best approach for a f
19
19
  |---------|----------|------|-------|
20
20
  | `work implement <feature-id>` | Transition feature to implementation phase | After chores created (Step 8C) | Feature Planning |
21
21
  | `work tests start <feature-id>` | Create worktree for test authoring | After transition (Step 8D) | Feature Planning |
22
- | `cd <main-repo> && work tests merge <feature-id>` | Merge tests to main, cleanup worktree | After tests validated (Step 8D) | Feature Planning |
22
+ | `work tests merge` `cd` → `work cleanup` | Merge tests to main, then cleanup worktree | After tests validated (Step 8D) | Feature Planning |
23
23
  | `work start <chore-id>` | Start implementing a specific chore | After tests merged (Step 8E) | Speed Mode |
24
24
 
25
25
  **CRITICAL:** All commands are run by **Claude**, not the user. The distinction is:
@@ -738,21 +738,29 @@ sqlite3 .jettypod/work.db "UPDATE work_items SET scenario_file = 'features/${FEA
738
738
 
739
739
  **Sub-step 5: Merge tests to main**
740
740
 
741
- **⚠️ CRITICAL: The merge will delete the worktree.** Your shell is currently inside it. Chain commands to ensure shell is in main repo BEFORE deletion:
741
+ **Merge and cleanup (3 steps):**
742
742
 
743
743
  ```bash
744
- # CRITICAL: cd to main repo AND merge in SAME command
745
- # This ensures shell is in main repo BEFORE worktree deletion
746
- cd <main-repo-path> && jettypod work tests merge ${FEATURE_ID}
744
+ # Step 1: Merge tests (can run from worktree - it won't delete it)
745
+ jettypod work tests merge ${FEATURE_ID}
747
746
  ```
748
747
 
749
- If you run the merge while your shell is in the worktree, subsequent commands will fail with "No such file or directory".
748
+ ```bash
749
+ # Step 2: cd to main repo
750
+ cd <main-repo-path>
751
+ pwd && ls .jettypod # verify
752
+ ```
753
+
754
+ ```bash
755
+ # Step 3: Clean up the worktree (now safe since shell is in main repo)
756
+ jettypod work cleanup ${FEATURE_ID}
757
+ ```
750
758
 
751
759
  This will:
752
760
  - Commit changes in the worktree
753
761
  - Merge to main
754
762
  - Push to remote
755
- - Clean up the worktree
763
+ - Mark worktree as merged (cleanup is separate)
756
764
 
757
765
  **🛑 STOP AND CHECK:** Verify merge succeeded:
758
766
  - ✅ "Tests merged to main" → Proceed to Step 8E
@@ -922,6 +930,6 @@ Before completing feature planning, ensure:
922
930
  - [ ] **Test worktree created** with `work tests start` (Step 8D)
923
931
  - [ ] **BDD files written** in worktree (Step 8D)
924
932
  - [ ] **BDD infrastructure validated** with dry-run (Step 8D)
925
- - [ ] **Tests merged to main** with `cd <main-repo> && work tests merge` (Step 8D)
933
+ - [ ] **Tests merged to main** with `work tests merge` → `cd` → `work cleanup` (Step 8D)
926
934
  - [ ] First chore started with `work start [chore-id]` (Step 8E)
927
935
  - [ ] **Speed-mode skill invoked using Skill tool** (Step 8E)
@@ -766,20 +766,22 @@ Added error handling and edge case scenarios for stable mode.
766
766
  - Step definitions for validation and error handling"
767
767
  ```
768
768
 
769
+ **Merge and cleanup (3 steps):**
770
+
769
771
  ```bash
770
- # CRITICAL: cd to main repo AND merge in SAME command
771
- # This ensures shell is in main repo BEFORE worktree deletion
772
- cd <main-repo-path> && jettypod work tests merge <feature-id>
772
+ # Step 1: Merge tests (can run from worktree - it won't delete it)
773
+ jettypod work tests merge <feature-id>
773
774
  ```
774
775
 
775
776
  ```bash
776
- # MANDATORY: Verify shell is in main repo (run this immediately after merge)
777
- pwd && ls .jettypod
777
+ # Step 2: cd to main repo
778
+ cd <main-repo-path>
779
+ pwd && ls .jettypod # verify
778
780
  ```
779
781
 
780
- **If you see "No such file or directory" errors:** Your shell CWD was corrupted. Run:
781
782
  ```bash
782
- cd <main-repo-path>
783
+ # Step 3: Clean up the worktree (now safe since shell is in main repo)
784
+ jettypod work cleanup <feature-id>
783
785
  ```
784
786
 
785
787
  **7. Present proposal to user:**
@@ -944,8 +946,9 @@ jettypod work start <chore-id> # Create worktree and start chore
944
946
  **Create test worktree (for writing BDD scenarios):**
945
947
  ```bash
946
948
  jettypod work tests <feature-id> # Create worktree for writing tests
947
- # CRITICAL: cd to main repo BEFORE merge (worktree will be deleted)
948
- cd <main-repo> && jettypod work tests merge <feature-id>
949
+ jettypod work tests merge <feature-id> # Merge tests (preserves worktree)
950
+ cd <main-repo> # cd to main repo
951
+ jettypod work cleanup <feature-id> # Clean up worktree
949
952
  ```
950
953
 
951
954
  **Set feature mode (BEFORE creating chores):**