jettypod 3.0.1

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 (122) hide show
  1. package/.claude/PROTECT_SKILLS.md +28 -0
  2. package/.claude/settings.json +24 -0
  3. package/.claude/settings.local.json +16 -0
  4. package/.claude/skills/epic-discover/SKILL.md +262 -0
  5. package/.claude/skills/feature-discover/SKILL.md +393 -0
  6. package/.claude/skills/speed-mode/SKILL.md +364 -0
  7. package/.claude/skills/stable-mode/SKILL.md +591 -0
  8. package/.github/workflows/test-safety.yml +85 -0
  9. package/README.md +25 -0
  10. package/SPEED-STABLE-AUDIT.md +853 -0
  11. package/SYSTEM-BEHAVIOR.md +1241 -0
  12. package/TEST_SAFETY_AUDIT.md +314 -0
  13. package/TEST_SAFETY_IMPLEMENTATION.md +97 -0
  14. package/cucumber.js +8 -0
  15. package/docs/COMMAND_REFERENCE.md +903 -0
  16. package/docs/DECISIONS.md +68 -0
  17. package/docs/README.md +48 -0
  18. package/docs/STANDARDS-SYSTEM-DOCUMENTATION.md +374 -0
  19. package/docs/TEST-REWRITE-PLAN.md +261 -0
  20. package/docs/ai-test-writing-requirements.md +219 -0
  21. package/docs/claude-code-skills.md +607 -0
  22. package/docs/core-jettypod-methodology/comprehensive-jettypod-methodology.md +582 -0
  23. package/docs/core-jettypod-methodology/deprecated/jettypod-comprehensive-standards.md +1222 -0
  24. package/docs/core-jettypod-methodology/deprecated/jettypod-operating-guide.md +3399 -0
  25. package/docs/core-jettypod-methodology/deprecated/jettypod-technical-checklist.md +1325 -0
  26. package/docs/core-jettypod-methodology/deprecated/jettypod-vibe-coding-framework.md +1544 -0
  27. package/docs/core-jettypod-methodology/deprecated/prompt-engineering-guide.md +320 -0
  28. package/docs/core-jettypod-methodology/deprecated/vibe-coding-cheatsheet (1).md +516 -0
  29. package/docs/core-jettypod-methodology/deprecated/vibe-coding-framework.md +1544 -0
  30. package/docs/features/jettypod-standards-explained.md +543 -0
  31. package/docs/features/standards-inventory.md +257 -0
  32. package/docs/gap-analysis-current-vs-comprehensive-methodology.md +939 -0
  33. package/docs/jettypod-system-overview.md +409 -0
  34. package/features/auto-generate-production-chores.feature +14 -0
  35. package/features/claude-md-protection/steps.js +487 -0
  36. package/features/decisions/index.js +490 -0
  37. package/features/decisions/index.test.js +208 -0
  38. package/features/git-hooks/git-hooks.feature +30 -0
  39. package/features/git-hooks/index.js +93 -0
  40. package/features/git-hooks/index.test.js +137 -0
  41. package/features/git-hooks/post-commit +56 -0
  42. package/features/git-hooks/post-merge +47 -0
  43. package/features/git-hooks/pre-commit +28 -0
  44. package/features/git-hooks/simple-steps.js +53 -0
  45. package/features/git-hooks/simple-test.feature +10 -0
  46. package/features/git-hooks/steps.js +196 -0
  47. package/features/jettypod-update-command.feature +46 -0
  48. package/features/mode-prompts/index.js +95 -0
  49. package/features/mode-prompts/simple-steps.js +44 -0
  50. package/features/mode-prompts/simple-test.feature +9 -0
  51. package/features/mode-prompts/validation.test.js +120 -0
  52. package/features/refactor-mode/steps.js +217 -0
  53. package/features/refactor-mode.feature +49 -0
  54. package/features/skills-update/index.test.js +216 -0
  55. package/features/step_definitions/auto-generate-production-chores.steps.js +162 -0
  56. package/features/step_definitions/terminal-logo.steps.js +145 -0
  57. package/features/step_definitions/update-command.steps.js +183 -0
  58. package/features/terminal-logo/index.js +39 -0
  59. package/features/terminal-logo/terminal-logo.feature +30 -0
  60. package/features/update-command/index.js +181 -0
  61. package/features/update-command/index.test.js +225 -0
  62. package/features/work-commands/bug-workflow-display.feature +22 -0
  63. package/features/work-commands/index.js +311 -0
  64. package/features/work-commands/simple-steps.js +69 -0
  65. package/features/work-commands/stable-tests.feature +57 -0
  66. package/features/work-commands/steps.js +1120 -0
  67. package/features/work-commands/validation.test.js +88 -0
  68. package/features/work-commands/work-commands.feature +13 -0
  69. package/features/work-tracking/discovery-validation.test.js +228 -0
  70. package/features/work-tracking/index.js +1511 -0
  71. package/features/work-tracking/mode-required.feature +112 -0
  72. package/features/work-tracking/phase-tracking.test.js +482 -0
  73. package/features/work-tracking/prototype-tracking.test.js +485 -0
  74. package/features/work-tracking/tree-view.test.js +310 -0
  75. package/features/work-tracking/work-set-mode.feature +71 -0
  76. package/features/work-tracking/work-start-mode.feature +88 -0
  77. package/full-test.txt +0 -0
  78. package/install.sh +89 -0
  79. package/jettypod.js +1640 -0
  80. package/lib/bug-workflow.js +94 -0
  81. package/lib/bug-workflow.test.js +177 -0
  82. package/lib/claudemd.js +130 -0
  83. package/lib/claudemd.test.js +195 -0
  84. package/lib/comprehensive-standards-full.json +1778 -0
  85. package/lib/config.js +181 -0
  86. package/lib/config.test.js +511 -0
  87. package/lib/constants.js +107 -0
  88. package/lib/constants.test.js +164 -0
  89. package/lib/current-work.js +130 -0
  90. package/lib/current-work.test.js +146 -0
  91. package/lib/database-project-config.test.js +107 -0
  92. package/lib/database.js +256 -0
  93. package/lib/database.test.js +106 -0
  94. package/lib/decisions-generator.js +102 -0
  95. package/lib/decisions-generator.test.js +457 -0
  96. package/lib/decisions-helpers.js +119 -0
  97. package/lib/decisions-helpers.test.js +310 -0
  98. package/lib/discovery-checkpoint.js +83 -0
  99. package/lib/docs-generator.js +280 -0
  100. package/lib/external-checklist.js +177 -0
  101. package/lib/git.js +142 -0
  102. package/lib/git.test.js +145 -0
  103. package/lib/logo.js +3 -0
  104. package/lib/migrations/001-epic-to-parent.js +24 -0
  105. package/lib/migrations/002-default-work-item-modes.js +37 -0
  106. package/lib/migrations/002-default-work-item-modes.test.js +351 -0
  107. package/lib/migrations/003-epic-discovery-fields.js +52 -0
  108. package/lib/migrations/004-discovery-decisions-table.js +32 -0
  109. package/lib/migrations/005-migrate-decision-data.js +62 -0
  110. package/lib/migrations/006-feature-phase-field.js +61 -0
  111. package/lib/migrations/007-prototype-tracking.js +38 -0
  112. package/lib/migrations/008-scenario-file-field.js +24 -0
  113. package/lib/migrations/index.js +74 -0
  114. package/lib/production-helpers.js +69 -0
  115. package/lib/project-state.test.js +92 -0
  116. package/lib/test-helpers.js +184 -0
  117. package/lib/test-helpers.test.js +255 -0
  118. package/package.json +36 -0
  119. package/prototypes/test/index.html +1 -0
  120. package/setup-dist-repo.sh +68 -0
  121. package/test-safety-check.sh +80 -0
  122. package/work-item-tracking-plan.md +199 -0
@@ -0,0 +1,311 @@
1
+ const { execSync } = require('child_process');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const { getDb, getDbPath, getJettypodDir } = require('../../lib/database');
5
+ const { getCurrentWork, setCurrentWork, clearCurrentWork, getCurrentWorkPath } = require('../../lib/current-work');
6
+ const { VALID_STATUSES } = require('../../lib/constants');
7
+ const { updateCurrentWork } = require('../../lib/claudemd');
8
+ const { createFeatureBranchName, createOrCheckoutBranch } = require('../../lib/git');
9
+ const config = require('../../lib/config');
10
+ const { getBugWorkflowForTerminal } = require('../../lib/bug-workflow');
11
+
12
+ /**
13
+ * Get paths to JettyPod files and directories
14
+ * @returns {Object} Paths object with jettypodDir, currentWorkPath, dbPath, claudePath
15
+ */
16
+ function getPaths() {
17
+ return {
18
+ jettypodDir: getJettypodDir(),
19
+ currentWorkPath: getCurrentWorkPath(),
20
+ dbPath: getDbPath(),
21
+ claudePath: path.join(process.cwd(), 'CLAUDE.md')
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Start work on a work item
27
+ * @param {number} id - Work item ID to start
28
+ * @returns {Promise<Object>} Work item, current work, and branch name
29
+ * @throws {Error} If ID is invalid, JettyPod not initialized, database missing, or work item not found
30
+ */
31
+ function startWork(id) {
32
+ // Input validation
33
+ if (!id || isNaN(id) || id < 1) {
34
+ return Promise.reject(new Error('Invalid work item ID'));
35
+ }
36
+
37
+ const paths = getPaths();
38
+
39
+ // Check jettypod directory exists
40
+ if (!fs.existsSync(paths.jettypodDir)) {
41
+ return Promise.reject(new Error('JettyPod not initialized. Run: jettypod init'));
42
+ }
43
+
44
+ // Check database exists
45
+ if (!fs.existsSync(paths.dbPath)) {
46
+ return Promise.reject(new Error('Work database not found. Run: jettypod init'));
47
+ }
48
+
49
+ const db = getDb();
50
+
51
+ return new Promise((resolve, reject) => {
52
+ // Get work item
53
+ db.get(`
54
+ SELECT w.*,
55
+ p.title as parent_title, p.id as parent_id, p.scenario_file as parent_scenario_file, p.mode as parent_mode,
56
+ e.title as epic_title, e.id as epic_id
57
+ FROM work_items w
58
+ LEFT JOIN work_items p ON w.parent_id = p.id
59
+ LEFT JOIN work_items e ON w.epic_id = e.id AND w.epic_id != w.id
60
+ WHERE w.id = ?
61
+ `, [id], (err, workItem) => {
62
+ if (err) {
63
+ return reject(new Error(`Database error: ${err.message}`));
64
+ }
65
+
66
+ if (!workItem) {
67
+ return reject(new Error(`Work item #${id} not found`));
68
+ }
69
+
70
+ // Update status to in_progress if currently todo
71
+ const finalStatus = workItem.status === 'todo' ? 'in_progress' : workItem.status;
72
+
73
+ const updateAndContinue = () => {
74
+ // Create current work file
75
+ const currentWork = {
76
+ id: workItem.id,
77
+ title: workItem.title,
78
+ type: workItem.type,
79
+ status: finalStatus,
80
+ parent_id: workItem.parent_id,
81
+ parent_title: workItem.parent_title,
82
+ epic_id: workItem.epic_id,
83
+ epic_title: workItem.epic_title
84
+ };
85
+
86
+ try {
87
+ setCurrentWork(currentWork);
88
+ } catch (err) {
89
+ return reject(new Error(`Failed to write current work file: ${err.message}`));
90
+ }
91
+
92
+ // Create feature branch
93
+ let branchName = null;
94
+ try {
95
+ branchName = createFeatureBranchName(id, workItem.title);
96
+ createOrCheckoutBranch(branchName);
97
+ } catch (gitError) {
98
+ // Git operations failed, but continue - work tracking still works
99
+ console.warn(`Warning: ${gitError.message}`);
100
+ }
101
+
102
+ // Update CLAUDE.md with work item's mode
103
+ // For chores, inherit the parent feature's mode
104
+ const modeToUse = (workItem.type === 'chore' && workItem.parent_mode)
105
+ ? workItem.parent_mode
106
+ : workItem.mode;
107
+ updateCurrentWork(currentWork, modeToUse);
108
+
109
+ // Display output
110
+ let output = `Working on: [#${workItem.id}] ${workItem.title} (${workItem.type})`;
111
+ if (workItem.parent_title) {
112
+ output = `Working on: [#${workItem.id}] ${workItem.title} (${workItem.type} of #${workItem.parent_id} ${workItem.parent_title})`;
113
+ }
114
+ console.log(output);
115
+
116
+ // Display bug workflow guidance for bugs
117
+ // Only display if workItem has a type (defensive check)
118
+ if (workItem && workItem.type === 'bug') {
119
+ try {
120
+ console.log(getBugWorkflowForTerminal());
121
+ } catch (err) {
122
+ // Silently fail if workflow display fails - don't block work start
123
+ // This is a non-critical feature
124
+ }
125
+ }
126
+
127
+ // Display epic discovery guidance for epics with needs_discovery
128
+ if (workItem && workItem.type === 'epic' && workItem.needs_discovery) {
129
+ // Check if decisions have been recorded
130
+ db.all(
131
+ `SELECT * FROM discovery_decisions WHERE work_item_id = ?`,
132
+ [workItem.id],
133
+ (err, decisions) => {
134
+ if (err || !decisions || decisions.length === 0) {
135
+ console.log('');
136
+ console.log('⚠️ This epic needs architectural discovery before building features.');
137
+ console.log('');
138
+ console.log('💬 Recommended: Talk to Claude Code');
139
+ console.log(` Say: "Let's do epic discovery for #${workItem.id}"`);
140
+ console.log('');
141
+ console.log(' Claude Code will guide you through:');
142
+ console.log(' • Suggesting 3 architectural options');
143
+ console.log(' • Building prototypes');
144
+ console.log(' • Recording your decisions');
145
+ console.log('');
146
+ }
147
+ }
148
+ );
149
+ }
150
+
151
+ // Auto-trigger feature discovery for features in discovery phase
152
+ if (workItem && workItem.type === 'feature' && workItem.phase === 'discovery') {
153
+ console.log('');
154
+ console.log('✨ Feature Discovery Mode');
155
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
156
+ console.log('');
157
+ console.log('This feature is in discovery phase. Claude Code will help you:');
158
+ console.log(' 1. Explore 3 different UX approaches');
159
+ console.log(' 2. (Optional) Build throwaway prototypes');
160
+ console.log(' 3. Choose the winning approach');
161
+ console.log(' 4. Generate BDD scenarios for the happy path');
162
+ console.log(' 5. Transition to implementation (speed mode)');
163
+ console.log('');
164
+ console.log('💬 Claude Code is ready to guide you through feature discovery.');
165
+ console.log('');
166
+ console.log('📋 The feature-discover skill will automatically activate.');
167
+ console.log('');
168
+ }
169
+
170
+ // Auto-trigger mode skills for chores in speed or stable mode
171
+ if (workItem && workItem.type === 'chore' && workItem.parent_id) {
172
+ // Validate parent feature exists
173
+ if (!workItem.parent_title) {
174
+ console.log('');
175
+ console.log('⚠️ Warning: Parent feature not found');
176
+ console.log('');
177
+ console.log(`This chore references parent feature #${workItem.parent_id}, but that feature`);
178
+ console.log('does not exist in the database.');
179
+ console.log('');
180
+ console.log('Suggestion: Check the parent_id or create the missing feature.');
181
+ console.log('');
182
+ }
183
+ // Validate scenario file exists
184
+ else if (!workItem.parent_scenario_file) {
185
+ console.log('');
186
+ console.log('⚠️ Warning: Parent feature has no scenario file');
187
+ console.log('');
188
+ console.log(`Parent feature #${workItem.parent_id} "${workItem.parent_title}" does not have`);
189
+ console.log('a scenario file set.');
190
+ console.log('');
191
+ console.log('Suggestion: Create a BDD scenario file for the feature and update scenario_file.');
192
+ console.log('');
193
+ }
194
+ else if (!fs.existsSync(path.join(process.cwd(), workItem.parent_scenario_file))) {
195
+ console.log('');
196
+ console.log('⚠️ Warning: Scenario file not found');
197
+ console.log('');
198
+ console.log(`Parent feature references scenario file: ${workItem.parent_scenario_file}`);
199
+ console.log('but the file does not exist on disk.');
200
+ console.log('');
201
+ console.log('Suggestion: Create the scenario file or update the feature.scenario_file path.');
202
+ console.log('');
203
+ }
204
+ else if (workItem.mode === 'speed') {
205
+ console.log('');
206
+ console.log('🚀 Speed Mode Skill Activated');
207
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
208
+ console.log('');
209
+ console.log('Claude Code will autonomously:');
210
+ console.log(' 1. Analyze the BDD scenario for this feature');
211
+ console.log(' 2. Analyze the codebase to understand patterns');
212
+ console.log(' 3. Propose an implementation approach');
213
+ console.log(' 4. Implement until the happy path scenario passes');
214
+ console.log(' 5. Generate stable mode chores for comprehensive testing');
215
+ console.log('');
216
+ console.log('💬 The speed-mode skill is now active.');
217
+ console.log(' Claude Code will guide you through implementation.');
218
+ console.log('');
219
+ } else if (workItem.mode === 'stable') {
220
+ console.log('');
221
+ console.log('🧪 Stable Mode Skill Activated');
222
+ console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
223
+ console.log('');
224
+ console.log('Claude Code will autonomously:');
225
+ console.log(' 1. Analyze the BDD scenario to implement');
226
+ console.log(' 2. Review the existing speed mode implementation');
227
+ console.log(' 3. Propose comprehensive error handling approach');
228
+ console.log(' 4. Implement with proper validation and edge case coverage');
229
+ console.log(' 5. Ensure all BDD scenarios pass');
230
+ console.log('');
231
+ console.log('💬 The stable-mode skill is now active.');
232
+ console.log(' Claude Code will guide you through comprehensive testing.');
233
+ console.log('');
234
+ }
235
+ }
236
+
237
+ resolve({ workItem, currentWork, branchName });
238
+ };
239
+
240
+ // Update status to in_progress if currently todo
241
+ if (workItem.status === 'todo') {
242
+ db.run(`UPDATE work_items SET status = 'in_progress' WHERE id = ?`, [id], updateAndContinue);
243
+ } else {
244
+ updateAndContinue();
245
+ }
246
+ });
247
+ });
248
+ }
249
+
250
+ /**
251
+ * Stop work on current work item
252
+ * @param {string|null} newStatus - Optional status to set (e.g., 'done', 'blocked')
253
+ * @returns {Promise<Object|null>} Work item ID and status, or null if no active work
254
+ * @throws {Error} If status is invalid, database missing, or file operations fail
255
+ */
256
+ function stopWork(newStatus = null) {
257
+ const paths = getPaths();
258
+
259
+ const currentWork = getCurrentWork();
260
+ if (!currentWork) {
261
+ console.log('No active work item');
262
+ return Promise.resolve(null);
263
+ }
264
+
265
+ // Validate status if provided
266
+ if (newStatus && !VALID_STATUSES.includes(newStatus)) {
267
+ return Promise.reject(new Error(`Invalid status: ${newStatus}`));
268
+ }
269
+
270
+ return new Promise((resolve, reject) => {
271
+ if (newStatus) {
272
+ if (!fs.existsSync(paths.dbPath)) {
273
+ return reject(new Error('Work database not found'));
274
+ }
275
+
276
+ const db = getDb();
277
+ db.run(`UPDATE work_items SET status = ? WHERE id = ?`, [newStatus, currentWork.id], (err) => {
278
+ if (err) {
279
+ return reject(new Error(`Database error: ${err.message}`));
280
+ }
281
+
282
+ try {
283
+ clearCurrentWork();
284
+ } catch (unlinkErr) {
285
+ return reject(new Error(`Failed to remove current work file: ${unlinkErr.message}`));
286
+ }
287
+
288
+ console.log(`Stopped work on #${currentWork.id}, status set to ${newStatus}`);
289
+ resolve({ id: currentWork.id, status: newStatus });
290
+ });
291
+ } else {
292
+ try {
293
+ clearCurrentWork();
294
+ } catch (err) {
295
+ return reject(new Error(`Failed to remove current work file: ${err.message}`));
296
+ }
297
+
298
+ console.log(`Stopped work on #${currentWork.id}`);
299
+ resolve({ id: currentWork.id });
300
+ }
301
+ });
302
+ }
303
+
304
+ // Re-export getCurrentWork from shared module for backwards compatibility
305
+ // (used by jettypod.js)
306
+
307
+ module.exports = {
308
+ startWork,
309
+ stopWork,
310
+ getCurrentWork
311
+ };
@@ -0,0 +1,69 @@
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 { resetDb } = require('../../lib/database');
7
+
8
+ const testDir = path.join('/tmp', 'jettypod-test-' + Date.now());
9
+ let originalDir;
10
+
11
+ Given('I have initialized jettypod', function () {
12
+ resetDb(); // Clear singleton db to avoid stale connections
13
+
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' });
26
+ });
27
+
28
+ Given('I create an epic with id {int}', function (id) {
29
+ execSync(`node ${path.join(originalDir, 'jettypod.js')} work create epic "Test Epic"`, { stdio: 'pipe' });
30
+ });
31
+
32
+ Given('I create a feature with id {int} under epic {int}', function (featureId, epicId) {
33
+ execSync(`node ${path.join(originalDir, 'jettypod.js')} work create feature "Test Feature" "" --parent=${epicId}`, { stdio: 'pipe' });
34
+ });
35
+
36
+ When('I start work on item {int}', function (id) {
37
+ execSync(`node ${path.join(originalDir, 'jettypod.js')} work start ${id}`, { stdio: 'pipe' });
38
+ });
39
+
40
+ Then('the current work file exists', function () {
41
+ const currentWorkPath = path.join(testDir, '.jettypod', 'current-work.json');
42
+ assert(fs.existsSync(currentWorkPath), 'Current work file does not exist');
43
+ });
44
+
45
+ Then('the current work contains item {int}', function (id) {
46
+ const currentWorkPath = path.join(testDir, '.jettypod', 'current-work.json');
47
+ const currentWork = JSON.parse(fs.readFileSync(currentWorkPath, 'utf-8'));
48
+ assert.strictEqual(currentWork.id, id);
49
+ });
50
+
51
+ Then('item {int} status is in_progress or backlog', function (id) {
52
+ // Use CLI to check status to avoid database connection issues
53
+ try {
54
+ const output = execSync(`node ${path.join(originalDir, 'jettypod.js')} work show ${id}`, { encoding: 'utf-8' });
55
+ const statusMatch = output.match(/Status:\s+(\w+)/);
56
+ if (!statusMatch) {
57
+ throw new Error('Could not find status in output');
58
+ }
59
+ const status = statusMatch[1];
60
+ assert(status === 'in_progress' || status === 'backlog', `Status is ${status}`);
61
+ } finally {
62
+ // SAFETY: Only delete if testDir is in /tmp
63
+ if (fs.existsSync(testDir) && testDir.startsWith('/tmp/')) {
64
+ process.chdir(originalDir);
65
+ fs.rmSync(testDir, { recursive: true, force: true });
66
+ }
67
+ resetDb(); // Clear singleton after cleanup
68
+ }
69
+ });
@@ -0,0 +1,57 @@
1
+ Feature: Work Commands - Stable Mode
2
+ Edge cases and error handling for work commands
3
+
4
+ Scenario: Start work with invalid ID
5
+ Given jettypod is initialized
6
+ When I try to start work with ID "invalid"
7
+ Then I get an error "Invalid work item ID"
8
+
9
+ Scenario: Start work with negative ID
10
+ Given jettypod is initialized
11
+ When I try to start work with ID "-1"
12
+ Then I get an error "Invalid work item ID"
13
+
14
+ Scenario: Start work when not initialized
15
+ Given jettypod is not initialized
16
+ When I try to start work with ID "1"
17
+ Then I get an error "JettyPod not initialized"
18
+
19
+ Scenario: Start work on non-existent item
20
+ Given jettypod is initialized
21
+ When I try to start work with ID "999"
22
+ Then I get an error "Work item #999 not found"
23
+
24
+ Scenario: Stop work with invalid status
25
+ Given I have current work
26
+ When I try to stop work with status "invalid"
27
+ Then I get an error "Invalid status"
28
+
29
+ Scenario: Stop work when no current work
30
+ Given jettypod is initialized
31
+ And no work is active
32
+ When I try to stop work
33
+ Then operation succeeds with no changes
34
+
35
+ Scenario: Get current work with corrupted file
36
+ Given jettypod is initialized
37
+ And current work file is corrupted
38
+ When I get current work
39
+ Then it returns null
40
+
41
+ Scenario: Start work without git repo
42
+ Given jettypod is initialized without git
43
+ And I have a work item
44
+ When I start work on the item
45
+ Then it succeeds without creating branch
46
+
47
+ Scenario: Multiple start work calls
48
+ Given I have a work item
49
+ And I start work on it
50
+ When I start work on a different item
51
+ Then the first item stops being current
52
+ And the second item becomes current
53
+
54
+ Scenario: Start work preserves existing status
55
+ Given I have a work item with status "in_progress"
56
+ When I start work on it
57
+ Then the status remains "in_progress"