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.
- package/claude-hooks/global-guardrails.js +38 -22
- package/jettypod.js +13 -3
- package/package.json +1 -1
|
@@ -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
|
|
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
|
|
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
|
-
//
|
|
289
|
-
|
|
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-
|
|
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
|
|
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>
|
|
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
|