jettypod 4.4.63 → 4.4.64

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.
@@ -185,6 +185,19 @@ function evaluateBashCommand(command, inputRef, cwd) {
185
185
  }
186
186
  }
187
187
 
188
+ // BLOCKED: work merge or tests merge from inside a worktree
189
+ // This prevents shell CWD corruption when worktree is deleted
190
+ if (/jettypod\s+(work|tests)\s+merge\b/.test(strippedCommand)) {
191
+ const isInWorktree = cwd && cwd.includes('.jettypod-work');
192
+ if (isInWorktree) {
193
+ return {
194
+ allowed: false,
195
+ message: 'Cannot merge from inside a worktree',
196
+ hint: 'Merging deletes the worktree. Run from main repo: cd <main-repo-path> && jettypod work merge'
197
+ };
198
+ }
199
+ }
200
+
188
201
 
189
202
  // ALLOWED: Git read-only commands
190
203
  if (/git\s+(status|log|diff|show|branch\s*$|remote|fetch)\b/.test(strippedCommand)) {
@@ -222,7 +235,7 @@ function findDatabasePath(cwd) {
222
235
  * @param {string} cwd - Current working directory
223
236
  * @returns {string|null} Active worktree path or null
224
237
  */
225
- function getActiveWorktreePathFromDB(cwd) {
238
+ function getActiveWorktreePathFromDB(cwd, filePath) {
226
239
  const dbPath = findDatabasePath(cwd);
227
240
  if (!dbPath) {
228
241
  debug('db_lookup', { status: 'no_db_found', cwd });
@@ -240,7 +253,8 @@ function getActiveWorktreePathFromDB(cwd) {
240
253
  db.close();
241
254
 
242
255
  // Find the worktree whose path is a prefix of cwd (we're inside it)
243
- const matchingWorktree = rows.find(row => cwd.startsWith(row.worktree_path));
256
+ const normalizedFilePath = filePath ? path.resolve(cwd, filePath) : null;
257
+ const matchingWorktree = rows.find(row => cwd.startsWith(row.worktree_path) || (normalizedFilePath && normalizedFilePath.startsWith(row.worktree_path + path.sep)));
244
258
  const result = matchingWorktree ? matchingWorktree.worktree_path : null;
245
259
  debug('db_lookup', { status: 'success', method: 'better-sqlite3', worktree: result, candidates: rows.length });
246
260
  return result;
@@ -260,7 +274,8 @@ function getActiveWorktreePathFromDB(cwd) {
260
274
  }
261
275
  // Parse all worktree paths and find the one containing cwd
262
276
  const paths = result.stdout.trim().split('\n').filter(Boolean);
263
- const matchingPath = paths.find(p => cwd.startsWith(p));
277
+ const normalizedFilePath2 = filePath ? path.resolve(cwd, filePath) : null;
278
+ const matchingPath = paths.find(p => cwd.startsWith(p) || (normalizedFilePath2 && normalizedFilePath2.startsWith(p + path.sep)));
264
279
  const worktree = matchingPath || null;
265
280
  debug('db_lookup', { status: 'success', method: 'sqlite3-cli', worktree, candidates: paths.length });
266
281
  return worktree;
@@ -272,7 +287,7 @@ function getActiveWorktreePathFromDB(cwd) {
272
287
  */
273
288
  function evaluateWriteOperation(filePath, inputWorktreePath, cwd) {
274
289
  // Query database for active worktree, fall back to input if provided
275
- const activeWorktreePath = getActiveWorktreePathFromDB(cwd) || inputWorktreePath;
290
+ const activeWorktreePath = getActiveWorktreePathFromDB(cwd, filePath) || inputWorktreePath;
276
291
 
277
292
  // Normalize paths
278
293
  const normalizedPath = path.resolve(cwd || '.', filePath);
@@ -285,24 +300,8 @@ function evaluateWriteOperation(filePath, inputWorktreePath, cwd) {
285
300
  normalizedWorktree
286
301
  });
287
302
 
288
- // BLOCKED: Protected files (skills, hooks)
289
- const protectedPatterns = [
290
- /\.claude\/skills\//i,
291
- /claude-hooks\//i,
292
- /\.jettypod\/hooks\//i
293
- ];
294
-
295
- for (const pattern of protectedPatterns) {
296
- if (pattern.test(normalizedPath) || pattern.test(filePath)) {
297
- return {
298
- allowed: false,
299
- message: 'Protected file - cannot modify',
300
- hint: 'Skill and hook files are protected. Modify them through proper channels.'
301
- };
302
- }
303
- }
304
-
305
- // Check if path is in a worktree
303
+ // Check if path is in a worktree FIRST
304
+ // This allows editing protected files (hooks, skills) in worktrees
306
305
  const isInWorktree = /\.jettypod-work\//.test(filePath) || /\.jettypod-work\//.test(normalizedPath);
307
306
 
308
307
  if (isInWorktree) {
@@ -331,6 +330,23 @@ function evaluateWriteOperation(filePath, inputWorktreePath, cwd) {
331
330
  };
332
331
  }
333
332
 
333
+ // BLOCKED: Protected files in main repo (skills, hooks)
334
+ const protectedPatterns = [
335
+ /\.claude\/skills\//i,
336
+ /claude-hooks\//i,
337
+ /\.jettypod\/hooks\//i
338
+ ];
339
+
340
+ for (const pattern of protectedPatterns) {
341
+ if (pattern.test(normalizedPath) || pattern.test(filePath)) {
342
+ return {
343
+ allowed: false,
344
+ message: 'Protected file - cannot modify',
345
+ hint: 'Skill and hook files are protected. Use jettypod work start to create a worktree first.'
346
+ };
347
+ }
348
+ }
349
+
334
350
  // BLOCKED: Write to main repo (not in worktree)
335
351
  return {
336
352
  allowed: false,
package/jettypod.js CHANGED
@@ -244,11 +244,17 @@ Status: ${currentWork.status}
244
244
  <jettypod_essentials>
245
245
  JettyPod: Structured workflow system with skills that guide complex workflows.
246
246
 
247
+ ## ⚠️ CRITICAL: All Work Requires a Work Item
248
+ **Claude CANNOT write code directly to main branch.**
249
+ - All work requires: \`work create\` → \`work start\` → skill workflow → \`work merge\`
250
+ - If user asks to implement something without a work item, create one first and invoke the matching skill
251
+ - Pre-commit hooks block direct commits to main
252
+
247
253
  ## ⚠️ CRITICAL: Skills are MANDATORY for workflows
248
254
  Skills auto-activate and MUST complete their full workflow:
249
255
  - epic-planning: Guides architectural decisions
250
256
  - feature-planning: Guides UX discovery + BDD scenarios
251
- - speed-mode: Implements happy path, THEN auto-generates stable chores
257
+ - speed-mode: Implements happy path, THEN auto-invokes stable-mode
252
258
  - stable-mode: Adds error handling to speed implementation
253
259
  - external-transition: Guides launch preparation
254
260
 
@@ -260,10 +266,14 @@ Skills auto-activate and MUST complete their full workflow:
260
266
  ## Basic Commands (for non-workflow operations)
261
267
  jettypod work create epic "<title>"
262
268
  jettypod work create feature "<title>" --parent=<id>
263
- jettypod work start <id>
269
+ jettypod work create chore "<title>" --parent=<id>
270
+ jettypod work start <id> # Creates worktree branch
271
+ jettypod work merge # Merges worktree back to main
272
+ jettypod work tests <feature-id> # Create test worktree for BDD
273
+ jettypod work tests merge <id> # Merge tests to main
264
274
  jettypod work status <id> cancelled
265
275
  jettypod backlog
266
- jettypod impact <file> # Show tests/features affected by changing a file
276
+ jettypod impact <file> # Show tests/features affected
267
277
 
268
278
  ## Advanced Commands
269
279
  For mode management, decisions, project state: docs/COMMAND_REFERENCE.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jettypod",
3
- "version": "4.4.63",
3
+ "version": "4.4.64",
4
4
  "description": "AI-powered development workflow manager with TDD, BDD, and automatic test generation",
5
5
  "main": "jettypod.js",
6
6
  "bin": {