specsmd 0.0.0-dev.79 → 0.0.0-dev.80
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.
|
@@ -44,6 +44,12 @@ You are the **Builder Agent** for FIRE (Fast Intent-Run Engineering).
|
|
|
44
44
|
|
|
45
45
|
<step n="4" title="Route by State">
|
|
46
46
|
<check if="active run exists">
|
|
47
|
+
<action>Read runs.active[0] from state.yaml</action>
|
|
48
|
+
<action>Read scope (single/batch/wide) and work_items array</action>
|
|
49
|
+
<action>Count items by status: completed, in_progress, pending</action>
|
|
50
|
+
<output>Active run {id} ({scope}) — {completed_count} done, {remaining_count} remaining</output>
|
|
51
|
+
<mandate>DO NOT treat completed items as needing re-execution</mandate>
|
|
52
|
+
<mandate>ONLY work on the current_item from state.yaml</mandate>
|
|
47
53
|
<action>Resume execution — invoke run-execute skill</action>
|
|
48
54
|
</check>
|
|
49
55
|
<check if="pending work items exist">
|
|
@@ -61,28 +61,48 @@ Supports both single-item and multi-item (batch/wide) runs.
|
|
|
61
61
|
</check>
|
|
62
62
|
|
|
63
63
|
<check if="runs.active has entries">
|
|
64
|
-
<action>Load run
|
|
65
|
-
<action>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
64
|
+
<action>Load active run from state.yaml runs.active[0]</action>
|
|
65
|
+
<action>Read scope (single/batch/wide) and work_items array</action>
|
|
66
|
+
|
|
67
|
+
<substep n="0a" title="Enumerate Work Item Status">
|
|
68
|
+
<action>For EACH work item in runs.active[0].work_items, classify by status:</action>
|
|
69
|
+
<action>Build status summary from state.yaml (NOT from artifact files):</action>
|
|
70
|
+
<format>
|
|
71
|
+
[DONE] {item-id} — completed
|
|
72
|
+
[WORKING] {item-id} (phase: {current_phase}) — in_progress
|
|
73
|
+
[PENDING] {item-id} — pending
|
|
74
|
+
</format>
|
|
75
|
+
<action>Count: completed={X}, in_progress={Y}, pending={Z}</action>
|
|
76
|
+
</substep>
|
|
77
|
+
|
|
78
|
+
<substep n="0b" title="Determine Resume Point for Current Item">
|
|
79
|
+
<action>Get current_item from state.yaml</action>
|
|
80
|
+
<action>Read current_phase from the current item's entry in work_items</action>
|
|
81
|
+
|
|
82
|
+
<determine_resume_point>
|
|
83
|
+
Use current_phase from state.yaml to determine resume point:
|
|
84
|
+
|
|
85
|
+
| current_phase | Resume At |
|
|
86
|
+
|---------------|-----------|
|
|
87
|
+
| plan (or unset) | Step 3 (Generate Plan) |
|
|
88
|
+
| execute | Step 5 (Implementation) |
|
|
89
|
+
| test | Step 6 (Run Tests) |
|
|
90
|
+
| review | Step 6b (Code Review) |
|
|
91
|
+
</determine_resume_point>
|
|
92
|
+
</substep>
|
|
93
|
+
|
|
94
|
+
<llm critical="true">
|
|
95
|
+
<mandate>NEVER call --complete-item for items with status "completed" — they are already done</mandate>
|
|
96
|
+
<mandate>NEVER re-execute steps (plan, implement, test) for completed items</mandate>
|
|
97
|
+
<mandate>ONLY work on the current_item identified in state.yaml</mandate>
|
|
98
|
+
<mandate>Use current_phase from state.yaml — do NOT infer phase from artifact file existence</mandate>
|
|
99
|
+
</llm>
|
|
81
100
|
|
|
82
101
|
<output>
|
|
83
|
-
Resuming run {run-id} for work item {current_item}.
|
|
102
|
+
Resuming run {run-id} ({scope}) for work item {current_item}.
|
|
84
103
|
Mode: {mode}
|
|
85
|
-
|
|
104
|
+
Phase: {current_phase}
|
|
105
|
+
Status: {completed_count} done, {in_progress_count} working, {pending_count} pending
|
|
86
106
|
Resuming at: Step {step_number}
|
|
87
107
|
</output>
|
|
88
108
|
</check>
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
* --decisions=JSON - JSON array of {decision, choice, rationale}
|
|
22
22
|
* --tests=N - Number of tests added
|
|
23
23
|
* --coverage=N - Coverage percentage
|
|
24
|
+
* --force - Override phase guard (skip review phase check)
|
|
24
25
|
*/
|
|
25
26
|
|
|
26
27
|
const fs = require('fs');
|
|
@@ -391,7 +392,7 @@ function updateRunLog(runLogPath, activeRun, params, completedTime, isFullComple
|
|
|
391
392
|
// Complete Current Item (for batch runs)
|
|
392
393
|
// =============================================================================
|
|
393
394
|
|
|
394
|
-
function completeCurrentItem(rootPath, runId, params = {}) {
|
|
395
|
+
function completeCurrentItem(rootPath, runId, params = {}, options = {}) {
|
|
395
396
|
const completionParams = {
|
|
396
397
|
filesCreated: params.filesCreated || [],
|
|
397
398
|
filesModified: params.filesModified || [],
|
|
@@ -399,6 +400,7 @@ function completeCurrentItem(rootPath, runId, params = {}) {
|
|
|
399
400
|
testsAdded: params.testsAdded || 0,
|
|
400
401
|
coverage: params.coverage || 0,
|
|
401
402
|
};
|
|
403
|
+
const force = options.force || false;
|
|
402
404
|
|
|
403
405
|
validateInputs(rootPath, runId);
|
|
404
406
|
const { statePath, runLogPath } = validateFireProject(rootPath, runId);
|
|
@@ -440,6 +442,16 @@ function completeCurrentItem(rootPath, runId, params = {}) {
|
|
|
440
442
|
);
|
|
441
443
|
}
|
|
442
444
|
|
|
445
|
+
// Phase guard: item must be at 'review' phase before completion
|
|
446
|
+
const currentPhase = workItems[currentItemIndex].current_phase;
|
|
447
|
+
if (!force && currentPhase !== 'review') {
|
|
448
|
+
throw fireError(
|
|
449
|
+
`Cannot complete item "${currentItemId}" — current phase is "${currentPhase || 'unknown'}", not "review".`,
|
|
450
|
+
'COMPLETE_051',
|
|
451
|
+
'The item must reach the review phase before completion. Use --force to override.'
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
443
455
|
// Find next pending item
|
|
444
456
|
let nextItem = null;
|
|
445
457
|
for (let i = currentItemIndex + 1; i < workItems.length; i++) {
|
|
@@ -497,7 +509,7 @@ function completeCurrentItem(rootPath, runId, params = {}) {
|
|
|
497
509
|
// Complete Entire Run
|
|
498
510
|
// =============================================================================
|
|
499
511
|
|
|
500
|
-
function completeRun(rootPath, runId, params = {}) {
|
|
512
|
+
function completeRun(rootPath, runId, params = {}, options = {}) {
|
|
501
513
|
const completionParams = {
|
|
502
514
|
filesCreated: params.filesCreated || [],
|
|
503
515
|
filesModified: params.filesModified || [],
|
|
@@ -505,6 +517,7 @@ function completeRun(rootPath, runId, params = {}) {
|
|
|
505
517
|
testsAdded: params.testsAdded || 0,
|
|
506
518
|
coverage: params.coverage || 0,
|
|
507
519
|
};
|
|
520
|
+
const force = options.force || false;
|
|
508
521
|
|
|
509
522
|
validateInputs(rootPath, runId);
|
|
510
523
|
const { statePath, runLogPath } = validateFireProject(rootPath, runId);
|
|
@@ -537,6 +550,21 @@ function completeRun(rootPath, runId, params = {}) {
|
|
|
537
550
|
const workItems = activeRun.work_items || [];
|
|
538
551
|
const scope = activeRun.scope || 'single';
|
|
539
552
|
|
|
553
|
+
// Phase guard: all non-completed items must be at 'review' phase
|
|
554
|
+
if (!force) {
|
|
555
|
+
const notReady = workItems.filter(
|
|
556
|
+
item => item.status !== 'completed' && item.current_phase !== 'review'
|
|
557
|
+
);
|
|
558
|
+
if (notReady.length > 0) {
|
|
559
|
+
const list = notReady.map(i => `${i.id} (phase: ${i.current_phase || 'unknown'})`).join(', ');
|
|
560
|
+
throw fireError(
|
|
561
|
+
`Cannot complete run — ${notReady.length} item(s) have not reached review phase: ${list}.`,
|
|
562
|
+
'COMPLETE_060',
|
|
563
|
+
'All items must reach the review phase before run completion. Use --force to override.'
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
540
568
|
// Mark all items as completed
|
|
541
569
|
for (const item of workItems) {
|
|
542
570
|
if (item.status !== 'completed') {
|
|
@@ -636,6 +664,7 @@ function parseArgs(args) {
|
|
|
636
664
|
runId: args[1],
|
|
637
665
|
completeItem: false,
|
|
638
666
|
completeRunFlag: false,
|
|
667
|
+
force: false,
|
|
639
668
|
filesCreated: [],
|
|
640
669
|
filesModified: [],
|
|
641
670
|
decisions: [],
|
|
@@ -649,6 +678,8 @@ function parseArgs(args) {
|
|
|
649
678
|
result.completeItem = true;
|
|
650
679
|
} else if (arg === '--complete-run') {
|
|
651
680
|
result.completeRunFlag = true;
|
|
681
|
+
} else if (arg === '--force') {
|
|
682
|
+
result.force = true;
|
|
652
683
|
} else if (arg.startsWith('--files-created=')) {
|
|
653
684
|
try {
|
|
654
685
|
result.filesCreated = JSON.parse(arg.substring('--files-created='.length));
|
|
@@ -690,6 +721,7 @@ function printUsage() {
|
|
|
690
721
|
console.error('Flags:');
|
|
691
722
|
console.error(' --complete-item - Complete only the current work item (batch/wide runs)');
|
|
692
723
|
console.error(' --complete-run - Complete the entire run');
|
|
724
|
+
console.error(' --force - Override phase guard (skip review phase check)');
|
|
693
725
|
console.error('');
|
|
694
726
|
console.error('Options:');
|
|
695
727
|
console.error(' --files-created=JSON - JSON array of {path, purpose}');
|
|
@@ -718,6 +750,7 @@ if (require.main === module) {
|
|
|
718
750
|
const params = parseArgs(args);
|
|
719
751
|
|
|
720
752
|
try {
|
|
753
|
+
const cliOptions = { force: params.force };
|
|
721
754
|
let result;
|
|
722
755
|
if (params.completeItem) {
|
|
723
756
|
result = completeCurrentItem(params.rootPath, params.runId, {
|
|
@@ -726,7 +759,7 @@ if (require.main === module) {
|
|
|
726
759
|
decisions: params.decisions,
|
|
727
760
|
testsAdded: params.testsAdded,
|
|
728
761
|
coverage: params.coverage,
|
|
729
|
-
});
|
|
762
|
+
}, cliOptions);
|
|
730
763
|
} else {
|
|
731
764
|
// Default: complete entire run
|
|
732
765
|
result = completeRun(params.rootPath, params.runId, {
|
|
@@ -735,7 +768,7 @@ if (require.main === module) {
|
|
|
735
768
|
decisions: params.decisions,
|
|
736
769
|
testsAdded: params.testsAdded,
|
|
737
770
|
coverage: params.coverage,
|
|
738
|
-
});
|
|
771
|
+
}, cliOptions);
|
|
739
772
|
}
|
|
740
773
|
console.log(JSON.stringify(result, null, 2));
|
|
741
774
|
process.exit(0);
|
|
@@ -113,6 +113,18 @@ Plan the scope of a run by discovering available work items and suggesting group
|
|
|
113
113
|
</action>
|
|
114
114
|
</check>
|
|
115
115
|
|
|
116
|
+
<check if="state says completed but item is in runs.active[].work_items with current_phase != review">
|
|
117
|
+
<output>
|
|
118
|
+
**Suspect completion**: {work-item-id}
|
|
119
|
+
- state.yaml status: completed
|
|
120
|
+
- But current_phase: {current_phase} (not "review")
|
|
121
|
+
- Item is still in active run {run-id}
|
|
122
|
+
Resetting to in_progress — item was likely marked complete prematurely.
|
|
123
|
+
</output>
|
|
124
|
+
<action>Reset work item status to in_progress in state.yaml</action>
|
|
125
|
+
<action>Update frontmatter to match</action>
|
|
126
|
+
</check>
|
|
127
|
+
|
|
116
128
|
<check if="in state.yaml but file missing">
|
|
117
129
|
<output>Warning: {item} in state but file not found on disk</output>
|
|
118
130
|
</check>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specsmd",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.80",
|
|
4
4
|
"description": "Multi-agent orchestration system for AI-native software development. Delivers AI-DLC, Agile, and custom SDLC flows as markdown-based agent systems.",
|
|
5
5
|
"main": "lib/installer.js",
|
|
6
6
|
"bin": {
|