@comfanion/workflow 4.37.1 → 4.38.0-dev.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.
- package/package.json +1 -1
- package/src/build-info.json +2 -2
- package/src/opencode/FLOW.yaml +77 -0
- package/src/opencode/agents/architect.md +23 -1
- package/src/opencode/agents/pm.md +19 -2
- package/src/opencode/commands/dev-epic.md +169 -0
- package/src/opencode/commands/dev-sprint.md +178 -0
- package/src/opencode/config.yaml +47 -0
- package/src/opencode/plugins/README.md +32 -1
- package/src/opencode/plugins/custom-compaction.ts +296 -15
package/package.json
CHANGED
package/src/build-info.json
CHANGED
package/src/opencode/FLOW.yaml
CHANGED
|
@@ -254,6 +254,83 @@ pipeline:
|
|
|
254
254
|
# IMPLEMENTATION PHASE
|
|
255
255
|
# =========================================================================
|
|
256
256
|
|
|
257
|
+
- id: dev-sprint
|
|
258
|
+
name: Sprint Implementation (Full Workflow)
|
|
259
|
+
description: Implement entire sprint - all epics with auto-compaction
|
|
260
|
+
phase: implementation
|
|
261
|
+
command: /dev-sprint [sprint-number]
|
|
262
|
+
agent: dev
|
|
263
|
+
skills:
|
|
264
|
+
- dev-story
|
|
265
|
+
- test-design
|
|
266
|
+
- code-review
|
|
267
|
+
artifacts:
|
|
268
|
+
input:
|
|
269
|
+
- docs/sprint-artifacts/sprint-status.yaml
|
|
270
|
+
- docs/sprint-artifacts/backlog/epic-*.md
|
|
271
|
+
- CLAUDE.md
|
|
272
|
+
output:
|
|
273
|
+
- All epic implementations
|
|
274
|
+
- Updated sprint-status.yaml
|
|
275
|
+
- Sprint summary report
|
|
276
|
+
workflow:
|
|
277
|
+
description: |
|
|
278
|
+
Execute all epics in sprint sequentially:
|
|
279
|
+
1. Read sprint-status.yaml, find epics
|
|
280
|
+
2. For each epic: /dev-epic → compact
|
|
281
|
+
3. Continue until all epics done
|
|
282
|
+
4. Run sprint integration tests
|
|
283
|
+
config:
|
|
284
|
+
auto_compact: "config.yaml → epic_workflow.auto_compact"
|
|
285
|
+
auto_fix: "config.yaml → epic_workflow.auto_fix"
|
|
286
|
+
next: dev-epic # Can also run individual epics
|
|
287
|
+
|
|
288
|
+
- id: dev-epic
|
|
289
|
+
name: Epic Implementation (Full Workflow)
|
|
290
|
+
description: Implement entire epic - all stories with auto-compaction
|
|
291
|
+
phase: implementation
|
|
292
|
+
command: /dev-epic [epic-path]
|
|
293
|
+
agent: dev
|
|
294
|
+
skills:
|
|
295
|
+
- dev-story
|
|
296
|
+
- test-design
|
|
297
|
+
- code-review
|
|
298
|
+
artifacts:
|
|
299
|
+
input:
|
|
300
|
+
- docs/sprint-artifacts/backlog/epic-*.md
|
|
301
|
+
- docs/sprint-artifacts/sprint-*/.sprint-state/epic-*-state.yaml
|
|
302
|
+
- CLAUDE.md
|
|
303
|
+
output:
|
|
304
|
+
- All story implementations
|
|
305
|
+
- Epic state file (updated)
|
|
306
|
+
- Epic summary report
|
|
307
|
+
workflow:
|
|
308
|
+
description: |
|
|
309
|
+
Execute all stories in epic sequentially:
|
|
310
|
+
1. Read epic file, find stories
|
|
311
|
+
2. For each story: /dev-story → @reviewer → compact
|
|
312
|
+
3. Auto-fix review issues (max 3 attempts)
|
|
313
|
+
4. Continue until all stories done
|
|
314
|
+
5. Run epic integration tests
|
|
315
|
+
state_management:
|
|
316
|
+
location: "docs/sprint-artifacts/sprint-N/.sprint-state/epic-XX-state.yaml"
|
|
317
|
+
preserves:
|
|
318
|
+
- Current story index
|
|
319
|
+
- Completed stories
|
|
320
|
+
- Pending stories
|
|
321
|
+
- Review status
|
|
322
|
+
compaction:
|
|
323
|
+
trigger: "After each story completion"
|
|
324
|
+
restores:
|
|
325
|
+
- Epic state file (progress)
|
|
326
|
+
- Next story file (what to do)
|
|
327
|
+
- CLAUDE.md, PRD, Architecture (context)
|
|
328
|
+
config:
|
|
329
|
+
auto_compact: "config.yaml → epic_workflow.auto_compact"
|
|
330
|
+
auto_fix: "config.yaml → epic_workflow.auto_fix"
|
|
331
|
+
max_fix_attempts: "config.yaml → epic_workflow.max_fix_attempts"
|
|
332
|
+
next: dev-story # Can also run individual stories
|
|
333
|
+
|
|
257
334
|
- id: dev-story
|
|
258
335
|
name: Story Implementation
|
|
259
336
|
description: Implement story using red-green-refactor cycle
|
|
@@ -96,9 +96,31 @@ permission:
|
|
|
96
96
|
<phase name="1. Discovery">
|
|
97
97
|
<action>Search for related documents (search → then glob/grep if needed)</action>
|
|
98
98
|
<action>Read existing architecture, PRD, related modules</action>
|
|
99
|
-
<action>
|
|
99
|
+
<action critical="MANDATORY">Read PRD "Project Classification" section (first section) to understand project size</action>
|
|
100
|
+
<action>If no PRD: Load skill `architecture-design` → check size guidelines table</action>
|
|
100
101
|
<action>Identify what needs to be created/updated</action>
|
|
101
102
|
</phase>
|
|
103
|
+
|
|
104
|
+
<size-awareness critical="MANDATORY">
|
|
105
|
+
BEFORE writing architecture, you MUST know project size:
|
|
106
|
+
|
|
107
|
+
1. Read PRD → "Project Classification" section
|
|
108
|
+
2. Note the size: TOY/SMALL/MEDIUM/LARGE/ENTERPRISE
|
|
109
|
+
3. Load skill: architecture-design → see size guidelines table
|
|
110
|
+
4. Adapt your architecture depth:
|
|
111
|
+
- TOY: 200-500 lines, simple diagram
|
|
112
|
+
- SMALL: 500-1000 lines, C4 Context+Container+Component
|
|
113
|
+
- MEDIUM: 1000-2000 lines, full C4 + break into MODULES
|
|
114
|
+
- LARGE: 2000-4000 lines, multiple files, DOMAINS
|
|
115
|
+
- ENTERPRISE: 4000+ lines, per-domain files
|
|
116
|
+
|
|
117
|
+
Example:
|
|
118
|
+
- PRD says "TOY" → Write 350 lines, 3 components, NO modules
|
|
119
|
+
- PRD says "MEDIUM" → Write 1500 lines, 3 MODULES with Unit docs
|
|
120
|
+
|
|
121
|
+
DON'T write 2000-line architecture for Tetris!
|
|
122
|
+
DON'T write 500-line architecture for E-commerce!
|
|
123
|
+
</size-awareness>
|
|
102
124
|
|
|
103
125
|
<phase name="2. Planning">
|
|
104
126
|
<action>Create tasklist with todowrite()</action>
|
|
@@ -148,8 +148,25 @@ permission:
|
|
|
148
148
|
<instruction>BEFORE starting ANY work (PRD, epics, stories):</instruction>
|
|
149
149
|
|
|
150
150
|
<step n="1">If PRD exists: Read "Project Classification" section (first section)</step>
|
|
151
|
-
<step n="2">If no PRD: Load skill `prd-writing` to
|
|
152
|
-
<step n="3">
|
|
151
|
+
<step n="2">If no PRD yet: Load skill `prd-writing` → read "How to Classify Project Size" section</step>
|
|
152
|
+
<step n="3">Determine project size based on scope/complexity/data/integrations (NOT timeline!)</step>
|
|
153
|
+
<step n="4">If creating PRD: Fill "Project Classification" section FIRST before writing anything else</step>
|
|
154
|
+
<step n="5">Adapt your approach based on size</step>
|
|
155
|
+
|
|
156
|
+
<classification-reminder>
|
|
157
|
+
When creating PRD, you MUST:
|
|
158
|
+
1. Load skill: prd-writing
|
|
159
|
+
2. Read the classification guide in the skill
|
|
160
|
+
3. Ask user about: scope, data model, integrations, team size
|
|
161
|
+
4. Classify: TOY/SMALL/MEDIUM/LARGE/ENTERPRISE
|
|
162
|
+
5. Fill Project Classification table in PRD (first section!)
|
|
163
|
+
6. Then write rest of PRD according to that size
|
|
164
|
+
|
|
165
|
+
Example questions:
|
|
166
|
+
- "How many database tables do you expect?" (5-10 = SMALL, 20+ = MEDIUM)
|
|
167
|
+
- "How many external integrations?" (0-2 = SMALL, 3-5 = MEDIUM)
|
|
168
|
+
- "Is this a single app or multiple modules?" (single = SMALL, modules = MEDIUM)
|
|
169
|
+
</classification-reminder>
|
|
153
170
|
|
|
154
171
|
<key-principle>
|
|
155
172
|
TOY/SMALL → Flat structure, no modules
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Execute full epic - implement all stories sequentially with auto-compaction between stories
|
|
3
|
+
agent: dev
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /dev-epic Command
|
|
7
|
+
|
|
8
|
+
Implement entire epic by executing all stories with automatic compaction and context preservation.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
### Phase 1: Epic Setup
|
|
13
|
+
1. Find or load epic file (from path or sprint-status.yaml)
|
|
14
|
+
2. Parse all story references from epic
|
|
15
|
+
3. Load project context (CLAUDE.md, docs/prd.md, docs/architecture.md)
|
|
16
|
+
4. **Create TODO list from epic** (critical for compaction!):
|
|
17
|
+
- Parse epic file, extract all stories
|
|
18
|
+
- For each story: read story file, count tasks
|
|
19
|
+
- Add stories to TODO with task counts
|
|
20
|
+
- Add epic-level tasks (integration tests, acceptance criteria)
|
|
21
|
+
```
|
|
22
|
+
[ ] Story 1: User Registration (12 tasks)
|
|
23
|
+
[ ] Story 2: Login Flow (8 tasks)
|
|
24
|
+
[ ] Story 3: Password Reset (6 tasks)
|
|
25
|
+
[ ] Run epic integration tests
|
|
26
|
+
[ ] Verify all acceptance criteria
|
|
27
|
+
```
|
|
28
|
+
5. **Create epic state file:** `docs/sprint-artifacts/sprint-N/.sprint-state/epic-XX-state.yaml`
|
|
29
|
+
6. Mark epic as `in-progress`
|
|
30
|
+
|
|
31
|
+
### Phase 2: Story Execution Loop (for each story)
|
|
32
|
+
|
|
33
|
+
7. **Mark story as `in_progress` in TODO** (e.g., "Story 1: User Registration")
|
|
34
|
+
8. Execute story via `/dev-story` workflow:
|
|
35
|
+
- RED → GREEN → REFACTOR
|
|
36
|
+
- @coder implements tasks
|
|
37
|
+
- @reviewer validates (if auto_review: true)
|
|
38
|
+
9. **Mark story as `completed` in TODO** (✓ Story 1: User Registration)
|
|
39
|
+
10. **Update epic state file**:
|
|
40
|
+
- Move story from `pending_stories` → `completed_stories`
|
|
41
|
+
- Add metadata (tasks_completed, tests_added, review_status)
|
|
42
|
+
- Increment `current_story_index`
|
|
43
|
+
- Set `next_action: "Execute story-XX-XX.md"` (next story filename)
|
|
44
|
+
- Update `last_compaction` timestamp
|
|
45
|
+
11. **Trigger compaction** (if `epic_workflow.auto_compact: true`)
|
|
46
|
+
12. **After compaction:**
|
|
47
|
+
- Plugin reads TODO → sees next pending story
|
|
48
|
+
- Plugin reads epic state → gets story path
|
|
49
|
+
- Agent continues next story automatically
|
|
50
|
+
|
|
51
|
+
### Phase 3: Epic Completion
|
|
52
|
+
|
|
53
|
+
13. All stories done → **mark integration test TODO as `in_progress`**
|
|
54
|
+
14. Run epic integration tests (if configured)
|
|
55
|
+
15. **Mark integration test TODO as `completed`**
|
|
56
|
+
16. Update epic state: `status: "done"`
|
|
57
|
+
17. **Clear TODO** (all tasks done)
|
|
58
|
+
18. Generate epic summary
|
|
59
|
+
|
|
60
|
+
## TODO List
|
|
61
|
+
|
|
62
|
+
**Create at epic start:**
|
|
63
|
+
```
|
|
64
|
+
[ ] Story 1: User Registration
|
|
65
|
+
[ ] Story 2: Login Flow
|
|
66
|
+
[ ] Story 3: Password Reset
|
|
67
|
+
[ ] Run epic integration tests
|
|
68
|
+
[ ] Verify acceptance criteria
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Update after each story:**
|
|
72
|
+
- Mark story `completed` in TODO
|
|
73
|
+
- Mark next story `in_progress` in TODO
|
|
74
|
+
- TODO survives compaction - plugin shows it to agent
|
|
75
|
+
|
|
76
|
+
## Epic State File Format
|
|
77
|
+
|
|
78
|
+
**Location:** `docs/sprint-artifacts/sprint-N/.sprint-state/epic-XX-state.yaml`
|
|
79
|
+
|
|
80
|
+
```yaml
|
|
81
|
+
epic_id: "PROJ-E01"
|
|
82
|
+
epic_title: "User Authentication"
|
|
83
|
+
epic_path: "docs/sprint-artifacts/backlog/epic-01-user-auth.md"
|
|
84
|
+
sprint: "sprint-1"
|
|
85
|
+
status: "in-progress"
|
|
86
|
+
|
|
87
|
+
current_story_index: 1
|
|
88
|
+
total_stories: 3
|
|
89
|
+
|
|
90
|
+
completed_stories:
|
|
91
|
+
- path: "docs/sprint-artifacts/sprint-1/stories/story-01-01-registration.md"
|
|
92
|
+
title: "User Registration"
|
|
93
|
+
tasks_completed: 12
|
|
94
|
+
tests_added: 45
|
|
95
|
+
review_status: "approved"
|
|
96
|
+
completed_at: "2026-01-27T10:15:00Z"
|
|
97
|
+
|
|
98
|
+
pending_stories:
|
|
99
|
+
- path: "docs/sprint-artifacts/sprint-1/stories/story-01-02-login.md"
|
|
100
|
+
title: "Login Flow"
|
|
101
|
+
- path: "docs/sprint-artifacts/sprint-1/stories/story-01-03-password-reset.md"
|
|
102
|
+
title: "Password Reset"
|
|
103
|
+
|
|
104
|
+
next_action: "Execute story-01-02-login.md"
|
|
105
|
+
last_compaction: "2026-01-27T10:15:00Z"
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Compaction Strategy
|
|
109
|
+
|
|
110
|
+
**After compaction, agent reads (minimal context):**
|
|
111
|
+
1. Epic state file (progress + next action)
|
|
112
|
+
2. Next story file (from `next_action`)
|
|
113
|
+
3. CLAUDE.md, docs/prd.md, docs/architecture.md
|
|
114
|
+
|
|
115
|
+
**Agent does NOT re-read:**
|
|
116
|
+
- ❌ Epic file (info in state)
|
|
117
|
+
- ❌ Completed stories
|
|
118
|
+
- ❌ Previous tasks
|
|
119
|
+
|
|
120
|
+
**Context savings: ~68% less than reading all files**
|
|
121
|
+
|
|
122
|
+
## Configuration
|
|
123
|
+
|
|
124
|
+
From `config.yaml → epic_workflow`:
|
|
125
|
+
|
|
126
|
+
```yaml
|
|
127
|
+
epic_workflow:
|
|
128
|
+
auto_compact: true # Compact between stories
|
|
129
|
+
auto_fix: true # Auto-fix review issues
|
|
130
|
+
max_fix_attempts: 3 # Max fix attempts before HALT
|
|
131
|
+
pause_between_stories: false # Continue automatically
|
|
132
|
+
test_after_each_story: false # Skip per-story integration tests
|
|
133
|
+
test_after_epic: true # Run epic integration tests at end
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## IMPORTANT SKILLS TO LOAD
|
|
137
|
+
|
|
138
|
+
- `dev-story` - Story implementation workflow
|
|
139
|
+
- `test-design` - Test writing patterns
|
|
140
|
+
- `code-review` - Review and validation
|
|
141
|
+
|
|
142
|
+
## Output
|
|
143
|
+
|
|
144
|
+
- All story implementations (code + tests)
|
|
145
|
+
- Epic state file (updated)
|
|
146
|
+
- Updated epic file (stories marked `[x]`)
|
|
147
|
+
- Epic summary report
|
|
148
|
+
|
|
149
|
+
## HALT Conditions
|
|
150
|
+
|
|
151
|
+
The workflow will HALT and ask for input when:
|
|
152
|
+
- Story fails 3 times (implementation/tests)
|
|
153
|
+
- Code review fails after max_fix_attempts
|
|
154
|
+
- Missing dependencies
|
|
155
|
+
- Ambiguous requirements
|
|
156
|
+
- Integration tests fail
|
|
157
|
+
|
|
158
|
+
## Epic Status Flow
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
ready-for-dev → in-progress → [story 1] → compact → [story 2] → compact → ... → done
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Next Steps After Completion
|
|
165
|
+
|
|
166
|
+
- Epic marked `done` in epic state file
|
|
167
|
+
- All stories marked `done`
|
|
168
|
+
- If part of `/dev-sprint`: continue to next epic automatically
|
|
169
|
+
- If standalone: ready for sprint review
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Execute full sprint - implement all epics sequentially with auto-compaction between epics
|
|
3
|
+
agent: dev
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /dev-sprint Command
|
|
7
|
+
|
|
8
|
+
Implement entire sprint by executing all epics with automatic compaction.
|
|
9
|
+
|
|
10
|
+
## Process
|
|
11
|
+
|
|
12
|
+
### Phase 1: Sprint Setup
|
|
13
|
+
1. Find sprint (from number or sprint-status.yaml)
|
|
14
|
+
2. Read `sprint-status.yaml`
|
|
15
|
+
3. Parse all epics in sprint
|
|
16
|
+
4. Load project context (CLAUDE.md, docs/prd.md, docs/architecture.md)
|
|
17
|
+
5. **Create TODO list from sprint** (critical for compaction!):
|
|
18
|
+
- Parse sprint-status.yaml, extract all epics
|
|
19
|
+
- For each epic: read epic file, count stories and tasks
|
|
20
|
+
- Add epics to TODO with story/task counts
|
|
21
|
+
- Add sprint-level tasks (integration tests, acceptance criteria, metrics)
|
|
22
|
+
```
|
|
23
|
+
[ ] Epic 1: User Authentication (3 stories, 26 tasks)
|
|
24
|
+
[ ] Epic 2: Product Catalog (5 stories, 42 tasks)
|
|
25
|
+
[ ] Epic 3: Shopping Cart (4 stories, 31 tasks)
|
|
26
|
+
[ ] Run sprint integration tests
|
|
27
|
+
[ ] Verify sprint acceptance criteria
|
|
28
|
+
[ ] Generate sprint metrics
|
|
29
|
+
```
|
|
30
|
+
6. Mark sprint as `in-progress` in sprint-status.yaml
|
|
31
|
+
|
|
32
|
+
### Phase 2: Epic Execution Loop (for each epic)
|
|
33
|
+
|
|
34
|
+
7. **Mark epic as `in_progress` in TODO** (e.g., "Epic 1: User Authentication")
|
|
35
|
+
8. Execute epic via `/dev-epic` workflow:
|
|
36
|
+
- Epic creates its own TODO for stories
|
|
37
|
+
- Epic executes all stories
|
|
38
|
+
- Auto-compacts between stories
|
|
39
|
+
- Auto-fixes code review issues
|
|
40
|
+
9. **Mark epic as `completed` in TODO** (✓ Epic 1: User Authentication)
|
|
41
|
+
10. **Update sprint-status.yaml**:
|
|
42
|
+
- Mark epic as `done`
|
|
43
|
+
- Update `stories_completed` count
|
|
44
|
+
- Find next epic
|
|
45
|
+
11. **Trigger compaction** (if `epic_workflow.auto_compact: true`)
|
|
46
|
+
12. **After compaction:**
|
|
47
|
+
- Plugin reads TODO → sees next pending epic
|
|
48
|
+
- Plugin reads sprint-status.yaml → gets epic path
|
|
49
|
+
- Agent continues next epic automatically
|
|
50
|
+
|
|
51
|
+
### Phase 3: Sprint Completion
|
|
52
|
+
|
|
53
|
+
13. All epics done → **mark integration test TODO as `in_progress`**
|
|
54
|
+
14. Run sprint integration tests (if configured)
|
|
55
|
+
15. **Mark integration test TODO as `completed`**
|
|
56
|
+
16. **Mark acceptance criteria TODO as `in_progress`**
|
|
57
|
+
17. Verify sprint acceptance criteria
|
|
58
|
+
18. **Mark acceptance criteria TODO as `completed`**
|
|
59
|
+
19. **Mark metrics TODO as `in_progress`**
|
|
60
|
+
20. Generate sprint metrics (velocity, completion rate, etc.)
|
|
61
|
+
21. **Mark metrics TODO as `completed`**
|
|
62
|
+
22. Update sprint-status.yaml: `status: "done"`
|
|
63
|
+
23. **Clear TODO** (all tasks done)
|
|
64
|
+
24. Generate sprint summary
|
|
65
|
+
|
|
66
|
+
## TODO List
|
|
67
|
+
|
|
68
|
+
**Create at sprint start:**
|
|
69
|
+
```
|
|
70
|
+
[ ] Epic 1: User Authentication (3 stories)
|
|
71
|
+
[ ] Epic 2: Product Catalog (5 stories)
|
|
72
|
+
[ ] Epic 3: Shopping Cart (4 stories)
|
|
73
|
+
[ ] Run sprint integration tests
|
|
74
|
+
[ ] Verify sprint acceptance criteria
|
|
75
|
+
[ ] Generate sprint metrics
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Update after each epic:**
|
|
79
|
+
- Mark epic `completed` in TODO
|
|
80
|
+
- Mark next epic `in_progress` in TODO
|
|
81
|
+
- TODO survives compaction - plugin shows it to agent
|
|
82
|
+
|
|
83
|
+
**Note:** Each epic creates its own TODO for stories, clears it when done
|
|
84
|
+
|
|
85
|
+
## Sprint State Tracking
|
|
86
|
+
|
|
87
|
+
**Location:** `docs/sprint-artifacts/sprint-status.yaml`
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
sprints:
|
|
91
|
+
- id: sprint-1
|
|
92
|
+
name: "Sprint 1 - Core Features"
|
|
93
|
+
status: in-progress
|
|
94
|
+
start_date: "2026-01-20"
|
|
95
|
+
end_date: "2026-02-03"
|
|
96
|
+
|
|
97
|
+
epics:
|
|
98
|
+
- id: PROJ-E01
|
|
99
|
+
title: "User Authentication"
|
|
100
|
+
path: "docs/sprint-artifacts/backlog/epic-01-user-auth.md"
|
|
101
|
+
status: done
|
|
102
|
+
stories_completed: 3
|
|
103
|
+
stories_total: 3
|
|
104
|
+
|
|
105
|
+
- id: PROJ-E02
|
|
106
|
+
title: "Product Catalog"
|
|
107
|
+
path: "docs/sprint-artifacts/backlog/epic-02-catalog.md"
|
|
108
|
+
status: in-progress # ← Current epic
|
|
109
|
+
stories_completed: 2
|
|
110
|
+
stories_total: 5
|
|
111
|
+
|
|
112
|
+
- id: PROJ-E03
|
|
113
|
+
title: "Shopping Cart"
|
|
114
|
+
path: "docs/sprint-artifacts/backlog/epic-03-cart.md"
|
|
115
|
+
status: ready-for-dev
|
|
116
|
+
stories_total: 4
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Each epic also has state file in `.sprint-state/epic-XX-state.yaml`
|
|
120
|
+
|
|
121
|
+
## Compaction Strategy
|
|
122
|
+
|
|
123
|
+
**After compaction, agent reads:**
|
|
124
|
+
1. sprint-status.yaml (knows which epic is next)
|
|
125
|
+
2. Next epic file
|
|
126
|
+
3. Next epic state file (if exists)
|
|
127
|
+
4. CLAUDE.md, docs/prd.md, docs/architecture.md
|
|
128
|
+
|
|
129
|
+
**Agent does NOT re-read:**
|
|
130
|
+
- ❌ Completed epic files
|
|
131
|
+
- ❌ Completed story files
|
|
132
|
+
- ❌ Previous epic states
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
From `config.yaml → epic_workflow`:
|
|
137
|
+
|
|
138
|
+
```yaml
|
|
139
|
+
epic_workflow:
|
|
140
|
+
auto_compact: true # Compact between epics
|
|
141
|
+
auto_fix: true # Auto-fix review issues
|
|
142
|
+
pause_between_stories: false # Continue automatically
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## IMPORTANT SKILLS TO LOAD
|
|
146
|
+
|
|
147
|
+
- `dev-story` - Story implementation workflow
|
|
148
|
+
- `test-design` - Test writing patterns
|
|
149
|
+
- `code-review` - Review and validation
|
|
150
|
+
|
|
151
|
+
## Output
|
|
152
|
+
|
|
153
|
+
- All epic implementations (code + tests)
|
|
154
|
+
- Updated sprint-status.yaml
|
|
155
|
+
- Sprint summary report
|
|
156
|
+
- Sprint metrics (velocity, completion rate)
|
|
157
|
+
|
|
158
|
+
## HALT Conditions
|
|
159
|
+
|
|
160
|
+
The workflow will HALT and ask for input when:
|
|
161
|
+
- Epic fails repeatedly (3+ failed stories)
|
|
162
|
+
- Multiple stories rejected by @reviewer
|
|
163
|
+
- Sprint deadline approaching (< 20% time, > 50% work)
|
|
164
|
+
- Missing dependencies
|
|
165
|
+
- Sprint integration tests fail
|
|
166
|
+
|
|
167
|
+
## Sprint Status Flow
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
planned → in-progress → [epic 1] → compact → [epic 2] → compact → ... → done
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Next Steps After Completion
|
|
174
|
+
|
|
175
|
+
- Sprint marked `done` in sprint-status.yaml
|
|
176
|
+
- All epics and stories marked `done`
|
|
177
|
+
- Ready for sprint review/retrospective
|
|
178
|
+
- Run `/retrospective` to capture learnings
|
package/src/opencode/config.yaml
CHANGED
|
@@ -197,6 +197,53 @@ development:
|
|
|
197
197
|
- NUMBERS # Add metrics/numbers
|
|
198
198
|
- LINK # Add links/references
|
|
199
199
|
|
|
200
|
+
# =============================================================================
|
|
201
|
+
# EPIC WORKFLOW (/dev-epic command)
|
|
202
|
+
# =============================================================================
|
|
203
|
+
epic_workflow:
|
|
204
|
+
# Auto-compact between stories (saves context, continues next story)
|
|
205
|
+
# When true: story done → compact → restore context → next story
|
|
206
|
+
# When false: story done → ask user to continue
|
|
207
|
+
auto_compact: true
|
|
208
|
+
|
|
209
|
+
# Auto-fix code review issues
|
|
210
|
+
# When true: review failed → @coder fixes → re-review → continue
|
|
211
|
+
# When false: review failed → HALT, ask user
|
|
212
|
+
auto_fix: true
|
|
213
|
+
|
|
214
|
+
# Max fix attempts before HALT (prevents infinite loops)
|
|
215
|
+
max_fix_attempts: 3
|
|
216
|
+
|
|
217
|
+
# Pause between stories for manual review
|
|
218
|
+
# When true: story done → show summary → ask to continue
|
|
219
|
+
# When false: story done → immediately start next story
|
|
220
|
+
pause_between_stories: false
|
|
221
|
+
|
|
222
|
+
# Run integration tests after each story
|
|
223
|
+
# When true: story done → run integration tests → continue
|
|
224
|
+
# When false: skip per-story integration tests
|
|
225
|
+
test_after_each_story: false
|
|
226
|
+
|
|
227
|
+
# Run integration tests after epic complete
|
|
228
|
+
# When true: all stories done → run epic integration tests
|
|
229
|
+
# When false: skip epic integration tests
|
|
230
|
+
test_after_epic: true
|
|
231
|
+
|
|
232
|
+
# Compaction strategy
|
|
233
|
+
compaction:
|
|
234
|
+
# Save epic state to sprint-status.yaml
|
|
235
|
+
save_epic_state: true
|
|
236
|
+
|
|
237
|
+
# Files to preserve in context after compaction
|
|
238
|
+
preserve_files:
|
|
239
|
+
- "CLAUDE.md"
|
|
240
|
+
- "AGENTS.md"
|
|
241
|
+
- "docs/prd.md"
|
|
242
|
+
- "docs/architecture.md"
|
|
243
|
+
- "docs/coding-standards/README.md"
|
|
244
|
+
- "docs/coding-standards/patterns.md"
|
|
245
|
+
# Epic file and next story added dynamically
|
|
246
|
+
|
|
200
247
|
# =============================================================================
|
|
201
248
|
# CHANGELOG
|
|
202
249
|
# =============================================================================
|
|
@@ -52,10 +52,11 @@ Checks for updates and shows a toast notification if a newer version is availabl
|
|
|
52
52
|
|
|
53
53
|
### custom-compaction.ts
|
|
54
54
|
|
|
55
|
-
Intelligent session compaction that preserves flow context.
|
|
55
|
+
Intelligent session compaction that preserves flow context with epic workflow support.
|
|
56
56
|
|
|
57
57
|
**Features:**
|
|
58
58
|
- Tracks todo list and story task status
|
|
59
|
+
- **Epic workflow state preservation** (new!)
|
|
59
60
|
- Identifies critical documentation files for context
|
|
60
61
|
- Generates smart continuation prompts
|
|
61
62
|
- Differentiates between completed and interrupted tasks
|
|
@@ -68,8 +69,31 @@ Intelligent session compaction that preserves flow context.
|
|
|
68
69
|
|----------|-------------------|
|
|
69
70
|
| **Task Completed** | Summary of completed work, next steps, validation reminders |
|
|
70
71
|
| **Task Interrupted** | Current task, what was done, resume instructions, file list |
|
|
72
|
+
| **Epic in Progress** | Epic state file, current story, next action, minimal context |
|
|
73
|
+
|
|
74
|
+
**Epic Workflow Support:**
|
|
75
|
+
|
|
76
|
+
When `/dev-epic` is running, the plugin:
|
|
77
|
+
1. Finds active epic state file in `sprint-N/.sprint-state/epic-XX-state.yaml`
|
|
78
|
+
2. Reads current story from epic state
|
|
79
|
+
3. Generates minimal read commands:
|
|
80
|
+
- Epic state file (progress tracking)
|
|
81
|
+
- Next story file (what to do)
|
|
82
|
+
- CLAUDE.md, PRD, Architecture (context)
|
|
83
|
+
4. Agent resumes automatically without re-reading completed stories
|
|
84
|
+
|
|
85
|
+
**Epic State File Location:**
|
|
86
|
+
```
|
|
87
|
+
docs/sprint-artifacts/
|
|
88
|
+
sprint-1/
|
|
89
|
+
.sprint-state/
|
|
90
|
+
epic-01-state.yaml # Tracks epic-01 progress
|
|
91
|
+
epic-02-state.yaml # Tracks epic-02 progress
|
|
92
|
+
```
|
|
71
93
|
|
|
72
94
|
**Critical Files Passed to Context:**
|
|
95
|
+
|
|
96
|
+
**For regular /dev-story:**
|
|
73
97
|
- `CLAUDE.md` - Project coding standards
|
|
74
98
|
- `AGENTS.md` - Agent definitions
|
|
75
99
|
- `project-context.md` - Project overview
|
|
@@ -79,6 +103,13 @@ Intelligent session compaction that preserves flow context.
|
|
|
79
103
|
- `docs/coding-standards/*.md` - Coding patterns
|
|
80
104
|
- Active story file (if in progress)
|
|
81
105
|
|
|
106
|
+
**For /dev-epic workflow:**
|
|
107
|
+
- Epic state file (e.g., `sprint-1/.sprint-state/epic-01-state.yaml`)
|
|
108
|
+
- Next story file (from epic state)
|
|
109
|
+
- `CLAUDE.md`, `AGENTS.md`, `docs/prd.md`, `docs/architecture.md`
|
|
110
|
+
- ❌ **NOT** completed story files (saves context!)
|
|
111
|
+
- ❌ **NOT** epic file (info in state file)
|
|
112
|
+
|
|
82
113
|
## Installation
|
|
83
114
|
|
|
84
115
|
Plugins in `.opencode/plugins/` are automatically loaded by OpenCode.
|
|
@@ -44,6 +44,7 @@ interface SessionContext {
|
|
|
44
44
|
story: StoryContext | null
|
|
45
45
|
relevantFiles: string[]
|
|
46
46
|
activeAgent: string | null
|
|
47
|
+
activeCommand: string | null // /dev-story, /dev-epic, /dev-sprint
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
// Base files ALL agents need after compaction (to remember who they are)
|
|
@@ -116,6 +117,7 @@ const MUST_READ_FILES: Record<string, string[]> = {
|
|
|
116
117
|
"CLAUDE.md",
|
|
117
118
|
"docs/prd.md",
|
|
118
119
|
"docs/architecture.md",
|
|
120
|
+
// epic state path added dynamically (if in epic workflow)
|
|
119
121
|
// story path added dynamically
|
|
120
122
|
],
|
|
121
123
|
coder: [
|
|
@@ -173,13 +175,28 @@ export const CustomCompactionPlugin: Plugin = async (ctx) => {
|
|
|
173
175
|
/**
|
|
174
176
|
* Generate Read commands that agent MUST execute after compaction
|
|
175
177
|
*/
|
|
176
|
-
function generateReadCommands(agent: string | null, story: StoryContext | null): string {
|
|
178
|
+
async function generateReadCommands(agent: string | null, story: StoryContext | null, activeCommand: string | null): Promise<string> {
|
|
177
179
|
const agentKey = (typeof agent === 'string' ? agent.toLowerCase() : null) || "default"
|
|
178
180
|
const filesToRead = [...(MUST_READ_FILES[agentKey] || MUST_READ_FILES.default)]
|
|
179
181
|
|
|
180
|
-
// For dev/coder: add
|
|
181
|
-
if ((agentKey === "dev" || agentKey === "coder") &&
|
|
182
|
-
|
|
182
|
+
// For dev/coder: add command file first
|
|
183
|
+
if ((agentKey === "dev" || agentKey === "coder") && activeCommand) {
|
|
184
|
+
const commandFile = activeCommand.replace("/", "") + ".md"
|
|
185
|
+
filesToRead.unshift(`.opencode/commands/${commandFile}`)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// For dev/coder: add epic state file if in epic workflow
|
|
189
|
+
if ((agentKey === "dev" || agentKey === "coder")) {
|
|
190
|
+
const epicState = await getActiveEpicState()
|
|
191
|
+
if (epicState) {
|
|
192
|
+
// Epic state file (has all context)
|
|
193
|
+
filesToRead.unshift(epicState.statePath.replace(directory + "/", ""))
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Then story file if active
|
|
197
|
+
if (story) {
|
|
198
|
+
filesToRead.unshift(story.path) // Story first!
|
|
199
|
+
}
|
|
183
200
|
}
|
|
184
201
|
|
|
185
202
|
const commands = filesToRead.map((f, i) => `${i + 1}. Read("${f}")`).join("\n")
|
|
@@ -203,8 +220,158 @@ DO NOT skip this step. DO NOT ask user what to do. Just read these files first.`
|
|
|
203
220
|
}
|
|
204
221
|
}
|
|
205
222
|
|
|
223
|
+
interface EpicState {
|
|
224
|
+
statePath: string
|
|
225
|
+
epicId: string
|
|
226
|
+
epicTitle: string
|
|
227
|
+
status: string
|
|
228
|
+
currentStoryIndex: number
|
|
229
|
+
totalStories: number
|
|
230
|
+
nextAction: string | null
|
|
231
|
+
nextStoryPath: string | null
|
|
232
|
+
completedCount: number
|
|
233
|
+
pendingCount: number
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async function getActiveEpicState(): Promise<EpicState | null> {
|
|
237
|
+
try {
|
|
238
|
+
// Search for epic state files in all sprint folders
|
|
239
|
+
const sprintArtifactsPath = join(directory, "docs", "sprint-artifacts")
|
|
240
|
+
const entries = await readdir(sprintArtifactsPath)
|
|
241
|
+
|
|
242
|
+
for (const entry of entries) {
|
|
243
|
+
if (entry.startsWith("sprint-")) {
|
|
244
|
+
const statePath = join(sprintArtifactsPath, entry, ".sprint-state")
|
|
245
|
+
try {
|
|
246
|
+
const stateFiles = await readdir(statePath)
|
|
247
|
+
for (const stateFile of stateFiles) {
|
|
248
|
+
if (stateFile.endsWith("-state.yaml")) {
|
|
249
|
+
const fullPath = join(statePath, stateFile)
|
|
250
|
+
const content = await readFile(fullPath, "utf-8")
|
|
251
|
+
|
|
252
|
+
// Check if this epic is in-progress
|
|
253
|
+
if (content.includes("status: \"in-progress\"") || content.includes("status: in-progress")) {
|
|
254
|
+
// Parse epic state
|
|
255
|
+
const epicIdMatch = content.match(/epic_id:\s*["']?([^"'\n]+)["']?/i)
|
|
256
|
+
const epicTitleMatch = content.match(/epic_title:\s*["']?([^"'\n]+)["']?/i)
|
|
257
|
+
const statusMatch = content.match(/status:\s*["']?([^"'\n]+)["']?/i)
|
|
258
|
+
const currentIndexMatch = content.match(/current_story_index:\s*(\d+)/i)
|
|
259
|
+
const totalStoriesMatch = content.match(/total_stories:\s*(\d+)/i)
|
|
260
|
+
const nextActionMatch = content.match(/next_action:\s*["']?([^"'\n]+)["']?/i)
|
|
261
|
+
|
|
262
|
+
// Count completed/pending stories
|
|
263
|
+
const completedSection = content.match(/completed_stories:([\s\S]*?)(?=pending_stories:|$)/i)
|
|
264
|
+
const pendingSection = content.match(/pending_stories:([\s\S]*?)(?=\n\w+:|$)/i)
|
|
265
|
+
|
|
266
|
+
const completedCount = completedSection
|
|
267
|
+
? (completedSection[1].match(/- path:/g) || []).length
|
|
268
|
+
: 0
|
|
269
|
+
const pendingCount = pendingSection
|
|
270
|
+
? (pendingSection[1].match(/- path:/g) || []).length
|
|
271
|
+
: 0
|
|
272
|
+
|
|
273
|
+
// Extract next story path from next_action
|
|
274
|
+
let nextStoryPath: string | null = null
|
|
275
|
+
if (nextActionMatch) {
|
|
276
|
+
const actionText = nextActionMatch[1]
|
|
277
|
+
const storyFileMatch = actionText.match(/story-[\w-]+\.md/i)
|
|
278
|
+
if (storyFileMatch) {
|
|
279
|
+
// Find full path in pending_stories
|
|
280
|
+
const pathMatch = content.match(new RegExp(`path:\\s*["']?([^"'\\n]*${storyFileMatch[0]}[^"'\\n]*)["']?`, 'i'))
|
|
281
|
+
if (pathMatch) {
|
|
282
|
+
nextStoryPath = pathMatch[1]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
statePath: fullPath.replace(directory + "/", ""),
|
|
289
|
+
epicId: epicIdMatch?.[1] || "unknown",
|
|
290
|
+
epicTitle: epicTitleMatch?.[1] || "Unknown Epic",
|
|
291
|
+
status: statusMatch?.[1] || "in-progress",
|
|
292
|
+
currentStoryIndex: currentIndexMatch ? parseInt(currentIndexMatch[1]) : 0,
|
|
293
|
+
totalStories: totalStoriesMatch ? parseInt(totalStoriesMatch[1]) : 0,
|
|
294
|
+
nextAction: nextActionMatch?.[1] || null,
|
|
295
|
+
nextStoryPath,
|
|
296
|
+
completedCount,
|
|
297
|
+
pendingCount
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
// No .sprint-state folder in this sprint
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return null
|
|
308
|
+
} catch {
|
|
309
|
+
return null
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
206
313
|
async function getActiveStory(): Promise<StoryContext | null> {
|
|
207
314
|
try {
|
|
315
|
+
// First, try to find epic state file
|
|
316
|
+
const epicState = await getActiveEpicState()
|
|
317
|
+
if (epicState) {
|
|
318
|
+
// Parse epic state to get current story
|
|
319
|
+
const storyPathMatch = epicState.content.match(/next_action:\s*["']?Execute\s+(.+?)["']?$/m)
|
|
320
|
+
if (storyPathMatch) {
|
|
321
|
+
const storyFileName = storyPathMatch[1]
|
|
322
|
+
// Find story file
|
|
323
|
+
const sprintMatch = epicState.statePath.match(/sprint-(\d+)/)
|
|
324
|
+
if (sprintMatch) {
|
|
325
|
+
const storyPath = `docs/sprint-artifacts/sprint-${sprintMatch[1]}/stories/${storyFileName}`
|
|
326
|
+
const storyContent = await readFile(join(directory, storyPath), "utf-8")
|
|
327
|
+
|
|
328
|
+
const titleMatch = storyContent.match(/^#\s+(.+)/m)
|
|
329
|
+
const statusMatch = storyContent.match(/\*\*Status:\*\*\s*(\w+)/i)
|
|
330
|
+
|
|
331
|
+
const completedTasks: string[] = []
|
|
332
|
+
const pendingTasks: string[] = []
|
|
333
|
+
let currentTask: string | null = null
|
|
334
|
+
|
|
335
|
+
// Parse tasks with more detail
|
|
336
|
+
const taskRegex = /- \[([ x])\]\s+\*\*T(\d+)\*\*[:\s]+(.+?)(?=\n|$)/g
|
|
337
|
+
let match
|
|
338
|
+
while ((match = taskRegex.exec(storyContent)) !== null) {
|
|
339
|
+
const [, checked, taskId, taskName] = match
|
|
340
|
+
const taskInfo = `T${taskId}: ${taskName.trim()}`
|
|
341
|
+
if (checked === "x") {
|
|
342
|
+
completedTasks.push(taskInfo)
|
|
343
|
+
} else {
|
|
344
|
+
if (!currentTask) currentTask = taskInfo
|
|
345
|
+
pendingTasks.push(taskInfo)
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Parse acceptance criteria
|
|
350
|
+
const acceptanceCriteria: string[] = []
|
|
351
|
+
const acSection = storyContent.match(/## Acceptance Criteria[\s\S]*?(?=##|$)/i)
|
|
352
|
+
if (acSection) {
|
|
353
|
+
const acRegex = /- \[([ x])\]\s+(.+?)(?=\n|$)/g
|
|
354
|
+
while ((match = acRegex.exec(acSection[0])) !== null) {
|
|
355
|
+
const [, checked, criteria] = match
|
|
356
|
+
acceptanceCriteria.push(`${checked === "x" ? "✅" : "⬜"} ${criteria.trim()}`)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
path: storyPath,
|
|
362
|
+
title: titleMatch?.[1] || "Unknown Story",
|
|
363
|
+
status: statusMatch?.[1] || "unknown",
|
|
364
|
+
currentTask,
|
|
365
|
+
completedTasks,
|
|
366
|
+
pendingTasks,
|
|
367
|
+
acceptanceCriteria,
|
|
368
|
+
fullContent: storyContent
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Fallback: try old sprint-status.yaml format
|
|
208
375
|
const sprintStatusPath = join(directory, "docs", "sprint-artifacts", "sprint-status.yaml")
|
|
209
376
|
const content = await readFile(sprintStatusPath, "utf-8")
|
|
210
377
|
|
|
@@ -300,21 +467,72 @@ DO NOT skip this step. DO NOT ask user what to do. Just read these files first.`
|
|
|
300
467
|
return relevantPaths
|
|
301
468
|
}
|
|
302
469
|
|
|
470
|
+
async function detectActiveCommand(todos: TaskStatus[], epicState: EpicState | null): Promise<string | null> {
|
|
471
|
+
// Detect command from TODO structure
|
|
472
|
+
if (todos.length === 0) return null
|
|
473
|
+
|
|
474
|
+
// Check if TODOs are epics (sprint mode)
|
|
475
|
+
const hasEpicTodos = todos.some(t => t.content.toLowerCase().includes("epic"))
|
|
476
|
+
if (hasEpicTodos) return "/dev-sprint"
|
|
477
|
+
|
|
478
|
+
// Check if TODOs are stories (epic mode)
|
|
479
|
+
const hasStoryTodos = todos.some(t => t.content.toLowerCase().includes("story"))
|
|
480
|
+
if (hasStoryTodos || epicState) return "/dev-epic"
|
|
481
|
+
|
|
482
|
+
// Regular story mode
|
|
483
|
+
return "/dev-story"
|
|
484
|
+
}
|
|
485
|
+
|
|
303
486
|
async function buildContext(agent: string | null): Promise<SessionContext> {
|
|
304
487
|
const [todos, story] = await Promise.all([
|
|
305
488
|
getTodoList(),
|
|
306
489
|
getActiveStory()
|
|
307
490
|
])
|
|
308
491
|
|
|
492
|
+
const epicState = await getActiveEpicState()
|
|
309
493
|
const relevantFiles = await getRelevantFiles(agent, story)
|
|
494
|
+
const activeCommand = await detectActiveCommand(todos, epicState)
|
|
310
495
|
|
|
311
|
-
return { todos, story, relevantFiles, activeAgent: agent }
|
|
496
|
+
return { todos, story, relevantFiles, activeAgent: agent, activeCommand }
|
|
312
497
|
}
|
|
313
498
|
|
|
314
|
-
function formatDevContext(ctx: SessionContext): string {
|
|
499
|
+
async function formatDevContext(ctx: SessionContext): Promise<string> {
|
|
315
500
|
const sections: string[] = []
|
|
316
501
|
|
|
317
|
-
if
|
|
502
|
+
// Check if we're in epic workflow
|
|
503
|
+
const epicState = await getActiveEpicState()
|
|
504
|
+
|
|
505
|
+
if (epicState) {
|
|
506
|
+
// Epic/Sprint workflow mode - show epic progress
|
|
507
|
+
const progress = epicState.totalStories > 0
|
|
508
|
+
? ((epicState.completedCount / epicState.totalStories) * 100).toFixed(0)
|
|
509
|
+
: 0
|
|
510
|
+
|
|
511
|
+
sections.push(`## 🎯 Epic Workflow: ${epicState.epicTitle}
|
|
512
|
+
|
|
513
|
+
**Epic ID:** ${epicState.epicId}
|
|
514
|
+
**Epic State:** \`${epicState.statePath}\` ← READ THIS FIRST
|
|
515
|
+
**Progress:** ${progress}% (${epicState.completedCount}/${epicState.totalStories} stories)
|
|
516
|
+
|
|
517
|
+
### Next Action (DO THIS NOW)
|
|
518
|
+
\`\`\`
|
|
519
|
+
${epicState.nextAction || "All stories complete - run epic integration tests"}
|
|
520
|
+
\`\`\`
|
|
521
|
+
|
|
522
|
+
${epicState.nextStoryPath ? `**Next Story:** \`${epicState.nextStoryPath}\` ← READ THIS SECOND` : ""}
|
|
523
|
+
|
|
524
|
+
### Epic Progress
|
|
525
|
+
**Completed Stories:** ${epicState.completedCount}
|
|
526
|
+
**Pending Stories:** ${epicState.pendingCount}
|
|
527
|
+
**Current Index:** ${epicState.currentStoryIndex}
|
|
528
|
+
|
|
529
|
+
---
|
|
530
|
+
|
|
531
|
+
💡 **Note:** If this is part of /dev-sprint, after epic completes:
|
|
532
|
+
1. Update sprint-status.yaml (mark epic done)
|
|
533
|
+
2. Continue to next epic automatically`)
|
|
534
|
+
} else if (ctx.story) {
|
|
535
|
+
// Regular story mode
|
|
318
536
|
const s = ctx.story
|
|
319
537
|
const total = s.completedTasks.length + s.pendingTasks.length
|
|
320
538
|
const progress = total > 0 ? (s.completedTasks.length / total * 100).toFixed(0) : 0
|
|
@@ -433,13 +651,13 @@ ${ctx.relevantFiles.map(f => `- \`${f}\``).join("\n")}`)
|
|
|
433
651
|
return sections.join("\n\n---\n\n")
|
|
434
652
|
}
|
|
435
653
|
|
|
436
|
-
function formatContext(ctx: SessionContext): string {
|
|
654
|
+
async function formatContext(ctx: SessionContext): Promise<string> {
|
|
437
655
|
const agent = ctx.activeAgent?.toLowerCase()
|
|
438
656
|
|
|
439
657
|
switch (agent) {
|
|
440
658
|
case "dev":
|
|
441
659
|
case "coder":
|
|
442
|
-
return formatDevContext(ctx)
|
|
660
|
+
return await formatDevContext(ctx)
|
|
443
661
|
case "architect":
|
|
444
662
|
return formatArchitectContext(ctx)
|
|
445
663
|
case "pm":
|
|
@@ -453,12 +671,15 @@ ${ctx.relevantFiles.map(f => `- \`${f}\``).join("\n")}`)
|
|
|
453
671
|
}
|
|
454
672
|
}
|
|
455
673
|
|
|
456
|
-
function formatInstructions(ctx: SessionContext): string {
|
|
674
|
+
async function formatInstructions(ctx: SessionContext): Promise<string> {
|
|
457
675
|
const agent = ctx.activeAgent?.toLowerCase()
|
|
458
676
|
const hasInProgressTasks = ctx.todos.some(t => t.status === "in_progress")
|
|
459
677
|
const hasInProgressStory = ctx.story?.status === "in-progress"
|
|
678
|
+
|
|
679
|
+
// Check if we're in epic workflow
|
|
680
|
+
const epicState = await getActiveEpicState()
|
|
460
681
|
|
|
461
|
-
if (!hasInProgressTasks && !hasInProgressStory) {
|
|
682
|
+
if (!hasInProgressTasks && !hasInProgressStory && !epicState) {
|
|
462
683
|
return `## Status: COMPLETED ✅
|
|
463
684
|
|
|
464
685
|
Previous task was completed successfully.
|
|
@@ -469,7 +690,67 @@ Previous task was completed successfully.
|
|
|
469
690
|
3. Ask user for next task`
|
|
470
691
|
}
|
|
471
692
|
|
|
472
|
-
//
|
|
693
|
+
// Sprint workflow instructions
|
|
694
|
+
if (ctx.activeCommand === "/dev-sprint" && (agent === "dev" || agent === "coder")) {
|
|
695
|
+
const nextEpicTodo = ctx.todos.find(t => t.status === "in_progress" && t.content.toLowerCase().includes("epic"))
|
|
696
|
+
return `## Status: SPRINT IN PROGRESS 🔄
|
|
697
|
+
|
|
698
|
+
**Active Command:** ${ctx.activeCommand}
|
|
699
|
+
**Active Agent:** @${agent}
|
|
700
|
+
**Next Epic:** ${nextEpicTodo?.content || "check TODO"}
|
|
701
|
+
|
|
702
|
+
### Resume Protocol (AUTOMATIC - DO NOT ASK USER)
|
|
703
|
+
1. **Read command:** \`.opencode/commands/dev-sprint.md\`
|
|
704
|
+
2. **Read sprint-status.yaml**
|
|
705
|
+
3. **Find next epic** from TODO or sprint-status.yaml
|
|
706
|
+
4. **Execute epic** via /dev-epic workflow
|
|
707
|
+
5. **After epic done:**
|
|
708
|
+
- Update sprint-status.yaml (mark epic done)
|
|
709
|
+
- Update TODO (mark epic completed, next epic in_progress)
|
|
710
|
+
- Continue next epic automatically
|
|
711
|
+
|
|
712
|
+
### DO NOT
|
|
713
|
+
- Ask user what to do (TODO + sprint-status.yaml tell you)
|
|
714
|
+
- Re-read completed epics
|
|
715
|
+
- Wait for confirmation between epics (auto-continue)
|
|
716
|
+
|
|
717
|
+
### IMPORTANT
|
|
718
|
+
This is /dev-sprint autopilot mode. Execute epics sequentially until sprint done.`
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Epic workflow instructions
|
|
722
|
+
if ((ctx.activeCommand === "/dev-epic" || epicState) && (agent === "dev" || agent === "coder")) {
|
|
723
|
+
return `## Status: EPIC IN PROGRESS 🔄
|
|
724
|
+
|
|
725
|
+
**Active Command:** ${ctx.activeCommand || "/dev-epic"}
|
|
726
|
+
**Active Agent:** @${agent}
|
|
727
|
+
**Epic:** ${epicState?.epicTitle || "check epic state"}
|
|
728
|
+
**Next Action:** ${epicState?.nextAction || "check TODO"}
|
|
729
|
+
|
|
730
|
+
### Resume Protocol (AUTOMATIC - DO NOT ASK USER)
|
|
731
|
+
1. **Read command:** \`.opencode/commands/dev-epic.md\`
|
|
732
|
+
2. **Read epic state:** \`${epicState?.statePath || "find in .sprint-state/"}\`
|
|
733
|
+
3. **Read next story:** \`${epicState?.nextStoryPath || "check epic state"}\`
|
|
734
|
+
4. **Load skill:** \`.opencode/skills/dev-story/SKILL.md\`
|
|
735
|
+
5. **Execute story** following /dev-story workflow
|
|
736
|
+
6. **After story done:**
|
|
737
|
+
- Update epic state file (move story to completed)
|
|
738
|
+
- Update TODO (mark story completed, next story in_progress)
|
|
739
|
+
- Increment current_story_index
|
|
740
|
+
- Set next_action to next story
|
|
741
|
+
- Continue next story automatically
|
|
742
|
+
|
|
743
|
+
### DO NOT
|
|
744
|
+
- Ask user what to do (epic state + TODO tell you)
|
|
745
|
+
- Re-read completed stories
|
|
746
|
+
- Re-read epic file (info in state)
|
|
747
|
+
- Wait for confirmation between stories (auto-continue)
|
|
748
|
+
|
|
749
|
+
### IMPORTANT
|
|
750
|
+
This is /dev-epic autopilot mode. Execute stories sequentially until epic done.`
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Dev-specific instructions (regular story)
|
|
473
754
|
if ((agent === "dev" || agent === "coder") && ctx.story) {
|
|
474
755
|
return `## Status: IN PROGRESS 🔄
|
|
475
756
|
|
|
@@ -554,9 +835,9 @@ Previous task was completed successfully.
|
|
|
554
835
|
await log(directory, ` todos: ${ctx.todos.length}`)
|
|
555
836
|
await log(directory, ` relevantFiles: ${ctx.relevantFiles.length}`)
|
|
556
837
|
|
|
557
|
-
const context = formatContext(ctx)
|
|
558
|
-
const instructions = formatInstructions(ctx)
|
|
559
|
-
const readCommands = generateReadCommands(agent, ctx.story)
|
|
838
|
+
const context = await formatContext(ctx)
|
|
839
|
+
const instructions = await formatInstructions(ctx)
|
|
840
|
+
const readCommands = await generateReadCommands(agent, ctx.story, ctx.activeCommand)
|
|
560
841
|
|
|
561
842
|
// Agent identity reminder
|
|
562
843
|
const agentIdentity = agent
|