maestro-flow 0.3.11 → 0.3.12
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/agents/conceptual-planning-agent.md +1 -0
- package/.claude/agents/workflow-analyzer.md +114 -114
- package/.claude/agents/workflow-collab-planner.md +144 -144
- package/.claude/agents/workflow-debugger.md +102 -103
- package/.claude/agents/workflow-executor.md +127 -128
- package/.claude/agents/workflow-integration-checker.md +82 -82
- package/.claude/agents/workflow-nyquist-auditor.md +85 -84
- package/.claude/agents/workflow-phase-researcher.md +85 -85
- package/.claude/agents/workflow-plan-checker.md +90 -90
- package/.claude/agents/workflow-planner.md +178 -178
- package/.claude/agents/workflow-roadmapper.md +81 -83
- package/.claude/agents/workflow-verifier.md +119 -119
- package/.claude/commands/learn-retro.md +2 -2
- package/.claude/commands/learn-second-opinion.md +2 -2
- package/.claude/commands/maestro-brainstorm.md +1 -0
- package/.claude/commands/maestro-fork.md +133 -111
- package/.claude/commands/maestro-merge.md +85 -77
- package/.claude/commands/maestro-plan.md +88 -2
- package/.claude/commands/maestro-roadmap.md +113 -2
- package/.claude/commands/maestro.md +1 -0
- package/.claude/commands/quality-business-test.md +5 -5
- package/.claude/commands/quality-debug.md +3 -2
- package/.claude/commands/quality-retrospective.md +6 -4
- package/.claude/commands/quality-review.md +1 -1
- package/.claude/commands/quality-test-gen.md +5 -4
- package/.codex/skills/maestro-brainstorm/SKILL.md +1 -1
- package/.codex/skills/maestro-fork/SKILL.md +98 -68
- package/.codex/skills/maestro-init/SKILL.md +4 -3
- package/.codex/skills/maestro-merge/SKILL.md +69 -62
- package/.codex/skills/maestro-ui-design/SKILL.md +1 -1
- package/.codex/skills/maestro-verify/SKILL.md +12 -12
- package/.codex/skills/manage-learn/SKILL.md +1 -1
- package/.codex/skills/manage-status/SKILL.md +4 -4
- package/.codex/skills/quality-business-test/SKILL.md +2 -2
- package/.codex/skills/quality-integration-test/SKILL.md +1 -1
- package/.codex/skills/quality-retrospective/SKILL.md +7 -7
- package/.codex/skills/quality-review/SKILL.md +2 -2
- package/.codex/skills/quality-test/SKILL.md +2 -2
- package/.codex/skills/quality-test-gen/SKILL.md +1 -1
- package/README.md +2 -0
- package/README.zh-CN.md +2 -0
- package/dashboard/dist/assets/{ArtifactsPage-DZNCi6tn.js → ArtifactsPage-CUrrDGgN.js} +1 -1
- package/dashboard/dist/assets/ChatInput-pUOLJIKE.js +49 -0
- package/dashboard/dist/assets/ChatPage-B8Xqkt0v.js +27 -0
- package/dashboard/dist/assets/{CollabPage-B4NAHXS2.js → CollabPage-DIUXeazv.js} +1 -1
- package/dashboard/dist/assets/{ExecutionPanel-CFt4LJyq.js → ExecutionPanel-VmYeADFj.js} +1 -1
- package/dashboard/dist/assets/KanbanPage-DLq8v7hg.js +21 -0
- package/dashboard/dist/assets/{MarkdownRenderer-X4af_WNb.js → MarkdownRenderer-D7AehrnR.js} +1 -1
- package/dashboard/dist/assets/{McpPage-BKfCVIyU.js → McpPage-BY0SjTgw.js} +2 -2
- package/dashboard/dist/assets/{OutputPanel-BlBQFJSW.js → OutputPanel-B-Rjwgmv.js} +1 -1
- package/dashboard/dist/assets/{ProblemsPanel-De3DLvoI.js → ProblemsPanel-GEpF-oi4.js} +1 -1
- package/dashboard/dist/assets/RequirementBoardPage-xs8uDM7I.js +6 -0
- package/dashboard/dist/assets/{RequirementPage-Bllxe2XI.js → RequirementPage-BKDSFwjA.js} +5 -10
- package/dashboard/dist/assets/SpecsPage-DLFb9ZH0.js +36 -0
- package/dashboard/dist/assets/SupervisorPage-SOki_kgz.js +6 -0
- package/dashboard/dist/assets/TeamsPage-BO2kP70F.js +11 -0
- package/dashboard/dist/assets/{TreeBrowser-Q12qobZs.js → TreeBrowser-B9DHdULE.js} +1 -1
- package/dashboard/dist/assets/{WorkflowPage-D_Fzdy3_.js → WorkflowPage-C8hWbYim.js} +1 -1
- package/dashboard/dist/assets/{check-u6fGOwQO.js → check-DJDk3A2a.js} +1 -1
- package/dashboard/dist/assets/{chevron-right-Csu22t58.js → chevron-right-C7bVDreZ.js} +1 -1
- package/dashboard/dist/assets/{circle-CMrkbRNg.js → circle-Qfgy4LB_.js} +1 -1
- package/dashboard/dist/assets/{circle-alert-c3tH1P4z.js → circle-alert-Na1vf6qQ.js} +1 -1
- package/dashboard/dist/assets/{circle-check-gYxxSYuH.js → circle-check-CEGgy3NV.js} +1 -1
- package/dashboard/dist/assets/{circle-check-big-TDSeWstm.js → circle-check-big-3JB8zRYj.js} +1 -1
- package/dashboard/dist/assets/{code-CFN2uX9V.js → code-Ble63Idz.js} +1 -1
- package/dashboard/dist/assets/{columns-3-38xIDlzy.js → columns-3-BUcKlxve.js} +1 -1
- package/dashboard/dist/assets/{download-DC7KkKyP.js → download-CMqkfn8x.js} +1 -1
- package/dashboard/dist/assets/{folder-CWq_lAnf.js → folder-B9ewx9LL.js} +1 -1
- package/dashboard/dist/assets/index-C2Mcb4TJ.js +231 -0
- package/dashboard/dist/assets/index-DyBbPc18.css +1 -0
- package/dashboard/dist/assets/{index-Do71weNR.js → index-JTmGteaT.js} +1 -1
- package/dashboard/dist/assets/{list-CgIP_2A-.js → list-DI8Wn2aT.js} +1 -1
- package/dashboard/dist/assets/loader-B5F6PzFT.js +11 -0
- package/dashboard/dist/assets/{minus-DYoN5UGk.js → minus-Lp_BfctG.js} +1 -1
- package/dashboard/dist/assets/{pen-line-Bh_WKYHm.js → pen-line-Ch7sphzZ.js} +1 -1
- package/dashboard/dist/assets/pencil-_yRMHmGT.js +6 -0
- package/dashboard/dist/assets/{proxy-BKxDAKTj.js → proxy-D72Y8a4Y.js} +1 -1
- package/dashboard/dist/assets/{search-SieXnOgr.js → search-BS6fI6Bg.js} +1 -1
- package/dashboard/dist/assets/{shallow-Bme1JY57.js → shallow-BXasQBvr.js} +1 -1
- package/dashboard/dist/assets/table-CeGlFjlP.js +6 -0
- package/dashboard/dist/assets/{terminal-BB3Xfuv5.js → terminal-BJic2yW-.js} +1 -1
- package/dashboard/dist/assets/{trash-2-C8f4vFFM.js → trash-2-Czz4X8Fb.js} +1 -1
- package/dashboard/dist/assets/{zap-4uwlzVm0.js → zap-C3H0jVFA.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dashboard/dist-server/dashboard/src/server/agents/agent-manager.js +16 -1
- package/dashboard/dist-server/dashboard/src/server/agents/agent-manager.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/agents/delegate-broker-monitor.js +1 -2
- package/dashboard/dist-server/dashboard/src/server/agents/delegate-broker-monitor.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/commander/commander-prompts.d.ts +1 -1
- package/dashboard/dist-server/dashboard/src/server/commander/commander-prompts.js +2 -1
- package/dashboard/dist-server/dashboard/src/server/commander/commander-prompts.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/index.js +3 -0
- package/dashboard/dist-server/dashboard/src/server/index.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/routes/collab.js +124 -0
- package/dashboard/dist-server/dashboard/src/server/routes/collab.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/server/ws/handlers/team-handler.d.ts +10 -0
- package/dashboard/dist-server/dashboard/src/server/ws/handlers/team-handler.js +73 -0
- package/dashboard/dist-server/dashboard/src/server/ws/handlers/team-handler.js.map +1 -0
- package/dashboard/dist-server/dashboard/src/shared/collab-types.d.ts +31 -0
- package/dashboard/dist-server/dashboard/src/shared/collab-types.js +28 -0
- package/dashboard/dist-server/dashboard/src/shared/collab-types.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/shared/constants.js +5 -0
- package/dashboard/dist-server/dashboard/src/shared/constants.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/shared/coordinate-types.d.ts +22 -0
- package/dashboard/dist-server/dashboard/src/shared/issue-types.d.ts +12 -0
- package/dashboard/dist-server/dashboard/src/shared/issue-types.js +12 -0
- package/dashboard/dist-server/dashboard/src/shared/issue-types.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/shared/team-types.d.ts +1 -0
- package/dashboard/dist-server/dashboard/src/shared/team-types.js +7 -0
- package/dashboard/dist-server/dashboard/src/shared/team-types.js.map +1 -1
- package/dashboard/dist-server/dashboard/src/shared/ws-protocol.d.ts +27 -1
- package/dashboard/dist-server/dashboard/src/shared/ws-protocol.js.map +1 -1
- package/dashboard/dist-server/shared/agent-types.d.ts +4 -0
- package/dashboard/dist-server/src/hooks/constants.d.ts +1 -1
- package/dashboard/dist-server/src/hooks/constants.js +2 -2
- package/dashboard/dist-server/src/hooks/constants.js.map +1 -1
- package/dist/shared/agent-types.d.ts +4 -0
- package/dist/shared/agent-types.d.ts.map +1 -1
- package/dist/src/commands/install-backend.d.ts.map +1 -1
- package/dist/src/commands/install-backend.js +29 -18
- package/dist/src/commands/install-backend.js.map +1 -1
- package/dist/src/hooks/__tests__/statusline-visual-test.js +23 -1
- package/dist/src/hooks/__tests__/statusline-visual-test.js.map +1 -1
- package/dist/src/hooks/constants.d.ts +1 -1
- package/dist/src/hooks/constants.d.ts.map +1 -1
- package/dist/src/hooks/constants.js +2 -2
- package/dist/src/hooks/constants.js.map +1 -1
- package/dist/src/hooks/skill-context.d.ts +3 -0
- package/dist/src/hooks/skill-context.d.ts.map +1 -1
- package/dist/src/hooks/skill-context.js +95 -9
- package/dist/src/hooks/skill-context.js.map +1 -1
- package/dist/src/hooks/statusline.d.ts.map +1 -1
- package/dist/src/hooks/statusline.js +6 -3
- package/dist/src/hooks/statusline.js.map +1 -1
- package/dist/src/tools/merge-validator.d.ts.map +1 -1
- package/dist/src/tools/merge-validator.js +114 -16
- package/dist/src/tools/merge-validator.js.map +1 -1
- package/package.json +1 -1
- package/shared/agent-types.ts +4 -0
- package/templates/worktree-scope.json +9 -10
- package/templates/worktrees.json +26 -27
- package/workflows/brainstorm.md +10 -1
- package/workflows/debug.md +16 -6
- package/workflows/fork.md +100 -36
- package/workflows/integration-test.md +14 -2
- package/workflows/issue.md +14 -4
- package/workflows/learn.md +19 -5
- package/workflows/maestro.md +1 -0
- package/workflows/merge.md +113 -55
- package/workflows/retrospective.md +61 -22
- package/workflows/review.md +17 -4
- package/workflows/test.md +12 -2
- package/workflows/ui-style.md +9 -2
- package/dashboard/dist/assets/ChatInput-Bvr-FeEq.js +0 -49
- package/dashboard/dist/assets/ChatPage-D9zTkJZo.js +0 -22
- package/dashboard/dist/assets/KanbanPage-C8USth6H.js +0 -21
- package/dashboard/dist/assets/RequirementBoardPage-Bf1trzqs.js +0 -11
- package/dashboard/dist/assets/SpecsPage-9lwxKT27.js +0 -36
- package/dashboard/dist/assets/SupervisorPage-SusdfHFq.js +0 -6
- package/dashboard/dist/assets/TeamsPage-DsuM6OwC.js +0 -6
- package/dashboard/dist/assets/arrow-left-Bqtb2hle.js +0 -6
- package/dashboard/dist/assets/index-DWG-WrzT.js +0 -231
- package/dashboard/dist/assets/index-GUNJodSR.css +0 -1
- package/dashboard/dist/assets/table-llyEtj-7.js +0 -6
package/workflows/fork.md
CHANGED
|
@@ -121,12 +121,25 @@ IF syncMode:
|
|
|
121
121
|
## Step 5: Validate & Confirm
|
|
122
122
|
|
|
123
123
|
```
|
|
124
|
-
// Load phase
|
|
124
|
+
// Load phase status — artifact registry first, fallback to legacy phases/
|
|
125
125
|
phaseList = []
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
artifacts = projectState.artifacts ?? []
|
|
127
|
+
useArtifactRegistry = artifacts.length > 0
|
|
128
|
+
|
|
129
|
+
IF useArtifactRegistry:
|
|
130
|
+
// Derive phase status from artifact registry
|
|
131
|
+
for (phaseNum of milestonePhases):
|
|
132
|
+
execArtifacts = artifacts.filter(a => a.type === 'execute' && a.phase === phaseNum)
|
|
133
|
+
status = execArtifacts.some(a => a.status === 'completed') ? 'completed'
|
|
134
|
+
: execArtifacts.length > 0 ? 'in_progress'
|
|
135
|
+
: 'pending'
|
|
136
|
+
phaseList.push({ phase: phaseNum, title: "Phase " + phaseNum, status })
|
|
137
|
+
ELSE:
|
|
138
|
+
// Legacy: load from phases/ directory
|
|
139
|
+
for (phaseNum of milestonePhases):
|
|
140
|
+
Glob: .workflow/phases/{NN}-*/index.json where NN matches phaseNum
|
|
141
|
+
Read index.json → phaseIndex
|
|
142
|
+
phaseList.push(phaseIndex)
|
|
130
143
|
|
|
131
144
|
// Validate: milestone should have at least one non-completed phase
|
|
132
145
|
nonCompleted = phaseList.filter(p => p.status !== "completed")
|
|
@@ -172,7 +185,7 @@ Bash("git branch -D {branch}") // ignore errors (may not exist)
|
|
|
172
185
|
Bash("git worktree add -b {branch} {wtPath} {baseBranch}")
|
|
173
186
|
|
|
174
187
|
// 6c: Create .workflow/ structure in worktree
|
|
175
|
-
Bash("mkdir -p {wtPath}/.workflow/
|
|
188
|
+
Bash("mkdir -p {wtPath}/.workflow/scratch")
|
|
176
189
|
|
|
177
190
|
// 6d: Copy shared context (read-only)
|
|
178
191
|
Copy .workflow/project.md → {wtPath}/.workflow/project.md
|
|
@@ -182,46 +195,92 @@ IF file_exists(".workflow/config.json"):
|
|
|
182
195
|
IF directory_exists(".workflow/specs"):
|
|
183
196
|
Copy .workflow/specs/ → {wtPath}/.workflow/specs/
|
|
184
197
|
|
|
185
|
-
// 6e: Copy
|
|
186
|
-
ownedPhaseNumbers =
|
|
187
|
-
for (p of phaseList):
|
|
188
|
-
NN = String(p.phase).padStart(2, '0')
|
|
189
|
-
Copy .workflow/phases/{NN}-{p.slug}/ → {wtPath}/.workflow/phases/{NN}-{p.slug}/
|
|
190
|
-
ownedPhaseNumbers.push(p.phase)
|
|
191
|
-
|
|
192
|
-
// 6f: Copy completed dependency phase dirs outside this milestone (read-only reference)
|
|
193
|
-
allDeps = new Set()
|
|
194
|
-
for (p of phaseList):
|
|
195
|
-
for (dep of p.depends_on):
|
|
196
|
-
IF NOT ownedPhaseNumbers.includes(dep):
|
|
197
|
-
allDeps.add(dep)
|
|
198
|
+
// 6e: Copy milestone artifacts to worktree
|
|
199
|
+
ownedPhaseNumbers = milestonePhases.slice() // all phases in this milestone
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
IF useArtifactRegistry:
|
|
202
|
+
// Copy scratch dirs for this milestone's artifacts
|
|
203
|
+
milestoneArtifacts = artifacts.filter(a =>
|
|
204
|
+
a.milestone === milestoneName && a.path
|
|
205
|
+
)
|
|
206
|
+
for (art of milestoneArtifacts):
|
|
207
|
+
IF directory_exists(".workflow/" + art.path):
|
|
208
|
+
Copy .workflow/{art.path}/ → {wtPath}/.workflow/{art.path}/
|
|
209
|
+
ELSE:
|
|
210
|
+
// Legacy: copy phase directories
|
|
211
|
+
Bash("mkdir -p {wtPath}/.workflow/phases")
|
|
212
|
+
for (p of phaseList):
|
|
213
|
+
NN = String(p.phase).padStart(2, '0')
|
|
214
|
+
Copy .workflow/phases/{NN}-{p.slug}/ → {wtPath}/.workflow/phases/{NN}-{p.slug}/
|
|
215
|
+
|
|
216
|
+
// 6f: Copy dependency artifacts (phases outside this milestone)
|
|
217
|
+
IF useArtifactRegistry:
|
|
218
|
+
// Collect dependency phases from roadmap milestone entry
|
|
219
|
+
// (cross-milestone dependencies are defined in milestoneEntry.depends_on or roadmap)
|
|
220
|
+
depPhases = new Set()
|
|
221
|
+
IF milestoneEntry.depends_on:
|
|
222
|
+
for (dep of milestoneEntry.depends_on):
|
|
223
|
+
IF NOT ownedPhaseNumbers.includes(dep):
|
|
224
|
+
depPhases.add(dep)
|
|
225
|
+
// Copy dependency artifacts from main
|
|
226
|
+
for (dep of depPhases):
|
|
227
|
+
depArtifacts = artifacts.filter(a => a.phase === dep && a.path)
|
|
228
|
+
for (art of depArtifacts):
|
|
229
|
+
IF directory_exists(".workflow/" + art.path):
|
|
230
|
+
Copy .workflow/{art.path}/ → {wtPath}/.workflow/{art.path}/
|
|
231
|
+
ELSE:
|
|
232
|
+
// Legacy: copy completed dependency phase dirs
|
|
233
|
+
allDeps = new Set()
|
|
234
|
+
for (p of phaseList):
|
|
235
|
+
IF p.depends_on:
|
|
236
|
+
for (dep of p.depends_on):
|
|
237
|
+
IF NOT ownedPhaseNumbers.includes(dep):
|
|
238
|
+
allDeps.add(dep)
|
|
239
|
+
for (dep of allDeps):
|
|
240
|
+
depNN = String(dep).padStart(2, '0')
|
|
241
|
+
Glob: .workflow/phases/{depNN}-*/index.json
|
|
242
|
+
Read → depIndex
|
|
243
|
+
Copy .workflow/phases/{depNN}-{depIndex.slug}/ → {wtPath}/.workflow/phases/{depNN}-{depIndex.slug}/
|
|
244
|
+
|
|
245
|
+
// 6g: Build phase_dependencies map for worktree-scope
|
|
246
|
+
phaseDeps = {}
|
|
247
|
+
IF useArtifactRegistry:
|
|
248
|
+
IF milestoneEntry.depends_on:
|
|
249
|
+
for (phaseNum of ownedPhaseNumbers):
|
|
250
|
+
phaseDeps[String(phaseNum)] = milestoneEntry.depends_on
|
|
251
|
+
.filter(d => !ownedPhaseNumbers.includes(d))
|
|
252
|
+
ELSE:
|
|
253
|
+
for (p of phaseList):
|
|
254
|
+
IF p.depends_on:
|
|
255
|
+
externalDeps = p.depends_on.filter(d => !ownedPhaseNumbers.includes(d))
|
|
256
|
+
IF externalDeps.length > 0:
|
|
257
|
+
phaseDeps[String(p.phase)] = externalDeps
|
|
204
258
|
|
|
205
|
-
//
|
|
259
|
+
// 6h: Write worktree-scope.json
|
|
206
260
|
Write {wtPath}/.workflow/worktree-scope.json:
|
|
207
261
|
{
|
|
208
262
|
"worktree": true,
|
|
209
263
|
"milestone_num": milestoneNum,
|
|
210
264
|
"milestone": milestoneName,
|
|
211
265
|
"owned_phases": ownedPhaseNumbers,
|
|
266
|
+
"phase_dependencies": phaseDeps,
|
|
212
267
|
"main_worktree": resolve(cwd),
|
|
213
268
|
"branch": branch,
|
|
214
269
|
"base_commit": baseCommit,
|
|
215
270
|
"created_at": getUtc8ISOString()
|
|
216
271
|
}
|
|
217
272
|
|
|
218
|
-
//
|
|
273
|
+
// 6i: Write scoped state.json
|
|
219
274
|
Read .workflow/state.json → mainState
|
|
220
275
|
firstPending = phaseList.find(p => p.status !== "completed")
|
|
221
276
|
scopedState = {
|
|
222
277
|
...mainState,
|
|
223
278
|
current_phase: firstPending?.phase ?? phaseList[0].phase,
|
|
224
|
-
current_milestone: milestoneName
|
|
279
|
+
current_milestone: milestoneName,
|
|
280
|
+
// Carry over milestone-scoped artifacts to worktree
|
|
281
|
+
artifacts: useArtifactRegistry
|
|
282
|
+
? artifacts.filter(a => a.milestone === milestoneName || ownedPhaseNumbers.includes(a.phase))
|
|
283
|
+
: []
|
|
225
284
|
}
|
|
226
285
|
Write {wtPath}/.workflow/state.json: scopedState
|
|
227
286
|
```
|
|
@@ -260,14 +319,20 @@ registry.fork_sessions.push({
|
|
|
260
319
|
|
|
261
320
|
Write .workflow/worktrees.json: registry
|
|
262
321
|
|
|
263
|
-
// Mark milestone phases as "forked"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
322
|
+
// Mark milestone phases as "forked"
|
|
323
|
+
IF useArtifactRegistry:
|
|
324
|
+
// In artifact registry model, worktrees.json tracks forked state.
|
|
325
|
+
// No per-phase marking needed — the registry entry signals ownership.
|
|
326
|
+
// (worktrees.json already updated above with owned_phases)
|
|
327
|
+
ELSE:
|
|
328
|
+
// Legacy: mark phase index.json as forked
|
|
329
|
+
for (p of phaseList):
|
|
330
|
+
IF p.status !== "completed":
|
|
331
|
+
NN = String(p.phase).padStart(2, '0')
|
|
332
|
+
Read .workflow/phases/{NN}-{p.slug}/index.json → idx
|
|
333
|
+
idx.status = "forked"
|
|
334
|
+
idx.updated_at = getUtc8ISOString()
|
|
335
|
+
Write .workflow/phases/{NN}-{p.slug}/index.json: idx
|
|
271
336
|
|
|
272
337
|
mainState.last_updated = getUtc8ISOString()
|
|
273
338
|
Write .workflow/state.json: mainState
|
|
@@ -295,7 +360,6 @@ Display:
|
|
|
295
360
|
/maestro-plan {firstPending.phase}
|
|
296
361
|
/maestro-execute {firstPending.phase}
|
|
297
362
|
/maestro-verify {firstPending.phase}
|
|
298
|
-
/maestro-phase-transition {firstPending.phase}
|
|
299
363
|
# ... repeat for next phases in milestone
|
|
300
364
|
|
|
301
365
|
Or delegate (automated):
|
|
@@ -15,13 +15,25 @@ L0-L3 progressive layers: Static Analysis -> Unit -> Integration -> E2E
|
|
|
15
15
|
| Input | Result |
|
|
16
16
|
|-------|--------|
|
|
17
17
|
| No arguments | Error E001 |
|
|
18
|
-
| Phase number | Resolve `.workflow/phases/{NN}-{slug}/` |
|
|
18
|
+
| Phase number | Resolve phase dir (artifact registry or legacy `.workflow/phases/{NN}-{slug}/`) |
|
|
19
19
|
| `--max-iter N` | Set MAX_ITER = N (default 5) |
|
|
20
20
|
| `--layer L2` | Start from L2 layer |
|
|
21
21
|
|
|
22
|
+
**Resolve phase dir:**
|
|
23
|
+
```
|
|
24
|
+
Read .workflow/state.json → state
|
|
25
|
+
artifacts = state.artifacts ?? []
|
|
26
|
+
IF artifacts.length > 0:
|
|
27
|
+
art = artifacts.find(a => a.type === 'execute' && a.phase === phaseNum)
|
|
28
|
+
PHASE_DIR = ".workflow/" + art.path
|
|
29
|
+
ELSE:
|
|
30
|
+
Glob: .workflow/phases/{NN}-*/
|
|
31
|
+
PHASE_DIR = resolved path
|
|
32
|
+
```
|
|
33
|
+
|
|
22
34
|
Check for existing integration test session:
|
|
23
35
|
```bash
|
|
24
|
-
ls
|
|
36
|
+
ls ${PHASE_DIR}/.tests/integration/state.json 2>/dev/null
|
|
25
37
|
```
|
|
26
38
|
|
|
27
39
|
If session exists: offer resume or restart.
|
package/workflows/issue.md
CHANGED
|
@@ -178,8 +178,13 @@ Cross-milestone conflict check (for supplement issues):
|
|
|
178
178
|
6. IF source == "supplement" AND milestone_ref is not null:
|
|
179
179
|
a. Read .workflow/roadmap.md
|
|
180
180
|
b. Identify phases belonging to OTHER milestones (not milestone_ref)
|
|
181
|
-
c. For each other-milestone phase, check if plan.json exists:
|
|
182
|
-
Read .workflow/
|
|
181
|
+
c. For each other-milestone phase, resolve phase dir and check if plan.json exists:
|
|
182
|
+
Read .workflow/state.json → state; artifacts = state.artifacts ?? []
|
|
183
|
+
IF artifacts.length > 0:
|
|
184
|
+
art = artifacts.find(a => a.type === 'plan' && a.phase === phaseNum)
|
|
185
|
+
IF art: Read .workflow/{art.path}/plan.json (if exists)
|
|
186
|
+
ELSE:
|
|
187
|
+
Read .workflow/phases/{NN}-{slug}/plan.json (if exists)
|
|
183
188
|
Collect files_to_create[] as planned_files
|
|
184
189
|
d. IF affected_components in the new issue overlap with planned_files:
|
|
185
190
|
WARNING: "Conflict detected: this supplement issue affects components planned in milestone {other_milestone}"
|
|
@@ -449,8 +454,13 @@ Process bidirectional link:
|
|
|
449
454
|
If not found → error: "Issue {ID} not found"
|
|
450
455
|
|
|
451
456
|
2. Locate task file:
|
|
452
|
-
-
|
|
453
|
-
-
|
|
457
|
+
- Read .workflow/state.json → state
|
|
458
|
+
- artifacts = state.artifacts ?? []
|
|
459
|
+
- IF artifacts.length > 0:
|
|
460
|
+
Search .workflow/scratch/*/.task/{TASK_ID}.json (artifact registry scratch paths)
|
|
461
|
+
ELSE:
|
|
462
|
+
Search .workflow/phases/*/.task/{TASK_ID}.json (legacy)
|
|
463
|
+
- Also search .workflow/scratch/*/.task/{TASK_ID}.json (standalone scratch tasks)
|
|
454
464
|
- If still not found → error: "Task {TASK_ID} not found"
|
|
455
465
|
|
|
456
466
|
3. Update issue record:
|
package/workflows/learn.md
CHANGED
|
@@ -86,9 +86,14 @@ IF .workflow/state.json exists:
|
|
|
86
86
|
IF state.current_phase is not null:
|
|
87
87
|
phase = state.current_phase
|
|
88
88
|
|
|
89
|
-
# Resolve slug
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
# Resolve slug — artifact registry first, fallback to legacy phases/
|
|
90
|
+
artifacts = state.artifacts ?? []
|
|
91
|
+
IF artifacts.length > 0:
|
|
92
|
+
art = artifacts.find(a => a.phase === phase)
|
|
93
|
+
phase_slug = art?.slug ?? "phase-" + phase
|
|
94
|
+
ELSE:
|
|
95
|
+
Glob ".workflow/phases/{NN}-*/" where NN == phase
|
|
96
|
+
phase_slug = matched directory basename (e.g. "01-auth")
|
|
92
97
|
```
|
|
93
98
|
|
|
94
99
|
If `--phase 0` is passed, force `phase = null, phase_slug = null` regardless.
|
|
@@ -299,8 +304,17 @@ IF row is null → error E004: "Insight {target_id} not found"
|
|
|
299
304
|
```
|
|
300
305
|
phase_context = null
|
|
301
306
|
IF row.phase_slug is not null:
|
|
302
|
-
|
|
303
|
-
|
|
307
|
+
// Resolve phase dir — artifact registry first, fallback to legacy phases/
|
|
308
|
+
Read .workflow/state.json → state
|
|
309
|
+
artifacts = state.artifacts ?? []
|
|
310
|
+
phase_dir = null
|
|
311
|
+
IF artifacts.length > 0:
|
|
312
|
+
art = artifacts.find(a => a.phase === row.phase && a.path)
|
|
313
|
+
IF art: phase_dir = ".workflow/" + art.path
|
|
314
|
+
ELSE:
|
|
315
|
+
phase_dir = ".workflow/phases/" + row.phase_slug
|
|
316
|
+
|
|
317
|
+
IF phase_dir AND directory exists:
|
|
304
318
|
phase_context = {
|
|
305
319
|
title: read index.json.title from phase_dir,
|
|
306
320
|
status: read index.json.status,
|
package/workflows/maestro.md
CHANGED
package/workflows/merge.md
CHANGED
|
@@ -103,15 +103,31 @@ IF NOT target:
|
|
|
103
103
|
completedPhases = []
|
|
104
104
|
incompletePhases = []
|
|
105
105
|
|
|
106
|
-
for
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
// Read worktree state for artifact registry check
|
|
107
|
+
Read {target.path}/.workflow/state.json → wtState (if exists)
|
|
108
|
+
wtArtifacts = wtState?.artifacts ?? []
|
|
109
|
+
useArtifactRegistry = wtArtifacts.length > 0
|
|
110
|
+
|
|
111
|
+
IF useArtifactRegistry:
|
|
112
|
+
// Check phase completeness via artifact registry
|
|
113
|
+
for (phaseNum of target.owned_phases):
|
|
114
|
+
execArtifacts = wtArtifacts.filter(a => a.type === 'execute' && a.phase === phaseNum)
|
|
115
|
+
IF execArtifacts.some(a => a.status === 'completed'):
|
|
116
|
+
completedPhases.push({ phase: phaseNum })
|
|
117
|
+
ELSE:
|
|
118
|
+
status = execArtifacts.length > 0 ? execArtifacts[0].status : 'no_execute_artifact'
|
|
119
|
+
incompletePhases.push({ phase: phaseNum, status })
|
|
120
|
+
ELSE:
|
|
121
|
+
// Legacy: check phases/ directory
|
|
122
|
+
for (phaseNum of target.owned_phases):
|
|
123
|
+
NN = String(phaseNum).padStart(2, '0')
|
|
124
|
+
Glob: {target.path}/.workflow/phases/{NN}-*/index.json
|
|
125
|
+
Read → wtIndex
|
|
110
126
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
IF wtIndex.status === "completed":
|
|
128
|
+
completedPhases.push({ phase: phaseNum, index: wtIndex })
|
|
129
|
+
ELSE:
|
|
130
|
+
incompletePhases.push({ phase: phaseNum, status: wtIndex.status })
|
|
115
131
|
|
|
116
132
|
IF incompletePhases.length > 0 AND NOT force:
|
|
117
133
|
WARN W002: "M{target.milestone_num} ({target.milestone}) has incomplete phases:"
|
|
@@ -181,51 +197,90 @@ Step_7:
|
|
|
181
197
|
|
|
182
198
|
Display "Syncing workflow artifacts for M{target.milestone_num} ({target.milestone})..."
|
|
183
199
|
|
|
184
|
-
// 7a: Copy all owned phase directories from worktree to main
|
|
185
|
-
for (phaseNum of target.owned_phases):
|
|
186
|
-
NN = String(phaseNum).padStart(2, '0')
|
|
187
|
-
Glob: {target.path}/.workflow/phases/{NN}-*/
|
|
188
|
-
phaseDir = matched directory name
|
|
189
|
-
|
|
190
|
-
srcDir = target.path + "/.workflow/phases/" + phaseDir + "/"
|
|
191
|
-
dstDir = ".workflow/phases/" + phaseDir + "/"
|
|
192
|
-
|
|
193
|
-
Bash("cp -r {srcDir}* {dstDir}")
|
|
194
|
-
|
|
195
|
-
// 7b: Atomic state reconciliation
|
|
196
200
|
Read .workflow/state.json → mainState
|
|
197
201
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
202
|
+
IF useArtifactRegistry:
|
|
203
|
+
// 7a: Copy scratch dirs from worktree to main
|
|
204
|
+
Read {target.path}/.workflow/state.json → wtState
|
|
205
|
+
wtArtifacts = wtState?.artifacts ?? []
|
|
206
|
+
milestoneArtifacts = wtArtifacts.filter(a =>
|
|
207
|
+
a.path && (a.milestone === target.milestone || target.owned_phases.includes(a.phase))
|
|
208
|
+
)
|
|
209
|
+
for (art of milestoneArtifacts):
|
|
210
|
+
srcDir = target.path + "/.workflow/" + art.path
|
|
211
|
+
dstDir = ".workflow/" + art.path
|
|
212
|
+
IF directory_exists(srcDir):
|
|
213
|
+
Bash("mkdir -p {dstDir} && cp -r {srcDir}/* {dstDir}/")
|
|
214
|
+
|
|
215
|
+
// 7b: Merge artifact registries
|
|
216
|
+
mainArtifacts = mainState.artifacts ?? []
|
|
217
|
+
existingIds = new Set(mainArtifacts.map(a => a.id))
|
|
218
|
+
for (art of wtArtifacts):
|
|
219
|
+
IF existingIds.has(art.id):
|
|
220
|
+
// Update existing artifact status
|
|
221
|
+
idx = mainArtifacts.findIndex(a => a.id === art.id)
|
|
222
|
+
mainArtifacts[idx] = art
|
|
223
|
+
ELSE:
|
|
224
|
+
mainArtifacts.push(art)
|
|
225
|
+
mainState.artifacts = mainArtifacts
|
|
226
|
+
|
|
227
|
+
// Record merge in transition history
|
|
228
|
+
mainState.transition_history = mainState.transition_history ?? []
|
|
229
|
+
mainState.transition_history.push({
|
|
230
|
+
milestone_num: target.milestone_num,
|
|
231
|
+
milestone: target.milestone,
|
|
232
|
+
action: "worktree_merge",
|
|
233
|
+
completed_at: getUtc8ISOString(),
|
|
234
|
+
branch: target.branch,
|
|
235
|
+
phases: target.owned_phases
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
ELSE:
|
|
239
|
+
// Legacy: copy phase directories from worktree to main
|
|
240
|
+
// 7a: Copy all owned phase directories
|
|
241
|
+
for (phaseNum of target.owned_phases):
|
|
242
|
+
NN = String(phaseNum).padStart(2, '0')
|
|
243
|
+
Glob: {target.path}/.workflow/phases/{NN}-*/
|
|
244
|
+
phaseDir = matched directory name
|
|
245
|
+
|
|
246
|
+
srcDir = target.path + "/.workflow/phases/" + phaseDir + "/"
|
|
247
|
+
dstDir = ".workflow/phases/" + phaseDir + "/"
|
|
248
|
+
|
|
249
|
+
Bash("cp -r {srcDir}* {dstDir}")
|
|
250
|
+
|
|
251
|
+
// 7b: Update phase summaries
|
|
252
|
+
for (phaseNum of target.owned_phases):
|
|
253
|
+
NN = String(phaseNum).padStart(2, '0')
|
|
254
|
+
Glob: .workflow/phases/{NN}-*/index.json
|
|
255
|
+
Read → phaseIndex
|
|
256
|
+
|
|
257
|
+
IF phaseIndex.status === "completed":
|
|
258
|
+
mainState.phases_summary.completed += 1
|
|
259
|
+
mainState.phases_summary.pending -= 1
|
|
260
|
+
IF mainState.phases_summary.pending < 0:
|
|
261
|
+
mainState.phases_summary.pending = 0
|
|
262
|
+
|
|
263
|
+
mainState.transition_history = mainState.transition_history ?? []
|
|
264
|
+
mainState.transition_history.push({
|
|
265
|
+
milestone_num: target.milestone_num,
|
|
266
|
+
milestone: target.milestone,
|
|
267
|
+
phase: phaseNum,
|
|
268
|
+
action: "worktree_merge",
|
|
269
|
+
completed_at: phaseIndex.completed_at ?? getUtc8ISOString(),
|
|
270
|
+
branch: target.branch
|
|
271
|
+
})
|
|
272
|
+
ELSE IF phaseIndex.status !== "forked":
|
|
273
|
+
mainState.phases_summary.in_progress += 1
|
|
274
|
+
mainState.phases_summary.pending -= 1
|
|
275
|
+
IF mainState.phases_summary.pending < 0:
|
|
276
|
+
mainState.phases_summary.pending = 0
|
|
277
|
+
|
|
278
|
+
phaseIndex.updated_at = getUtc8ISOString()
|
|
279
|
+
Write .workflow/phases/{NN}-{slug}/index.json: phaseIndex
|
|
280
|
+
|
|
281
|
+
// Merge accumulated context from worktree (both paths)
|
|
282
|
+
IF NOT useArtifactRegistry:
|
|
283
|
+
Read target.path + "/.workflow/state.json" → wtState (if exists)
|
|
229
284
|
IF wtState?.accumulated_context:
|
|
230
285
|
for (decision of (wtState.accumulated_context.key_decisions ?? [])):
|
|
231
286
|
IF NOT mainState.accumulated_context.key_decisions.includes(decision):
|
|
@@ -236,12 +291,15 @@ IF wtState?.accumulated_context:
|
|
|
236
291
|
mainState.last_updated = getUtc8ISOString()
|
|
237
292
|
Write .workflow/state.json: mainState
|
|
238
293
|
|
|
239
|
-
// 7c: Update roadmap.md
|
|
294
|
+
// 7c: Update roadmap.md (mark completed phases)
|
|
240
295
|
Read .workflow/roadmap.md → roadmap
|
|
241
296
|
for (phaseNum of target.owned_phases):
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
297
|
+
IF useArtifactRegistry:
|
|
298
|
+
isCompleted = completedPhases.some(p => p.phase === phaseNum)
|
|
299
|
+
ELSE:
|
|
300
|
+
Read phase index → isCompleted = (status === "completed")
|
|
301
|
+
IF isCompleted:
|
|
302
|
+
Append " ✅ COMPLETED" to phase title line in roadmap
|
|
245
303
|
Write .workflow/roadmap.md: roadmap
|
|
246
304
|
```
|
|
247
305
|
|
|
@@ -9,7 +9,7 @@ This is a **post-execution analysis** workflow. It reads only — until the rout
|
|
|
9
9
|
## Prerequisites
|
|
10
10
|
|
|
11
11
|
- `.workflow/` initialized (`.workflow/state.json` exists)
|
|
12
|
-
- At least one phase
|
|
12
|
+
- At least one completed phase (via artifact registry in state.json, or legacy `.workflow/phases/{NN}-{slug}/`)
|
|
13
13
|
- Target phase has been executed (has `.task/` and `.summaries/`)
|
|
14
14
|
- `maestro delegate` available (used for the four lens analyses via Agent calls)
|
|
15
15
|
|
|
@@ -61,19 +61,46 @@ This is a **post-execution analysis** workflow. It reads only — until the rout
|
|
|
61
61
|
|
|
62
62
|
```
|
|
63
63
|
candidates = []
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
64
|
+
|
|
65
|
+
Read .workflow/state.json → state
|
|
66
|
+
artifacts = state.artifacts ?? []
|
|
67
|
+
useArtifactRegistry = artifacts.length > 0
|
|
68
|
+
|
|
69
|
+
IF useArtifactRegistry:
|
|
70
|
+
// Resolve completed phases from artifact registry
|
|
71
|
+
phaseNums = [...new Set(artifacts.map(a => a.phase).filter(Boolean))]
|
|
72
|
+
FOR each phaseNum in phaseNums:
|
|
73
|
+
execArt = artifacts.find(a => a.type === 'execute' && a.phase === phaseNum && a.status === 'completed')
|
|
74
|
+
IF execArt:
|
|
75
|
+
scratchDir = ".workflow/" + execArt.path
|
|
76
|
+
has_retro = file exists at "{scratchDir}/retrospective.json"
|
|
77
|
+
candidates.push({
|
|
78
|
+
number: phaseNum,
|
|
79
|
+
slug: execArt.slug ?? "phase-" + phaseNum,
|
|
80
|
+
title: execArt.title ?? execArt.slug ?? "Phase " + phaseNum,
|
|
81
|
+
completed_at: execArt.completed_at,
|
|
82
|
+
has_retro: has_retro,
|
|
83
|
+
phase_dir: scratchDir,
|
|
84
|
+
gaps: 0,
|
|
85
|
+
review_verdict: "—"
|
|
86
|
+
})
|
|
87
|
+
ELSE:
|
|
88
|
+
// Legacy: scan phases/ directory
|
|
89
|
+
FOR each .workflow/phases/{NN}-{slug}/index.json:
|
|
90
|
+
Read index.json
|
|
91
|
+
IF index.json.status == "completed":
|
|
92
|
+
phase_dir = ".workflow/phases/{NN}-{slug}"
|
|
93
|
+
has_retro = file exists at "{phase_dir}/retrospective.json"
|
|
94
|
+
candidates.push({
|
|
95
|
+
number: NN,
|
|
96
|
+
slug: slug,
|
|
97
|
+
title: index.json.title or slug,
|
|
98
|
+
completed_at: index.json.completed_at,
|
|
99
|
+
has_retro: has_retro,
|
|
100
|
+
phase_dir: phase_dir,
|
|
101
|
+
gaps: index.json.verification?.gaps?.length or 0,
|
|
102
|
+
review_verdict: index.json.review?.verdict or "—"
|
|
103
|
+
})
|
|
77
104
|
```
|
|
78
105
|
|
|
79
106
|
### Display backlog
|
|
@@ -103,24 +130,26 @@ FOR each .workflow/phases/{NN}-{slug}/index.json:
|
|
|
103
130
|
|
|
104
131
|
If overwriting existing retrospective.json:
|
|
105
132
|
```
|
|
106
|
-
mkdir -p "{phase_dir}/.history"
|
|
133
|
+
mkdir -p "{candidate.phase_dir}/.history"
|
|
107
134
|
TIMESTAMP = format(now(), "YYYY-MM-DDTHH-mm-ss")
|
|
108
|
-
mv "{phase_dir}/retrospective.json" "{phase_dir}/.history/retrospective-{TIMESTAMP}.json"
|
|
109
|
-
mv "{phase_dir}/retrospective.md" "{phase_dir}/.history/retrospective-{TIMESTAMP}.md"
|
|
135
|
+
mv "{candidate.phase_dir}/retrospective.json" "{candidate.phase_dir}/.history/retrospective-{TIMESTAMP}.json"
|
|
136
|
+
mv "{candidate.phase_dir}/retrospective.md" "{candidate.phase_dir}/.history/retrospective-{TIMESTAMP}.md"
|
|
110
137
|
```
|
|
111
138
|
|
|
112
139
|
---
|
|
113
140
|
|
|
114
141
|
## Stage 3: load_artifacts (per phase)
|
|
115
142
|
|
|
116
|
-
For each selected phase, build the in-memory artifacts bundle:
|
|
143
|
+
For each selected phase (using `candidate.phase_dir` resolved in Stage 2), build the in-memory artifacts bundle:
|
|
117
144
|
|
|
118
145
|
```
|
|
146
|
+
phase_dir = candidate.phase_dir // already resolved: scratch path (artifact registry) or legacy phases/ path
|
|
147
|
+
|
|
119
148
|
artifacts = {
|
|
120
149
|
phase_num: NN,
|
|
121
150
|
phase_slug: slug,
|
|
122
|
-
phase_dir:
|
|
123
|
-
index: read
|
|
151
|
+
phase_dir: phase_dir,
|
|
152
|
+
index: read "{phase_dir}/index.json" or null,
|
|
124
153
|
state: read .workflow/state.json,
|
|
125
154
|
plan: read "{phase_dir}/plan.json" or null,
|
|
126
155
|
verification: read "{phase_dir}/verification.json" or null,
|
|
@@ -130,7 +159,17 @@ artifacts = {
|
|
|
130
159
|
task_jsons: read all "{phase_dir}/.task/TASK-*.json",
|
|
131
160
|
phase_issues: filter ".workflow/issues/issues.jsonl" + ".workflow/issues/issue-history.jsonl"
|
|
132
161
|
where issue.phase_ref == phase_slug or issue.phase_ref == NN,
|
|
133
|
-
prior_retro:
|
|
162
|
+
prior_retro: null
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Resolve --compare target
|
|
166
|
+
IF --compare M:
|
|
167
|
+
IF useArtifactRegistry:
|
|
168
|
+
compareArt = state.artifacts.find(a => a.type === 'execute' && a.phase === M)
|
|
169
|
+
IF compareArt:
|
|
170
|
+
artifacts.prior_retro = read ".workflow/" + compareArt.path + "/retrospective.json"
|
|
171
|
+
ELSE:
|
|
172
|
+
artifacts.prior_retro = read .workflow/phases/{MM}-*/retrospective.json
|
|
134
173
|
}
|
|
135
174
|
```
|
|
136
175
|
|
|
@@ -422,7 +461,7 @@ retrospective = {
|
|
|
422
461
|
| {INS-id} | note | ... |
|
|
423
462
|
```
|
|
424
463
|
|
|
425
|
-
Write both files:
|
|
464
|
+
Write both files (phase_dir already resolved in Stage 2):
|
|
426
465
|
```
|
|
427
466
|
Write "{phase_dir}/retrospective.json"
|
|
428
467
|
Write "{phase_dir}/retrospective.md"
|
package/workflows/review.md
CHANGED
|
@@ -15,10 +15,23 @@ Tiered multi-dimensional code review with parallel agents, severity classificati
|
|
|
15
15
|
|
|
16
16
|
```
|
|
17
17
|
Input: <phase> argument (number or slug)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
|
|
19
|
+
Read .workflow/state.json → state
|
|
20
|
+
artifacts = state.artifacts ?? []
|
|
21
|
+
useArtifactRegistry = artifacts.length > 0
|
|
22
|
+
|
|
23
|
+
IF useArtifactRegistry:
|
|
24
|
+
IF number: art = artifacts.find(a => a.type === 'execute' && a.phase === number)
|
|
25
|
+
IF slug: art = artifacts.find(a => a.type === 'execute' && a.slug?.includes(slug))
|
|
26
|
+
IF art: PHASE_DIR = ".workflow/" + art.path
|
|
27
|
+
ELSE: ERROR "Phase not found in artifact registry"
|
|
28
|
+
ELSE:
|
|
29
|
+
// Legacy: resolve from phases/ directory
|
|
30
|
+
IF number: find .workflow/phases/{NN}-*/index.json
|
|
31
|
+
IF slug: find .workflow/phases/*-{slug}/index.json
|
|
32
|
+
PHASE_DIR = resolved path
|
|
33
|
+
|
|
34
|
+
Validate execution has occurred (tasks_completed > 0 or .task/ exists)
|
|
22
35
|
```
|
|
23
36
|
|
|
24
37
|
---
|