maestro-flow 0.3.8 → 0.3.9

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.
Files changed (211) hide show
  1. package/.claude/commands/learn-decompose.md +3 -3
  2. package/.claude/commands/learn-follow.md +5 -5
  3. package/.claude/commands/learn-investigate.md +3 -3
  4. package/.claude/commands/learn-retro.md +6 -6
  5. package/.claude/commands/learn-second-opinion.md +3 -3
  6. package/.claude/commands/maestro-analyze.md +123 -99
  7. package/.claude/commands/maestro-brainstorm.md +2 -2
  8. package/.claude/commands/maestro-execute.md +137 -97
  9. package/.claude/commands/maestro-fork.md +111 -0
  10. package/.claude/commands/maestro-init.md +6 -6
  11. package/.claude/commands/maestro-merge.md +77 -0
  12. package/.claude/commands/maestro-milestone-audit.md +72 -60
  13. package/.claude/commands/maestro-milestone-complete.md +67 -59
  14. package/.claude/commands/maestro-milestone-release.md +6 -6
  15. package/.claude/commands/maestro-plan.md +151 -130
  16. package/.claude/commands/maestro-quick.md +4 -4
  17. package/.claude/commands/maestro-roadmap.md +5 -5
  18. package/.claude/commands/maestro-spec-generate.md +5 -5
  19. package/.claude/commands/maestro-ui-design.md +3 -3
  20. package/.claude/commands/maestro-verify.md +106 -87
  21. package/.claude/commands/maestro.md +10 -4
  22. package/.claude/commands/manage-codebase-rebuild.md +4 -4
  23. package/.claude/commands/manage-codebase-refresh.md +1 -1
  24. package/.claude/commands/manage-harvest.md +5 -5
  25. package/.claude/commands/manage-issue-discover.md +1 -1
  26. package/.claude/commands/manage-issue-execute.md +6 -6
  27. package/.claude/commands/manage-issue.md +6 -6
  28. package/.claude/commands/manage-learn.md +2 -2
  29. package/.claude/commands/manage-memory-capture.md +4 -4
  30. package/.claude/commands/manage-memory.md +2 -2
  31. package/.claude/commands/manage-status.md +24 -24
  32. package/.claude/commands/quality-business-test.md +5 -5
  33. package/.claude/commands/quality-debug.md +4 -4
  34. package/.claude/commands/quality-integration-test.md +4 -4
  35. package/.claude/commands/quality-refactor.md +3 -3
  36. package/.claude/commands/quality-retrospective.md +2 -2
  37. package/.claude/commands/quality-review.md +4 -4
  38. package/.claude/commands/quality-sync.md +3 -3
  39. package/.claude/commands/quality-test-gen.md +4 -4
  40. package/.claude/commands/quality-test.md +9 -9
  41. package/.claude/commands/spec-add.md +2 -2
  42. package/.claude/commands/spec-load.md +1 -1
  43. package/.claude/commands/spec-setup.md +5 -5
  44. package/.claude/commands/wiki-connect.md +3 -3
  45. package/.claude/commands/wiki-digest.md +4 -4
  46. package/.codex/skills/maestro-analyze/SKILL.md +52 -14
  47. package/.codex/skills/maestro-execute/SKILL.md +27 -26
  48. package/.codex/skills/maestro-milestone-audit/SKILL.md +103 -209
  49. package/.codex/skills/maestro-milestone-complete/SKILL.md +149 -158
  50. package/.codex/skills/maestro-plan/SKILL.md +47 -17
  51. package/.codex/skills/maestro-roadmap/SKILL.md +3 -2
  52. package/.codex/skills/team-coordinate/roles/coordinator/commands/monitor.md +2 -2
  53. package/.codex/skills/team-executor/roles/executor/commands/monitor.md +1 -1
  54. package/.codex/skills/team-lifecycle-v4/roles/coordinator/commands/monitor.md +2 -2
  55. package/.codex/skills/team-lifecycle-v4/specs/knowledge-transfer.md +2 -2
  56. package/.codex/skills/team-quality-assurance/roles/coordinator/commands/monitor.md +1 -1
  57. package/.codex/skills/team-review/roles/coordinator/commands/monitor.md +1 -1
  58. package/.codex/skills/team-tech-debt/roles/coordinator/commands/monitor.md +1 -1
  59. package/.codex/skills/team-testing/roles/coordinator/commands/monitor.md +1 -1
  60. package/README.md +19 -14
  61. package/README.zh-CN.md +16 -12
  62. package/bin/maestro-mcp.js +1 -1
  63. package/chains/_intent-map.json +21 -9
  64. package/chains/_router.json +30 -77
  65. package/chains/brainstorm-driven.json +17 -6
  66. package/chains/full-lifecycle.json +22 -23
  67. package/chains/milestone-close.json +20 -7
  68. package/chains/milestone-fork-merge.json +50 -0
  69. package/chains/roadmap-driven.json +17 -6
  70. package/chains/spec-driven.json +17 -6
  71. package/dashboard/dist/assets/{ArtifactsPage-BmPOu8sO.js → ArtifactsPage-DZNCi6tn.js} +12 -7
  72. package/dashboard/dist/assets/ChatInput-Bvr-FeEq.js +49 -0
  73. package/dashboard/dist/assets/ChatPage-D9zTkJZo.js +22 -0
  74. package/dashboard/dist/assets/CollabPage-B4NAHXS2.js +1 -0
  75. package/dashboard/dist/assets/ExecutionPanel-CFt4LJyq.js +1 -0
  76. package/dashboard/dist/assets/KanbanPage-C8USth6H.js +21 -0
  77. package/dashboard/dist/assets/{MarkdownRenderer-BjZ43aSa.js → MarkdownRenderer-X4af_WNb.js} +1 -1
  78. package/dashboard/dist/assets/McpPage-BKfCVIyU.js +21 -0
  79. package/dashboard/dist/assets/OutputPanel-BlBQFJSW.js +1 -0
  80. package/dashboard/dist/assets/ProblemsPanel-De3DLvoI.js +1 -0
  81. package/dashboard/dist/assets/{RequirementBoardPage-B7yRL0s_.js → RequirementBoardPage-Bf1trzqs.js} +2 -2
  82. package/dashboard/dist/assets/{RequirementPage-D8J_-b6O.js → RequirementPage-Bllxe2XI.js} +10 -5
  83. package/dashboard/dist/assets/{SpecsPage-6lO8v8_C.js → SpecsPage-9lwxKT27.js} +2 -2
  84. package/dashboard/dist/assets/{SupervisorPage-Ds5N378a.js → SupervisorPage-SusdfHFq.js} +1 -1
  85. package/dashboard/dist/assets/{TeamsPage-DrkKr17T.js → TeamsPage-DsuM6OwC.js} +2 -2
  86. package/dashboard/dist/assets/TreeBrowser-Q12qobZs.js +6 -0
  87. package/dashboard/dist/assets/WorkflowPage-D_Fzdy3_.js +6 -0
  88. package/dashboard/dist/assets/{arrow-left-CadP5YgU.js → arrow-left-Bqtb2hle.js} +1 -1
  89. package/dashboard/dist/assets/{check-5xufDzS8.js → check-u6fGOwQO.js} +1 -1
  90. package/dashboard/dist/assets/{chevron-right-CYbpR4ev.js → chevron-right-Csu22t58.js} +1 -1
  91. package/dashboard/dist/assets/{circle-Bm-5Q-Yh.js → circle-CMrkbRNg.js} +1 -1
  92. package/dashboard/dist/assets/{circle-alert-BqcYuT7x.js → circle-alert-c3tH1P4z.js} +1 -1
  93. package/dashboard/dist/assets/{circle-check-big-yyzAFysU.js → circle-check-big-TDSeWstm.js} +1 -1
  94. package/dashboard/dist/assets/{circle-check-DEVzW_lm.js → circle-check-gYxxSYuH.js} +1 -1
  95. package/dashboard/dist/assets/{code-BBdC8Wmw.js → code-CFN2uX9V.js} +1 -1
  96. package/dashboard/dist/assets/{columns-3-CQ9Trztr.js → columns-3-38xIDlzy.js} +1 -1
  97. package/dashboard/dist/assets/{download-DayuF-sn.js → download-DC7KkKyP.js} +1 -1
  98. package/dashboard/dist/assets/{folder-CqXeSKeC.js → folder-CWq_lAnf.js} +1 -1
  99. package/dashboard/dist/assets/index-DWG-WrzT.js +231 -0
  100. package/dashboard/dist/assets/{index-Dru5HYy0.js → index-Do71weNR.js} +1 -1
  101. package/dashboard/dist/assets/index-GUNJodSR.css +1 -0
  102. package/dashboard/dist/assets/{list-DBOD6IUt.js → list-CgIP_2A-.js} +1 -1
  103. package/dashboard/dist/assets/{minus-fQI1Syn2.js → minus-DYoN5UGk.js} +1 -1
  104. package/dashboard/dist/assets/{pen-line-Bkbbngl5.js → pen-line-Bh_WKYHm.js} +1 -1
  105. package/dashboard/dist/assets/{proxy-teW12DdZ.js → proxy-BKxDAKTj.js} +1 -1
  106. package/dashboard/dist/assets/{search-Bq3ygFUW.js → search-SieXnOgr.js} +1 -1
  107. package/dashboard/dist/assets/{shallow-22ZN8sFt.js → shallow-Bme1JY57.js} +1 -1
  108. package/dashboard/dist/assets/{table-BEYtdWc4.js → table-llyEtj-7.js} +1 -1
  109. package/dashboard/dist/assets/terminal-BB3Xfuv5.js +6 -0
  110. package/dashboard/dist/assets/{trash-2-DMqGBgcF.js → trash-2-C8f4vFFM.js} +1 -1
  111. package/dashboard/dist/assets/{zap-9DVkGVtt.js → zap-4uwlzVm0.js} +1 -1
  112. package/dashboard/dist/index.html +2 -2
  113. package/dashboard/dist-server/dashboard/src/server/agents/claude-code-adapter.js +8 -4
  114. package/dashboard/dist-server/dashboard/src/server/agents/claude-code-adapter.js.map +1 -1
  115. package/dashboard/dist-server/dashboard/src/server/agents/entry-normalizer.d.ts +1 -0
  116. package/dashboard/dist-server/dashboard/src/server/agents/entry-normalizer.js +2 -1
  117. package/dashboard/dist-server/dashboard/src/server/agents/entry-normalizer.js.map +1 -1
  118. package/dashboard/dist-server/dashboard/src/server/agents/stream-json-adapter.js +20 -10
  119. package/dashboard/dist-server/dashboard/src/server/agents/stream-json-adapter.js.map +1 -1
  120. package/dashboard/dist-server/dashboard/src/server/routes/git.d.ts +2 -0
  121. package/dashboard/dist-server/dashboard/src/server/routes/git.js +79 -0
  122. package/dashboard/dist-server/dashboard/src/server/routes/git.js.map +1 -0
  123. package/dashboard/dist-server/dashboard/src/server/routes/index.js +3 -0
  124. package/dashboard/dist-server/dashboard/src/server/routes/index.js.map +1 -1
  125. package/dashboard/dist-server/dashboard/src/server/routes/workspace.js +43 -0
  126. package/dashboard/dist-server/dashboard/src/server/routes/workspace.js.map +1 -1
  127. package/dashboard/dist-server/dashboard/src/server/state/state-manager.js +43 -3
  128. package/dashboard/dist-server/dashboard/src/server/state/state-manager.js.map +1 -1
  129. package/dashboard/package.json +59 -59
  130. package/dist/src/cli.js +3 -1
  131. package/dist/src/cli.js.map +1 -1
  132. package/dist/src/commands/{team.d.ts → collab.d.ts} +2 -2
  133. package/dist/src/commands/collab.d.ts.map +1 -0
  134. package/dist/src/commands/{team.js → collab.js} +391 -24
  135. package/dist/src/commands/collab.js.map +1 -0
  136. package/dist/src/commands/msg.d.ts.map +1 -1
  137. package/dist/src/commands/msg.js +4 -3
  138. package/dist/src/commands/msg.js.map +1 -1
  139. package/dist/src/hooks/team-monitor.d.ts.map +1 -1
  140. package/dist/src/hooks/team-monitor.js +16 -0
  141. package/dist/src/hooks/team-monitor.js.map +1 -1
  142. package/dist/src/tools/collab-adapter.d.ts +85 -0
  143. package/dist/src/tools/collab-adapter.d.ts.map +1 -0
  144. package/dist/src/tools/collab-adapter.js +320 -0
  145. package/dist/src/tools/collab-adapter.js.map +1 -0
  146. package/dist/src/tools/namespace-guard.d.ts +2 -0
  147. package/dist/src/tools/namespace-guard.d.ts.map +1 -1
  148. package/dist/src/tools/namespace-guard.js +12 -0
  149. package/dist/src/tools/namespace-guard.js.map +1 -1
  150. package/dist/src/tools/phase-gate-evaluator.d.ts +45 -0
  151. package/dist/src/tools/phase-gate-evaluator.d.ts.map +1 -0
  152. package/dist/src/tools/phase-gate-evaluator.js +42 -0
  153. package/dist/src/tools/phase-gate-evaluator.js.map +1 -0
  154. package/dist/src/tools/team-members.d.ts +18 -0
  155. package/dist/src/tools/team-members.d.ts.map +1 -1
  156. package/dist/src/tools/team-members.js +50 -0
  157. package/dist/src/tools/team-members.js.map +1 -1
  158. package/dist/src/tools/team-tasks.d.ts +120 -0
  159. package/dist/src/tools/team-tasks.d.ts.map +1 -0
  160. package/dist/src/tools/team-tasks.js +365 -0
  161. package/dist/src/tools/team-tasks.js.map +1 -0
  162. package/dist/src/tools/transition-recorder.d.ts +3 -0
  163. package/dist/src/tools/transition-recorder.d.ts.map +1 -1
  164. package/dist/src/tools/transition-recorder.js +52 -1
  165. package/dist/src/tools/transition-recorder.js.map +1 -1
  166. package/dist/src/utils/get-version.d.ts.map +1 -1
  167. package/dist/src/utils/get-version.js +15 -4
  168. package/dist/src/utils/get-version.js.map +1 -1
  169. package/package.json +1 -1
  170. package/templates/config.json +7 -0
  171. package/templates/worktree-scope.json +10 -0
  172. package/templates/worktrees.json +27 -0
  173. package/workflows/analyze.md +86 -36
  174. package/workflows/brainstorm.md +17 -37
  175. package/workflows/execute.md +94 -28
  176. package/workflows/fork.md +309 -0
  177. package/workflows/init.md +10 -1
  178. package/workflows/issue.md +66 -7
  179. package/workflows/maestro-coordinate.md +23 -16
  180. package/workflows/maestro.md +52 -35
  181. package/workflows/merge.md +285 -0
  182. package/workflows/milestone-audit.md +89 -70
  183. package/workflows/milestone-complete.md +89 -156
  184. package/workflows/plan.md +122 -17
  185. package/workflows/retrospective.md +3 -3
  186. package/workflows/roadmap.md +11 -3
  187. package/workflows/spec-generate.md +9 -0
  188. package/workflows/status.md +76 -27
  189. package/workflows/ui-design.md +14 -12
  190. package/workflows/verify.md +44 -8
  191. package/.claude/commands/maestro-phase-add.md +0 -63
  192. package/.claude/commands/maestro-phase-transition.md +0 -75
  193. package/.codex/skills/maestro-phase-add/SKILL.md +0 -154
  194. package/.codex/skills/maestro-phase-transition/SKILL.md +0 -173
  195. package/chains/singles/phase-add.json +0 -31
  196. package/chains/singles/phase-transition.json +0 -23
  197. package/dashboard/dist/assets/ChatInput-CL8YDfOU.js +0 -67
  198. package/dashboard/dist/assets/ChatPage-CT-ozBK2.js +0 -8
  199. package/dashboard/dist/assets/CollabPage-C0rWMden.js +0 -1
  200. package/dashboard/dist/assets/KanbanPage-C6WbAlwI.js +0 -16
  201. package/dashboard/dist/assets/McpPage-BPIXADQi.js +0 -16
  202. package/dashboard/dist/assets/TreeBrowser-g_QUKemL.js +0 -11
  203. package/dashboard/dist/assets/WorkflowPage-X8aNkDEr.js +0 -6
  204. package/dashboard/dist/assets/git-branch-SqFf4Ru5.js +0 -6
  205. package/dashboard/dist/assets/index-D2Mtyw7I.css +0 -1
  206. package/dashboard/dist/assets/index-nufWop4p.js +0 -231
  207. package/dashboard/dist/assets/wrench-B84-zdLI.js +0 -11
  208. package/dist/src/commands/team.d.ts.map +0 -1
  209. package/dist/src/commands/team.js.map +0 -1
  210. package/workflows/phase-add.md +0 -252
  211. package/workflows/phase-transition.md +0 -399
@@ -4,7 +4,9 @@
4
4
  * Provides pure functions for building transition entries and appending
5
5
  * them to the transition_history array in .workflow/state.json.
6
6
  */
7
- import { readFileSync, writeFileSync, existsSync } from 'node:fs';
7
+ import { readFileSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
8
+ import { join, dirname } from 'node:path';
9
+ import { evaluatePhaseGate } from './phase-gate-evaluator.js';
8
10
  // ---------------------------------------------------------------------------
9
11
  // Public API
10
12
  // ---------------------------------------------------------------------------
@@ -33,10 +35,31 @@ export function buildTransitionEntry(opts) {
33
35
  /**
34
36
  * Append a transition entry to state.json's transition_history[].
35
37
  * Creates the array if it doesn't exist.
38
+ *
39
+ * For phase-completion transitions, evaluates the phase gate first.
40
+ * Throws if the gate blocks and force is false.
36
41
  */
37
42
  export function appendTransition(statePath, entry) {
38
43
  if (!existsSync(statePath))
39
44
  return;
45
+ // Gate check: validate phase readiness before allowing completion
46
+ if (entry.type === 'phase' && entry.from_phase != null) {
47
+ const phaseIndex = loadPhaseIndex(statePath, entry.from_phase);
48
+ if (phaseIndex) {
49
+ const gate = evaluatePhaseGate(phaseIndex);
50
+ if (!gate.allowed) {
51
+ if (!gate.overridable || !entry.force) {
52
+ const tag = gate.overridable ? '[GATE_BLOCKED]' : '[GATE_HARD_BLOCK]';
53
+ throw new Error(`${tag} Phase ${entry.from_phase} cannot be completed:\n` +
54
+ gate.reasons.map((r) => ` - ${r}`).join('\n') +
55
+ (gate.overridable ? '\nUse force=true to override soft blocks.' : '\nResolve BLOCK verdict before completing.'));
56
+ }
57
+ // Force override — record the reasons in snapshot for audit
58
+ entry.snapshot.verification_status =
59
+ `force_override: ${gate.reasons.join('; ')}`;
60
+ }
61
+ }
62
+ }
40
63
  const state = JSON.parse(readFileSync(statePath, 'utf8'));
41
64
  if (!Array.isArray(state.transition_history)) {
42
65
  state.transition_history = [];
@@ -45,4 +68,32 @@ export function appendTransition(statePath, entry) {
45
68
  state.last_updated = new Date().toISOString();
46
69
  writeFileSync(statePath, JSON.stringify(state, null, 2));
47
70
  }
71
+ // ---------------------------------------------------------------------------
72
+ // Internal helpers
73
+ // ---------------------------------------------------------------------------
74
+ /**
75
+ * Load phase index.json from the phases directory sibling to state.json.
76
+ * Returns null if not found.
77
+ */
78
+ function loadPhaseIndex(statePath, phaseNum) {
79
+ const workflowDir = dirname(statePath);
80
+ const phasesDir = join(workflowDir, 'phases');
81
+ if (!existsSync(phasesDir))
82
+ return null;
83
+ // Find directory starting with the phase number prefix (e.g. "01-")
84
+ try {
85
+ const prefix = String(phaseNum).padStart(2, '0') + '-';
86
+ const entries = readdirSync(phasesDir);
87
+ const phaseSlug = entries.find((e) => e.startsWith(prefix));
88
+ if (!phaseSlug)
89
+ return null;
90
+ const indexPath = join(phasesDir, phaseSlug, 'index.json');
91
+ if (!existsSync(indexPath))
92
+ return null;
93
+ return JSON.parse(readFileSync(indexPath, 'utf8'));
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ }
48
99
  //# sourceMappingURL=transition-recorder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transition-recorder.js","sourceRoot":"","sources":["../../../src/tools/transition-recorder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAuClE,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAyB;IAC5D,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,QAAQ,EAAE,IAAI,CAAC,OAAO;QACtB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,eAAe,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACzC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,QAAQ,EAAE;YACR,gBAAgB,EAAE,IAAI,CAAC,eAAe;YACtC,YAAY,EAAE,IAAI,CAAC,WAAW;YAC9B,cAAc,EAAE,IAAI,CAAC,aAAa;YAClC,mBAAmB,EAAE,IAAI,CAAC,kBAAkB;YAC5C,eAAe,EAAE,IAAI,CAAC,cAAc;SACrC;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB,EAAE,KAAsB;IACxE,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,CAAC;QAC7C,KAAK,CAAC,kBAAkB,GAAG,EAAE,CAAC;IAChC,CAAC;IACD,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrC,KAAK,CAAC,YAAY,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC9C,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"transition-recorder.js","sourceRoot":"","sources":["../../../src/tools/transition-recorder.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"get-version.d.ts","sourceRoot":"","sources":["../../../src/utils/get-version.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAO1C"}
1
+ {"version":3,"file":"get-version.d.ts","sourceRoot":"","sources":["../../../src/utils/get-version.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAiB1C"}
@@ -12,10 +12,21 @@ let cached = null;
12
12
  export function getPackageVersion() {
13
13
  if (cached)
14
14
  return cached;
15
- // Compiled JS lives at dist/src/utils/get-version.js 4 levels up to project root
16
- const pkgRoot = resolve(fileURLToPath(import.meta.url), '..', '..', '..', '..');
17
- const pkg = JSON.parse(readFileSync(resolve(pkgRoot, 'package.json'), 'utf-8'));
18
- cached = pkg.version ?? '0.0.0';
15
+ // Walk up from this file until we find a package.json with "maestro" in it
16
+ let dir = resolve(fileURLToPath(import.meta.url), '..');
17
+ for (let i = 0; i < 8; i++) {
18
+ const pkgPath = resolve(dir, 'package.json');
19
+ try {
20
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
21
+ if (pkg.name === 'maestro-flow' || pkg.name === 'maestro') {
22
+ cached = pkg.version ?? '0.0.0';
23
+ return cached;
24
+ }
25
+ }
26
+ catch { /* not found, keep going up */ }
27
+ dir = resolve(dir, '..');
28
+ }
29
+ cached = '0.0.0';
19
30
  return cached;
20
31
  }
21
32
  //# sourceMappingURL=get-version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get-version.js","sourceRoot":"","sources":["../../../src/utils/get-version.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,mFAAmF;IACnF,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,MAAM,GAAI,GAAG,CAAC,OAAkB,IAAI,OAAO,CAAC;IAC5C,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"get-version.js","sourceRoot":"","sources":["../../../src/utils/get-version.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAE9E,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,IAAI,GAAG,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;YACvD,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC1D,MAAM,GAAI,GAAG,CAAC,OAAkB,IAAI,OAAO,CAAC;gBAC5C,OAAO,MAAM,CAAC;YAChB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,8BAA8B,CAAC,CAAC;QAC1C,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,GAAG,OAAO,CAAC;IACjB,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maestro-flow",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Workflow orchestration CLI with MCP endpoint support and extensible architecture",
5
5
  "type": "module",
6
6
  "imports": {
@@ -49,5 +49,12 @@
49
49
  "doc_index": true,
50
50
  "auto_sync_after_execute": true,
51
51
  "action_log": true
52
+ },
53
+
54
+ "worktree": {
55
+ "enabled": true,
56
+ "root": ".worktrees",
57
+ "branch_prefix": "milestone/",
58
+ "auto_cleanup": true
52
59
  }
53
60
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "worktree": true,
3
+ "milestone_num": "{{MILESTONE_NUMBER}}",
4
+ "milestone": "{{MILESTONE_NAME}}",
5
+ "owned_phases": [],
6
+ "main_worktree": "{{MAIN_WORKTREE_PATH}}",
7
+ "branch": "milestone/{{MILESTONE_SLUG}}",
8
+ "base_commit": "{{BASE_COMMIT}}",
9
+ "created_at": "{{TIMESTAMP}}"
10
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "version": "1.0",
3
+ "worktrees": [
4
+ {
5
+ "milestone_num": "{{MILESTONE_NUMBER}}",
6
+ "milestone": "{{MILESTONE_NAME}}",
7
+ "slug": "{{MILESTONE_SLUG}}",
8
+ "branch": "milestone/{{MILESTONE_SLUG}}",
9
+ "path": "{{WORKTREE_ROOT}}/m{{MILESTONE_NUMBER}}-{{MILESTONE_SLUG}}",
10
+ "base_commit": "{{BASE_COMMIT}}",
11
+ "status": "active",
12
+ "created_at": "{{TIMESTAMP}}",
13
+ "owned_phases": [],
14
+ "fork_session": "{{FORK_SESSION_ID}}"
15
+ }
16
+ ],
17
+ "fork_sessions": [
18
+ {
19
+ "session_id": "fork-{{TIMESTAMP_SHORT}}",
20
+ "created_at": "{{TIMESTAMP}}",
21
+ "milestone_num": "{{MILESTONE_NUMBER}}",
22
+ "milestone": "{{MILESTONE_NAME}}",
23
+ "base_branch": "{{BASE_BRANCH}}",
24
+ "base_commit": "{{BASE_COMMIT}}"
25
+ }
26
+ ]
27
+ }
@@ -41,29 +41,60 @@ Quick mode (-q):
41
41
  ## Arguments
42
42
 
43
43
  ```
44
- $ARGUMENTS: "<phase|topic> [-y] [-c] [-q]"
44
+ $ARGUMENTS: "[phase|topic] [-y] [-c] [-q]"
45
45
 
46
- <phase> -- Phase number (phase mode, operates within phase directory)
47
- <topic> -- Topic text (scratch mode, creates scratch directory)
46
+ (no args) -- Milestone-wide analysis (requires init + roadmap)
47
+ <phase> -- Phase number (phase-scoped, requires init + roadmap)
48
+ <topic> -- Topic text (adhoc if milestone exists, standalone if not)
48
49
  -y / --yes -- Auto mode, skip interactive scoping, auto-deepen
49
50
  -c / --continue -- Resume from existing session
50
51
  -q / --quick -- Quick mode, skip exploration + scoring, go straight to decision extraction
51
52
  ```
52
53
 
53
- ## Dual-Mode Routing
54
-
55
- ```
56
- IF $ARGUMENTS matches /^\d+$/
57
- Phase mode
58
- Resolve phase dir from state.json + roadmap
59
- Set OUTPUT_DIR = .workflow/phases/{NN}-{slug}/
60
- Update index.json: status → "exploring"
61
-
62
- ELSE
63
- Scratch mode
64
- Slugify topic (lowercase, hyphens, max 40 chars)
65
- Set OUTPUT_DIR = .workflow/scratch/analyze-{slug}-{date}/
66
- Create directory + index.json from scratch-index template (type="analyze")
54
+ ## Scope Routing
55
+
56
+ ```
57
+ // Worktree scope check
58
+ IF file_exists(".workflow/worktree-scope.json"):
59
+ scope = read(".workflow/worktree-scope.json")
60
+ IF $ARGUMENTS matches /^\d+$/ AND parseInt($ARGUMENTS) NOT IN scope.owned_phases:
61
+ ERROR "Phase {$ARGUMENTS} not owned by this worktree. Owned: {scope.owned_phases}"
62
+ EXIT
63
+
64
+ // Auto-bootstrap state.json if missing
65
+ IF NOT file_exists(".workflow/state.json"):
66
+ mkdir -p .workflow/scratch/
67
+ Write minimal state.json: { project: null, status: "active", current_milestone: null,
68
+ current_task_id: null, milestones: [], artifacts: [], last_updated: now() }
69
+
70
+ // Scope determination
71
+ IF $ARGUMENTS is empty:
72
+ IF state.json.current_milestone is non-null AND roadmap.md exists:
73
+ → scope = "milestone"
74
+ → milestone_slug = slugify(current_milestone name)
75
+ → Set OUTPUT_DIR = .workflow/scratch/analyze-{milestone_slug}-{date}/
76
+ ELSE:
77
+ → ERROR E001 "No args and no roadmap — provide topic text or create roadmap first"
78
+
79
+ ELSE IF $ARGUMENTS matches /^\d+$/:
80
+ IF state.json.current_milestone is non-null AND roadmap.md exists:
81
+ → scope = "phase"
82
+ → phase_num = parsed number
83
+ → phase_slug = resolve from roadmap.md
84
+ → Set OUTPUT_DIR = .workflow/scratch/analyze-{phase_slug}-{date}/
85
+ ELSE:
86
+ → ERROR "Phase number requires init + roadmap"
87
+
88
+ ELSE (text argument):
89
+ → topic_slug = slugify(text, max 40 chars)
90
+ IF state.json.current_milestone is non-null:
91
+ → scope = "adhoc"
92
+ ELSE:
93
+ → scope = "standalone"
94
+ → Set OUTPUT_DIR = .workflow/scratch/analyze-{topic_slug}-{date}/
95
+
96
+ // Create output directory
97
+ mkdir -p {OUTPUT_DIR}
67
98
  ```
68
99
 
69
100
  ## Output Structure
@@ -89,31 +120,23 @@ Parse $ARGUMENTS to determine mode and flags:
89
120
  - `-c` present: locate existing session folder (discussion.md exists), resume from last round
90
121
  - `-y` present: set AUTO_MODE=true
91
122
  - `-q` present: set QUICK_MODE=true (skip Steps 2-7, jump to Step 8: Decision Extraction)
92
- - Number (e.g., "3") = phase mode: resolve `.workflow/phases/{NN}-*/`, verify phase exists in roadmap
93
- - Text (e.g., "microservices vs monolith") = scratch mode: slugify topic, prepare scratch directory path
94
- - Missing/empty = error E001
123
+ - Number (e.g., "3") = phase scope: resolve phase slug from roadmap, output to scratch/analyze-{phase-slug}-{date}/
124
+ - Text (e.g., "microservices vs monolith") = adhoc/standalone scope: output to scratch/analyze-{slug}-{date}/
125
+ - Missing/empty = milestone scope (if roadmap exists) or error E001
95
126
 
96
127
  **Session initialization:**
97
128
  - Session ID: `ANL-{slug}-{YYYY-MM-DD}`
98
- - Phase mode output: phase directory
99
- - Scratch mode output: `.workflow/scratch/analyze-{slug}-{date}/`
129
+ - Output: `OUTPUT_DIR` (always under `.workflow/scratch/`)
100
130
 
101
- **Load prior context** (phase mode):
131
+ **Load prior context** (milestone/phase scope):
102
132
  1. Read `.workflow/project.md` — project vision, constraints, Validated requirements (already shipped), Active requirements (current scope)
103
133
  2. Read `.workflow/roadmap.md` — phase structure and dependencies
104
- 3. Read index.json in phase dir goal, success_criteria
105
- 4. Read `.brainstorming/guidance-specification.md` in phase dir (if exists) detailed requirements, constraints, RFC 2119 decisions from brainstorm. Skip areas marked as MUST/MUST NOT (already locked).
106
- 5. Read `.brainstorming/feature-index.json` in phase dir (if exists) feature decomposition
107
- 6. Read `brainstorm.md` in phase dir (if exists, legacy fallback, skip if guidance-specification.md loaded)
108
- 7. Read `analysis.md` in phase dir (if exists, for continuation)
109
- 8. Read `conclusions.json` in phase dir (if exists, for continuation)
110
- 9. Read prior phases' `context.md` files — skip already-decided areas
111
- 10. Read existing `context.md` in this phase (if exists, for continuation)
112
- 11. Load project specs: `specs_content = maestro spec load --category planning`
113
- Ensures analysis decisions don't conflict with existing architecture constraints.
114
- 12. Read `.workflow/state.json` → `accumulated_context` (key_decisions, deferred items, blockers)
115
-
116
- **Load prior context** (scratch mode):
134
+ 3. Read `.workflow/state.json` `current_milestone`, `artifacts[]`, `accumulated_context` (key_decisions, deferred items, blockers)
135
+ 4. Find prior analyze artifacts from `state.json.artifacts[]` where type=analyze and same milestone load their `context.md` to skip already-decided areas
136
+ 5. Find brainstorm artifacts from `state.json.artifacts[]` where type=brainstorm and same milestone load `guidance-specification.md` if exists
137
+ 6. Load project specs: `specs_content = maestro spec load --category planning`
138
+
139
+ **Load prior context** (adhoc/standalone scope):
117
140
  1. Read `.workflow/project.md` (if exists) — project vision, Validated requirements, Active requirements, Key Decisions
118
141
  2. Read `.workflow/state.json` (if exists) → `accumulated_context` (key_decisions, deferred, blockers)
119
142
  3. Load project specs: `specs_content = maestro spec load --category planning`
@@ -571,6 +594,33 @@ IF deferred_items.length > 0:
571
594
  Print: "Created {deferred_items.length} deferred issues for tracking"
572
595
  ```
573
596
 
597
+ ### Step 8.8: Register Artifact
598
+
599
+ ```
600
+ // Register in state.json artifact registry
601
+ Read .workflow/state.json
602
+ next_id = max(artifacts.filter(a => a.type == "analyze").map(a => parseInt(a.id.replace("ANL-","")))) + 1
603
+ // If no analyze artifacts exist: next_id = 1
604
+
605
+ artifact = {
606
+ id: "ANL-{next_id padded to 3}",
607
+ type: "analyze",
608
+ milestone: state.json.current_milestone, // null if standalone
609
+ phase: phase_num, // null if milestone/adhoc/standalone
610
+ scope: scope, // "milestone"|"phase"|"adhoc"|"standalone"
611
+ path: OUTPUT_DIR relative to .workflow/, // e.g. "scratch/analyze-auth-2026-04-20"
612
+ status: "completed",
613
+ depends_on: null,
614
+ harvested: false,
615
+ created_at: session_start_time,
616
+ completed_at: now()
617
+ }
618
+
619
+ state.json.artifacts.push(artifact)
620
+ state.json.last_updated = now()
621
+ Write state.json (atomic: write tmp + rename)
622
+ ```
623
+
574
624
  ### Step 9: Report & Next Step
575
625
 
576
626
  Display summary:
@@ -47,8 +47,8 @@ Phase 3: Single Role Analysis → Detection → Context → Agent → Validation
47
47
  ## Input
48
48
 
49
49
  - `$ARGUMENTS`: topic text (auto mode) or role name (single role mode)
50
- - Phase mode: operates within `.workflow/phases/{NN}-{slug}/`
51
- - Scratch mode: creates `.workflow/scratch/brainstorm-{slug}-{date}/`
50
+ - All output goes to `.workflow/scratch/brainstorm-{slug}-{date}/`
51
+ - Registers artifact (type=brainstorm) in state.json on completion
52
52
 
53
53
  ### Parameters
54
54
 
@@ -80,32 +80,21 @@ Phase 3: Single Role Analysis → Detection → Context → Agent → Validation
80
80
 
81
81
  ### Directory Structure
82
82
 
83
- **Phase mode**:
84
- ```
85
- .workflow/phases/{NN}-{slug}/
86
- ├── brainstorm.md # Legacy simple output (if no session)
87
- ├── index.json # Updated timestamps
88
- └── .brainstorming/ # Full brainstorm session
89
- ├── guidance-specification.md # Phase 2 output
90
- ├── feature-index.json # Phase 4 output
91
- ├── synthesis-changelog.md # Phase 4 audit trail
92
- ├── feature-specs/ # Phase 4 feature specs
93
- │ ├── F-001-{slug}.md
94
- │ └── F-00N-{slug}.md
95
- ├── {role}/ # Phase 3 role analyses (immutable)
96
- │ ├── {role}-context.md
97
- │ ├── analysis.md
98
- │ ├── analysis-cross-cutting.md
99
- │ └── analysis-F-{id}-{slug}.md
100
- └── synthesis-specification.md # Non-feature mode fallback
101
- ```
102
-
103
- **Scratch mode**:
83
+ All brainstorm output goes to scratch:
104
84
  ```
105
85
  .workflow/scratch/brainstorm-{slug}-{date}/
106
- ├── index.json # scratch-index template
107
- └── .brainstorming/ # Same structure as phase mode
108
- └── ...
86
+ ├── guidance-specification.md # Phase 2 output
87
+ ├── feature-index.json # Phase 4 output
88
+ ├── synthesis-changelog.md # Phase 4 audit trail
89
+ ├── feature-specs/ # Phase 4 feature specs
90
+ │ ├── F-001-{slug}.md
91
+ │ └── F-00N-{slug}.md
92
+ ├── {role}/ # Phase 3 role analyses (immutable)
93
+ │ ├── {role}-context.md
94
+ │ ├── analysis.md
95
+ │ ├── analysis-cross-cutting.md
96
+ │ └── analysis-F-{id}-{slug}.md
97
+ └── synthesis-specification.md # Non-feature mode fallback
109
98
  ```
110
99
 
111
100
  ---
@@ -138,17 +127,8 @@ Parse $ARGUMENTS to determine execution mode:
138
127
 
139
128
  **Output Directory Resolution**:
140
129
  - Phase mode (number): `.workflow/phases/{NN}-{slug}/.brainstorming/`
141
- - Scratch mode (text): `.workflow/scratch/brainstorm-{slug}-{date}/.brainstorming/`
142
- - Existing session: use session's `.brainstorming/` directory
143
-
144
- **Archive previous brainstorming session** (Phase mode only, skip if `--session` or `--update`):
145
- ```
146
- PARENT_DIR = parent of output directory (e.g., .workflow/phases/{NN}-{slug}/)
147
- IF directory exists "${PARENT_DIR}/.brainstorming" AND NOT --session AND NOT --update:
148
- mkdir -p "${PARENT_DIR}/.history"
149
- TIMESTAMP = current timestamp formatted as "YYYY-MM-DDTHH-mm-ss"
150
- mv "${PARENT_DIR}/.brainstorming" "${PARENT_DIR}/.history/.brainstorming-${TIMESTAMP}"
151
- ```
130
+ - All output: `.workflow/scratch/brainstorm-{slug}-{date}/`
131
+ - Existing session: use existing session directory
152
132
 
153
133
  ---
154
134
 
@@ -2,32 +2,59 @@
2
2
 
3
3
  Wave-based parallel execution with atomic commits, breakpoint resume, and optional sync/reflection.
4
4
 
5
+ Core principle: **Execute per-plan, not per-phase.** Each plan's wave DAG runs independently. Multiple plans execute sequentially.
6
+
5
7
  ---
6
8
 
7
9
  ## Prerequisites
8
10
 
9
- - Phase has a completed plan: `plan.json` + `.task/TASK-*.json` exist
10
- - `index.json` present with `plan.waves` populated
11
+ - Plan exists in scratch directory: `plan.json` + `.task/TASK-*.json`
11
12
  - OR: executionContext handoff received from `/workflow:plan`
12
13
 
13
14
  ---
14
15
 
15
- ## Phase Resolution
16
+ ## Plan Resolution
16
17
 
17
18
  ```
18
- Input: <phase> argument (number or slug) OR --dir <path>
19
+ Input: [phase] argument OR --dir <path>
19
20
 
20
- IF --dir <path> is provided:
21
- 1. Set PHASE_DIR = <path> (absolute or relative to project root)
22
- 2. Validate directory exists and contains index.json
23
- 3. Set SCRATCH_MODE = true (skip roadmap validation, phase transition)
24
- 4. Set PHASE_NUM = null, PHASE_SLUG = directory basename
21
+ # Worktree scope check
22
+ IF file_exists(".workflow/worktree-scope.json"):
23
+ scope = read(".workflow/worktree-scope.json")
24
+ IF <phase> is a number AND <phase> NOT IN scope.owned_phases:
25
+ ERROR "Phase {phase} not owned by this worktree. Owned: {scope.owned_phases}"
26
+ EXIT
25
27
 
26
- ELSE (standard phase resolution):
27
- 1. If number: find .workflow/phases/{NN}-*/index.json
28
- 2. If slug: find .workflow/phases/*-{slug}/index.json
29
- 3. Validate plan exists (index.json.plan.task_count > 0)
30
- 4. Set PHASE_DIR = resolved path
28
+ # Auto-bootstrap state.json if missing
29
+ IF NOT file_exists(".workflow/state.json"):
30
+ mkdir -p .workflow/scratch/
31
+ Write minimal state.json
32
+
33
+ IF --dir <path> is provided:
34
+ 1. Set PLAN_DIRS = [<path>] // single plan
35
+ 2. Validate directory exists and contains plan.json
36
+
37
+ ELSE IF no arguments:
38
+ // Find all pending plans for current milestone
39
+ 1. Read state.json.artifacts
40
+ 2. Filter: milestone == current_milestone, type == "plan", status == "completed"
41
+ 3. Exclude plans that already have a corresponding EXC artifact (same path)
42
+ 4. Sort by phase order (from roadmap), adhoc plans last
43
+ 5. Set PLAN_DIRS = filtered plan paths
44
+ 6. If empty: ERROR E001 "No pending plans found"
45
+
46
+ ELSE IF argument is a number:
47
+ // Find pending plans for specific phase
48
+ 1. Read state.json.artifacts
49
+ 2. Filter: milestone == current_milestone, type == "plan", status == "completed", phase == arg
50
+ 3. Exclude plans with existing EXC artifacts
51
+ 4. Set PLAN_DIRS = filtered plan paths
52
+
53
+ // Execute plans sequentially
54
+ FOR each PLAN_DIR IN PLAN_DIRS:
55
+ execute_single_plan(PLAN_DIR)
56
+ register_exc_artifact(PLAN_DIR)
57
+ extract_incremental_learnings(PLAN_DIR)
31
58
  ```
32
59
 
33
60
  ---
@@ -43,11 +70,11 @@ ELSE (standard phase resolution):
43
70
 
44
71
  ---
45
72
 
46
- ## E1: Load Plan
73
+ ## E1: Load Plan (per PLAN_DIR)
47
74
 
48
- **Purpose:** Build or receive the execution queue.
75
+ **Purpose:** Build or receive the execution queue for a single plan.
49
76
 
50
- ### From executionContext handoff (preferred)
77
+ ### From executionContext handoff (preferred, first plan only)
51
78
 
52
79
  ```
53
80
  If executionContext is available in memory:
@@ -60,23 +87,22 @@ If executionContext is available in memory:
60
87
  Skip disk reload
61
88
  ```
62
89
 
63
- ### From disk (fallback / resume)
90
+ ### From disk (fallback / resume / subsequent plans)
64
91
 
65
92
  ```
66
- Read ${PHASE_DIR}/index.json
67
- Read ${PHASE_DIR}/plan.json
93
+ Read ${PLAN_DIR}/plan.json
68
94
 
69
95
  executionMethod = --method flag || config.json.execution.method || "agent"
70
96
  defaultExecutor = --executor flag || config.json.execution.default_executor || "gemini"
71
- executorAssignments = index.json.plan.executor_assignments || {}
97
+ executorAssignments = plan.json.executor_assignments || {}
72
98
  ```
73
99
 
74
100
  ### Detect completed tasks (breakpoint resume)
75
101
 
76
102
  ```
77
103
  completed_tasks = []
78
- For each task_id in index.json.plan.task_ids:
79
- Read .task/${task_id}.json
104
+ For each task_id in plan.json.task_ids:
105
+ Read ${PLAN_DIR}/.task/${task_id}.json
80
106
  If status == "completed":
81
107
  completed_tasks.push(task_id)
82
108
 
@@ -89,7 +115,7 @@ If completed_tasks.length > 0:
89
115
  ### Build wave execution queue
90
116
 
91
117
  ```
92
- waves = plan.json.waves (or index.json.plan.waves)
118
+ waves = plan.json.waves
93
119
 
94
120
  execution_queue = []
95
121
  For each wave in waves:
@@ -195,7 +221,9 @@ For each wave in execution_queue (sequential):
195
221
  Read .workflow/state.json
196
222
  If state.json.status != "executing":
197
223
  state.json.status = "executing"
198
- state.json.phases_summary.in_progress += 1
224
+ # Worktree mode: skip phases_summary (reconciled on merge)
225
+ IF NOT file_exists(".workflow/worktree-scope.json"):
226
+ state.json.phases_summary.in_progress += 1
199
227
  state.json.last_updated = now()
200
228
  Write .workflow/state.json
201
229
 
@@ -466,7 +494,7 @@ If config.json.workflow.reflection == true:
466
494
  - Any blocked tasks?
467
495
  - Patterns observed?
468
496
 
469
- Append to ${PHASE_DIR}/reflection-log.md:
497
+ Append to ${PLAN_DIR}/reflection-log.md:
470
498
  ## Reflection - Wave Execution {timestamp}
471
499
  - Strategy adjustments: [...]
472
500
  - Patterns noted: [...]
@@ -506,12 +534,50 @@ If NOT SCRATCH_MODE:
506
534
 
507
535
  ---
508
536
 
537
+ ## E5: Register Artifact & Extract Learnings (per PLAN_DIR)
538
+
539
+ **Purpose:** Register execution completion and extract incremental learnings.
540
+
541
+ ```
542
+ // Register EXC artifact
543
+ Read .workflow/state.json
544
+ plan_artifact = state.json.artifacts.find(a => a.type == "plan" && a.path == PLAN_DIR_relative)
545
+ next_id = max(artifacts.filter(a => a.type == "execute").map(a => parseInt(a.id.replace("EXC-","")))) + 1
546
+
547
+ artifact = {
548
+ id: "EXC-{next_id padded to 3}",
549
+ type: "execute",
550
+ milestone: plan_artifact.milestone,
551
+ phase: plan_artifact.phase,
552
+ scope: plan_artifact.scope,
553
+ path: plan_artifact.path, // same path — execute writes into plan dir
554
+ status: "completed",
555
+ depends_on: plan_artifact.id,
556
+ harvested: false,
557
+ created_at: execution_start_time,
558
+ completed_at: now()
559
+ }
560
+
561
+ state.json.artifacts.push(artifact)
562
+ state.json.last_updated = now()
563
+ Write state.json (atomic)
564
+
565
+ // Incremental learning extraction
566
+ Read all ${PLAN_DIR}/.summaries/TASK-*-summary.md
567
+ Extract: strategy adjustments, patterns discovered, pitfalls encountered
568
+ Append to .workflow/specs/learnings.md under "## Entries"
569
+ Mark artifact.harvested = true
570
+ Write state.json (atomic)
571
+ ```
572
+
573
+ ---
574
+
509
575
  ## Error Handling
510
576
 
511
577
  | Error | Action |
512
578
  |-------|--------|
513
- | Phase directory not found | Abort: "Phase {phase} not found." |
514
- | No plan exists | Abort: "No plan found. Run /workflow:plan first." |
579
+ | No pending plans found | Abort: "No pending plans. Run /workflow:plan first." |
580
+ | Plan directory not found | Abort: "Plan dir not found." |
515
581
  | Task file missing | Skip task, log error, continue wave |
516
582
  | Agent spawn fails | Retry once, then mark task as "blocked" |
517
583
  | Delegate fails | Resume with `--resume ${fixedId}`, then fallback to agent |