jettypod 4.1.2 → 4.1.4

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.
Files changed (179) hide show
  1. package/.nvmrc +1 -0
  2. package/docs/COMPLETE-TESTING-STRATEGY.md +970 -0
  3. package/docs/DECISIONS.md +10 -12
  4. package/docs/NODE_VERSION.md +83 -0
  5. package/docs/TDD-INFRASTRUCTURE-STRATEGY.md +1374 -0
  6. package/docs/TESTING-FOR-NON-ENGINEERS.md +1588 -0
  7. package/docs/TESTING-STRATEGY-AUDIT.md +698 -0
  8. package/hooks/post-checkout +17 -0
  9. package/hooks/post-merge +17 -0
  10. package/hooks/pre-commit +30 -0
  11. package/jettypod.js +259 -120
  12. package/lib/coverage-tracker.js +218 -0
  13. package/lib/database.js +2 -0
  14. package/lib/db-export.js +192 -0
  15. package/lib/db-import.js +193 -0
  16. package/lib/external-transition-handler.js +32 -0
  17. package/lib/git-hook-helpers.js +174 -0
  18. package/lib/git-root.js +90 -0
  19. package/lib/infrastructure-chore-generator.js +45 -0
  20. package/lib/install-hooks.js +52 -0
  21. package/lib/jettypod-backup.js +238 -0
  22. package/lib/merge-lock.js +193 -0
  23. package/lib/migrations/012-add-worktree-path.js +38 -0
  24. package/lib/migrations/013-worktrees-table.js +86 -0
  25. package/lib/migrations/014-migrate-worktree-data.js +161 -0
  26. package/lib/migrations/015-merge-locks-table.js +67 -0
  27. package/lib/pattern-finder.js +152 -0
  28. package/lib/process-manager.js +140 -0
  29. package/lib/production-standards-reader.js +13 -2
  30. package/lib/production-standards-writer.js +85 -0
  31. package/lib/skills/feature-planning/dry-run-validator.js +135 -0
  32. package/lib/skills/feature-planning/validation-formatter.js +160 -0
  33. package/lib/smart-conflict-detection.js +168 -0
  34. package/lib/smart-fetch-rebase.js +614 -0
  35. package/lib/step-definition-parser.js +76 -0
  36. package/lib/unit-test-generator.js +232 -0
  37. package/lib/verification-command-generator.js +66 -0
  38. package/lib/worktree-diagnostics.js +413 -0
  39. package/lib/worktree-facade.js +174 -0
  40. package/lib/worktree-manager.js +636 -0
  41. package/lib/worktree-reconciler.js +429 -0
  42. package/package.json +30 -3
  43. package/skills-templates/external-transition/SKILL.md +34 -3
  44. package/skills-templates/feature-planning/SKILL.md +190 -24
  45. package/skills-templates/production-mode/SKILL.md +127 -9
  46. package/skills-templates/speed-mode/SKILL.md +454 -51
  47. package/skills-templates/stable-mode/SKILL.md +285 -76
  48. package/.claude/PROTECT_SKILLS.md +0 -28
  49. package/.claude/settings.json +0 -24
  50. package/.claude/settings.local.json +0 -16
  51. package/.claude/skills/epic-planning/SKILL.md +0 -297
  52. package/.claude/skills/external-transition/SKILL.md +0 -384
  53. package/.claude/skills/feature-planning/SKILL.md +0 -464
  54. package/.claude/skills/production-mode/SKILL.md +0 -369
  55. package/.claude/skills/speed-mode/SKILL.md +0 -481
  56. package/.claude/skills/stable-mode/SKILL.md +0 -713
  57. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/epic-planning/SKILL.md +0 -297
  58. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/feature-planning/SKILL.md +0 -464
  59. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/speed-mode/SKILL.md +0 -467
  60. package/.claude/skills.backup-2025-11-10T23-33-09-368Z/stable-mode/SKILL.md +0 -673
  61. package/.claude/skills.backup-2025-11-11T16-15-10-070Z/epic-discover/SKILL.md +0 -297
  62. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/epic-planning/SKILL.md +0 -297
  63. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/feature-planning/SKILL.md +0 -464
  64. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/speed-mode/SKILL.md +0 -467
  65. package/.claude/skills.backup-2025-11-11T16-42-43-212Z/stable-mode/SKILL.md +0 -673
  66. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/epic-planning/SKILL.md +0 -297
  67. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/feature-planning/SKILL.md +0 -464
  68. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/speed-mode/SKILL.md +0 -467
  69. package/.claude/skills.backup-2025-11-11T17-06-09-783Z/stable-mode/SKILL.md +0 -673
  70. package/.devpod/current-work.json +0 -10
  71. package/.devpod/work.db +0 -0
  72. package/.github/workflows/test-safety.yml +0 -85
  73. package/.jettypod/config.json +0 -5
  74. package/.jettypod/current-work.json +0 -10
  75. package/.jettypod/hooks/README.md +0 -77
  76. package/.jettypod/hooks/protect-claude-md.js +0 -338
  77. package/.jettypod/test-work.db +0 -0
  78. package/.jettypod/work.db +0 -0
  79. package/CLAUDE.md +0 -49
  80. package/SPEED-STABLE-AUDIT.md +0 -853
  81. package/SYSTEM-BEHAVIOR.md +0 -2199
  82. package/TEST_SAFETY_AUDIT.md +0 -314
  83. package/TEST_SAFETY_IMPLEMENTATION.md +0 -97
  84. package/cucumber-report.html +0 -45
  85. package/dist/devpod-linux +0 -0
  86. package/dist/devpod-macos +0 -0
  87. package/dist/devpod-win.exe +0 -0
  88. package/docs/features/jettypod-standards-explained.md +0 -543
  89. package/docs/features/standards-inventory.md +0 -257
  90. package/features/auto-generate-production-chores.feature +0 -13
  91. package/features/backlog-command.feature +0 -26
  92. package/features/backlog-filtering-production.feature +0 -10
  93. package/features/claude-md-protection/steps.js +0 -498
  94. package/features/decisions/index.js +0 -490
  95. package/features/decisions/index.test.js +0 -208
  96. package/features/fix-text-wrapping.feature +0 -42
  97. package/features/git-hooks/git-hooks.feature +0 -30
  98. package/features/git-hooks/index.js +0 -93
  99. package/features/git-hooks/index.test.js +0 -137
  100. package/features/git-hooks/post-commit +0 -56
  101. package/features/git-hooks/post-merge +0 -47
  102. package/features/git-hooks/pre-commit +0 -28
  103. package/features/git-hooks/simple-steps.js +0 -53
  104. package/features/git-hooks/simple-test.feature +0 -10
  105. package/features/git-hooks/steps.js +0 -196
  106. package/features/jettypod-update-command.feature +0 -46
  107. package/features/mode-prompts/index.js +0 -95
  108. package/features/mode-prompts/simple-steps.js +0 -44
  109. package/features/mode-prompts/simple-test.feature +0 -9
  110. package/features/mode-prompts/validation.test.js +0 -120
  111. package/features/multiple-claude-instances.feature +0 -121
  112. package/features/production-mode-skill.feature +0 -121
  113. package/features/refactor-mode/steps.js +0 -217
  114. package/features/refactor-mode.feature +0 -49
  115. package/features/simplify-external-transition.feature +0 -166
  116. package/features/skills-update/index.test.js +0 -216
  117. package/features/step_definitions/backlog-command.steps.js +0 -37
  118. package/features/step_definitions/fix-text-wrapping.steps.js +0 -271
  119. package/features/step_definitions/multiple-claude-instances.steps.js +0 -621
  120. package/features/step_definitions/production-mode-skill.steps.js +0 -862
  121. package/features/step_definitions/simplify-external-transition.steps.js +0 -370
  122. package/features/step_definitions/terminal-logo.steps.js +0 -145
  123. package/features/step_definitions/update-command.steps.js +0 -183
  124. package/features/support/hooks.js +0 -9
  125. package/features/terminal-logo/index.js +0 -39
  126. package/features/terminal-logo/terminal-logo.feature +0 -30
  127. package/features/update-command/index.js +0 -181
  128. package/features/update-command/index.test.js +0 -225
  129. package/features/work-commands/bug-workflow-display.feature +0 -22
  130. package/features/work-commands/index.js +0 -498
  131. package/features/work-commands/simple-steps.js +0 -69
  132. package/features/work-commands/stable-tests.feature +0 -57
  133. package/features/work-commands/steps.js +0 -1174
  134. package/features/work-commands/validation.test.js +0 -88
  135. package/features/work-commands/work-commands.feature +0 -13
  136. package/features/work-tracking/discovery-validation.test.js +0 -228
  137. package/features/work-tracking/index.js +0 -1921
  138. package/features/work-tracking/mode-required.feature +0 -112
  139. package/features/work-tracking/phase-tracking.test.js +0 -482
  140. package/features/work-tracking/prototype-tracking.test.js +0 -485
  141. package/features/work-tracking/tree-view.test.js +0 -310
  142. package/features/work-tracking/work-set-mode.feature +0 -71
  143. package/features/work-tracking/work-start-mode.feature +0 -88
  144. package/full-test.txt +0 -0
  145. package/lib/bug-workflow.test.js +0 -177
  146. package/lib/claudemd.test.js +0 -195
  147. package/lib/config.test.js +0 -511
  148. package/lib/constants.test.js +0 -164
  149. package/lib/current-work.test.js +0 -146
  150. package/lib/database-project-config.test.js +0 -111
  151. package/lib/database.test.js +0 -106
  152. package/lib/decisions-generator.test.js +0 -457
  153. package/lib/decisions-helpers.test.js +0 -310
  154. package/lib/git-coordinator.js +0 -167
  155. package/lib/git.test.js +0 -145
  156. package/lib/migrations/002-default-work-item-modes.test.js +0 -351
  157. package/lib/production-chore-generator.test.js +0 -432
  158. package/lib/production-context-detector.test.js +0 -277
  159. package/lib/production-scenario-appender.test.js +0 -235
  160. package/lib/production-scenario-validator.test.js +0 -246
  161. package/lib/production-standards-reader.test.js +0 -270
  162. package/lib/project-state.test.js +0 -92
  163. package/lib/push-queue.js +0 -417
  164. package/lib/queue-processor.js +0 -74
  165. package/lib/test-helpers.js +0 -202
  166. package/lib/test-helpers.test.js +0 -255
  167. package/prototypes/2025-01-11-production-mode-autonomous.js +0 -119
  168. package/prototypes/2025-01-11-production-mode-collaborative.js +0 -166
  169. package/prototypes/2025-01-11-production-mode-guided.js +0 -217
  170. package/prototypes/2025-01-11-production-mode-smart-context.js +0 -347
  171. package/prototypes/2025-01-11-production-standards-example.md +0 -204
  172. package/prototypes/2025-11-10-backlog-filtering-tree-aware.js +0 -242
  173. package/prototypes/test/index.html +0 -1
  174. package/setup-dist-repo.sh +0 -68
  175. package/test-production-standards-engine.js +0 -130
  176. package/test-results.json +0 -2195
  177. package/test-safety-check.sh +0 -80
  178. package/work-item-tracking-plan.md +0 -199
  179. /package/{.jettypod/devpod.db → jettypod.db} +0 -0
@@ -1,42 +0,0 @@
1
- Feature: Fix Text Wrapping in Terminal Output
2
- Terminal-aware word wrapping that respects terminal width and aligns
3
- continuation lines with tree structure indentation
4
-
5
- Approach: Terminal-Aware Word-Wrap with Alignment
6
-
7
- @text-wrapping
8
- Scenario: Long titles wrap at word boundaries within terminal width
9
- Given I have a feature with a title longer than the terminal width
10
- When I run jettypod backlog with current terminal width
11
- Then the title wraps at word boundaries
12
- And continuation lines align with the content indentation
13
- And no words are split mid-character
14
-
15
- @text-wrapping
16
- Scenario: Long descriptions wrap cleanly in expanded view
17
- Given I have a feature with a long description
18
- When I run jettypod backlog --expand=1 with current terminal width
19
- Then the description wraps at word boundaries
20
- And continuation lines have proper "Description: " prefix indentation
21
- And the text fits within terminal width
22
-
23
- @text-wrapping
24
- Scenario: Tree structure preserved with wrapped text
25
- Given I have nested items with long titles
26
- When I run jettypod backlog --expand=all with current terminal width
27
- Then tree connectors (├──, └──) display correctly
28
- And wrapped continuation lines align under the item content
29
- And tree structure remains visually clear
30
-
31
- @text-wrapping
32
- Scenario: Terminal width changes are respected
33
- Given the terminal width is 120 columns
34
- And I have items with titles that wrap at 120 columns
35
- When the terminal is resized to 80 columns
36
- And I run jettypod backlog with current terminal width
37
- Then text wraps to fit 80 columns
38
- And alignment adjusts to the new width
39
-
40
- # SPEED MODE: Only happy paths above
41
- # STABLE MODE: Will add error handling (very narrow terminals, missing columns value, very long words)
42
- # PRODUCTION MODE: Will add performance testing for large backlogs
@@ -1,30 +0,0 @@
1
- Feature: Git Hook Integration
2
- As a developer
3
- I want work item status to update automatically on git operations
4
- So that I don't have to manually track progress
5
-
6
- Scenario: First commit updates status to in_progress
7
- Given I have a work item with status "todo"
8
- And the work item is set as current work
9
- When I make my first commit
10
- Then the work item status should be "in_progress"
11
-
12
- Scenario: Merge to main updates status to done
13
- Given I have a work item with status "in_progress"
14
- And the work item is set as current work
15
- And I am on a feature branch
16
- When I merge to main
17
- Then the work item status should be "done"
18
-
19
- Scenario: No current work item - hooks do nothing
20
- Given no work item is set as current
21
- When I make a commit
22
- Then no errors occur
23
-
24
- Scenario: Integration - hooks work with existing work commands
25
- Given I have initialized jettypod with git
26
- And I create a work item via work commands
27
- And I start work on the item
28
- When I commit changes
29
- Then the work item status updates automatically
30
- And the current work file still exists
@@ -1,93 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
- /**
5
- * Install JettyPod git hooks into .git/hooks directory
6
- * @returns {boolean} True if hooks installed successfully, false if not a git repo
7
- * @throws {Error} If hook files cannot be copied or made executable
8
- */
9
- function installHooks() {
10
- const gitHooksDir = path.join(process.cwd(), '.git', 'hooks');
11
- const jettypodHooksDir = path.join(__dirname);
12
-
13
- if (!fs.existsSync(gitHooksDir)) {
14
- console.log('⚠️ Not a git repository - skipping hook installation');
15
- return false;
16
- }
17
-
18
- const hooks = ['pre-commit', 'post-commit', 'post-merge'];
19
-
20
- hooks.forEach(hook => {
21
- // Check both locations: features/git-hooks and .jettypod/hooks
22
- let sourcePath = path.join(jettypodHooksDir, hook);
23
- if (!fs.existsSync(sourcePath)) {
24
- sourcePath = path.join(process.cwd(), '.jettypod', 'hooks', hook);
25
- }
26
-
27
- if (!fs.existsSync(sourcePath)) {
28
- console.log(`⚠️ Hook ${hook} not found, skipping`);
29
- return;
30
- }
31
-
32
- const targetPath = path.join(gitHooksDir, hook);
33
-
34
- try {
35
- // Read hook content and inject module path
36
- let hookContent = fs.readFileSync(sourcePath, 'utf-8');
37
-
38
- // Find the jettypod root (where node_modules is)
39
- const jettypodRoot = path.dirname(require.main.filename);
40
- const modulesPath = path.join(jettypodRoot, 'node_modules');
41
-
42
- // Inject NODE_PATH setup after shebang
43
- if (hookContent.includes('require(\'sqlite3\')')) {
44
- hookContent = hookContent.replace(
45
- '#!/usr/bin/env node',
46
- `#!/usr/bin/env node\n\n// Injected module path\nprocess.env.NODE_PATH = '${modulesPath}' + ':' + (process.env.NODE_PATH || '');require('module').Module._initPaths();`
47
- );
48
- }
49
-
50
- // Replace __JETTYPOD_ROOT__ placeholder with actual jettypod root path
51
- hookContent = hookContent.replace(/__JETTYPOD_ROOT__/g, jettypodRoot);
52
-
53
- fs.writeFileSync(targetPath, hookContent);
54
-
55
- // Make executable
56
- fs.chmodSync(targetPath, 0o755);
57
- } catch (err) {
58
- throw new Error(`Failed to install ${hook} hook: ${err.message}`);
59
- }
60
- });
61
-
62
- console.log('✓ Git hooks installed (pre-commit, post-commit, post-merge)');
63
- return true;
64
- }
65
-
66
- /**
67
- * Check if JettyPod git hooks are installed
68
- * @returns {boolean} True if hooks are installed
69
- */
70
- function areHooksInstalled() {
71
- const gitHooksDir = path.join(process.cwd(), '.git', 'hooks');
72
- if (!fs.existsSync(gitHooksDir)) {
73
- return false;
74
- }
75
-
76
- try {
77
- const postCommitPath = path.join(gitHooksDir, 'post-commit');
78
- if (!fs.existsSync(postCommitPath)) {
79
- return false;
80
- }
81
-
82
- const content = fs.readFileSync(postCommitPath, 'utf-8');
83
- return content.includes('JettyPod');
84
- } catch (err) {
85
- // If we can't read the file, assume not installed
86
- return false;
87
- }
88
- }
89
-
90
- module.exports = {
91
- installHooks,
92
- areHooksInstalled
93
- };
@@ -1,137 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const { createTestEnvironment } = require('../../lib/test-helpers');
4
- const { installHooks, areHooksInstalled } = require('./index');
5
- const { execSync } = require('child_process');
6
-
7
- describe('Git Hooks', () => {
8
- let testEnv;
9
-
10
- beforeEach(() => {
11
- testEnv = createTestEnvironment();
12
- process.chdir(testEnv.testDir);
13
- });
14
-
15
- afterEach(() => {
16
- testEnv.cleanup();
17
- });
18
-
19
- describe('installHooks()', () => {
20
- test('should return false if not a git repository', () => {
21
- const result = installHooks();
22
- expect(result).toBe(false);
23
- });
24
-
25
- test('should install hooks in git repository', () => {
26
- // Initialize git repo
27
- execSync('git init', { stdio: 'pipe' });
28
-
29
- // Create source hooks
30
- const hooksSourceDir = path.join(testEnv.testDir, 'features', 'git-hooks');
31
- fs.mkdirSync(hooksSourceDir, { recursive: true });
32
-
33
- fs.writeFileSync(path.join(hooksSourceDir, 'pre-commit'), '#!/usr/bin/env node\nconsole.log("test");');
34
- fs.writeFileSync(path.join(hooksSourceDir, 'post-commit'), '#!/usr/bin/env node\n// JettyPod hook');
35
- fs.writeFileSync(path.join(hooksSourceDir, 'post-merge'), '#!/usr/bin/env node\nconsole.log("test");');
36
-
37
- const result = installHooks();
38
-
39
- expect(result).toBe(true);
40
- expect(fs.existsSync('.git/hooks/pre-commit')).toBe(true);
41
- expect(fs.existsSync('.git/hooks/post-commit')).toBe(true);
42
- expect(fs.existsSync('.git/hooks/post-merge')).toBe(true);
43
- });
44
-
45
- test('should make hooks executable', () => {
46
- execSync('git init', { stdio: 'pipe' });
47
-
48
- const hooksSourceDir = path.join(testEnv.testDir, 'features', 'git-hooks');
49
- fs.mkdirSync(hooksSourceDir, { recursive: true });
50
-
51
- fs.writeFileSync(path.join(hooksSourceDir, 'pre-commit'), '#!/usr/bin/env node\nconsole.log("test");');
52
- fs.writeFileSync(path.join(hooksSourceDir, 'post-commit'), '#!/usr/bin/env node\n// JettyPod');
53
- fs.writeFileSync(path.join(hooksSourceDir, 'post-merge'), '#!/usr/bin/env node\nconsole.log("test");');
54
-
55
- installHooks();
56
-
57
- const preCommitPath = path.join(testEnv.testDir, '.git', 'hooks', 'pre-commit');
58
- const stats = fs.statSync(preCommitPath);
59
- // Check if executable bit is set (mode & 0o111)
60
- expect(stats.mode & 0o111).not.toBe(0);
61
- });
62
-
63
- test('should succeed when hooks exist in production directory', () => {
64
- execSync('git init', { stdio: 'pipe' });
65
-
66
- const consoleSpy = jest.spyOn(console, 'log').mockImplementation();
67
-
68
- // This will find hooks in the real features/git-hooks directory
69
- const result = installHooks();
70
-
71
- expect(result).toBe(true);
72
- consoleSpy.mockRestore();
73
- });
74
-
75
- test('should check alternate hook location (.jettypod/hooks)', () => {
76
- execSync('git init', { stdio: 'pipe' });
77
-
78
- const altHooksDir = path.join(testEnv.testDir, '.jettypod', 'hooks');
79
- fs.mkdirSync(altHooksDir, { recursive: true });
80
-
81
- fs.writeFileSync(path.join(altHooksDir, 'pre-commit'), '#!/usr/bin/env node\nconsole.log("test");');
82
- fs.writeFileSync(path.join(altHooksDir, 'post-commit'), '#!/usr/bin/env node\n// JettyPod');
83
- fs.writeFileSync(path.join(altHooksDir, 'post-merge'), '#!/usr/bin/env node\nconsole.log("test");');
84
-
85
- const result = installHooks();
86
-
87
- expect(result).toBe(true);
88
- expect(fs.existsSync('.git/hooks/post-commit')).toBe(true);
89
- });
90
- });
91
-
92
- describe('areHooksInstalled()', () => {
93
- test('should return false if not a git repository', () => {
94
- const result = areHooksInstalled();
95
- expect(result).toBe(false);
96
- });
97
-
98
- test('should return false if hooks not installed', () => {
99
- execSync('git init', { stdio: 'pipe' });
100
-
101
- const result = areHooksInstalled();
102
- expect(result).toBe(false);
103
- });
104
-
105
- test('should return true if JettyPod hooks installed', () => {
106
- execSync('git init', { stdio: 'pipe' });
107
-
108
- fs.writeFileSync('.git/hooks/post-commit', '#!/usr/bin/env node\n// JettyPod hook\nconsole.log("test");');
109
-
110
- const result = areHooksInstalled();
111
- expect(result).toBe(true);
112
- });
113
-
114
- test('should return false if hooks exist but are not JettyPod hooks', () => {
115
- execSync('git init', { stdio: 'pipe' });
116
-
117
- fs.writeFileSync('.git/hooks/post-commit', '#!/usr/bin/env node\nconsole.log("other hook");');
118
-
119
- const result = areHooksInstalled();
120
- expect(result).toBe(false);
121
- });
122
-
123
- test('should return false if hook file cannot be read', () => {
124
- execSync('git init', { stdio: 'pipe' });
125
-
126
- fs.writeFileSync('.git/hooks/post-commit', '#!/usr/bin/env node\n// JettyPod');
127
- fs.chmodSync('.git/hooks/post-commit', 0o000);
128
-
129
- const result = areHooksInstalled();
130
-
131
- // Cleanup
132
- fs.chmodSync('.git/hooks/post-commit', 0o644);
133
-
134
- expect(result).toBe(false);
135
- });
136
- });
137
- });
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // JettyPod Git Hook: post-commit
4
- // Auto-updates work item status and regenerates docs
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
- const { execSync } = require('child_process');
9
-
10
- const jettypodDir = path.join(process.cwd(), '.jettypod');
11
- const currentWorkPath = path.join(jettypodDir, 'current-work.json');
12
- const dbPath = path.join(jettypodDir, 'work.db');
13
-
14
- // Update work item status if needed
15
- (async () => {
16
- if (fs.existsSync(currentWorkPath)) {
17
- const currentWork = JSON.parse(fs.readFileSync(currentWorkPath, 'utf-8'));
18
-
19
- // Only update if status is todo
20
- if (currentWork.status === 'todo') {
21
- try {
22
- const { updateStatus } = require('../../features/work-tracking');
23
- await updateStatus(currentWork.id, 'in_progress');
24
-
25
- // Update current work file
26
- currentWork.status = 'in_progress';
27
- fs.writeFileSync(currentWorkPath, JSON.stringify(currentWork, null, 2));
28
-
29
- console.log(`\n✓ Work item #${currentWork.id} status updated: todo → in_progress`);
30
- } catch (err) {
31
- console.error('Failed to update work item:', err);
32
- }
33
- }
34
- }
35
- })();
36
-
37
- // Always generate docs on every commit
38
- generateDocs();
39
-
40
- function generateDocs() {
41
- const featuresDir = path.join(process.cwd(), 'features');
42
- const outputPath = path.join(process.cwd(), 'SYSTEM-BEHAVIOR.md');
43
-
44
- // Skip if no features directory
45
- if (!fs.existsSync(featuresDir)) {
46
- return;
47
- }
48
-
49
- try {
50
- const docsGenerator = require(path.join(process.cwd(), 'lib', 'docs-generator'));
51
- docsGenerator.generate();
52
- console.log('📚 Documentation updated');
53
- } catch (err) {
54
- // Fail silently - docs generation is optional
55
- }
56
- }
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // JettyPod Git Hook: post-merge
4
- // Auto-updates work item status to done when merging to main
5
-
6
- const fs = require('fs');
7
- const path = require('path');
8
- const { execSync } = require('child_process');
9
-
10
- const jettypodDir = path.join(process.cwd(), '.jettypod');
11
- const currentWorkPath = path.join(jettypodDir, 'current-work.json');
12
- const dbPath = path.join(jettypodDir, 'work.db');
13
-
14
- // Skip if no current work
15
- if (!fs.existsSync(currentWorkPath)) {
16
- process.exit(0);
17
- }
18
-
19
- // Check if we're on main/master
20
- let currentBranch;
21
- try {
22
- currentBranch = execSync('git branch --show-current', { encoding: 'utf-8' }).trim();
23
- } catch (e) {
24
- process.exit(0);
25
- }
26
-
27
- if (currentBranch !== 'main' && currentBranch !== 'master') {
28
- process.exit(0);
29
- }
30
-
31
- const currentWork = JSON.parse(fs.readFileSync(currentWorkPath, 'utf-8'));
32
-
33
- // Update to done using shared updateStatus (includes epic auto-close logic)
34
- (async () => {
35
- try {
36
- const { updateStatus } = require('__JETTYPOD_ROOT__/features/work-tracking');
37
- await updateStatus(currentWork.id, 'done');
38
-
39
- // Clear current work pointer since work is done
40
- fs.unlinkSync(currentWorkPath);
41
-
42
- console.log(`\n✓ Work item #${currentWork.id} status updated: → done (merged to ${currentBranch})`);
43
- } catch (err) {
44
- console.error('Failed to update work item:', err);
45
- process.exit(1);
46
- }
47
- })();
@@ -1,28 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // Pre-commit hook: Run tests before allowing commit
4
-
5
- const { execSync } = require('child_process');
6
- const fs = require('fs');
7
- const path = require('path');
8
-
9
- // Check if we're in a real project (not a test directory)
10
- const packageJsonPath = path.join(process.cwd(), 'package.json');
11
- if (!fs.existsSync(packageJsonPath)) {
12
- // Skip tests in test directories
13
- process.exit(0);
14
- }
15
-
16
- console.log('\n🧪 Running tests before commit...\n');
17
-
18
- try {
19
- // Run tests
20
- execSync('npm test', { stdio: 'inherit' });
21
-
22
- console.log('\n✅ Tests passed! Proceeding with commit.\n');
23
- process.exit(0);
24
- } catch (err) {
25
- console.log('\n❌ Tests failed! Commit blocked.\n');
26
- console.log('Fix the failing tests or use --no-verify to skip this check.\n');
27
- process.exit(1);
28
- }
@@ -1,53 +0,0 @@
1
- const { Given, When, Then } = require('@cucumber/cucumber');
2
- const assert = require('assert');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const { execSync } = require('child_process');
6
- const sqlite3 = require('sqlite3').verbose();
7
-
8
- const testDir = path.join('/tmp', 'hooks-simple-' + Date.now());
9
- const dbFileName = process.env.NODE_ENV === 'test' ? 'test-work.db' : 'work.db';
10
- let originalDir;
11
- let workItemId;
12
-
13
- Given('I initialize a git repo with jettypod', function () {
14
- originalDir = process.cwd();
15
- // SAFETY: Only delete if testDir is in /tmp
16
- if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
17
- fs.rmSync(testDir, { recursive: true, force: true });
18
- }
19
- fs.mkdirSync(testDir, { recursive: true });
20
- process.chdir(testDir);
21
-
22
- execSync('git init', { stdio: 'pipe' });
23
- execSync('git config user.email "test@test.com"', { stdio: 'pipe' });
24
- execSync('git config user.name "Test"', { stdio: 'pipe' });
25
- execSync(`node ${path.join(originalDir, 'jettypod.js')} init`, { stdio: 'pipe', env: { ...process.env, NODE_ENV: 'test' } });
26
- });
27
-
28
- Given('I create and start work on a todo item', function () {
29
- execSync(`node ${path.join(originalDir, 'jettypod.js')} work create feature "Test"`, { stdio: 'pipe', env: { ...process.env, NODE_ENV: 'test' } });
30
- execSync(`node ${path.join(originalDir, 'jettypod.js')} work status 1 todo`, { stdio: 'pipe', env: { ...process.env, NODE_ENV: 'test' } });
31
- execSync(`node ${path.join(originalDir, 'jettypod.js')} work start 1`, { stdio: 'pipe', env: { ...process.env, NODE_ENV: 'test' } });
32
- workItemId = 1;
33
- });
34
-
35
- Then('the hook updates status to in_progress', function () {
36
- const dbPath = path.join(testDir, '.jettypod', dbFileName);
37
- const db = new sqlite3.Database(dbPath);
38
-
39
- return new Promise((resolve) => {
40
- db.get(`SELECT status FROM work_items WHERE id = ?`, [workItemId], (err, row) => {
41
- db.close();
42
- assert.strictEqual(row.status, 'in_progress');
43
-
44
- // Cleanup
45
- if (fs.existsSync(testDir)) {
46
- process.chdir(originalDir);
47
- fs.rmSync(testDir, { recursive: true, force: true });
48
- }
49
-
50
- resolve();
51
- });
52
- });
53
- });
@@ -1,10 +0,0 @@
1
- Feature: Git Hooks Integration
2
- As a developer
3
- I want work item status to auto-update on commits
4
- So I don't manually track progress
5
-
6
- Scenario: Integration - post-commit hook updates status
7
- Given I initialize a git repo with jettypod
8
- And I create and start work on a todo item
9
- When I make a commit
10
- Then the hook updates status to in_progress