jettypod 4.4.35 → 4.4.37

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/hooks/pre-commit CHANGED
@@ -1,30 +1,61 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { exportAll } = require('jettypod/lib/db-export');
3
+ // JettyPod pre-commit hook: Block direct commits to main branch
4
+ // This is the standalone version used for BDD testing
5
+ // The production version is in lib/git-hooks/pre-commit
6
+
4
7
  const { execSync } = require('child_process');
8
+ const fs = require('fs');
9
+ const path = require('path');
5
10
 
6
- (async () => {
11
+ // Check if direct commits to main should be blocked
12
+ function checkBranchRestriction() {
7
13
  try {
8
- // Export databases to JSON
9
- await exportAll();
10
-
11
- // Stage the JSON files
12
- try {
13
- execSync('git add .jettypod/snapshots/work.json', { stdio: 'inherit' });
14
- execSync('git add .jettypod/snapshots/database.json', { stdio: 'inherit' });
15
- } catch (gitErr) {
16
- // Log warning but don't block commit
17
- console.error('Pre-commit hook warning: Failed to stage snapshot files');
18
- console.error(` ${gitErr.message}`);
19
- console.error(' Commit will proceed but snapshots may not be included');
14
+ // Get current branch name
15
+ const branch = execSync('git symbolic-ref --short HEAD', {
16
+ encoding: 'utf-8',
17
+ stdio: ['pipe', 'pipe', 'pipe']
18
+ }).trim();
19
+
20
+ // Only restrict main/master branches
21
+ if (branch !== 'main' && branch !== 'master') {
22
+ return true; // Allow commits on feature branches
20
23
  }
21
24
 
22
- // Always exit successfully to allow commit to proceed
23
- process.exit(0);
25
+ // Check if this is a merge commit (MERGE_HEAD exists)
26
+ const gitDir = execSync('git rev-parse --git-dir', {
27
+ encoding: 'utf-8',
28
+ stdio: ['pipe', 'pipe', 'pipe']
29
+ }).trim();
30
+
31
+ if (fs.existsSync(path.join(gitDir, 'MERGE_HEAD'))) {
32
+ return true; // Allow merge commits on main
33
+ }
34
+
35
+ // Block direct commits to main
36
+ console.error('');
37
+ console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
38
+ console.error('❌ Direct commits to main are not allowed');
39
+ console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
40
+ console.error('');
41
+ console.error('Use the JettyPod workflow instead:');
42
+ console.error('');
43
+ console.error(' jettypod work start <work-item-id>');
44
+ console.error('');
45
+ console.error('This creates a feature branch where you can commit freely.');
46
+ console.error('When done, use \'jettypod work done\' to merge back to main.');
47
+ console.error('');
48
+ return false;
24
49
  } catch (err) {
25
- // Log warning but don't block commit
26
- console.error('Pre-commit hook warning:', err.message);
27
- console.error(' Commit will proceed but snapshots were not updated');
28
- process.exit(0);
50
+ // If we can't determine branch (detached HEAD, etc.), allow the commit
51
+ return true;
29
52
  }
30
- })();
53
+ }
54
+
55
+ // Check branch restriction first
56
+ if (!checkBranchRestriction()) {
57
+ process.exit(1);
58
+ }
59
+
60
+ // Allow commit
61
+ process.exit(0);
@@ -1,11 +1,60 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- // Pre-commit hook: Run tests before allowing commit
3
+ // Pre-commit hook: Block direct commits to main + run tests
4
4
 
5
5
  const { execSync } = require('child_process');
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
 
9
+ // Check if direct commits to main should be blocked
10
+ function checkBranchRestriction() {
11
+ try {
12
+ // Get current branch name
13
+ const branch = execSync('git symbolic-ref --short HEAD', {
14
+ encoding: 'utf-8',
15
+ stdio: ['pipe', 'pipe', 'pipe']
16
+ }).trim();
17
+
18
+ // Only restrict main/master branches
19
+ if (branch !== 'main' && branch !== 'master') {
20
+ return true; // Allow commits on feature branches
21
+ }
22
+
23
+ // Check if this is a merge commit (MERGE_HEAD exists)
24
+ const gitDir = execSync('git rev-parse --git-dir', {
25
+ encoding: 'utf-8',
26
+ stdio: ['pipe', 'pipe', 'pipe']
27
+ }).trim();
28
+
29
+ if (fs.existsSync(path.join(gitDir, 'MERGE_HEAD'))) {
30
+ return true; // Allow merge commits on main
31
+ }
32
+
33
+ // Block direct commits to main
34
+ console.error('');
35
+ console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
36
+ console.error('❌ Direct commits to main are not allowed');
37
+ console.error('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
38
+ console.error('');
39
+ console.error('Use the JettyPod workflow instead:');
40
+ console.error('');
41
+ console.error(' jettypod work start <work-item-id>');
42
+ console.error('');
43
+ console.error('This creates a feature branch where you can commit freely.');
44
+ console.error('When done, use \'jettypod work done\' to merge back to main.');
45
+ console.error('');
46
+ return false;
47
+ } catch (err) {
48
+ // If we can't determine branch (detached HEAD, etc.), allow the commit
49
+ return true;
50
+ }
51
+ }
52
+
53
+ // First check branch restriction
54
+ if (!checkBranchRestriction()) {
55
+ process.exit(1);
56
+ }
57
+
9
58
  // Check if we're in a real project (not a test directory)
10
59
  const packageJsonPath = path.join(process.cwd(), 'package.json');
11
60
  if (!fs.existsSync(packageJsonPath)) {
@@ -101,11 +101,31 @@ async function startWork(id) {
101
101
  errorMsg += ` jettypod work start ${c.id} # ${c.title}\n`;
102
102
  });
103
103
  } else if (inProgressChores.length === 0) {
104
- errorMsg += `No chores available. Create chores first or check if feature is complete.`;
104
+ const doneChores = chores.filter(c => c.status === 'done');
105
+ if (doneChores.length === chores.length) {
106
+ errorMsg += `All chores are complete. This feature is done.\n`;
107
+ errorMsg += `Use: jettypod work status ${id} done # to mark the feature as done`;
108
+ } else {
109
+ errorMsg += `No chores available to start.\n`;
110
+ errorMsg += `Use: jettypod backlog # to see work item status`;
111
+ }
105
112
  }
106
113
  } else {
107
- errorMsg += `This feature has no chores yet. Use the feature-planning skill to plan it:\n`;
108
- errorMsg += ` Tell Claude: "Help me plan feature #${id}"`;
114
+ // No chores - check feature phase to give accurate guidance
115
+ if (workItem.status === 'done') {
116
+ errorMsg += `This feature is already done. No action needed.`;
117
+ } else if (workItem.phase === 'implementation') {
118
+ // Feature is in implementation but has no chores - unusual state
119
+ errorMsg += `This feature is in implementation phase but has no chores.\n`;
120
+ errorMsg += `The feature-planning skill should have generated chores.\n\n`;
121
+ errorMsg += `To regenerate chores, use the feature-planning skill:\n`;
122
+ errorMsg += ` Invoke skill: feature-planning`;
123
+ } else {
124
+ // Feature needs planning
125
+ errorMsg += `This feature needs planning first.\n\n`;
126
+ errorMsg += `Use the feature-planning skill to plan it:\n`;
127
+ errorMsg += ` Invoke skill: feature-planning`;
128
+ }
109
129
  }
110
130
 
111
131
  return reject(new Error(errorMsg));
@@ -116,7 +136,7 @@ async function startWork(id) {
116
136
 
117
137
  // Prevent starting epics directly
118
138
  if (workItem.type === 'epic') {
119
- return reject(new Error(`Cannot start epic #${id} directly. Start a feature or chore instead.\n\nUse: jettypod backlog # to see available work items`));
139
+ return reject(new Error(`Cannot start epic #${id} directly.\n\nTo plan this epic's features, use the epic-planning skill:\n Invoke skill: epic-planning\n\nOr start an existing feature/chore:\n jettypod backlog # to see available work items`));
120
140
  }
121
141
 
122
142
  // Update status to in_progress if currently todo
@@ -1077,16 +1077,14 @@ async function main() {
1077
1077
  console.log('🎯 Plan this epic now?');
1078
1078
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
1079
1079
  console.log('');
1080
- console.log('Ask Claude Code:');
1081
- console.log(` "Help me plan epic #${newId}"`);
1080
+ console.log('Use the epic-planning skill:');
1081
+ console.log(' Invoke skill: epic-planning');
1082
1082
  console.log('');
1083
- console.log('Claude will help you:');
1083
+ console.log('The skill will guide you to:');
1084
1084
  console.log(' • Brainstorm features for this epic');
1085
1085
  console.log(' • Identify architectural decisions (if needed)');
1086
1086
  console.log(' • Create features automatically');
1087
1087
  console.log('');
1088
- console.log('Or run: jettypod work epic-planning ' + newId);
1089
- console.log('');
1090
1088
  console.log('💡 You can also plan later when ready');
1091
1089
  }
1092
1090
 
@@ -1101,10 +1099,8 @@ async function main() {
1101
1099
  console.log('');
1102
1100
  console.log('💡 Tip: Consider planning this epic first');
1103
1101
  console.log('');
1104
- console.log('Ask Claude Code:');
1105
- console.log(` "Help me plan epic #${parentId}"`);
1106
- console.log('');
1107
- console.log(`Or run: jettypod work epic-planning ${parentId}`);
1102
+ console.log('Use the epic-planning skill:');
1103
+ console.log(' Invoke skill: epic-planning');
1108
1104
  }
1109
1105
  });
1110
1106
  }
@@ -1831,16 +1827,14 @@ async function main() {
1831
1827
  console.log(`Description: ${epic.description || 'Not provided'}`);
1832
1828
  console.log('Needs Discovery: true');
1833
1829
  console.log('');
1834
- console.log('💬 Now ask Claude Code:');
1835
- console.log(` "Help me with epic discovery for #${epicId}"`);
1830
+ console.log('Use the epic-planning skill:');
1831
+ console.log(' Invoke skill: epic-planning');
1836
1832
  console.log('');
1837
- console.log('Claude will use the epic-planning skill to guide you through:');
1833
+ console.log('The skill will guide you through:');
1838
1834
  console.log(' 1. Feature brainstorming');
1839
1835
  console.log(' 2. Architectural decisions (if needed)');
1840
1836
  console.log(' 3. Prototype validation (optional)');
1841
1837
  console.log(' 4. Feature creation');
1842
- console.log('');
1843
- console.log('📋 The skill is at: .claude/skills/epic-planning/SKILL.md');
1844
1838
  }
1845
1839
  );
1846
1840
  });
@@ -2236,17 +2230,15 @@ async function main() {
2236
2230
  }
2237
2231
  }
2238
2232
  console.log('');
2239
- console.log('💬 Now ask Claude Code:');
2240
- console.log(` "Help me with feature discovery for #${featureId}"`);
2233
+ console.log('Use the feature-planning skill:');
2234
+ console.log(' Invoke skill: feature-planning');
2241
2235
  console.log('');
2242
- console.log('Claude will use the feature-planning skill to guide you through:');
2236
+ console.log('The skill will guide you through:');
2243
2237
  console.log(' 1. Suggesting 3 UX approaches');
2244
2238
  console.log(' 2. Optional prototyping');
2245
2239
  console.log(' 3. Choosing the winner');
2246
2240
  console.log(' 4. Generating BDD scenarios');
2247
2241
  console.log(' 5. Transitioning to implementation');
2248
- console.log('');
2249
- console.log('📋 The skill is at: .claude/skills/feature-planning/SKILL.md');
2250
2242
  }
2251
2243
  );
2252
2244
  } else {
@@ -2261,17 +2253,15 @@ async function main() {
2261
2253
  console.log(`Title: ${feature.title}`);
2262
2254
  console.log(`Description: ${feature.description || 'Not provided'}`);
2263
2255
  console.log('');
2264
- console.log('💬 Now ask Claude Code:');
2265
- console.log(` "Help me with feature discovery for #${featureId}"`);
2256
+ console.log('Use the feature-planning skill:');
2257
+ console.log(' Invoke skill: feature-planning');
2266
2258
  console.log('');
2267
- console.log('Claude will use the feature-planning skill to guide you through:');
2259
+ console.log('The skill will guide you through:');
2268
2260
  console.log(' 1. Suggesting 3 UX approaches');
2269
2261
  console.log(' 2. Optional prototyping');
2270
2262
  console.log(' 3. Choosing the winner');
2271
2263
  console.log(' 4. Generating BDD scenarios');
2272
2264
  console.log(' 5. Transitioning to implementation');
2273
- console.log('');
2274
- console.log('📋 The skill is at: .claude/skills/feature-planning/SKILL.md');
2275
2265
  }
2276
2266
  });
2277
2267
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jettypod",
3
- "version": "4.4.35",
3
+ "version": "4.4.37",
4
4
  "description": "AI-powered development workflow manager with TDD, BDD, and automatic test generation",
5
5
  "main": "jettypod.js",
6
6
  "bin": {