jettypod 4.2.10 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,84 +0,0 @@
1
- /**
2
- * Migration: Create worktree_sessions table
3
- *
4
- * Purpose: Track which work item is active in each worktree to support multiple
5
- * concurrent Claude Code instances working on different features simultaneously.
6
- *
7
- * Why this is critical:
8
- * - Enable true concurrent development with multiple worktrees
9
- * - Prevent confusion when Claude switches between worktrees
10
- * - Provide centralized visibility of what's active where
11
- * - Support automatic cleanup when work items are completed
12
- */
13
-
14
- module.exports = {
15
- id: '016-worktree-sessions-table',
16
- description: 'Create worktree_sessions table for multi-worktree current work tracking',
17
-
18
- async up(db) {
19
- return new Promise((resolve, reject) => {
20
- db.run(`
21
- CREATE TABLE IF NOT EXISTS worktree_sessions (
22
- id INTEGER PRIMARY KEY AUTOINCREMENT,
23
- worktree_path TEXT UNIQUE NOT NULL,
24
- work_item_id INTEGER NOT NULL,
25
- branch_name TEXT NOT NULL,
26
- last_activity DATETIME DEFAULT CURRENT_TIMESTAMP,
27
- FOREIGN KEY (work_item_id) REFERENCES work_items(id)
28
- )
29
- `, (err) => {
30
- if (err) {
31
- return reject(err);
32
- }
33
-
34
- // Create index on worktree_path for fast lookups
35
- db.run(`
36
- CREATE INDEX IF NOT EXISTS idx_worktree_sessions_path
37
- ON worktree_sessions(worktree_path)
38
- `, (err) => {
39
- if (err) {
40
- return reject(err);
41
- }
42
-
43
- // Create index on work_item_id for reverse lookups
44
- db.run(`
45
- CREATE INDEX IF NOT EXISTS idx_worktree_sessions_work_item
46
- ON worktree_sessions(work_item_id)
47
- `, (err) => {
48
- if (err) {
49
- return reject(err);
50
- }
51
-
52
- resolve();
53
- });
54
- });
55
- });
56
- });
57
- },
58
-
59
- async down(db) {
60
- return new Promise((resolve, reject) => {
61
- // Drop indexes first
62
- db.run('DROP INDEX IF EXISTS idx_worktree_sessions_work_item', (err) => {
63
- if (err) {
64
- return reject(err);
65
- }
66
-
67
- db.run('DROP INDEX IF EXISTS idx_worktree_sessions_path', (err) => {
68
- if (err) {
69
- return reject(err);
70
- }
71
-
72
- // Drop table
73
- db.run('DROP TABLE IF EXISTS worktree_sessions', (err) => {
74
- if (err) {
75
- return reject(err);
76
- }
77
-
78
- resolve();
79
- });
80
- });
81
- });
82
- });
83
- }
84
- };
@@ -1,186 +0,0 @@
1
- /**
2
- * Worktree Session Management
3
- *
4
- * CRUD operations for tracking which work item is active in each worktree.
5
- * Enables multiple concurrent Claude Code instances working in different worktrees.
6
- */
7
-
8
- const { getDb } = require('./database');
9
-
10
- /**
11
- * Create or update a worktree session
12
- *
13
- * @param {string} worktreePath - Absolute path to the worktree
14
- * @param {number} workItemId - ID of the work item
15
- * @param {string} branchName - Git branch name
16
- * @returns {Promise<void>}
17
- */
18
- function createOrUpdateSession(worktreePath, workItemId, branchName) {
19
- const db = getDb();
20
-
21
- return new Promise((resolve, reject) => {
22
- db.run(
23
- `INSERT OR REPLACE INTO worktree_sessions
24
- (worktree_path, work_item_id, branch_name, last_activity)
25
- VALUES (?, ?, ?, datetime('now'))`,
26
- [worktreePath, workItemId, branchName],
27
- (err) => {
28
- if (err) {
29
- // Provide user-friendly error messages based on error type
30
- if (err.code === 'SQLITE_BUSY') {
31
- return reject(new Error('Database is locked by another process. Please try again in a moment.'));
32
- } else if (err.code === 'SQLITE_CORRUPT') {
33
- return reject(new Error('Database is corrupted. Please run: jettypod init --reset'));
34
- } else if (err.code === 'SQLITE_CANTOPEN') {
35
- return reject(new Error('Cannot open database. Check file permissions or run: jettypod init'));
36
- } else if (err.code === 'SQLITE_READONLY') {
37
- return reject(new Error('Database is read-only. Check file permissions.'));
38
- }
39
- // Generic database error
40
- console.error('Database error in createOrUpdateSession:', err);
41
- return reject(new Error(`Failed to create/update worktree session: ${err.message}`));
42
- }
43
- resolve();
44
- }
45
- );
46
- });
47
- }
48
-
49
- /**
50
- * Get session by worktree path
51
- *
52
- * @param {string} worktreePath - Absolute path to the worktree
53
- * @returns {Promise<object|null>} Session object or null if not found
54
- */
55
- function getSessionByWorktreePath(worktreePath) {
56
- const db = getDb();
57
-
58
- return new Promise((resolve, reject) => {
59
- db.get(
60
- `SELECT * FROM worktree_sessions WHERE worktree_path = ?`,
61
- [worktreePath],
62
- (err, row) => {
63
- if (err) {
64
- // Provide user-friendly error messages
65
- if (err.code === 'SQLITE_BUSY') {
66
- return reject(new Error('Database is locked. Please try again in a moment.'));
67
- } else if (err.code === 'SQLITE_CORRUPT') {
68
- return reject(new Error('Database is corrupted. Please run: jettypod init --reset'));
69
- } else if (err.code === 'SQLITE_CANTOPEN') {
70
- return reject(new Error('Cannot open database. Run: jettypod init'));
71
- }
72
- console.error('Database error in getSessionByWorktreePath:', err);
73
- return reject(new Error(`Failed to get worktree session: ${err.message}`));
74
- }
75
- resolve(row || null);
76
- }
77
- );
78
- });
79
- }
80
-
81
- /**
82
- * Get all active worktree sessions
83
- *
84
- * @returns {Promise<Array>} Array of session objects
85
- */
86
- function getAllActiveSessions() {
87
- const db = getDb();
88
-
89
- return new Promise((resolve, reject) => {
90
- db.all(
91
- `SELECT * FROM worktree_sessions ORDER BY last_activity DESC`,
92
- [],
93
- (err, rows) => {
94
- if (err) {
95
- // Provide user-friendly error messages
96
- if (err.code === 'SQLITE_BUSY') {
97
- return reject(new Error('Database is locked. Please try again in a moment.'));
98
- } else if (err.code === 'SQLITE_CORRUPT') {
99
- return reject(new Error('Database is corrupted. Please run: jettypod init --reset'));
100
- } else if (err.code === 'SQLITE_CANTOPEN') {
101
- return reject(new Error('Cannot open database. Run: jettypod init'));
102
- }
103
- console.error('Database error in getAllActiveSessions:', err);
104
- return reject(new Error(`Failed to get active sessions: ${err.message}`));
105
- }
106
- resolve(rows || []);
107
- }
108
- );
109
- });
110
- }
111
-
112
- /**
113
- * Delete session by worktree path
114
- *
115
- * @param {string} worktreePath - Absolute path to the worktree
116
- * @returns {Promise<void>}
117
- */
118
- function deleteSession(worktreePath) {
119
- const db = getDb();
120
-
121
- return new Promise((resolve, reject) => {
122
- db.run(
123
- `DELETE FROM worktree_sessions WHERE worktree_path = ?`,
124
- [worktreePath],
125
- (err) => {
126
- if (err) {
127
- // Provide user-friendly error messages
128
- if (err.code === 'SQLITE_BUSY') {
129
- return reject(new Error('Database is locked. Please try again in a moment.'));
130
- } else if (err.code === 'SQLITE_CORRUPT') {
131
- return reject(new Error('Database is corrupted. Please run: jettypod init --reset'));
132
- } else if (err.code === 'SQLITE_CANTOPEN') {
133
- return reject(new Error('Cannot open database. Run: jettypod init'));
134
- } else if (err.code === 'SQLITE_READONLY') {
135
- return reject(new Error('Database is read-only. Check file permissions.'));
136
- }
137
- console.error('Database error in deleteSession:', err);
138
- return reject(new Error(`Failed to delete worktree session: ${err.message}`));
139
- }
140
- resolve();
141
- }
142
- );
143
- });
144
- }
145
-
146
- /**
147
- * Delete session by work item ID
148
- *
149
- * @param {number} workItemId - ID of the work item
150
- * @returns {Promise<void>}
151
- */
152
- function deleteSessionByWorkItem(workItemId) {
153
- const db = getDb();
154
-
155
- return new Promise((resolve, reject) => {
156
- db.run(
157
- `DELETE FROM worktree_sessions WHERE work_item_id = ?`,
158
- [workItemId],
159
- (err) => {
160
- if (err) {
161
- // Provide user-friendly error messages
162
- if (err.code === 'SQLITE_BUSY') {
163
- return reject(new Error('Database is locked. Please try again in a moment.'));
164
- } else if (err.code === 'SQLITE_CORRUPT') {
165
- return reject(new Error('Database is corrupted. Please run: jettypod init --reset'));
166
- } else if (err.code === 'SQLITE_CANTOPEN') {
167
- return reject(new Error('Cannot open database. Run: jettypod init'));
168
- } else if (err.code === 'SQLITE_READONLY') {
169
- return reject(new Error('Database is read-only. Check file permissions.'));
170
- }
171
- console.error('Database error in deleteSessionByWorkItem:', err);
172
- return reject(new Error(`Failed to delete session by work item: ${err.message}`));
173
- }
174
- resolve();
175
- }
176
- );
177
- });
178
- }
179
-
180
- module.exports = {
181
- createOrUpdateSession,
182
- getSessionByWorktreePath,
183
- getAllActiveSessions,
184
- deleteSession,
185
- deleteSessionByWorkItem
186
- };