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.
- package/.nvmrc +1 -0
- package/docs/COMPLETE-TESTING-STRATEGY.md +970 -0
- package/docs/DECISIONS.md +10 -12
- package/docs/NODE_VERSION.md +83 -0
- package/docs/TDD-INFRASTRUCTURE-STRATEGY.md +1374 -0
- package/docs/TESTING-FOR-NON-ENGINEERS.md +1588 -0
- package/docs/TESTING-STRATEGY-AUDIT.md +698 -0
- package/hooks/post-checkout +17 -0
- package/hooks/post-merge +17 -0
- package/hooks/pre-commit +30 -0
- package/jettypod.js +259 -120
- package/lib/coverage-tracker.js +218 -0
- package/lib/database.js +2 -0
- package/lib/db-export.js +192 -0
- package/lib/db-import.js +193 -0
- package/lib/external-transition-handler.js +32 -0
- package/lib/git-hook-helpers.js +174 -0
- package/lib/git-root.js +90 -0
- package/lib/infrastructure-chore-generator.js +45 -0
- package/lib/install-hooks.js +52 -0
- package/lib/jettypod-backup.js +238 -0
- package/lib/merge-lock.js +193 -0
- package/lib/migrations/012-add-worktree-path.js +38 -0
- package/lib/migrations/013-worktrees-table.js +86 -0
- package/lib/migrations/014-migrate-worktree-data.js +161 -0
- package/lib/migrations/015-merge-locks-table.js +67 -0
- package/lib/pattern-finder.js +152 -0
- package/lib/process-manager.js +140 -0
- package/lib/production-standards-reader.js +13 -2
- package/lib/production-standards-writer.js +85 -0
- package/lib/skills/feature-planning/dry-run-validator.js +135 -0
- package/lib/skills/feature-planning/validation-formatter.js +160 -0
- package/lib/smart-conflict-detection.js +168 -0
- package/lib/smart-fetch-rebase.js +614 -0
- package/lib/step-definition-parser.js +76 -0
- package/lib/unit-test-generator.js +232 -0
- package/lib/verification-command-generator.js +66 -0
- package/lib/worktree-diagnostics.js +413 -0
- package/lib/worktree-facade.js +174 -0
- package/lib/worktree-manager.js +636 -0
- package/lib/worktree-reconciler.js +429 -0
- package/package.json +30 -3
- package/skills-templates/external-transition/SKILL.md +34 -3
- package/skills-templates/feature-planning/SKILL.md +190 -24
- package/skills-templates/production-mode/SKILL.md +127 -9
- package/skills-templates/speed-mode/SKILL.md +454 -51
- package/skills-templates/stable-mode/SKILL.md +285 -76
- package/.claude/PROTECT_SKILLS.md +0 -28
- package/.claude/settings.json +0 -24
- package/.claude/settings.local.json +0 -16
- package/.claude/skills/epic-planning/SKILL.md +0 -297
- package/.claude/skills/external-transition/SKILL.md +0 -384
- package/.claude/skills/feature-planning/SKILL.md +0 -464
- package/.claude/skills/production-mode/SKILL.md +0 -369
- package/.claude/skills/speed-mode/SKILL.md +0 -481
- package/.claude/skills/stable-mode/SKILL.md +0 -713
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-10T23-33-09-368Z/stable-mode/SKILL.md +0 -673
- package/.claude/skills.backup-2025-11-11T16-15-10-070Z/epic-discover/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-11T16-42-43-212Z/stable-mode/SKILL.md +0 -673
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/epic-planning/SKILL.md +0 -297
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/feature-planning/SKILL.md +0 -464
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/speed-mode/SKILL.md +0 -467
- package/.claude/skills.backup-2025-11-11T17-06-09-783Z/stable-mode/SKILL.md +0 -673
- package/.devpod/current-work.json +0 -10
- package/.devpod/work.db +0 -0
- package/.github/workflows/test-safety.yml +0 -85
- package/.jettypod/config.json +0 -5
- package/.jettypod/current-work.json +0 -10
- package/.jettypod/hooks/README.md +0 -77
- package/.jettypod/hooks/protect-claude-md.js +0 -338
- package/.jettypod/test-work.db +0 -0
- package/.jettypod/work.db +0 -0
- package/CLAUDE.md +0 -49
- package/SPEED-STABLE-AUDIT.md +0 -853
- package/SYSTEM-BEHAVIOR.md +0 -2199
- package/TEST_SAFETY_AUDIT.md +0 -314
- package/TEST_SAFETY_IMPLEMENTATION.md +0 -97
- package/cucumber-report.html +0 -45
- package/dist/devpod-linux +0 -0
- package/dist/devpod-macos +0 -0
- package/dist/devpod-win.exe +0 -0
- package/docs/features/jettypod-standards-explained.md +0 -543
- package/docs/features/standards-inventory.md +0 -257
- package/features/auto-generate-production-chores.feature +0 -13
- package/features/backlog-command.feature +0 -26
- package/features/backlog-filtering-production.feature +0 -10
- package/features/claude-md-protection/steps.js +0 -498
- package/features/decisions/index.js +0 -490
- package/features/decisions/index.test.js +0 -208
- package/features/fix-text-wrapping.feature +0 -42
- package/features/git-hooks/git-hooks.feature +0 -30
- package/features/git-hooks/index.js +0 -93
- package/features/git-hooks/index.test.js +0 -137
- package/features/git-hooks/post-commit +0 -56
- package/features/git-hooks/post-merge +0 -47
- package/features/git-hooks/pre-commit +0 -28
- package/features/git-hooks/simple-steps.js +0 -53
- package/features/git-hooks/simple-test.feature +0 -10
- package/features/git-hooks/steps.js +0 -196
- package/features/jettypod-update-command.feature +0 -46
- package/features/mode-prompts/index.js +0 -95
- package/features/mode-prompts/simple-steps.js +0 -44
- package/features/mode-prompts/simple-test.feature +0 -9
- package/features/mode-prompts/validation.test.js +0 -120
- package/features/multiple-claude-instances.feature +0 -121
- package/features/production-mode-skill.feature +0 -121
- package/features/refactor-mode/steps.js +0 -217
- package/features/refactor-mode.feature +0 -49
- package/features/simplify-external-transition.feature +0 -166
- package/features/skills-update/index.test.js +0 -216
- package/features/step_definitions/backlog-command.steps.js +0 -37
- package/features/step_definitions/fix-text-wrapping.steps.js +0 -271
- package/features/step_definitions/multiple-claude-instances.steps.js +0 -621
- package/features/step_definitions/production-mode-skill.steps.js +0 -862
- package/features/step_definitions/simplify-external-transition.steps.js +0 -370
- package/features/step_definitions/terminal-logo.steps.js +0 -145
- package/features/step_definitions/update-command.steps.js +0 -183
- package/features/support/hooks.js +0 -9
- package/features/terminal-logo/index.js +0 -39
- package/features/terminal-logo/terminal-logo.feature +0 -30
- package/features/update-command/index.js +0 -181
- package/features/update-command/index.test.js +0 -225
- package/features/work-commands/bug-workflow-display.feature +0 -22
- package/features/work-commands/index.js +0 -498
- package/features/work-commands/simple-steps.js +0 -69
- package/features/work-commands/stable-tests.feature +0 -57
- package/features/work-commands/steps.js +0 -1174
- package/features/work-commands/validation.test.js +0 -88
- package/features/work-commands/work-commands.feature +0 -13
- package/features/work-tracking/discovery-validation.test.js +0 -228
- package/features/work-tracking/index.js +0 -1921
- package/features/work-tracking/mode-required.feature +0 -112
- package/features/work-tracking/phase-tracking.test.js +0 -482
- package/features/work-tracking/prototype-tracking.test.js +0 -485
- package/features/work-tracking/tree-view.test.js +0 -310
- package/features/work-tracking/work-set-mode.feature +0 -71
- package/features/work-tracking/work-start-mode.feature +0 -88
- package/full-test.txt +0 -0
- package/lib/bug-workflow.test.js +0 -177
- package/lib/claudemd.test.js +0 -195
- package/lib/config.test.js +0 -511
- package/lib/constants.test.js +0 -164
- package/lib/current-work.test.js +0 -146
- package/lib/database-project-config.test.js +0 -111
- package/lib/database.test.js +0 -106
- package/lib/decisions-generator.test.js +0 -457
- package/lib/decisions-helpers.test.js +0 -310
- package/lib/git-coordinator.js +0 -167
- package/lib/git.test.js +0 -145
- package/lib/migrations/002-default-work-item-modes.test.js +0 -351
- package/lib/production-chore-generator.test.js +0 -432
- package/lib/production-context-detector.test.js +0 -277
- package/lib/production-scenario-appender.test.js +0 -235
- package/lib/production-scenario-validator.test.js +0 -246
- package/lib/production-standards-reader.test.js +0 -270
- package/lib/project-state.test.js +0 -92
- package/lib/push-queue.js +0 -417
- package/lib/queue-processor.js +0 -74
- package/lib/test-helpers.js +0 -202
- package/lib/test-helpers.test.js +0 -255
- package/prototypes/2025-01-11-production-mode-autonomous.js +0 -119
- package/prototypes/2025-01-11-production-mode-collaborative.js +0 -166
- package/prototypes/2025-01-11-production-mode-guided.js +0 -217
- package/prototypes/2025-01-11-production-mode-smart-context.js +0 -347
- package/prototypes/2025-01-11-production-standards-example.md +0 -204
- package/prototypes/2025-11-10-backlog-filtering-tree-aware.js +0 -242
- package/prototypes/test/index.html +0 -1
- package/setup-dist-repo.sh +0 -68
- package/test-production-standards-engine.js +0 -130
- package/test-results.json +0 -2195
- package/test-safety-check.sh +0 -80
- package/work-item-tracking-plan.md +0 -199
- /package/{.jettypod/devpod.db → jettypod.db} +0 -0
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
// Tests for tree view validation and error handling
|
|
2
|
-
// These tests focus on the printTree and getTree functions' error handling
|
|
3
|
-
// rather than full integration tests
|
|
4
|
-
|
|
5
|
-
describe('Tree View - Error Handling', () => {
|
|
6
|
-
describe('printTree validation', () => {
|
|
7
|
-
const originalConsoleLog = console.log;
|
|
8
|
-
let logOutput = [];
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
logOutput = [];
|
|
12
|
-
console.log = jest.fn((...args) => {
|
|
13
|
-
logOutput.push(args.join(' '));
|
|
14
|
-
});
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
afterEach(() => {
|
|
18
|
-
console.log = originalConsoleLog;
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
function printTree(items, prefix = '') {
|
|
22
|
-
if (!Array.isArray(items)) {
|
|
23
|
-
throw new Error('Items must be an array');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
items.forEach((item, index) => {
|
|
27
|
-
if (!item || typeof item !== 'object') {
|
|
28
|
-
return; // Skip invalid items
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Print item (simplified for tests)
|
|
32
|
-
console.log(`${prefix}${item.title}`);
|
|
33
|
-
|
|
34
|
-
// Print description if present
|
|
35
|
-
if (item.description) {
|
|
36
|
-
console.log(`${prefix} "${item.description}"`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (item.children && item.children.length > 0) {
|
|
40
|
-
const newPrefix = prefix + ' ';
|
|
41
|
-
printTree(item.children, newPrefix);
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
test('should throw error for null input', () => {
|
|
47
|
-
expect(() => printTree(null)).toThrow('Items must be an array');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
test('should throw error for string input', () => {
|
|
51
|
-
expect(() => printTree('not-an-array')).toThrow('Items must be an array');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('should throw error for object input', () => {
|
|
55
|
-
expect(() => printTree({})).toThrow('Items must be an array');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('should not throw for empty array', () => {
|
|
59
|
-
expect(() => printTree([])).not.toThrow();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('should handle single valid item', () => {
|
|
63
|
-
const items = [{
|
|
64
|
-
id: 1,
|
|
65
|
-
title: 'Test',
|
|
66
|
-
type: 'feature',
|
|
67
|
-
status: 'backlog',
|
|
68
|
-
children: []
|
|
69
|
-
}];
|
|
70
|
-
expect(() => printTree(items)).not.toThrow();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('should handle nested items', () => {
|
|
74
|
-
const items = [{
|
|
75
|
-
id: 1,
|
|
76
|
-
title: 'Epic',
|
|
77
|
-
type: 'epic',
|
|
78
|
-
status: 'backlog',
|
|
79
|
-
children: [{
|
|
80
|
-
id: 2,
|
|
81
|
-
title: 'Feature',
|
|
82
|
-
type: 'feature',
|
|
83
|
-
status: 'backlog',
|
|
84
|
-
children: []
|
|
85
|
-
}]
|
|
86
|
-
}];
|
|
87
|
-
expect(() => printTree(items)).not.toThrow();
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test('should skip null items in array', () => {
|
|
91
|
-
const items = [
|
|
92
|
-
null,
|
|
93
|
-
{
|
|
94
|
-
id: 1,
|
|
95
|
-
title: 'Valid',
|
|
96
|
-
type: 'feature',
|
|
97
|
-
status: 'backlog',
|
|
98
|
-
children: []
|
|
99
|
-
}
|
|
100
|
-
];
|
|
101
|
-
expect(() => printTree(items)).not.toThrow();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test('should skip undefined items in array', () => {
|
|
105
|
-
const items = [
|
|
106
|
-
undefined,
|
|
107
|
-
{
|
|
108
|
-
id: 1,
|
|
109
|
-
title: 'Valid',
|
|
110
|
-
type: 'feature',
|
|
111
|
-
status: 'backlog',
|
|
112
|
-
children: []
|
|
113
|
-
}
|
|
114
|
-
];
|
|
115
|
-
expect(() => printTree(items)).not.toThrow();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('should handle items without children property', () => {
|
|
119
|
-
const items = [{
|
|
120
|
-
id: 1,
|
|
121
|
-
title: 'Test',
|
|
122
|
-
type: 'feature',
|
|
123
|
-
status: 'backlog'
|
|
124
|
-
// no children property
|
|
125
|
-
}];
|
|
126
|
-
expect(() => printTree(items)).not.toThrow();
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
test('should handle deeply nested structures', () => {
|
|
130
|
-
const items = [{
|
|
131
|
-
id: 1,
|
|
132
|
-
title: 'Level 1',
|
|
133
|
-
children: [{
|
|
134
|
-
id: 2,
|
|
135
|
-
title: 'Level 2',
|
|
136
|
-
children: [{
|
|
137
|
-
id: 3,
|
|
138
|
-
title: 'Level 3',
|
|
139
|
-
children: []
|
|
140
|
-
}]
|
|
141
|
-
}]
|
|
142
|
-
}];
|
|
143
|
-
expect(() => printTree(items)).not.toThrow();
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
test('should display description when present', () => {
|
|
147
|
-
const items = [{
|
|
148
|
-
id: 1,
|
|
149
|
-
title: 'Test Item',
|
|
150
|
-
type: 'feature',
|
|
151
|
-
status: 'backlog',
|
|
152
|
-
description: 'Test description',
|
|
153
|
-
children: []
|
|
154
|
-
}];
|
|
155
|
-
printTree(items);
|
|
156
|
-
expect(logOutput).toContain('Test Item');
|
|
157
|
-
expect(logOutput).toContain(' "Test description"');
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
test('should not break when description is missing', () => {
|
|
161
|
-
const items = [{
|
|
162
|
-
id: 1,
|
|
163
|
-
title: 'No Description',
|
|
164
|
-
type: 'feature',
|
|
165
|
-
status: 'backlog',
|
|
166
|
-
children: []
|
|
167
|
-
}];
|
|
168
|
-
expect(() => printTree(items)).not.toThrow();
|
|
169
|
-
expect(logOutput).toContain('No Description');
|
|
170
|
-
expect(logOutput).not.toContain('""');
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test('should handle empty string description', () => {
|
|
174
|
-
const items = [{
|
|
175
|
-
id: 1,
|
|
176
|
-
title: 'Empty Description',
|
|
177
|
-
type: 'feature',
|
|
178
|
-
status: 'backlog',
|
|
179
|
-
description: '',
|
|
180
|
-
children: []
|
|
181
|
-
}];
|
|
182
|
-
expect(() => printTree(items)).not.toThrow();
|
|
183
|
-
expect(logOutput).toContain('Empty Description');
|
|
184
|
-
// Empty string is falsy, so description should not display
|
|
185
|
-
expect(logOutput).not.toContain('""');
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
test('should display descriptions for nested items', () => {
|
|
189
|
-
const items = [{
|
|
190
|
-
id: 1,
|
|
191
|
-
title: 'Parent',
|
|
192
|
-
description: 'Parent description',
|
|
193
|
-
children: [{
|
|
194
|
-
id: 2,
|
|
195
|
-
title: 'Child',
|
|
196
|
-
description: 'Child description',
|
|
197
|
-
children: []
|
|
198
|
-
}]
|
|
199
|
-
}];
|
|
200
|
-
printTree(items);
|
|
201
|
-
expect(logOutput).toContain('Parent');
|
|
202
|
-
expect(logOutput).toContain(' "Parent description"');
|
|
203
|
-
expect(logOutput).toContain(' Child');
|
|
204
|
-
expect(logOutput).toContain(' "Child description"');
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
describe('getTree error handling', () => {
|
|
209
|
-
test('should build tree from flat structure', () => {
|
|
210
|
-
const rows = [
|
|
211
|
-
{ id: 1, title: 'Epic', type: 'epic', status: 'backlog', parent_id: null, epic_id: 1 },
|
|
212
|
-
{ id: 2, title: 'Feature', type: 'feature', status: 'backlog', parent_id: 1, epic_id: 1 }
|
|
213
|
-
];
|
|
214
|
-
|
|
215
|
-
const itemsById = {};
|
|
216
|
-
const rootItems = [];
|
|
217
|
-
|
|
218
|
-
// Build lookup
|
|
219
|
-
rows.forEach(item => {
|
|
220
|
-
itemsById[item.id] = item;
|
|
221
|
-
item.children = [];
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// Build tree
|
|
225
|
-
rows.forEach(item => {
|
|
226
|
-
if (item.parent_id && itemsById[item.parent_id]) {
|
|
227
|
-
itemsById[item.parent_id].children.push(item);
|
|
228
|
-
} else if (!item.parent_id) {
|
|
229
|
-
rootItems.push(item);
|
|
230
|
-
}
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
expect(rootItems).toHaveLength(1);
|
|
234
|
-
expect(rootItems[0].id).toBe(1);
|
|
235
|
-
expect(rootItems[0].children).toHaveLength(1);
|
|
236
|
-
expect(rootItems[0].children[0].id).toBe(2);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
test('should handle empty rows array', () => {
|
|
240
|
-
const rows = [];
|
|
241
|
-
const itemsById = {};
|
|
242
|
-
const rootItems = [];
|
|
243
|
-
|
|
244
|
-
rows.forEach(item => {
|
|
245
|
-
itemsById[item.id] = item;
|
|
246
|
-
item.children = [];
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
rows.forEach(item => {
|
|
250
|
-
if (item.parent_id && itemsById[item.parent_id]) {
|
|
251
|
-
itemsById[item.parent_id].children.push(item);
|
|
252
|
-
} else if (!item.parent_id) {
|
|
253
|
-
rootItems.push(item);
|
|
254
|
-
}
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
expect(rootItems).toEqual([]);
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
test('should handle orphaned items (missing parent)', () => {
|
|
261
|
-
const rows = [
|
|
262
|
-
{ id: 1, title: 'Orphan', type: 'feature', status: 'backlog', parent_id: 999, epic_id: null }
|
|
263
|
-
];
|
|
264
|
-
|
|
265
|
-
const itemsById = {};
|
|
266
|
-
const rootItems = [];
|
|
267
|
-
|
|
268
|
-
rows.forEach(item => {
|
|
269
|
-
itemsById[item.id] = item;
|
|
270
|
-
item.children = [];
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
rows.forEach(item => {
|
|
274
|
-
if (item.parent_id && itemsById[item.parent_id]) {
|
|
275
|
-
itemsById[item.parent_id].children.push(item);
|
|
276
|
-
} else if (!item.parent_id) {
|
|
277
|
-
rootItems.push(item);
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
// Orphaned item (has parent_id but parent doesn't exist) is not added to rootItems
|
|
282
|
-
expect(rootItems).toHaveLength(0);
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
test('should handle multiple root items', () => {
|
|
286
|
-
const rows = [
|
|
287
|
-
{ id: 1, title: 'Epic 1', type: 'epic', status: 'backlog', parent_id: null, epic_id: 1 },
|
|
288
|
-
{ id: 2, title: 'Epic 2', type: 'epic', status: 'backlog', parent_id: null, epic_id: 2 }
|
|
289
|
-
];
|
|
290
|
-
|
|
291
|
-
const itemsById = {};
|
|
292
|
-
const rootItems = [];
|
|
293
|
-
|
|
294
|
-
rows.forEach(item => {
|
|
295
|
-
itemsById[item.id] = item;
|
|
296
|
-
item.children = [];
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
rows.forEach(item => {
|
|
300
|
-
if (item.parent_id && itemsById[item.parent_id]) {
|
|
301
|
-
itemsById[item.parent_id].children.push(item);
|
|
302
|
-
} else if (!item.parent_id) {
|
|
303
|
-
rootItems.push(item);
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
expect(rootItems).toHaveLength(2);
|
|
308
|
-
});
|
|
309
|
-
});
|
|
310
|
-
});
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
Feature: Work set-mode updates CLAUDE.md if item is current
|
|
2
|
-
As a developer
|
|
3
|
-
I want to change a work item's mode with jettypod work set-mode
|
|
4
|
-
So I can adjust my approach without recreating the work item
|
|
5
|
-
|
|
6
|
-
Background:
|
|
7
|
-
Given jettypod is initialized
|
|
8
|
-
And CLAUDE.md exists
|
|
9
|
-
|
|
10
|
-
# Basic mode changes
|
|
11
|
-
Scenario: Set mode on current work item updates CLAUDE.md
|
|
12
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
13
|
-
And I start work on the feature
|
|
14
|
-
And CLAUDE.md mode is set to "speed"
|
|
15
|
-
When I set mode for current item to "stable"
|
|
16
|
-
Then the work item has mode "stable"
|
|
17
|
-
And CLAUDE.md mode is set to "stable"
|
|
18
|
-
|
|
19
|
-
Scenario: Set mode on non-current item does not update CLAUDE.md
|
|
20
|
-
Given I create a feature "Item 1" with mode "speed"
|
|
21
|
-
And I create a feature "Item 2" with mode "discovery"
|
|
22
|
-
And I start work on the feature "Item 1"
|
|
23
|
-
And CLAUDE.md mode is set to "speed"
|
|
24
|
-
When I set mode for item "Item 2" to "stable"
|
|
25
|
-
Then item "Item 2" has mode "stable"
|
|
26
|
-
But CLAUDE.md mode is set to "speed"
|
|
27
|
-
|
|
28
|
-
# Mode validation
|
|
29
|
-
Scenario: Set invalid mode shows error
|
|
30
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
31
|
-
When I try to set mode to "invalid"
|
|
32
|
-
Then I get error "Invalid mode"
|
|
33
|
-
And the work item still has mode "speed"
|
|
34
|
-
|
|
35
|
-
Scenario: Set mode is case-sensitive
|
|
36
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
37
|
-
When I try to set mode to "Speed"
|
|
38
|
-
Then I get error "Invalid mode"
|
|
39
|
-
|
|
40
|
-
# All valid modes
|
|
41
|
-
Scenario Outline: Change to all valid modes
|
|
42
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
43
|
-
And I start work on the feature
|
|
44
|
-
When I set mode for current item to "<new_mode>"
|
|
45
|
-
Then the work item has mode "<new_mode>"
|
|
46
|
-
And CLAUDE.md mode is set to "<new_mode>"
|
|
47
|
-
|
|
48
|
-
Examples:
|
|
49
|
-
| new_mode |
|
|
50
|
-
| discovery |
|
|
51
|
-
| stable |
|
|
52
|
-
| production |
|
|
53
|
-
|
|
54
|
-
# Mode persistence
|
|
55
|
-
Scenario: Mode change persists across work start/stop
|
|
56
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
57
|
-
And I start work on the feature
|
|
58
|
-
When I set mode for current item to "production"
|
|
59
|
-
And I stop work
|
|
60
|
-
And I start work on the feature
|
|
61
|
-
Then CLAUDE.md mode is set to "production"
|
|
62
|
-
|
|
63
|
-
# Multiple mode changes
|
|
64
|
-
Scenario: Change mode multiple times
|
|
65
|
-
Given I create a feature "Test Feature" with mode "speed"
|
|
66
|
-
And I start work on the feature
|
|
67
|
-
When I set mode for current item to "discovery"
|
|
68
|
-
And I set mode for current item to "stable"
|
|
69
|
-
And I set mode for current item to "production"
|
|
70
|
-
Then the work item has mode "production"
|
|
71
|
-
And CLAUDE.md mode is set to "production"
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
Feature: Work start sets CLAUDE.md mode from work item
|
|
2
|
-
As a developer
|
|
3
|
-
I want jettypod work start to set the CLAUDE.md mode from the work item's mode
|
|
4
|
-
So I automatically work in the correct mode for each work item
|
|
5
|
-
|
|
6
|
-
Background:
|
|
7
|
-
Given jettypod is initialized
|
|
8
|
-
And CLAUDE.md exists
|
|
9
|
-
|
|
10
|
-
# Basic mode inheritance
|
|
11
|
-
Scenario: Start work on feature in speed mode
|
|
12
|
-
Given I create a feature "Speed Feature" with mode "speed"
|
|
13
|
-
When I start work on the feature
|
|
14
|
-
Then CLAUDE.md mode is set to "speed"
|
|
15
|
-
|
|
16
|
-
Scenario: Start work on bug in stable mode
|
|
17
|
-
Given I create a bug "Stable Bug" with mode "stable"
|
|
18
|
-
When I start work on the bug
|
|
19
|
-
Then CLAUDE.md mode is set to "stable"
|
|
20
|
-
|
|
21
|
-
Scenario: Start work on chore inherits parent feature mode
|
|
22
|
-
Given I create a feature "Discovery Feature" with mode "discovery"
|
|
23
|
-
And I create a chore "Child Chore" without mode and parent feature
|
|
24
|
-
When I start work on the chore
|
|
25
|
-
Then CLAUDE.md mode is set to "discovery"
|
|
26
|
-
|
|
27
|
-
Scenario: Start work on feature in production mode
|
|
28
|
-
Given I create a feature "Production Feature" with mode "production"
|
|
29
|
-
When I start work on the feature
|
|
30
|
-
Then CLAUDE.md mode is set to "production"
|
|
31
|
-
|
|
32
|
-
# Mode switching between work items
|
|
33
|
-
Scenario: Switch from speed mode item to stable mode item
|
|
34
|
-
Given I create a feature "Speed Feature" with mode "speed"
|
|
35
|
-
And I create a bug "Stable Bug" with mode "stable"
|
|
36
|
-
And I start work on the feature
|
|
37
|
-
And CLAUDE.md mode is set to "speed"
|
|
38
|
-
When I stop work
|
|
39
|
-
And I start work on the bug
|
|
40
|
-
Then CLAUDE.md mode is set to "stable"
|
|
41
|
-
|
|
42
|
-
Scenario: Start work updates mode even if item already in progress
|
|
43
|
-
Given I create a feature "Test Feature" with mode "discovery"
|
|
44
|
-
And the feature status is "in_progress"
|
|
45
|
-
And CLAUDE.md has mode "speed"
|
|
46
|
-
When I start work on the feature
|
|
47
|
-
Then CLAUDE.md mode is set to "discovery"
|
|
48
|
-
|
|
49
|
-
# Epic handling - epics don't have modes
|
|
50
|
-
Scenario: Start work on epic (NULL mode)
|
|
51
|
-
Given I create an epic "Test Epic" without mode
|
|
52
|
-
When I start work on the epic
|
|
53
|
-
Then CLAUDE.md has no mode line
|
|
54
|
-
And the current work section exists
|
|
55
|
-
|
|
56
|
-
# Default mode from work item creation
|
|
57
|
-
Scenario: Start work on feature with default discovery mode
|
|
58
|
-
Given I create a feature "Default Feature" without mode
|
|
59
|
-
And the work item has mode "discovery"
|
|
60
|
-
When I start work on the feature
|
|
61
|
-
Then CLAUDE.md mode is set to "discovery"
|
|
62
|
-
|
|
63
|
-
# Hierarchical structure
|
|
64
|
-
Scenario: Start work on child features use their own mode, not parent's
|
|
65
|
-
Given I create an epic "Test Epic" without mode
|
|
66
|
-
And I create a feature "Speed Feature" with mode "speed" and parent epic
|
|
67
|
-
And I create a feature "Stable Feature" with mode "stable" and parent epic
|
|
68
|
-
When I start work on the speed feature
|
|
69
|
-
Then CLAUDE.md mode is set to "speed"
|
|
70
|
-
When I stop work
|
|
71
|
-
And I start work on the stable feature
|
|
72
|
-
Then CLAUDE.md mode is set to "stable"
|
|
73
|
-
|
|
74
|
-
# Mode persistence
|
|
75
|
-
Scenario: Work item mode persists in database after start
|
|
76
|
-
Given I create a feature "Test Feature" with mode "stable"
|
|
77
|
-
When I start work on the feature
|
|
78
|
-
And I stop work
|
|
79
|
-
Then the work item still has mode "stable"
|
|
80
|
-
|
|
81
|
-
# Edge cases
|
|
82
|
-
Scenario: Starting work multiple times preserves mode
|
|
83
|
-
Given I create a feature "Test Feature" with mode "production"
|
|
84
|
-
When I start work on the feature
|
|
85
|
-
And I stop work
|
|
86
|
-
And I start work on the feature
|
|
87
|
-
Then CLAUDE.md mode is set to "production"
|
|
88
|
-
And the work item still has mode "production"
|
package/full-test.txt
DELETED
|
File without changes
|
package/lib/bug-workflow.test.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
BUG_WORKFLOW_STEPS,
|
|
3
|
-
BUG_WORKFLOW_TECHNIQUES,
|
|
4
|
-
BUG_WORKFLOW_RED_FLAGS,
|
|
5
|
-
getBugWorkflowForClaudeMd,
|
|
6
|
-
getBugWorkflowForTerminal
|
|
7
|
-
} = require('./bug-workflow');
|
|
8
|
-
|
|
9
|
-
describe('Bug Workflow Module', () => {
|
|
10
|
-
describe('Constants', () => {
|
|
11
|
-
test('BUG_WORKFLOW_STEPS contains all 6 steps', () => {
|
|
12
|
-
expect(BUG_WORKFLOW_STEPS).toContain('1. REPRODUCE');
|
|
13
|
-
expect(BUG_WORKFLOW_STEPS).toContain('2. INVESTIGATE');
|
|
14
|
-
expect(BUG_WORKFLOW_STEPS).toContain('3. ISOLATE');
|
|
15
|
-
expect(BUG_WORKFLOW_STEPS).toContain('4. FIX');
|
|
16
|
-
expect(BUG_WORKFLOW_STEPS).toContain('5. VERIFY');
|
|
17
|
-
expect(BUG_WORKFLOW_STEPS).toContain('6. COMMIT');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('BUG_WORKFLOW_STEPS contains critical checklist items', () => {
|
|
21
|
-
// REPRODUCE checklist
|
|
22
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Create minimal reproduction case');
|
|
23
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Write down exact steps to trigger');
|
|
24
|
-
|
|
25
|
-
// INVESTIGATE checklist
|
|
26
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Read error messages/stack traces completely');
|
|
27
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Look for recent changes (git log/blame)');
|
|
28
|
-
|
|
29
|
-
// ISOLATE checklist
|
|
30
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Identify root cause, not just symptoms');
|
|
31
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Understand why the bug occurs');
|
|
32
|
-
|
|
33
|
-
// FIX checklist
|
|
34
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Make the minimal change that fixes root cause');
|
|
35
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Avoid "while I\'m here" refactoring');
|
|
36
|
-
|
|
37
|
-
// VERIFY checklist
|
|
38
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Add regression test for this specific bug');
|
|
39
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Run existing tests - ensure nothing broke');
|
|
40
|
-
|
|
41
|
-
// COMMIT checklist
|
|
42
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Clear commit message: "fix: [brief description]"');
|
|
43
|
-
expect(BUG_WORKFLOW_STEPS).toContain('Reference issue number if applicable');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('BUG_WORKFLOW_TECHNIQUES contains debugging tips', () => {
|
|
47
|
-
expect(BUG_WORKFLOW_TECHNIQUES).toContain('DEBUGGING TECHNIQUES:');
|
|
48
|
-
expect(BUG_WORKFLOW_TECHNIQUES).toContain('git bisect');
|
|
49
|
-
expect(BUG_WORKFLOW_TECHNIQUES).toContain('Rubber duck');
|
|
50
|
-
expect(BUG_WORKFLOW_TECHNIQUES).toContain('Take breaks');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('BUG_WORKFLOW_RED_FLAGS contains anti-patterns', () => {
|
|
54
|
-
expect(BUG_WORKFLOW_RED_FLAGS).toContain('RED FLAGS:');
|
|
55
|
-
expect(BUG_WORKFLOW_RED_FLAGS).toContain('"It works on my machine"');
|
|
56
|
-
expect(BUG_WORKFLOW_RED_FLAGS).toContain('Fixing symptoms without understanding cause');
|
|
57
|
-
expect(BUG_WORKFLOW_RED_FLAGS).toContain('Adding try/catch to hide errors');
|
|
58
|
-
expect(BUG_WORKFLOW_RED_FLAGS).toContain('Skipping reproduction');
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('getBugWorkflowForClaudeMd()', () => {
|
|
63
|
-
test('returns string with all workflow sections', () => {
|
|
64
|
-
const result = getBugWorkflowForClaudeMd();
|
|
65
|
-
|
|
66
|
-
expect(typeof result).toBe('string');
|
|
67
|
-
expect(result).toContain('SYSTEMATIC BUG FIXING WORKFLOW:');
|
|
68
|
-
expect(result).toContain(BUG_WORKFLOW_STEPS);
|
|
69
|
-
expect(result).toContain(BUG_WORKFLOW_TECHNIQUES);
|
|
70
|
-
expect(result).toContain(BUG_WORKFLOW_RED_FLAGS);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test('does not contain terminal formatting characters', () => {
|
|
74
|
-
const result = getBugWorkflowForClaudeMd();
|
|
75
|
-
|
|
76
|
-
// Should not have Unicode box-drawing characters
|
|
77
|
-
expect(result).not.toContain('━');
|
|
78
|
-
// Should not have emojis
|
|
79
|
-
expect(result).not.toContain('🐛');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test('has plain text header for markdown compatibility', () => {
|
|
83
|
-
const result = getBugWorkflowForClaudeMd();
|
|
84
|
-
|
|
85
|
-
expect(result).toContain('SYSTEMATIC BUG FIXING WORKFLOW:');
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe('getBugWorkflowForTerminal()', () => {
|
|
90
|
-
test('returns string with all workflow sections', () => {
|
|
91
|
-
const result = getBugWorkflowForTerminal();
|
|
92
|
-
|
|
93
|
-
expect(typeof result).toBe('string');
|
|
94
|
-
expect(result).toContain(BUG_WORKFLOW_STEPS);
|
|
95
|
-
expect(result).toContain(BUG_WORKFLOW_TECHNIQUES);
|
|
96
|
-
expect(result).toContain(BUG_WORKFLOW_RED_FLAGS);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('contains terminal formatting characters', () => {
|
|
100
|
-
const result = getBugWorkflowForTerminal();
|
|
101
|
-
|
|
102
|
-
// Should have Unicode box-drawing characters for borders
|
|
103
|
-
expect(result).toContain('━');
|
|
104
|
-
// Should have bug emoji
|
|
105
|
-
expect(result).toContain('🐛');
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('has formatted header with emoji', () => {
|
|
109
|
-
const result = getBugWorkflowForTerminal();
|
|
110
|
-
|
|
111
|
-
expect(result).toContain('🐛 BUG FIXING WORKFLOW');
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('has top and bottom borders', () => {
|
|
115
|
-
const result = getBugWorkflowForTerminal();
|
|
116
|
-
|
|
117
|
-
// Count border lines
|
|
118
|
-
const borderCount = (result.match(/━━━━━━━/g) || []).length;
|
|
119
|
-
expect(borderCount).toBeGreaterThanOrEqual(2); // Top and bottom borders
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe('Content Consistency', () => {
|
|
124
|
-
test('both formats contain the same workflow steps', () => {
|
|
125
|
-
const claudeMd = getBugWorkflowForClaudeMd();
|
|
126
|
-
const terminal = getBugWorkflowForTerminal();
|
|
127
|
-
|
|
128
|
-
// Both should contain the exact same steps content
|
|
129
|
-
expect(claudeMd).toContain(BUG_WORKFLOW_STEPS);
|
|
130
|
-
expect(terminal).toContain(BUG_WORKFLOW_STEPS);
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
test('both formats contain the same techniques', () => {
|
|
134
|
-
const claudeMd = getBugWorkflowForClaudeMd();
|
|
135
|
-
const terminal = getBugWorkflowForTerminal();
|
|
136
|
-
|
|
137
|
-
expect(claudeMd).toContain(BUG_WORKFLOW_TECHNIQUES);
|
|
138
|
-
expect(terminal).toContain(BUG_WORKFLOW_TECHNIQUES);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test('both formats contain the same red flags', () => {
|
|
142
|
-
const claudeMd = getBugWorkflowForClaudeMd();
|
|
143
|
-
const terminal = getBugWorkflowForTerminal();
|
|
144
|
-
|
|
145
|
-
expect(claudeMd).toContain(BUG_WORKFLOW_RED_FLAGS);
|
|
146
|
-
expect(terminal).toContain(BUG_WORKFLOW_RED_FLAGS);
|
|
147
|
-
});
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
describe('Edge Cases', () => {
|
|
151
|
-
test('functions return non-empty strings', () => {
|
|
152
|
-
expect(getBugWorkflowForClaudeMd().length).toBeGreaterThan(0);
|
|
153
|
-
expect(getBugWorkflowForTerminal().length).toBeGreaterThan(0);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
test('functions are deterministic (same output on multiple calls)', () => {
|
|
157
|
-
const claudeMd1 = getBugWorkflowForClaudeMd();
|
|
158
|
-
const claudeMd2 = getBugWorkflowForClaudeMd();
|
|
159
|
-
expect(claudeMd1).toBe(claudeMd2);
|
|
160
|
-
|
|
161
|
-
const terminal1 = getBugWorkflowForTerminal();
|
|
162
|
-
const terminal2 = getBugWorkflowForTerminal();
|
|
163
|
-
expect(terminal1).toBe(terminal2);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test('constants are immutable strings', () => {
|
|
167
|
-
expect(typeof BUG_WORKFLOW_STEPS).toBe('string');
|
|
168
|
-
expect(typeof BUG_WORKFLOW_TECHNIQUES).toBe('string');
|
|
169
|
-
expect(typeof BUG_WORKFLOW_RED_FLAGS).toBe('string');
|
|
170
|
-
|
|
171
|
-
// Verify they're not empty
|
|
172
|
-
expect(BUG_WORKFLOW_STEPS.length).toBeGreaterThan(0);
|
|
173
|
-
expect(BUG_WORKFLOW_TECHNIQUES.length).toBeGreaterThan(0);
|
|
174
|
-
expect(BUG_WORKFLOW_RED_FLAGS.length).toBeGreaterThan(0);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|