jettypod 4.4.67 → 4.4.69
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
|
+
};
|
|
@@ -1708,12 +1708,15 @@ async function mergeWork(options = {}) {
|
|
|
1708
1708
|
|
|
1709
1709
|
console.log(`✅ Work item #${currentWork.id} marked as done`);
|
|
1710
1710
|
|
|
1711
|
-
// Instruct user to cleanup worktree separately
|
|
1711
|
+
// Instruct user to cleanup worktree separately - be aggressive so AI doesn't forget
|
|
1712
1712
|
if (worktree && worktree.worktree_path && fs.existsSync(worktree.worktree_path)) {
|
|
1713
1713
|
console.log('');
|
|
1714
|
-
console.log('
|
|
1714
|
+
console.log('⚠️ CLEANUP REQUIRED - Run these commands NOW:');
|
|
1715
|
+
console.log('');
|
|
1715
1716
|
console.log(` cd ${gitRoot}`);
|
|
1716
1717
|
console.log(` jettypod work cleanup ${currentWork.id}`);
|
|
1718
|
+
console.log('');
|
|
1719
|
+
console.log(' Worktrees accumulate until cleaned up.');
|
|
1717
1720
|
}
|
|
1718
1721
|
|
|
1719
1722
|
if (withTransition) {
|
|
@@ -2002,12 +2005,15 @@ async function testsMerge(featureId) {
|
|
|
2002
2005
|
console.log('');
|
|
2003
2006
|
console.log(`✅ Test worktree for feature #${featureId} merged successfully`);
|
|
2004
2007
|
|
|
2005
|
-
// Instruct user to cleanup worktree separately
|
|
2008
|
+
// Instruct user to cleanup worktree separately - be aggressive so AI doesn't forget
|
|
2006
2009
|
if (fs.existsSync(worktreePath)) {
|
|
2007
2010
|
console.log('');
|
|
2008
|
-
console.log('
|
|
2011
|
+
console.log('⚠️ CLEANUP REQUIRED - Run these commands NOW:');
|
|
2012
|
+
console.log('');
|
|
2009
2013
|
console.log(` cd ${gitRoot}`);
|
|
2010
2014
|
console.log(` jettypod work cleanup ${featureId}`);
|
|
2015
|
+
console.log('');
|
|
2016
|
+
console.log(' Worktrees accumulate until cleaned up.');
|
|
2011
2017
|
}
|
|
2012
2018
|
|
|
2013
2019
|
return Promise.resolve();
|
package/package.json
CHANGED
|
@@ -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
|
-
| `
|
|
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
|
-
|
|
741
|
+
**Merge and cleanup (3 steps):**
|
|
742
742
|
|
|
743
743
|
```bash
|
|
744
|
-
#
|
|
745
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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 `
|
|
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
|
-
#
|
|
771
|
-
|
|
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
|
-
#
|
|
777
|
-
|
|
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
|
-
|
|
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
|
-
|
|
948
|
-
cd <main-repo>
|
|
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):**
|