jettypod 4.3.0 → 4.4.0
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/SECURITY-AUDIT-CATASTROPHIC-DELETE.md +196 -0
- package/TEST_HOOK.md +1 -0
- package/jettypod.js +210 -24
- package/lib/jettypod-backup.js +124 -8
- package/lib/safe-delete.js +794 -0
- package/lib/worktree-manager.js +54 -41
- package/package.json +1 -1
- package/skills-templates/feature-planning/SKILL.md +105 -155
- package/skills-templates/production-mode/SKILL.md +7 -4
- package/skills-templates/speed-mode/SKILL.md +463 -471
- package/skills-templates/stable-mode/SKILL.md +371 -319
package/lib/worktree-manager.js
CHANGED
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
// Database will be required lazily when implementing actual functions
|
|
15
15
|
// const getDb = require('./database');
|
|
16
16
|
|
|
17
|
+
// Safe delete module - ALWAYS use this for deletions
|
|
18
|
+
const safeDelete = require('./safe-delete');
|
|
19
|
+
|
|
17
20
|
/**
|
|
18
21
|
* Valid worktree statuses
|
|
19
22
|
*/
|
|
@@ -44,9 +47,16 @@ async function createWorktree(workItem, options = {}) {
|
|
|
44
47
|
return Promise.reject(new Error('SAFETY: repoPath must be explicitly provided to createWorktree'));
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
// SAFETY CHECK 0: Verify we're not running from within a worktree
|
|
51
|
+
try {
|
|
52
|
+
safeDelete.ensureNotInWorktree();
|
|
53
|
+
} catch (err) {
|
|
54
|
+
return Promise.reject(err);
|
|
55
|
+
}
|
|
56
|
+
|
|
47
57
|
const gitRoot = options.repoPath;
|
|
48
58
|
|
|
49
|
-
// SAFETY CHECK: Verify gitRoot is actually the main repository
|
|
59
|
+
// SAFETY CHECK 1: Verify gitRoot is actually the main repository
|
|
50
60
|
try {
|
|
51
61
|
const gitRootCheck = execSync('git rev-parse --show-toplevel', {
|
|
52
62
|
cwd: gitRoot,
|
|
@@ -205,7 +215,11 @@ async function createWorktree(workItem, options = {}) {
|
|
|
205
215
|
}
|
|
206
216
|
} else {
|
|
207
217
|
// It's a directory - remove it and create symlink
|
|
208
|
-
|
|
218
|
+
// SAFETY: Use safe delete with gitRoot validation
|
|
219
|
+
const deleteResult = safeDelete.safeRmRecursive(jettypodLink, { gitRoot, force: true });
|
|
220
|
+
if (!deleteResult.success) {
|
|
221
|
+
throw new Error(`Failed to remove .jettypod directory: ${deleteResult.error}`);
|
|
222
|
+
}
|
|
209
223
|
fs.symlinkSync(jettypodTarget, jettypodLink, 'dir');
|
|
210
224
|
}
|
|
211
225
|
} else {
|
|
@@ -324,10 +338,10 @@ async function createWorktree(workItem, options = {}) {
|
|
|
324
338
|
|
|
325
339
|
// Cleanup directory
|
|
326
340
|
if (fs.existsSync(worktreePath)) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
console.error(`Failed to cleanup worktree directory: ${
|
|
341
|
+
// SAFETY: Use safe delete with gitRoot validation
|
|
342
|
+
const deleteResult = safeDelete.safeRmRecursive(worktreePath, { gitRoot, force: true });
|
|
343
|
+
if (!deleteResult.success) {
|
|
344
|
+
console.error(`Failed to cleanup worktree directory: ${deleteResult.error}`);
|
|
331
345
|
}
|
|
332
346
|
}
|
|
333
347
|
|
|
@@ -478,12 +492,27 @@ async function removeDirectoryResilient(dirPath, gitRoot) {
|
|
|
478
492
|
const fs = require('fs');
|
|
479
493
|
const { execSync } = require('child_process');
|
|
480
494
|
|
|
495
|
+
// CRITICAL SAFETY: Validate path before ANY deletion attempt
|
|
496
|
+
const validation = safeDelete.validatePath(dirPath, gitRoot);
|
|
497
|
+
if (!validation.safe) {
|
|
498
|
+
throw new Error(`SAFETY: Cannot remove directory - ${validation.reason}`);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Additional safety: Ensure dirPath is within .jettypod-work
|
|
502
|
+
const path = require('path');
|
|
503
|
+
const resolvedDir = path.resolve(dirPath);
|
|
504
|
+
const worktreeBase = path.resolve(gitRoot, '.jettypod-work');
|
|
505
|
+
if (!resolvedDir.startsWith(worktreeBase)) {
|
|
506
|
+
throw new Error(`SAFETY: Can only remove directories within .jettypod-work/. Got: ${dirPath}`);
|
|
507
|
+
}
|
|
508
|
+
|
|
481
509
|
// Stage 1: Try standard git worktree remove (silent)
|
|
482
510
|
try {
|
|
483
511
|
execSync(`git worktree remove "${dirPath}"`, {
|
|
484
512
|
cwd: gitRoot,
|
|
485
513
|
stdio: 'pipe'
|
|
486
514
|
});
|
|
515
|
+
safeDelete.logDeletion(dirPath, 'git-worktree-remove', true);
|
|
487
516
|
return; // Success - exit silently
|
|
488
517
|
} catch (stage1Err) {
|
|
489
518
|
// Stage 1 failed - escalate with logging
|
|
@@ -497,16 +526,18 @@ async function removeDirectoryResilient(dirPath, gitRoot) {
|
|
|
497
526
|
stdio: 'pipe'
|
|
498
527
|
});
|
|
499
528
|
console.log(`✓ Forced git removal succeeded`);
|
|
529
|
+
safeDelete.logDeletion(dirPath, 'git-worktree-remove-force', true);
|
|
500
530
|
return;
|
|
501
531
|
} catch (stage2Err) {
|
|
502
|
-
console.log(`⚠️ Forced git removal failed, escalating to filesystem removal...`);
|
|
532
|
+
console.log(`⚠️ Forced git removal failed, escalating to safe filesystem removal...`);
|
|
503
533
|
}
|
|
504
534
|
|
|
505
|
-
// Stage 3: Try filesystem removal
|
|
535
|
+
// Stage 3: Try SAFE filesystem removal (validates path again)
|
|
506
536
|
if (fs.existsSync(dirPath)) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
537
|
+
const deleteResult = safeDelete.safeRmRecursive(dirPath, { gitRoot, force: true });
|
|
538
|
+
|
|
539
|
+
if (deleteResult.success) {
|
|
540
|
+
console.log(`✓ Safe filesystem removal succeeded`);
|
|
510
541
|
|
|
511
542
|
// Clean up git metadata
|
|
512
543
|
try {
|
|
@@ -515,25 +546,14 @@ async function removeDirectoryResilient(dirPath, gitRoot) {
|
|
|
515
546
|
// Non-fatal
|
|
516
547
|
}
|
|
517
548
|
return;
|
|
518
|
-
}
|
|
519
|
-
console.log(`⚠️
|
|
549
|
+
} else {
|
|
550
|
+
console.log(`⚠️ Safe filesystem removal failed: ${deleteResult.error}`);
|
|
551
|
+
throw new Error(`Directory removal failed: ${deleteResult.error}`);
|
|
520
552
|
}
|
|
521
553
|
}
|
|
522
554
|
|
|
523
|
-
//
|
|
524
|
-
|
|
525
|
-
await manualRecursiveDelete(dirPath);
|
|
526
|
-
console.log(`✓ Manual recursive deletion succeeded`);
|
|
527
|
-
|
|
528
|
-
// Clean up git metadata
|
|
529
|
-
try {
|
|
530
|
-
execSync('git worktree prune', { cwd: gitRoot, stdio: 'pipe' });
|
|
531
|
-
} catch (pruneErr) {
|
|
532
|
-
// Non-fatal
|
|
533
|
-
}
|
|
534
|
-
} catch (stage4Err) {
|
|
535
|
-
throw new Error(`All removal strategies failed: ${stage4Err.message}`);
|
|
536
|
-
}
|
|
555
|
+
// If we get here, directory doesn't exist - that's fine
|
|
556
|
+
console.log(`✓ Directory already removed or doesn't exist`);
|
|
537
557
|
}
|
|
538
558
|
|
|
539
559
|
/**
|
|
@@ -566,21 +586,14 @@ async function cleanupWorktree(worktreeId, options = {}) {
|
|
|
566
586
|
const db = options.db || getDb();
|
|
567
587
|
const deleteBranch = options.deleteBranch || false;
|
|
568
588
|
|
|
569
|
-
//
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (currentGitDir.includes('.jettypod-work') || currentGitDir !== '.git') {
|
|
577
|
-
return Promise.reject(new Error('SAFETY: Cannot run cleanup from within a worktree'));
|
|
578
|
-
}
|
|
579
|
-
} catch (err) {
|
|
580
|
-
// Ignore - might not be in a git repo
|
|
581
|
-
}
|
|
589
|
+
// NOTE: We intentionally do NOT check ensureNotInWorktree() here.
|
|
590
|
+
// The merge workflow (jettypod work merge) is designed to be run from
|
|
591
|
+
// within the worktree being merged. Safety comes from:
|
|
592
|
+
// 1. Requiring explicit repoPath (not relying on process.cwd())
|
|
593
|
+
// 2. Verifying repoPath is the main repo (check below)
|
|
594
|
+
// 3. Path validation in removeDirectoryResilient()
|
|
582
595
|
|
|
583
|
-
// SAFETY CHECK
|
|
596
|
+
// SAFETY CHECK: Verify gitRoot is actually the main repository
|
|
584
597
|
try {
|
|
585
598
|
const gitRootCheck = execSync('git rev-parse --show-toplevel', {
|
|
586
599
|
cwd: gitRoot,
|
package/package.json
CHANGED
|
@@ -11,21 +11,6 @@ Guides Claude through feature planning including UX approach exploration, option
|
|
|
11
11
|
|
|
12
12
|
When this skill is activated, you are helping discover the best approach for a feature. Follow this structured approach:
|
|
13
13
|
|
|
14
|
-
## 🔑 Critical Command Distinction
|
|
15
|
-
|
|
16
|
-
**Two different commands, two different purposes:**
|
|
17
|
-
|
|
18
|
-
| Command | Used For | When | Phase |
|
|
19
|
-
|---------|----------|------|-------|
|
|
20
|
-
| `work implement <feature-id>` | Transition feature to implementation phase | During feature planning (Step 8B) | Feature Planning |
|
|
21
|
-
| `work start <chore-id>` | Start implementing a specific chore | After feature planning complete (Step 8D) | Speed Mode |
|
|
22
|
-
|
|
23
|
-
**CRITICAL:** Both commands are run by **Claude**, not the user. The distinction is:
|
|
24
|
-
- `work implement` = Ends feature planning, creates chores
|
|
25
|
-
- `work start` = Begins implementing a chore (triggers speed-mode skill)
|
|
26
|
-
|
|
27
|
-
---
|
|
28
|
-
|
|
29
14
|
### Step 1: Understand the Feature Context
|
|
30
15
|
|
|
31
16
|
You'll receive context about:
|
|
@@ -111,42 +96,15 @@ If user wants prototypes:
|
|
|
111
96
|
1. **Build prototypes** in `/prototypes/feature-[id]-[approach-name]/`
|
|
112
97
|
2. **Name format**: `YYYY-MM-DD-[feature-slug]-[option].ext`
|
|
113
98
|
3. **Focus on UX**: Show the feel, not production code
|
|
114
|
-
4. **Add
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Created: [YYYY-MM-DD]<br>
|
|
121
|
-
Purpose: [what this explores]<br>
|
|
122
|
-
Decision: [to be filled after testing]
|
|
123
|
-
</div>
|
|
99
|
+
4. **Add prototype header**:
|
|
100
|
+
```
|
|
101
|
+
// Prototype: [feature] - [option]
|
|
102
|
+
// Created: [date]
|
|
103
|
+
// Purpose: [what this explores]
|
|
104
|
+
// Decision: [to be filled after testing]
|
|
124
105
|
```
|
|
125
|
-
For CLI/terminal prototypes, add similar info as first output.
|
|
126
106
|
5. **Offer to open them**: "Want me to open these in your browser?"
|
|
127
107
|
|
|
128
|
-
<details>
|
|
129
|
-
<summary><strong>📋 Prototyping Guidelines (click to expand)</strong></summary>
|
|
130
|
-
|
|
131
|
-
**Use fastest tech to demonstrate UX:**
|
|
132
|
-
- Quick HTML+JS for web UX
|
|
133
|
-
- Simple CLI scripts for command-line UX
|
|
134
|
-
- Minimal frameworks, maximum clarity
|
|
135
|
-
|
|
136
|
-
**What to prototype:**
|
|
137
|
-
- User interaction flow
|
|
138
|
-
- Visual layout (if UI)
|
|
139
|
-
- Command structure (if CLI)
|
|
140
|
-
- API shape (if API)
|
|
141
|
-
|
|
142
|
-
**What NOT to prototype:**
|
|
143
|
-
- Production error handling
|
|
144
|
-
- Database layer
|
|
145
|
-
- Authentication (unless that's the feature)
|
|
146
|
-
- Test coverage
|
|
147
|
-
|
|
148
|
-
</details>
|
|
149
|
-
|
|
150
108
|
### Step 5: Choose Winner
|
|
151
109
|
|
|
152
110
|
After user tests (or skips prototyping):
|
|
@@ -166,12 +124,10 @@ Based on chosen approach, generate:
|
|
|
166
124
|
**A. Scenario file** at `features/[feature-slug].feature` using Write tool:
|
|
167
125
|
|
|
168
126
|
1. **Create file** at `features/[feature-slug].feature` using Write tool
|
|
169
|
-
2. **
|
|
170
|
-
-
|
|
171
|
-
- Multiple valid workflows if the feature supports them
|
|
172
|
-
- Success variations (different outcomes that are all correct)
|
|
127
|
+
2. **ONLY include happy path scenario**:
|
|
128
|
+
- Happy path ONLY - the core user journey that proves it works
|
|
173
129
|
- NO error handling scenarios (added in stable mode)
|
|
174
|
-
- NO
|
|
130
|
+
- NO edge cases (added in stable mode)
|
|
175
131
|
- NO security/compliance scenarios (added in production mode)
|
|
176
132
|
|
|
177
133
|
**B. Step definitions file** at `features/step_definitions/[feature-slug].steps.js` using Write tool:
|
|
@@ -191,7 +147,7 @@ Based on chosen approach, generate:
|
|
|
191
147
|
sqlite3 .jettypod/work.db "UPDATE work_items SET scenario_file = 'features/[feature-slug].feature' WHERE id = <feature-id>"
|
|
192
148
|
```
|
|
193
149
|
|
|
194
|
-
**Template for speed mode (
|
|
150
|
+
**Template for speed mode (happy path only):**
|
|
195
151
|
|
|
196
152
|
```gherkin
|
|
197
153
|
Feature: [Feature Name]
|
|
@@ -200,20 +156,15 @@ Feature: [Feature Name]
|
|
|
200
156
|
Epic: [Epic name if applicable]
|
|
201
157
|
Approach: [Chosen approach name]
|
|
202
158
|
|
|
203
|
-
Scenario: [
|
|
159
|
+
Scenario: [Happy path scenario - core user journey]
|
|
204
160
|
Given [initial state]
|
|
205
161
|
When [user takes main action]
|
|
206
162
|
Then [expected successful outcome]
|
|
207
163
|
And [observable UI/system state change]
|
|
208
164
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Then [feature works correctly]
|
|
213
|
-
|
|
214
|
-
# SPEED MODE: All success scenarios above (required + optional functionality)
|
|
215
|
-
# STABLE MODE: Will add error handling, validation failures, edge cases
|
|
216
|
-
# These failure scenarios are added by stable-mode skill, NOT during feature discovery
|
|
165
|
+
# SPEED MODE: Only happy path above
|
|
166
|
+
# STABLE MODE: Will add error handling, edge cases, validation scenarios
|
|
167
|
+
# These additional scenarios are added by stable-mode skill, NOT during feature discovery
|
|
217
168
|
```
|
|
218
169
|
|
|
219
170
|
**Example for Login feature (speed mode):**
|
|
@@ -231,66 +182,8 @@ Scenario: User successfully logs in with valid credentials
|
|
|
231
182
|
Then I am redirected to the dashboard
|
|
232
183
|
And I see a welcome message with my name
|
|
233
184
|
And I have an active session token
|
|
234
|
-
|
|
235
|
-
Scenario: User logs in with "Remember me" option (optional feature)
|
|
236
|
-
Given I am on the login page
|
|
237
|
-
When I enter valid credentials
|
|
238
|
-
And I check the "Remember me" checkbox
|
|
239
|
-
And I click the login button
|
|
240
|
-
Then I am redirected to the dashboard
|
|
241
|
-
And my session persists for 30 days
|
|
242
185
|
```
|
|
243
186
|
|
|
244
|
-
<details>
|
|
245
|
-
<summary><strong>📋 BDD Scenario Guidelines (click to expand)</strong></summary>
|
|
246
|
-
|
|
247
|
-
**Scenario naming:**
|
|
248
|
-
- Use present tense
|
|
249
|
-
- Be specific about what's being tested
|
|
250
|
-
- Focus on user behavior
|
|
251
|
-
|
|
252
|
-
**Given/When/Then structure:**
|
|
253
|
-
- **Given**: Set up initial state
|
|
254
|
-
- **When**: User action
|
|
255
|
-
- **Then**: Observable outcome
|
|
256
|
-
|
|
257
|
-
**What feature planning creates:**
|
|
258
|
-
|
|
259
|
-
Feature planning creates speed mode scenarios (make it work - all success paths):
|
|
260
|
-
```gherkin
|
|
261
|
-
Scenario: User successfully [does the required thing]
|
|
262
|
-
Given [setup]
|
|
263
|
-
When [action]
|
|
264
|
-
Then [success]
|
|
265
|
-
|
|
266
|
-
Scenario: User successfully [uses optional feature]
|
|
267
|
-
Given [setup]
|
|
268
|
-
When [uses optional capability]
|
|
269
|
-
Then [feature works correctly]
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
**Additional scenarios are added LATER by stable-mode skill:**
|
|
273
|
-
|
|
274
|
-
Stable mode adds error handling and validation:
|
|
275
|
-
```gherkin
|
|
276
|
-
Scenario: Handle invalid input
|
|
277
|
-
Given [setup]
|
|
278
|
-
When [invalid action]
|
|
279
|
-
Then [appropriate error]
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Production mode adds security/scale/compliance:
|
|
283
|
-
```gherkin
|
|
284
|
-
Scenario: Prevent unauthorized access
|
|
285
|
-
Given [unauthorized user]
|
|
286
|
-
When [attempts action]
|
|
287
|
-
Then [access denied with proper error]
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
**IMPORTANT:** Feature planning creates all success scenarios (required + optional). Stable/production chores add failure scenarios later.
|
|
291
|
-
|
|
292
|
-
</details>
|
|
293
|
-
|
|
294
187
|
### Step 6.5: Validate BDD Infrastructure
|
|
295
188
|
|
|
296
189
|
**CRITICAL:** After creating both scenario and step definition files, automatically validate them with cucumber dry-run to catch errors immediately.
|
|
@@ -343,7 +236,7 @@ console.log(''); // Extra line before continuing
|
|
|
343
236
|
|
|
344
237
|
The speed-mode skill guides Claude to:
|
|
345
238
|
1. Implement the feature code
|
|
346
|
-
2. Create corresponding unit tests for
|
|
239
|
+
2. Create corresponding unit tests for the happy path
|
|
347
240
|
3. Ensure tests pass before completing the chore
|
|
348
241
|
|
|
349
242
|
This keeps feature planning focused on BDD scenarios (what users experience) while speed mode handles unit tests (implementation details).
|
|
@@ -353,7 +246,7 @@ This keeps feature planning focused on BDD scenarios (what users experience) whi
|
|
|
353
246
|
**CRITICAL:** After BDD validation passes, analyze the codebase and propose technical implementation chores. **DO NOT CREATE CHORES YET** - the feature must transition to implementation mode first (Step 8).
|
|
354
247
|
|
|
355
248
|
**Your analysis should consider:**
|
|
356
|
-
- The BDD scenarios (
|
|
249
|
+
- The BDD scenarios (especially the happy path)
|
|
357
250
|
- Existing codebase structure and patterns
|
|
358
251
|
- Epic's architectural decisions (if any)
|
|
359
252
|
- Tech stack and framework conventions
|
|
@@ -393,7 +286,7 @@ Based on the scenario and my understanding of the codebase, here are the chores
|
|
|
393
286
|
|
|
394
287
|
[etc.]
|
|
395
288
|
|
|
396
|
-
These chores will make
|
|
289
|
+
These chores will make the happy path scenario pass.
|
|
397
290
|
|
|
398
291
|
Sound good? Any adjustments?
|
|
399
292
|
```
|
|
@@ -469,7 +362,7 @@ After creating all chores, display:
|
|
|
469
362
|
✅ Created X chores for speed mode
|
|
470
363
|
|
|
471
364
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
472
|
-
🎯 Feature
|
|
365
|
+
🎯 Feature Discovery Complete!
|
|
473
366
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
474
367
|
|
|
475
368
|
📋 BDD scenarios: features/[feature-slug].feature
|
|
@@ -480,30 +373,97 @@ After creating all chores, display:
|
|
|
480
373
|
Ready to start implementation?
|
|
481
374
|
```
|
|
482
375
|
|
|
483
|
-
#### Step 8D:
|
|
376
|
+
#### Step 8D: Transition to Speed Mode
|
|
484
377
|
|
|
485
|
-
**
|
|
378
|
+
**WAIT for user confirmation.**
|
|
486
379
|
|
|
487
|
-
|
|
380
|
+
When user confirms they want to proceed with implementation (responds with "yes", "let's go", "proceed", "start", or similar):
|
|
381
|
+
|
|
382
|
+
**IMMEDIATELY invoke the speed-mode skill using the Skill tool:**
|
|
488
383
|
|
|
489
384
|
```
|
|
490
|
-
|
|
385
|
+
Use the Skill tool with skill: "speed-mode"
|
|
491
386
|
```
|
|
492
387
|
|
|
493
|
-
**
|
|
388
|
+
**The speed-mode skill will then:**
|
|
389
|
+
1. Guide the user to start the first chore with `jettypod work start [chore-id]`
|
|
390
|
+
2. Create a worktree for the chore
|
|
391
|
+
3. Follow TDD workflow to implement the chore
|
|
392
|
+
4. Merge when complete
|
|
494
393
|
|
|
495
|
-
|
|
496
|
-
|
|
394
|
+
**End feature-planning skill after invoking speed-mode.**
|
|
395
|
+
|
|
396
|
+
## Key Principles
|
|
397
|
+
|
|
398
|
+
1. **Always suggest exactly 3 options** - Simple, Balanced, Advanced
|
|
399
|
+
2. **Show epic's architectural decision** - Feature should align with epic's technical approach
|
|
400
|
+
3. **UX first, tech second** - Focus on what it feels like to use, not implementation details
|
|
401
|
+
4. **Prototypes are optional but valuable** - User can skip if approach is obvious
|
|
402
|
+
5. **BDD scenarios are required** - Discovery isn't complete without scenarios
|
|
403
|
+
6. **Guide to next step** - Always end with clear action
|
|
404
|
+
|
|
405
|
+
## Prototyping Guidelines
|
|
406
|
+
|
|
407
|
+
**Use fastest tech to demonstrate UX:**
|
|
408
|
+
- Quick HTML+JS for web UX
|
|
409
|
+
- Simple CLI scripts for command-line UX
|
|
410
|
+
- Minimal frameworks, maximum clarity
|
|
411
|
+
|
|
412
|
+
**What to prototype:**
|
|
413
|
+
- User interaction flow
|
|
414
|
+
- Visual layout (if UI)
|
|
415
|
+
- Command structure (if CLI)
|
|
416
|
+
- API shape (if API)
|
|
417
|
+
|
|
418
|
+
**What NOT to prototype:**
|
|
419
|
+
- Production error handling
|
|
420
|
+
- Database layer
|
|
421
|
+
- Authentication (unless that's the feature)
|
|
422
|
+
- Test coverage
|
|
423
|
+
|
|
424
|
+
## BDD Scenario Guidelines
|
|
425
|
+
|
|
426
|
+
**Scenario naming:**
|
|
427
|
+
- Use present tense
|
|
428
|
+
- Be specific about what's being tested
|
|
429
|
+
- Focus on user behavior
|
|
430
|
+
|
|
431
|
+
**Given/When/Then structure:**
|
|
432
|
+
- **Given**: Set up initial state
|
|
433
|
+
- **When**: User action
|
|
434
|
+
- **Then**: Observable outcome
|
|
435
|
+
|
|
436
|
+
**What feature-discover creates:**
|
|
437
|
+
|
|
438
|
+
**Feature discovery ONLY creates speed mode scenarios (happy path):**
|
|
439
|
+
```gherkin
|
|
440
|
+
Scenario: User successfully [does the thing]
|
|
441
|
+
Given [setup]
|
|
442
|
+
When [action]
|
|
443
|
+
Then [success]
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
**Additional scenarios are added LATER by stable-mode skill:**
|
|
447
|
+
|
|
448
|
+
Stable mode adds error handling:
|
|
449
|
+
```gherkin
|
|
450
|
+
Scenario: Handle invalid input
|
|
451
|
+
Given [setup]
|
|
452
|
+
When [invalid action]
|
|
453
|
+
Then [appropriate error]
|
|
497
454
|
```
|
|
498
455
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
456
|
+
Production mode adds security/scale/compliance:
|
|
457
|
+
```gherkin
|
|
458
|
+
Scenario: Prevent unauthorized access
|
|
459
|
+
Given [unauthorized user]
|
|
460
|
+
When [attempts action]
|
|
461
|
+
Then [access denied with proper error]
|
|
462
|
+
```
|
|
503
463
|
|
|
504
|
-
**
|
|
464
|
+
**IMPORTANT:** Feature discovery only creates happy path. Stable/production chores add more scenarios later.
|
|
505
465
|
|
|
506
|
-
## Example: Feature
|
|
466
|
+
## Example: Feature Discovery Flow
|
|
507
467
|
|
|
508
468
|
**Feature:** "Email/password login"
|
|
509
469
|
**Epic decision:** "Using Auth.js with JWT tokens"
|
|
@@ -515,25 +475,17 @@ jettypod work start [chore-id]
|
|
|
515
475
|
|
|
516
476
|
**User picks:** Option 1 (Simple inline form)
|
|
517
477
|
|
|
518
|
-
**Scenarios generated (
|
|
478
|
+
**Scenarios generated (happy path only for speed mode):**
|
|
519
479
|
```gherkin
|
|
520
480
|
Feature: Email/Password Login
|
|
521
481
|
|
|
522
|
-
Scenario: Successful login
|
|
482
|
+
Scenario: Successful login
|
|
523
483
|
Given I am on the login page
|
|
524
484
|
When I enter valid credentials and submit
|
|
525
485
|
Then I am redirected to the dashboard
|
|
526
486
|
And I have an active JWT token
|
|
527
487
|
|
|
528
|
-
|
|
529
|
-
Given I am on the login page
|
|
530
|
-
When I enter valid credentials
|
|
531
|
-
And I check "Remember me"
|
|
532
|
-
And I submit
|
|
533
|
-
Then I am redirected to the dashboard
|
|
534
|
-
And my session persists for 30 days
|
|
535
|
-
|
|
536
|
-
# SPEED MODE: All success scenarios above (required + optional features)
|
|
488
|
+
# SPEED MODE: Only happy path above
|
|
537
489
|
# STABLE MODE: Will add error handling scenarios like "Invalid credentials"
|
|
538
490
|
```
|
|
539
491
|
|
|
@@ -543,17 +495,15 @@ User confirms: "Yes, perfect"
|
|
|
543
495
|
|
|
544
496
|
**Transition:** `jettypod work implement 10 --winner="prototypes/2025-10-30-login-simple.html" --rationale="Simple inline form chosen - fastest for users, cleanest UX"`
|
|
545
497
|
|
|
546
|
-
## Validation
|
|
498
|
+
## Validation
|
|
547
499
|
|
|
548
|
-
Before completing feature
|
|
500
|
+
Before completing feature discovery, ensure:
|
|
549
501
|
- [ ] Epic's architectural decision is shown (if exists)
|
|
550
502
|
- [ ] Exactly 3 approaches suggested
|
|
551
503
|
- [ ] Winner chosen (with prototypes or without)
|
|
552
|
-
- [ ] BDD scenarios written
|
|
504
|
+
- [ ] BDD scenarios written
|
|
553
505
|
- [ ] Step definitions written for ALL scenario steps
|
|
554
506
|
- [ ] Scenarios file exists at `features/[feature-slug].feature`
|
|
555
507
|
- [ ] Step definitions file exists at `features/step_definitions/[feature-slug].steps.js`
|
|
556
508
|
- [ ] BDD infrastructure validated with dry-run (Step 6.5)
|
|
557
|
-
- [ ]
|
|
558
|
-
- [ ] Speed mode chores created
|
|
559
|
-
- [ ] First chore started with `work start [chore-id]` (Step 8D)
|
|
509
|
+
- [ ] User knows next step .jettypod work start [feature-id])
|
|
@@ -39,8 +39,8 @@ When this skill is activated, you are helping implement a production mode chore
|
|
|
39
39
|
**To detect context, check these conditions:**
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
# Get current work
|
|
43
|
-
|
|
42
|
+
# Get current work and parent feature
|
|
43
|
+
jettypod work current
|
|
44
44
|
|
|
45
45
|
# Check for production scenarios in the feature file
|
|
46
46
|
# (Look for scenarios tagged with @production or containing production-related keywords)
|
|
@@ -230,8 +230,11 @@ This will:
|
|
|
230
230
|
**Get current work and identify target scenario:**
|
|
231
231
|
|
|
232
232
|
```bash
|
|
233
|
-
# Get current chore details
|
|
234
|
-
|
|
233
|
+
# Get current chore details
|
|
234
|
+
jettypod work current
|
|
235
|
+
|
|
236
|
+
# Get parent feature's scenario file
|
|
237
|
+
sqlite3 .jettypod/work.db "SELECT scenario_file FROM work_items WHERE id = <parent-feature-id>"
|
|
235
238
|
```
|
|
236
239
|
|
|
237
240
|
Parse the chore description to find which scenario it addresses (look for "Scenario: ..." in the description).
|