jettypod 3.0.2 → 4.0.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/.claude/PROTECT_SKILLS.md +2 -2
- package/.claude/skills/{epic-discover → epic-planning}/SKILL.md +57 -22
- package/.claude/skills/{feature-discover → feature-planning}/SKILL.md +38 -22
- package/.claude/skills/speed-mode/SKILL.md +79 -8
- package/.claude/skills/stable-mode/SKILL.md +83 -1
- package/SYSTEM-BEHAVIOR.md +172 -21
- package/docs/COMMAND_REFERENCE.md +26 -26
- package/docs/gap-analysis-current-vs-comprehensive-methodology.md +3 -3
- package/features/auto-generate-production-chores.feature +62 -11
- package/features/backlog-command.feature +26 -0
- package/features/claude-md-protection/steps.js +6 -4
- package/features/decisions/index.js +10 -10
- package/features/git-hooks/simple-steps.js +4 -4
- package/features/git-hooks/steps.js +7 -7
- package/features/mode-prompts/simple-steps.js +3 -3
- package/features/step_definitions/auto-generate-production-chores.steps.js +542 -114
- package/features/step_definitions/backlog-command.steps.js +37 -0
- package/features/work-commands/index.js +192 -8
- package/features/work-commands/simple-steps.js +5 -5
- package/features/work-commands/steps.js +2 -2
- package/features/work-tracking/index.js +220 -38
- package/features/work-tracking/mode-required.feature +1 -1
- package/jettypod.js +15 -8
- package/lib/migrations/009-discovery-rationale-field.js +24 -0
- package/lib/production-chore-generator.js +198 -0
- package/package.json +1 -1
|
@@ -142,7 +142,7 @@ function getTree(includeCompleted = false) {
|
|
|
142
142
|
|
|
143
143
|
resolve(rootItems);
|
|
144
144
|
} catch (err) {
|
|
145
|
-
reject(new Error(`Failed to build
|
|
145
|
+
reject(new Error(`Failed to build backlog: ${err.message}`));
|
|
146
146
|
}
|
|
147
147
|
});
|
|
148
148
|
});
|
|
@@ -499,7 +499,7 @@ function showItem(id) {
|
|
|
499
499
|
console.log(`\n⚠️ DISCOVERY REQUIRED: This epic needs architectural decisions`);
|
|
500
500
|
console.log(``);
|
|
501
501
|
console.log(` 💬 Talk to Claude Code: "Let's do epic discovery for #${row.id}"`);
|
|
502
|
-
console.log(` Or run: jettypod work epic-
|
|
502
|
+
console.log(` Or run: jettypod work epic-planning ${row.id}`);
|
|
503
503
|
console.log(``);
|
|
504
504
|
console.log(` Claude Code will guide you through:`);
|
|
505
505
|
console.log(` • Suggesting 3 architectural options`);
|
|
@@ -611,7 +611,7 @@ async function main() {
|
|
|
611
611
|
console.log(' • Identify architectural decisions (if needed)');
|
|
612
612
|
console.log(' • Create features automatically');
|
|
613
613
|
console.log('');
|
|
614
|
-
console.log('Or run: jettypod work epic-
|
|
614
|
+
console.log('Or run: jettypod work epic-planning ' + newId);
|
|
615
615
|
console.log('');
|
|
616
616
|
console.log('💡 You can also plan later when ready');
|
|
617
617
|
}
|
|
@@ -630,7 +630,7 @@ async function main() {
|
|
|
630
630
|
console.log('Ask Claude Code:');
|
|
631
631
|
console.log(` "Help me plan epic #${parentId}"`);
|
|
632
632
|
console.log('');
|
|
633
|
-
console.log(`Or run: jettypod work epic-
|
|
633
|
+
console.log(`Or run: jettypod work epic-planning ${parentId}`);
|
|
634
634
|
}
|
|
635
635
|
});
|
|
636
636
|
}
|
|
@@ -756,13 +756,176 @@ async function main() {
|
|
|
756
756
|
console.log('Legend: ⊕ = collapsed ⊖ = expanded');
|
|
757
757
|
console.log('');
|
|
758
758
|
console.log('Commands:');
|
|
759
|
-
console.log(' jettypod
|
|
760
|
-
console.log(' jettypod
|
|
761
|
-
console.log(' jettypod
|
|
762
|
-
console.log(' jettypod
|
|
759
|
+
console.log(' jettypod backlog --expand=1 Show details for item #1');
|
|
760
|
+
console.log(' jettypod backlog --expand=1,2,3 Show details for multiple items');
|
|
761
|
+
console.log(' jettypod backlog --expand-all Show all details');
|
|
762
|
+
console.log(' jettypod backlog Collapse all (default)');
|
|
763
763
|
console.log('');
|
|
764
764
|
} catch (err) {
|
|
765
|
-
console.error(`Error displaying
|
|
765
|
+
console.error(`Error displaying backlog: ${err.message}`);
|
|
766
|
+
process.exit(1);
|
|
767
|
+
}
|
|
768
|
+
break;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
case 'backlog': {
|
|
772
|
+
try {
|
|
773
|
+
const filter = args[0]; // undefined, 'all', or 'completed'
|
|
774
|
+
|
|
775
|
+
// For 'all' and 'completed' filters, use old simple display
|
|
776
|
+
if (filter === 'all' || filter === 'completed') {
|
|
777
|
+
let items;
|
|
778
|
+
if (filter === 'all') {
|
|
779
|
+
items = await getTree(true);
|
|
780
|
+
} else {
|
|
781
|
+
items = await new Promise((resolve, reject) => {
|
|
782
|
+
db.all(`SELECT * FROM work_items WHERE status IN ('done', 'cancelled') ORDER BY parent_id, id`, [], (err, rows) => {
|
|
783
|
+
if (err) {
|
|
784
|
+
return reject(new Error(`Failed to fetch completed items: ${err.message}`));
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (!rows || rows.length === 0) {
|
|
788
|
+
return resolve([]);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const itemsById = {};
|
|
792
|
+
const rootItems = [];
|
|
793
|
+
|
|
794
|
+
rows.forEach(item => {
|
|
795
|
+
itemsById[item.id] = item;
|
|
796
|
+
item.children = [];
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
rows.forEach(item => {
|
|
800
|
+
if (item.parent_id && itemsById[item.parent_id]) {
|
|
801
|
+
itemsById[item.parent_id].children.push(item);
|
|
802
|
+
} else if (!item.parent_id) {
|
|
803
|
+
rootItems.push(item);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
resolve(rootItems);
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (items.length === 0) {
|
|
813
|
+
console.log('No items found.');
|
|
814
|
+
} else {
|
|
815
|
+
const expandedIds = new Set();
|
|
816
|
+
items.forEach(item => {
|
|
817
|
+
if (item.type === 'epic') {
|
|
818
|
+
expandedIds.add(item.id);
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
printTree(items, '', true, expandedIds);
|
|
822
|
+
}
|
|
823
|
+
console.log('');
|
|
824
|
+
} else {
|
|
825
|
+
// Default: show three-section view (active work, recently completed, backlog)
|
|
826
|
+
const currentWork = getCurrentWork();
|
|
827
|
+
|
|
828
|
+
// Show active work at top if exists
|
|
829
|
+
if (currentWork) {
|
|
830
|
+
const emoji = TYPE_EMOJIS[currentWork.type] || '📋';
|
|
831
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
832
|
+
console.log('🎯 ACTIVE WORK');
|
|
833
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
834
|
+
console.log(`${emoji} [#${currentWork.id}] ${currentWork.title}`);
|
|
835
|
+
if (currentWork.epic_title && currentWork.epic_id !== currentWork.id && currentWork.parent_id === currentWork.epic_id) {
|
|
836
|
+
console.log(`└─ Epic: 🎯 #${currentWork.epic_id} ${currentWork.epic_title}`);
|
|
837
|
+
} else if (currentWork.parent_title) {
|
|
838
|
+
const parentEmoji = TYPE_EMOJIS[currentWork.parent_type] || '📋';
|
|
839
|
+
console.log(`└─ Part of: ${parentEmoji} #${currentWork.parent_id} ${currentWork.parent_title}`);
|
|
840
|
+
} else if (currentWork.epic_title && currentWork.epic_id !== currentWork.id) {
|
|
841
|
+
console.log(`└─ Epic: 🎯 #${currentWork.epic_id} ${currentWork.epic_title}`);
|
|
842
|
+
}
|
|
843
|
+
console.log('');
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Show recently completed items
|
|
847
|
+
const recentlyCompleted = await new Promise((resolve, reject) => {
|
|
848
|
+
db.all(`
|
|
849
|
+
SELECT w.id, w.title, w.type, w.mode,
|
|
850
|
+
p.title as parent_title, p.id as parent_id, p.type as parent_type
|
|
851
|
+
FROM work_items w
|
|
852
|
+
LEFT JOIN work_items p ON w.parent_id = p.id
|
|
853
|
+
WHERE w.status = 'done'
|
|
854
|
+
ORDER BY w.id DESC
|
|
855
|
+
LIMIT 3
|
|
856
|
+
`, [], async (err, rows) => {
|
|
857
|
+
if (err) reject(err);
|
|
858
|
+
else {
|
|
859
|
+
// Add epic info to each item
|
|
860
|
+
for (const row of rows || []) {
|
|
861
|
+
const epic = await findEpic(row.id);
|
|
862
|
+
if (epic) {
|
|
863
|
+
row.epic_id = epic.id;
|
|
864
|
+
row.epic_title = epic.title;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
resolve(rows || []);
|
|
868
|
+
}
|
|
869
|
+
});
|
|
870
|
+
});
|
|
871
|
+
|
|
872
|
+
if (recentlyCompleted.length > 0) {
|
|
873
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
874
|
+
console.log('✅ RECENTLY COMPLETED');
|
|
875
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
876
|
+
recentlyCompleted.forEach(item => {
|
|
877
|
+
const emoji = TYPE_EMOJIS[item.type] || '📋';
|
|
878
|
+
let modeIndicator = '';
|
|
879
|
+
if (item.type === 'feature') {
|
|
880
|
+
if (item.phase === 'discovery') {
|
|
881
|
+
modeIndicator = ' [🔍 discovery]';
|
|
882
|
+
} else if (item.mode) {
|
|
883
|
+
modeIndicator = ` [${item.mode}]`;
|
|
884
|
+
}
|
|
885
|
+
} else if (item.mode) {
|
|
886
|
+
modeIndicator = ` [${item.mode}]`;
|
|
887
|
+
}
|
|
888
|
+
console.log(`${emoji} [${item.id}] ${item.title}${modeIndicator}`);
|
|
889
|
+
if (item.epic_title && item.epic_id !== item.id && item.parent_id === item.epic_id) {
|
|
890
|
+
console.log(` └─ Epic: 🎯 #${item.epic_id} ${item.epic_title}`);
|
|
891
|
+
} else if (item.parent_title) {
|
|
892
|
+
const parentEmoji = TYPE_EMOJIS[item.parent_type] || '📋';
|
|
893
|
+
console.log(` └─ Part of: ${parentEmoji} #${item.parent_id} ${item.parent_title}`);
|
|
894
|
+
} else if (item.epic_title && item.epic_id !== item.id) {
|
|
895
|
+
console.log(` └─ Epic: 🎯 #${item.epic_id} ${item.epic_title}`);
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
console.log('');
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
902
|
+
console.log('📋 BACKLOG');
|
|
903
|
+
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
904
|
+
const items = await getTree(false);
|
|
905
|
+
|
|
906
|
+
// Default: auto-expand all epics
|
|
907
|
+
const expandedIds = new Set();
|
|
908
|
+
items.forEach(item => {
|
|
909
|
+
if (item.type === 'epic') {
|
|
910
|
+
expandedIds.add(item.id);
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
printTree(items, '', true, expandedIds);
|
|
915
|
+
|
|
916
|
+
// Show legend and commands
|
|
917
|
+
console.log('');
|
|
918
|
+
console.log('Legend: ⊕ = collapsed ⊖ = expanded');
|
|
919
|
+
console.log('');
|
|
920
|
+
console.log('Commands:');
|
|
921
|
+
console.log(' jettypod backlog --expand=1 Show details for item #1');
|
|
922
|
+
console.log(' jettypod backlog --expand=1,2,3 Show details for multiple items');
|
|
923
|
+
console.log(' jettypod backlog --expand-all Show all details');
|
|
924
|
+
console.log(' jettypod backlog Collapse all (default)');
|
|
925
|
+
console.log('');
|
|
926
|
+
}
|
|
927
|
+
} catch (err) {
|
|
928
|
+
console.error(`Error displaying backlog: ${err.message}`);
|
|
766
929
|
process.exit(1);
|
|
767
930
|
}
|
|
768
931
|
break;
|
|
@@ -809,7 +972,7 @@ async function main() {
|
|
|
809
972
|
console.log('Example:');
|
|
810
973
|
console.log(' jettypod work show 5');
|
|
811
974
|
console.log('');
|
|
812
|
-
console.log('💡 Tip: Use `jettypod
|
|
975
|
+
console.log('💡 Tip: Use `jettypod backlog` to see all work items');
|
|
813
976
|
process.exit(1);
|
|
814
977
|
}
|
|
815
978
|
|
|
@@ -967,12 +1130,12 @@ async function main() {
|
|
|
967
1130
|
break;
|
|
968
1131
|
}
|
|
969
1132
|
|
|
970
|
-
case 'epic-
|
|
1133
|
+
case 'epic-planning': {
|
|
971
1134
|
const epicId = parseInt(args[0]);
|
|
972
1135
|
|
|
973
1136
|
if (!epicId || isNaN(epicId)) {
|
|
974
1137
|
console.error('Error: Epic ID is required');
|
|
975
|
-
console.log('Usage: jettypod work epic-
|
|
1138
|
+
console.log('Usage: jettypod work epic-planning <epic-id>');
|
|
976
1139
|
process.exit(1);
|
|
977
1140
|
}
|
|
978
1141
|
|
|
@@ -1038,13 +1201,13 @@ async function main() {
|
|
|
1038
1201
|
console.log('💬 Now ask Claude Code:');
|
|
1039
1202
|
console.log(` "Help me with epic discovery for #${epicId}"`);
|
|
1040
1203
|
console.log('');
|
|
1041
|
-
console.log('Claude will use the epic-
|
|
1204
|
+
console.log('Claude will use the epic-planning skill to guide you through:');
|
|
1042
1205
|
console.log(' 1. Feature brainstorming');
|
|
1043
1206
|
console.log(' 2. Architectural decisions (if needed)');
|
|
1044
1207
|
console.log(' 3. Prototype validation (optional)');
|
|
1045
1208
|
console.log(' 4. Feature creation');
|
|
1046
1209
|
console.log('');
|
|
1047
|
-
console.log('📋 The skill is at: .claude/skills/epic-
|
|
1210
|
+
console.log('📋 The skill is at: .claude/skills/epic-planning/SKILL.md');
|
|
1048
1211
|
}
|
|
1049
1212
|
);
|
|
1050
1213
|
});
|
|
@@ -1220,13 +1383,14 @@ async function main() {
|
|
|
1220
1383
|
|
|
1221
1384
|
if (!featureId || isNaN(featureId)) {
|
|
1222
1385
|
console.error('Error: Feature ID is required');
|
|
1223
|
-
console.log('Usage: jettypod work implement <feature-id> [--prototypes="file1,file2"] [--winner="file.js"]');
|
|
1386
|
+
console.log('Usage: jettypod work implement <feature-id> [--prototypes="file1,file2"] [--winner="file.js"] [--rationale="why this approach"]');
|
|
1224
1387
|
process.exit(1);
|
|
1225
1388
|
}
|
|
1226
1389
|
|
|
1227
|
-
// Parse optional --prototypes and --
|
|
1390
|
+
// Parse optional --prototypes, --winner, and --rationale flags
|
|
1228
1391
|
const prototypesIndex = args.findIndex(a => a.startsWith('--prototypes='));
|
|
1229
1392
|
const winnerIndex = args.findIndex(a => a.startsWith('--winner='));
|
|
1393
|
+
const rationaleIndex = args.findIndex(a => a.startsWith('--rationale='));
|
|
1230
1394
|
|
|
1231
1395
|
const prototypes = prototypesIndex !== -1
|
|
1232
1396
|
? args[prototypesIndex].split('=')[1].replace(/^["']|["']$/g, '').split(',').map(p => p.trim())
|
|
@@ -1234,6 +1398,9 @@ async function main() {
|
|
|
1234
1398
|
const winner = winnerIndex !== -1
|
|
1235
1399
|
? args[winnerIndex].split('=')[1].replace(/^["']|["']$/g, '')
|
|
1236
1400
|
: null;
|
|
1401
|
+
const rationale = rationaleIndex !== -1
|
|
1402
|
+
? args[rationaleIndex].split('=')[1].replace(/^["']|["']$/g, '')
|
|
1403
|
+
: null;
|
|
1237
1404
|
|
|
1238
1405
|
db.get(`SELECT * FROM work_items WHERE id = ?`, [featureId], (err, feature) => {
|
|
1239
1406
|
if (err) {
|
|
@@ -1254,21 +1421,14 @@ async function main() {
|
|
|
1254
1421
|
process.exit(1);
|
|
1255
1422
|
}
|
|
1256
1423
|
|
|
1257
|
-
|
|
1258
|
-
console.error(`Error: Feature #${featureId} is not in discovery phase (current phase: ${feature.phase || 'implementation'})`);
|
|
1259
|
-
console.log('');
|
|
1260
|
-
console.log('Features can only be transitioned to implementation from discovery phase.');
|
|
1261
|
-
process.exit(1);
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
// Validate that BDD scenarios exist before transitioning
|
|
1424
|
+
// Validate that BDD scenarios exist
|
|
1265
1425
|
if (!feature.scenario_file) {
|
|
1266
1426
|
console.error(`Error: Feature #${featureId} has no BDD scenarios`);
|
|
1267
1427
|
console.log('');
|
|
1268
1428
|
console.log('Discovery is not complete without BDD scenarios.');
|
|
1269
1429
|
console.log('');
|
|
1270
1430
|
console.log('To complete discovery:');
|
|
1271
|
-
console.log(' 1. Generate scenarios using feature-
|
|
1431
|
+
console.log(' 1. Generate scenarios using feature-planning skill');
|
|
1272
1432
|
console.log(' 2. Or manually create scenarios at features/[feature-name].feature');
|
|
1273
1433
|
console.log(' 3. Then run: jettypod work implement');
|
|
1274
1434
|
console.log('');
|
|
@@ -1294,13 +1454,30 @@ async function main() {
|
|
|
1294
1454
|
process.exit(1);
|
|
1295
1455
|
}
|
|
1296
1456
|
|
|
1297
|
-
//
|
|
1457
|
+
// Determine if this is a transition or an update
|
|
1458
|
+
const isTransition = feature.phase === 'discovery';
|
|
1459
|
+
const isUpdate = feature.phase === 'implementation';
|
|
1460
|
+
|
|
1461
|
+
if (!isTransition && !isUpdate) {
|
|
1462
|
+
console.error(`Error: Feature #${featureId} has invalid phase: ${feature.phase}`);
|
|
1463
|
+
console.log('');
|
|
1464
|
+
console.log('Expected phase to be either "discovery" or "implementation"');
|
|
1465
|
+
process.exit(1);
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
// Prepare values
|
|
1298
1469
|
const prototypeFilesValue = prototypes.length > 0 ? JSON.stringify(prototypes) : null;
|
|
1299
1470
|
const winnerValue = winner || null;
|
|
1471
|
+
const rationaleValue = rationale || null;
|
|
1472
|
+
|
|
1473
|
+
// Update query: if transitioning, set phase and mode; if updating, just update decision fields
|
|
1474
|
+
const updateSql = isTransition
|
|
1475
|
+
? `UPDATE work_items SET phase = 'implementation', mode = 'speed', prototype_files = ?, discovery_winner = ?, discovery_rationale = ? WHERE id = ?`
|
|
1476
|
+
: `UPDATE work_items SET prototype_files = ?, discovery_winner = ?, discovery_rationale = ? WHERE id = ?`;
|
|
1300
1477
|
|
|
1301
1478
|
db.run(
|
|
1302
|
-
|
|
1303
|
-
[prototypeFilesValue, winnerValue, featureId],
|
|
1479
|
+
updateSql,
|
|
1480
|
+
[prototypeFilesValue, winnerValue, rationaleValue, featureId],
|
|
1304
1481
|
(err) => {
|
|
1305
1482
|
if (err) {
|
|
1306
1483
|
console.error(`Error: ${err.message}`);
|
|
@@ -1309,7 +1486,11 @@ async function main() {
|
|
|
1309
1486
|
|
|
1310
1487
|
console.log('');
|
|
1311
1488
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1312
|
-
|
|
1489
|
+
if (isTransition) {
|
|
1490
|
+
console.log(`✅ Feature #${featureId} transitioned to Implementation Phase`);
|
|
1491
|
+
} else {
|
|
1492
|
+
console.log(`✅ Feature #${featureId} discovery decision updated`);
|
|
1493
|
+
}
|
|
1313
1494
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1314
1495
|
console.log('');
|
|
1315
1496
|
console.log(`Title: ${feature.title}`);
|
|
@@ -1321,6 +1502,9 @@ async function main() {
|
|
|
1321
1502
|
if (winner) {
|
|
1322
1503
|
console.log(`Winner: ${winner}`);
|
|
1323
1504
|
}
|
|
1505
|
+
if (rationale) {
|
|
1506
|
+
console.log(`Rationale: ${rationale}`);
|
|
1507
|
+
}
|
|
1324
1508
|
console.log('');
|
|
1325
1509
|
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
1326
1510
|
console.log('🚀 Speed Mode: Prove It Works');
|
|
@@ -1414,14 +1598,14 @@ async function main() {
|
|
|
1414
1598
|
console.log('💬 Now ask Claude Code:');
|
|
1415
1599
|
console.log(` "Help me with feature discovery for #${featureId}"`);
|
|
1416
1600
|
console.log('');
|
|
1417
|
-
console.log('Claude will use the feature-
|
|
1601
|
+
console.log('Claude will use the feature-planning skill to guide you through:');
|
|
1418
1602
|
console.log(' 1. Suggesting 3 UX approaches');
|
|
1419
1603
|
console.log(' 2. Optional prototyping');
|
|
1420
1604
|
console.log(' 3. Choosing the winner');
|
|
1421
1605
|
console.log(' 4. Generating BDD scenarios');
|
|
1422
1606
|
console.log(' 5. Transitioning to implementation');
|
|
1423
1607
|
console.log('');
|
|
1424
|
-
console.log('📋 The skill is at: .claude/skills/feature-
|
|
1608
|
+
console.log('📋 The skill is at: .claude/skills/feature-planning/SKILL.md');
|
|
1425
1609
|
}
|
|
1426
1610
|
);
|
|
1427
1611
|
} else {
|
|
@@ -1439,14 +1623,14 @@ async function main() {
|
|
|
1439
1623
|
console.log('💬 Now ask Claude Code:');
|
|
1440
1624
|
console.log(` "Help me with feature discovery for #${featureId}"`);
|
|
1441
1625
|
console.log('');
|
|
1442
|
-
console.log('Claude will use the feature-
|
|
1626
|
+
console.log('Claude will use the feature-planning skill to guide you through:');
|
|
1443
1627
|
console.log(' 1. Suggesting 3 UX approaches');
|
|
1444
1628
|
console.log(' 2. Optional prototyping');
|
|
1445
1629
|
console.log(' 3. Choosing the winner');
|
|
1446
1630
|
console.log(' 4. Generating BDD scenarios');
|
|
1447
1631
|
console.log(' 5. Transitioning to implementation');
|
|
1448
1632
|
console.log('');
|
|
1449
|
-
console.log('📋 The skill is at: .claude/skills/feature-
|
|
1633
|
+
console.log('📋 The skill is at: .claude/skills/feature-planning/SKILL.md');
|
|
1450
1634
|
}
|
|
1451
1635
|
});
|
|
1452
1636
|
});
|
|
@@ -1461,11 +1645,9 @@ Commands:
|
|
|
1461
1645
|
jettypod work create <type> <title> [desc] [--parent=ID]
|
|
1462
1646
|
Types: epic, feature, bug, chore
|
|
1463
1647
|
|
|
1464
|
-
jettypod
|
|
1465
|
-
Show
|
|
1466
|
-
|
|
1467
|
-
jettypod work completed
|
|
1468
|
-
Show all completed work items
|
|
1648
|
+
jettypod backlog [filter]
|
|
1649
|
+
Show work items (active by default)
|
|
1650
|
+
Filters: all, completed
|
|
1469
1651
|
|
|
1470
1652
|
jettypod work show <id>
|
|
1471
1653
|
Show work item details
|
|
@@ -82,7 +82,7 @@ Feature: Mode defaults to discovery on work item creation
|
|
|
82
82
|
And I create a feature "Speed Feature" with mode "speed" and parent epic
|
|
83
83
|
And I create a bug "Stable Bug" with mode "stable" and parent epic
|
|
84
84
|
And I create a chore "Test Chore" without mode and parent epic
|
|
85
|
-
When I view the
|
|
85
|
+
When I view the backlog
|
|
86
86
|
Then I see the epic without mode indicator
|
|
87
87
|
And I see the feature with mode "speed"
|
|
88
88
|
And I see the bug with mode "stable"
|
package/jettypod.js
CHANGED
|
@@ -138,7 +138,7 @@ Status: ${currentWork.status}
|
|
|
138
138
|
Use JettyPod commands to track work:
|
|
139
139
|
- jettypod work create <type> <title> [desc] [--parent=ID]
|
|
140
140
|
- jettypod work start <id>
|
|
141
|
-
- jettypod
|
|
141
|
+
- jettypod backlog
|
|
142
142
|
- jettypod decisions (view architectural and technical decisions)
|
|
143
143
|
|
|
144
144
|
EPIC DISCOVERY DETECTION:
|
|
@@ -194,7 +194,7 @@ CONFIRMATION REQUIRED BEFORE TRANSITION:
|
|
|
194
194
|
When user expresses intent to: prepare for production, launch to customers, accept external users, go live, deploy publicly, make it production-ready, or similar - you MUST:
|
|
195
195
|
|
|
196
196
|
1. **STOP - First, check what will be created**:
|
|
197
|
-
- Run \`jettypod
|
|
197
|
+
- Run \`jettypod backlog\` to count stable mode features
|
|
198
198
|
- Each stable feature will get 3 production chores (Security, Scale, Compliance)
|
|
199
199
|
|
|
200
200
|
2. **Ask for confirmation with specific impact**:
|
|
@@ -476,7 +476,7 @@ This splits your terminal so you can see both at once:
|
|
|
476
476
|
│ terminal │ terminal │
|
|
477
477
|
└────────────┴────────────┘
|
|
478
478
|
|
|
479
|
-
In the right terminal, type \`jettypod
|
|
479
|
+
In the right terminal, type \`jettypod backlog\` and press Enter - you'll see a visual tree of all your work."
|
|
480
480
|
|
|
481
481
|
**CRITICAL: After creating all epics, save checkpoint by running:**
|
|
482
482
|
try {
|
|
@@ -577,8 +577,8 @@ I'll help you:
|
|
|
577
577
|
|
|
578
578
|
**Which epic should we start with?**"
|
|
579
579
|
|
|
580
|
-
**CRITICAL: After user picks an epic, immediately invoke the epic-
|
|
581
|
-
Use the Skill tool to invoke: epic-
|
|
580
|
+
**CRITICAL: After user picks an epic, immediately invoke the epic-planning skill:**
|
|
581
|
+
Use the Skill tool to invoke: epic-planning
|
|
582
582
|
|
|
583
583
|
This ensures consistent epic planning workflow. DO NOT manually guide them - let the skill handle it.
|
|
584
584
|
|
|
@@ -1053,6 +1053,13 @@ switch (command) {
|
|
|
1053
1053
|
}
|
|
1054
1054
|
break;
|
|
1055
1055
|
|
|
1056
|
+
case 'backlog':
|
|
1057
|
+
// Backlog viewing - delegates to work tracking module
|
|
1058
|
+
const workTracking = require('./features/work-tracking/index.js');
|
|
1059
|
+
process.argv = ['node', 'work-tracking', 'backlog', ...args];
|
|
1060
|
+
workTracking.main();
|
|
1061
|
+
break;
|
|
1062
|
+
|
|
1056
1063
|
case 'docs':
|
|
1057
1064
|
const docsSubcommand = args[0];
|
|
1058
1065
|
|
|
@@ -1340,7 +1347,7 @@ switch (command) {
|
|
|
1340
1347
|
}
|
|
1341
1348
|
|
|
1342
1349
|
console.log(`✅ Created ${choresCreated} chores for external readiness`);
|
|
1343
|
-
console.log(`\nRun 'jettypod
|
|
1350
|
+
console.log(`\nRun 'jettypod backlog' to see all items`);
|
|
1344
1351
|
console.log(`Run 'jettypod work start <id>' to begin work`);
|
|
1345
1352
|
|
|
1346
1353
|
} catch (err) {
|
|
@@ -1508,7 +1515,7 @@ switch (command) {
|
|
|
1508
1515
|
console.log(' jettypod work create epic "Your First Epic" "Description"');
|
|
1509
1516
|
console.log('');
|
|
1510
1517
|
console.log('Then plan the features for that epic:');
|
|
1511
|
-
console.log(' jettypod work epic-
|
|
1518
|
+
console.log(' jettypod work epic-planning <epic-id>');
|
|
1512
1519
|
console.log('');
|
|
1513
1520
|
console.log('💡 Tip: Claude Code will help you brainstorm features for each epic');
|
|
1514
1521
|
|
|
@@ -1576,7 +1583,7 @@ CLAUDE.md has been generated with your current project context.
|
|
|
1576
1583
|
Open Claude Code to start working.
|
|
1577
1584
|
|
|
1578
1585
|
Quick commands:
|
|
1579
|
-
jettypod
|
|
1586
|
+
jettypod backlog Show all work items
|
|
1580
1587
|
jettypod project info Show project status
|
|
1581
1588
|
`);
|
|
1582
1589
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Migration: Add discovery_rationale field for feature discovery decisions
|
|
2
|
+
// Created: 2025-01-06
|
|
3
|
+
// Purpose: Track rationale for UX approach chosen during feature discovery
|
|
4
|
+
// Related: Feature-discover skill - records why an approach was selected
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
id: '009-discovery-rationale-field',
|
|
8
|
+
description: 'Add discovery_rationale field for feature discovery decisions',
|
|
9
|
+
|
|
10
|
+
up: (db) => {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
db.run(
|
|
13
|
+
`ALTER TABLE work_items ADD COLUMN discovery_rationale TEXT`,
|
|
14
|
+
(err) => {
|
|
15
|
+
if (err && !err.message.includes('duplicate column')) {
|
|
16
|
+
return reject(err);
|
|
17
|
+
}
|
|
18
|
+
console.log('Added discovery_rationale column to work_items');
|
|
19
|
+
resolve();
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
};
|