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,270 +0,0 @@
1
- const {
2
- readStandards,
3
- validateStandardsFormat,
4
- getStandardsByDomain,
5
- standardsFileExists,
6
- getDomains
7
- } = require('./production-standards-reader');
8
- const fs = require('fs');
9
- const path = require('path');
10
-
11
- describe('production-standards-reader', () => {
12
- let testDir;
13
-
14
- beforeEach(() => {
15
- // Create test directory
16
- testDir = path.join(__dirname, '../test-tmp', `standards-reader-${Date.now()}`);
17
- fs.mkdirSync(testDir, { recursive: true });
18
- fs.mkdirSync(path.join(testDir, '.jettypod'), { recursive: true });
19
- process.chdir(testDir);
20
- });
21
-
22
- afterEach(() => {
23
- if (testDir && fs.existsSync(testDir)) {
24
- fs.rmSync(testDir, { recursive: true, force: true });
25
- }
26
- });
27
-
28
- describe('standardsFileExists', () => {
29
- test('returns false when file does not exist', () => {
30
- expect(standardsFileExists()).toBe(false);
31
- });
32
-
33
- test('returns true when file exists', () => {
34
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
35
- fs.writeFileSync(standardsPath, '{}');
36
-
37
- expect(standardsFileExists()).toBe(true);
38
- });
39
- });
40
-
41
- describe('readStandards', () => {
42
- test('throws error when file does not exist', async () => {
43
- await expect(readStandards()).rejects.toThrow('Production standards file not found');
44
- });
45
-
46
- test('throws error when file has invalid JSON', async () => {
47
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
48
- fs.writeFileSync(standardsPath, 'invalid json');
49
-
50
- await expect(readStandards()).rejects.toThrow('Failed to read production standards');
51
- });
52
-
53
- test('reads and returns valid standards', async () => {
54
- const standards = {
55
- preset: 'production-saas',
56
- refinement: {
57
- app_description: 'Test app'
58
- },
59
- standards: [
60
- {
61
- id: 'tls_enforced',
62
- domain: 'security',
63
- acceptance: 'HSTS ≥ 6mo; TLS ≥1.2'
64
- }
65
- ]
66
- };
67
-
68
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
69
- fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
70
-
71
- const result = await readStandards();
72
-
73
- expect(result).toEqual(standards);
74
- expect(result.preset).toBe('production-saas');
75
- expect(result.standards).toHaveLength(1);
76
- });
77
- });
78
-
79
- describe('validateStandardsFormat', () => {
80
- test('throws error when standards is null', () => {
81
- expect(() => validateStandardsFormat(null)).toThrow('Standards object is null or undefined');
82
- });
83
-
84
- test('throws error when missing preset field', () => {
85
- const standards = {
86
- standards: []
87
- };
88
-
89
- expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: preset');
90
- });
91
-
92
- test('throws error when missing standards array', () => {
93
- const standards = {
94
- preset: 'production-saas'
95
- };
96
-
97
- expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: standards (array)');
98
- });
99
-
100
- test('throws error when standards is not an array', () => {
101
- const standards = {
102
- preset: 'production-saas',
103
- standards: 'not an array'
104
- };
105
-
106
- expect(() => validateStandardsFormat(standards)).toThrow('Standards missing required field: standards (array)');
107
- });
108
-
109
- test('throws error when standard missing id', () => {
110
- const standards = {
111
- preset: 'production-saas',
112
- standards: [
113
- {
114
- domain: 'security',
115
- acceptance: 'test'
116
- }
117
- ]
118
- };
119
-
120
- expect(() => validateStandardsFormat(standards)).toThrow('Standard missing required field: id');
121
- });
122
-
123
- test('throws error when standard missing domain', () => {
124
- const standards = {
125
- preset: 'production-saas',
126
- standards: [
127
- {
128
- id: 'test_standard',
129
- acceptance: 'test'
130
- }
131
- ]
132
- };
133
-
134
- expect(() => validateStandardsFormat(standards)).toThrow('Standard test_standard missing required field: domain');
135
- });
136
-
137
- test('throws error when standard missing acceptance', () => {
138
- const standards = {
139
- preset: 'production-saas',
140
- standards: [
141
- {
142
- id: 'test_standard',
143
- domain: 'security'
144
- }
145
- ]
146
- };
147
-
148
- expect(() => validateStandardsFormat(standards)).toThrow('Standard test_standard missing required field: acceptance');
149
- });
150
-
151
- test('validates correct format successfully', () => {
152
- const standards = {
153
- preset: 'production-saas',
154
- standards: [
155
- {
156
- id: 'test_standard',
157
- domain: 'security',
158
- acceptance: 'test criteria'
159
- }
160
- ]
161
- };
162
-
163
- expect(() => validateStandardsFormat(standards)).not.toThrow();
164
- });
165
- });
166
-
167
- describe('getStandardsByDomain', () => {
168
- test('returns empty array when no standards match domain', async () => {
169
- const standards = {
170
- preset: 'production-saas',
171
- standards: [
172
- {
173
- id: 'test1',
174
- domain: 'security',
175
- acceptance: 'test'
176
- }
177
- ]
178
- };
179
-
180
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
181
- fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
182
-
183
- const result = await getStandardsByDomain('performance');
184
- expect(result).toEqual([]);
185
- });
186
-
187
- test('returns standards for specified domain', async () => {
188
- const standards = {
189
- preset: 'production-saas',
190
- standards: [
191
- {
192
- id: 'test1',
193
- domain: 'security',
194
- acceptance: 'test'
195
- },
196
- {
197
- id: 'test2',
198
- domain: 'performance',
199
- acceptance: 'test'
200
- },
201
- {
202
- id: 'test3',
203
- domain: 'security',
204
- acceptance: 'test2'
205
- }
206
- ]
207
- };
208
-
209
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
210
- fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
211
-
212
- const result = await getStandardsByDomain('security');
213
- expect(result).toHaveLength(2);
214
- expect(result[0].id).toBe('test1');
215
- expect(result[1].id).toBe('test3');
216
- });
217
- });
218
-
219
- describe('getDomains', () => {
220
- test('returns empty array when no standards exist', async () => {
221
- const standards = {
222
- preset: 'production-saas',
223
- standards: []
224
- };
225
-
226
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
227
- fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
228
-
229
- const result = await getDomains();
230
- expect(result).toEqual([]);
231
- });
232
-
233
- test('returns unique domain names', async () => {
234
- const standards = {
235
- preset: 'production-saas',
236
- standards: [
237
- {
238
- id: 'test1',
239
- domain: 'security',
240
- acceptance: 'test'
241
- },
242
- {
243
- id: 'test2',
244
- domain: 'performance',
245
- acceptance: 'test'
246
- },
247
- {
248
- id: 'test3',
249
- domain: 'security',
250
- acceptance: 'test2'
251
- },
252
- {
253
- id: 'test4',
254
- domain: 'compliance',
255
- acceptance: 'test'
256
- }
257
- ]
258
- };
259
-
260
- const standardsPath = path.join(testDir, '.jettypod', 'production-standards.json');
261
- fs.writeFileSync(standardsPath, JSON.stringify(standards, null, 2));
262
-
263
- const result = await getDomains();
264
- expect(result).toHaveLength(3);
265
- expect(result).toContain('security');
266
- expect(result).toContain('performance');
267
- expect(result).toContain('compliance');
268
- });
269
- });
270
- });
@@ -1,92 +0,0 @@
1
- const config = require('./config');
2
- const fs = require('fs');
3
- const path = require('path');
4
-
5
- describe('Project State', () => {
6
- const testDir = path.join('/tmp', 'jettypod-project-state-test-' + Date.now());
7
- const testConfigPath = path.join(testDir, 'config.json');
8
- const originalPath = config.path;
9
-
10
- beforeEach(() => {
11
- config.path = testConfigPath;
12
- // SAFETY: Only delete if testDir is in /tmp
13
- if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
14
- fs.rmSync(testDir, { recursive: true });
15
- }
16
- fs.mkdirSync(testDir, { recursive: true });
17
- });
18
-
19
- afterEach(() => {
20
- config.path = originalPath;
21
- // SAFETY: Only delete if testDir is in /tmp
22
- if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
23
- fs.rmSync(testDir, { recursive: true });
24
- }
25
- });
26
-
27
- describe('isValidProjectState', () => {
28
- it('should accept "internal" as valid', () => {
29
- expect(config.isValidProjectState('internal')).toBe(true);
30
- });
31
-
32
- it('should accept "external" as valid', () => {
33
- expect(config.isValidProjectState('external')).toBe(true);
34
- });
35
-
36
- it('should reject invalid values', () => {
37
- expect(config.isValidProjectState('production')).toBe(false);
38
- expect(config.isValidProjectState('invalid')).toBe(false);
39
- expect(config.isValidProjectState('')).toBe(false);
40
- });
41
- });
42
-
43
- describe('read', () => {
44
- it('should default project_state to "external" if not exists', () => {
45
- const data = config.read();
46
- expect(data.project_state).toBe('external');
47
- });
48
-
49
- it('should default project_state to "external" if invalid value in file', () => {
50
- fs.mkdirSync(testDir, { recursive: true });
51
- fs.writeFileSync(testConfigPath, JSON.stringify({ name: 'test', project_state: 'invalid' }));
52
-
53
- const data = config.read();
54
- expect(data.project_state).toBe('external');
55
- });
56
-
57
- it('should preserve valid project_state from file', () => {
58
- fs.mkdirSync(testDir, { recursive: true });
59
- fs.writeFileSync(testConfigPath, JSON.stringify({ name: 'test', project_state: 'external' }));
60
-
61
- const data = config.read();
62
- expect(data.project_state).toBe('external');
63
- });
64
- });
65
-
66
- describe('update', () => {
67
- it('should update project_state to external', () => {
68
- config.write({ name: 'test', project_state: 'internal' });
69
- config.update({ project_state: 'external' });
70
-
71
- const data = config.read();
72
- expect(data.project_state).toBe('external');
73
- });
74
-
75
- it('should reject invalid project_state', () => {
76
- config.write({ name: 'test', project_state: 'internal' });
77
-
78
- expect(() => {
79
- config.update({ project_state: 'invalid' });
80
- }).toThrow('Invalid project_state: invalid');
81
- });
82
-
83
- it('should allow updating other fields without affecting project_state', () => {
84
- config.write({ name: 'test', project_state: 'internal' });
85
- config.update({ description: 'Test project' });
86
-
87
- const data = config.read();
88
- expect(data.project_state).toBe('internal');
89
- expect(data.description).toBe('Test project');
90
- });
91
- });
92
- });