@opengsd/gsd-core 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +2 -1
  3. package/.opencode/plugins/gsd-core.js +2 -3
  4. package/agents/gsd-advisor-researcher.compact.md +1 -1
  5. package/agents/gsd-advisor-researcher.md +1 -1
  6. package/agents/gsd-assumptions-analyzer.compact.md +1 -1
  7. package/agents/gsd-assumptions-analyzer.md +1 -1
  8. package/agents/gsd-code-fixer.compact.md +3 -3
  9. package/agents/gsd-code-fixer.md +5 -4
  10. package/agents/gsd-code-reviewer.compact.md +1 -1
  11. package/agents/gsd-code-reviewer.md +1 -1
  12. package/agents/gsd-codebase-mapper.compact.md +1 -1
  13. package/agents/gsd-codebase-mapper.md +1 -1
  14. package/agents/gsd-debugger.md +1 -1
  15. package/agents/gsd-doc-verifier.compact.md +4 -4
  16. package/agents/gsd-doc-verifier.md +4 -3
  17. package/agents/gsd-doc-writer.compact.md +23 -5
  18. package/agents/gsd-doc-writer.md +19 -6
  19. package/agents/gsd-eval-auditor.compact.md +1 -1
  20. package/agents/gsd-eval-auditor.md +1 -1
  21. package/agents/gsd-executor.md +7 -3
  22. package/agents/gsd-integration-checker.compact.md +1 -1
  23. package/agents/gsd-integration-checker.md +1 -1
  24. package/agents/gsd-nyquist-auditor.compact.md +1 -1
  25. package/agents/gsd-nyquist-auditor.md +1 -1
  26. package/agents/gsd-phase-researcher.md +1 -1
  27. package/agents/gsd-plan-checker.md +2 -1
  28. package/agents/gsd-planner.md +5 -4
  29. package/agents/gsd-project-researcher.compact.md +1 -1
  30. package/agents/gsd-project-researcher.md +1 -1
  31. package/agents/gsd-research-synthesizer.compact.md +5 -5
  32. package/agents/gsd-research-synthesizer.md +5 -5
  33. package/agents/gsd-roadmapper.compact.md +1 -1
  34. package/agents/gsd-roadmapper.md +1 -1
  35. package/agents/gsd-security-auditor.compact.md +1 -1
  36. package/agents/gsd-security-auditor.md +1 -1
  37. package/agents/gsd-ui-auditor.compact.md +1 -1
  38. package/agents/gsd-ui-auditor.md +1 -1
  39. package/agents/gsd-ui-checker.compact.md +1 -1
  40. package/agents/gsd-ui-checker.md +1 -1
  41. package/agents/gsd-ui-researcher.compact.md +13 -1
  42. package/agents/gsd-ui-researcher.md +28 -1
  43. package/agents/gsd-verifier.md +2 -2
  44. package/bin/install.js +460 -105
  45. package/commands/gsd/code-review.md +8 -0
  46. package/commands/gsd/pause-work.md +1 -1
  47. package/gsd-core/bin/gsd-tools.cjs +124 -18
  48. package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
  49. package/gsd-core/bin/lib/args-terminator.cjs +114 -0
  50. package/gsd-core/bin/lib/broken-windows.cjs +59 -1
  51. package/gsd-core/bin/lib/capability-ledger.cjs +25 -0
  52. package/gsd-core/bin/lib/capability-lock.cjs +41 -8
  53. package/gsd-core/bin/lib/capability-registry.cjs +162 -74
  54. package/gsd-core/bin/lib/capability-source.cjs +3 -1
  55. package/gsd-core/bin/lib/capability-state.cjs +20 -11
  56. package/gsd-core/bin/lib/capability-validator.cjs +23 -4
  57. package/gsd-core/bin/lib/commands.cjs +5 -1
  58. package/gsd-core/bin/lib/config-loader.cjs +13 -3
  59. package/gsd-core/bin/lib/config.cjs +256 -58
  60. package/gsd-core/bin/lib/core-utils.cjs +34 -0
  61. package/gsd-core/bin/lib/decision-coverage-support.cjs +93 -0
  62. package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
  63. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +21 -1
  64. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +19 -1
  65. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
  66. package/gsd-core/bin/lib/gate-predicate-evaluator.cjs +23 -3
  67. package/gsd-core/bin/lib/gate-predicate.cjs +8 -12
  68. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +114 -18
  69. package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
  70. package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
  71. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -3
  72. package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
  73. package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
  74. package/gsd-core/bin/lib/host-integration.cjs +13 -6
  75. package/gsd-core/bin/lib/init.cjs +76 -5
  76. package/gsd-core/bin/lib/install-effort-resolver.cjs +2 -2
  77. package/gsd-core/bin/lib/install-engine.cjs +246 -32
  78. package/gsd-core/bin/lib/install-model-override-resolver.cjs +4 -3
  79. package/gsd-core/bin/lib/install-profiles.cjs +14 -7
  80. package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
  81. package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
  82. package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
  83. package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
  84. package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
  85. package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
  86. package/gsd-core/bin/lib/milestone.cjs +43 -1
  87. package/gsd-core/bin/lib/model-catalog.cjs +8 -0
  88. package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
  89. package/gsd-core/bin/lib/phase-id.cjs +21 -4
  90. package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
  91. package/gsd-core/bin/lib/phase.cjs +235 -37
  92. package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
  93. package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
  94. package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
  95. package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
  96. package/gsd-core/bin/lib/report-parser.cjs +57 -1
  97. package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
  98. package/gsd-core/bin/lib/review-lane-invocation.cjs +40 -0
  99. package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
  100. package/gsd-core/bin/lib/review-reviewer-selection.cjs +20 -1
  101. package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
  102. package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
  103. package/gsd-core/bin/lib/roadmap.cjs +89 -30
  104. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +428 -16
  105. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
  106. package/gsd-core/bin/lib/runtime-homes.cjs +18 -0
  107. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
  108. package/gsd-core/bin/lib/shell-command-projection.cjs +123 -16
  109. package/gsd-core/bin/lib/smart-entry.cjs +37 -16
  110. package/gsd-core/bin/lib/state-contract.cjs +29 -9
  111. package/gsd-core/bin/lib/state-document.cjs +47 -5
  112. package/gsd-core/bin/lib/state-transition.cjs +150 -34
  113. package/gsd-core/bin/lib/state.cjs +140 -88
  114. package/gsd-core/bin/lib/surface.cjs +9 -0
  115. package/gsd-core/bin/lib/task-command-router.cjs +7 -28
  116. package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
  117. package/gsd-core/bin/lib/tdd-red-evidence.cjs +5 -0
  118. package/gsd-core/bin/lib/tdd-test-files.cjs +42 -0
  119. package/gsd-core/bin/lib/verification.cjs +96 -9
  120. package/gsd-core/bin/lib/verify.cjs +38 -1
  121. package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
  122. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  123. package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
  124. package/gsd-core/references/agent-contracts.md +1 -1
  125. package/gsd-core/references/agent-skills-bootstrap.md +26 -7
  126. package/gsd-core/references/git-integration.md +14 -3
  127. package/gsd-core/references/loop-hook-dispatch.md +13 -6
  128. package/gsd-core/references/planner-reversibility.md +18 -4
  129. package/gsd-core/references/planner-verify-command-grounding.md +18 -0
  130. package/gsd-core/references/planning-config.md +2 -0
  131. package/gsd-core/references/tdd.md +5 -4
  132. package/gsd-core/references/verifier-phase-gates.md +8 -1
  133. package/gsd-core/templates/DEBUG.md +16 -0
  134. package/gsd-core/templates/config.json +2 -1
  135. package/gsd-core/templates/verification-report.md +1 -1
  136. package/gsd-core/workflows/add-backlog.md +10 -2
  137. package/gsd-core/workflows/add-phase.md +5 -1
  138. package/gsd-core/workflows/add-tests.md +5 -1
  139. package/gsd-core/workflows/add-todo.md +5 -1
  140. package/gsd-core/workflows/ai-integration-phase.md +5 -1
  141. package/gsd-core/workflows/audit-fix.md +2 -1
  142. package/gsd-core/workflows/audit-milestone.md +21 -9
  143. package/gsd-core/workflows/autonomous/templates/minimal-context.md +41 -0
  144. package/gsd-core/workflows/autonomous.md +52 -64
  145. package/gsd-core/workflows/check-todos.md +5 -1
  146. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
  147. package/gsd-core/workflows/code-review-fix.md +5 -1
  148. package/gsd-core/workflows/code-review.md +66 -8
  149. package/gsd-core/workflows/complete-milestone/detail/elaboration.md +5 -1
  150. package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
  151. package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
  152. package/gsd-core/workflows/complete-milestone.md +64 -157
  153. package/gsd-core/workflows/debug.md +5 -1
  154. package/gsd-core/workflows/diagnose-issues.md +34 -6
  155. package/gsd-core/workflows/discuss-phase/modes/chain.md +5 -1
  156. package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
  157. package/gsd-core/workflows/discuss-phase-assumptions.md +44 -5
  158. package/gsd-core/workflows/discuss-phase-power.md +19 -2
  159. package/gsd-core/workflows/discuss-phase.md +11 -11
  160. package/gsd-core/workflows/docs-update/detail/elaboration.md +7 -6
  161. package/gsd-core/workflows/docs-update.md +27 -5
  162. package/gsd-core/workflows/edit-phase.md +5 -1
  163. package/gsd-core/workflows/eval-review.md +11 -3
  164. package/gsd-core/workflows/execute-phase/steps/codebase-drift-gate.md +5 -1
  165. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
  166. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +19 -8
  167. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +21 -3
  168. package/gsd-core/workflows/execute-phase/steps/regression-gate.md +18 -1
  169. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +7 -3
  170. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
  171. package/gsd-core/workflows/execute-phase.md +46 -11
  172. package/gsd-core/workflows/execute-plan.md +8 -4
  173. package/gsd-core/workflows/extract-learnings.md +6 -2
  174. package/gsd-core/workflows/forensics.md +5 -1
  175. package/gsd-core/workflows/health.md +2 -1
  176. package/gsd-core/workflows/import.md +6 -2
  177. package/gsd-core/workflows/insert-phase.md +5 -1
  178. package/gsd-core/workflows/manager.md +10 -2
  179. package/gsd-core/workflows/map-codebase.md +5 -1
  180. package/gsd-core/workflows/milestone-summary.md +10 -2
  181. package/gsd-core/workflows/new-milestone.md +13 -5
  182. package/gsd-core/workflows/new-project.md +9 -5
  183. package/gsd-core/workflows/next.md +8 -4
  184. package/gsd-core/workflows/pause-work.md +3 -3
  185. package/gsd-core/workflows/plan-phase/steps/auto-advance-check.md +70 -0
  186. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +7 -3
  187. package/gsd-core/workflows/plan-phase/steps/closed-phase-gate.md +6 -2
  188. package/gsd-core/workflows/plan-phase.md +54 -86
  189. package/gsd-core/workflows/plan-review-convergence.md +17 -5
  190. package/gsd-core/workflows/plant-seed.md +8 -4
  191. package/gsd-core/workflows/progress.md +6 -2
  192. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
  193. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
  194. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
  195. package/gsd-core/workflows/quick-batch.md +5 -1
  196. package/gsd-core/workflows/quick.md +23 -8
  197. package/gsd-core/workflows/remove-phase.md +5 -1
  198. package/gsd-core/workflows/resume-project.md +5 -1
  199. package/gsd-core/workflows/review.md +22 -15
  200. package/gsd-core/workflows/scan.md +5 -1
  201. package/gsd-core/workflows/section-manifest.json +5 -0
  202. package/gsd-core/workflows/secure-phase.md +6 -2
  203. package/gsd-core/workflows/settings.md +4 -3
  204. package/gsd-core/workflows/ship.md +16 -14
  205. package/gsd-core/workflows/spec-phase.md +3 -6
  206. package/gsd-core/workflows/thread.md +10 -2
  207. package/gsd-core/workflows/transition.md +5 -1
  208. package/gsd-core/workflows/ui-phase.md +5 -1
  209. package/gsd-core/workflows/ui-review.md +6 -2
  210. package/gsd-core/workflows/ultraplan-phase.md +5 -1
  211. package/gsd-core/workflows/update.md +5 -1
  212. package/gsd-core/workflows/validate-phase.md +6 -2
  213. package/gsd-core/workflows/verify-work/detail/elaboration.md +1 -1
  214. package/gsd-core/workflows/verify-work/steps/mvp-uat-framing.md +5 -1
  215. package/gsd-core/workflows/verify-work.md +15 -6
  216. package/hooks/dist/gsd-agent-isolation-guard.js +14 -2
  217. package/hooks/dist/gsd-cursor-subagent-start.js +8 -3
  218. package/hooks/dist/gsd-path-export.js +95 -0
  219. package/hooks/dist/gsd-secret-read-guard.js +244 -53
  220. package/hooks/dist/gsd-statusline.js +35 -2
  221. package/hooks/dist/gsd-validate-commit.sh +27 -5
  222. package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
  223. package/hooks/dist/gsd-workflow-guard.js +1 -1
  224. package/hooks/dist/gsd-worktree-path-guard.js +28 -1
  225. package/hooks/dist/lib/isolation-sentinel.js +44 -0
  226. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  227. package/hooks/gsd-agent-isolation-guard.js +14 -2
  228. package/hooks/gsd-cursor-subagent-start.js +8 -3
  229. package/hooks/gsd-path-export.js +95 -0
  230. package/hooks/gsd-secret-read-guard.js +244 -53
  231. package/hooks/gsd-statusline.js +35 -2
  232. package/hooks/gsd-validate-commit.sh +27 -5
  233. package/hooks/gsd-windsurf-pre-write.js +28 -1
  234. package/hooks/gsd-workflow-guard.js +1 -1
  235. package/hooks/gsd-worktree-path-guard.js +28 -1
  236. package/hooks/hooks.json +1 -0
  237. package/hooks/lib/isolation-sentinel.js +44 -0
  238. package/hooks/managed-hooks-registry.cjs +1 -0
  239. package/package.json +13 -6
  240. package/pi/gsd.cjs +1047 -10
  241. package/pi/package-agents/gsd-advisor-researcher.md +113 -0
  242. package/pi/package-agents/gsd-ai-researcher.md +111 -0
  243. package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
  244. package/pi/package-agents/gsd-code-fixer.md +769 -0
  245. package/pi/package-agents/gsd-code-reviewer.md +402 -0
  246. package/pi/package-agents/gsd-codebase-mapper.md +850 -0
  247. package/pi/package-agents/gsd-debug-session-manager.md +416 -0
  248. package/pi/package-agents/gsd-debugger.md +1274 -0
  249. package/pi/package-agents/gsd-doc-classifier.md +269 -0
  250. package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
  251. package/pi/package-agents/gsd-doc-verifier.md +212 -0
  252. package/pi/package-agents/gsd-doc-writer.md +626 -0
  253. package/pi/package-agents/gsd-dom-verifier.md +164 -0
  254. package/pi/package-agents/gsd-domain-researcher.md +144 -0
  255. package/pi/package-agents/gsd-eval-auditor.md +185 -0
  256. package/pi/package-agents/gsd-eval-planner.md +149 -0
  257. package/pi/package-agents/gsd-executor.md +894 -0
  258. package/pi/package-agents/gsd-framework-selector.md +159 -0
  259. package/pi/package-agents/gsd-integration-checker.md +476 -0
  260. package/pi/package-agents/gsd-intel-updater.md +338 -0
  261. package/pi/package-agents/gsd-mempalace-curator.md +49 -0
  262. package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
  263. package/pi/package-agents/gsd-pattern-mapper.md +340 -0
  264. package/pi/package-agents/gsd-phase-researcher.md +897 -0
  265. package/pi/package-agents/gsd-plan-checker.md +1077 -0
  266. package/pi/package-agents/gsd-planner.md +1003 -0
  267. package/pi/package-agents/gsd-project-researcher.md +611 -0
  268. package/pi/package-agents/gsd-research-synthesizer.md +259 -0
  269. package/pi/package-agents/gsd-roadmapper.md +779 -0
  270. package/pi/package-agents/gsd-security-auditor.md +171 -0
  271. package/pi/package-agents/gsd-ui-auditor.md +581 -0
  272. package/pi/package-agents/gsd-ui-checker.md +417 -0
  273. package/pi/package-agents/gsd-ui-researcher.md +469 -0
  274. package/pi/package-agents/gsd-user-profiler.md +174 -0
  275. package/pi/package-agents/gsd-verifier.md +963 -0
  276. package/pi/package-agents/manifest.json +39 -0
  277. package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
  278. package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
  279. package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
  280. package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
  281. package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
  282. package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
  283. package/pi/package-skills/gsd-capture/SKILL.md +68 -0
  284. package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
  285. package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
  286. package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
  287. package/pi/package-skills/gsd-config/SKILL.md +60 -0
  288. package/pi/package-skills/gsd-debug/SKILL.md +64 -0
  289. package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
  290. package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
  291. package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
  292. package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
  293. package/pi/package-skills/gsd-explore/SKILL.md +26 -0
  294. package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
  295. package/pi/package-skills/gsd-fast/SKILL.md +33 -0
  296. package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
  297. package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
  298. package/pi/package-skills/gsd-health/SKILL.md +36 -0
  299. package/pi/package-skills/gsd-help/SKILL.md +37 -0
  300. package/pi/package-skills/gsd-import/SKILL.md +46 -0
  301. package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
  302. package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
  303. package/pi/package-skills/gsd-manager/SKILL.md +46 -0
  304. package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
  305. package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
  306. package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
  307. package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
  308. package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
  309. package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
  310. package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
  311. package/pi/package-skills/gsd-next/SKILL.md +34 -0
  312. package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
  313. package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
  314. package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
  315. package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
  316. package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
  317. package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
  318. package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
  319. package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
  320. package/pi/package-skills/gsd-phase/SKILL.md +61 -0
  321. package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
  322. package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
  323. package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
  324. package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
  325. package/pi/package-skills/gsd-progress/SKILL.md +51 -0
  326. package/pi/package-skills/gsd-quick/SKILL.md +179 -0
  327. package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
  328. package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
  329. package/pi/package-skills/gsd-review/SKILL.md +50 -0
  330. package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
  331. package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
  332. package/pi/package-skills/gsd-settings/SKILL.md +30 -0
  333. package/pi/package-skills/gsd-ship/SKILL.md +27 -0
  334. package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
  335. package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
  336. package/pi/package-skills/gsd-spike/SKILL.md +53 -0
  337. package/pi/package-skills/gsd-stats/SKILL.md +22 -0
  338. package/pi/package-skills/gsd-surface/SKILL.md +177 -0
  339. package/pi/package-skills/gsd-thread/SKILL.md +29 -0
  340. package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
  341. package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
  342. package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
  343. package/pi/package-skills/gsd-undo/SKILL.md +38 -0
  344. package/pi/package-skills/gsd-update/SKILL.md +51 -0
  345. package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
  346. package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
  347. package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
  348. package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
  349. package/scripts/audit-workflow-script-paths.cjs +1 -1
  350. package/scripts/build-hooks.js +4 -0
  351. package/scripts/command-contract-helpers.cjs +1 -1
  352. package/scripts/diagnose-windows-spawn-watcher.cjs +317 -0
  353. package/scripts/docs-guard-registry.cjs +22 -7
  354. package/scripts/gen-health-docs.cjs +13 -1
  355. package/scripts/gen-pi-package-skills.cjs +217 -0
  356. package/scripts/lib/macos-conformance-tier.generated.cjs +19 -0
  357. package/scripts/lib/platform-conformance-tier.generated.cjs +41 -0
  358. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
  359. package/scripts/lint-phase-arg-assignment.cjs +2 -2
  360. package/scripts/lint-retired-runtime-name.cjs +5 -0
  361. package/scripts/lint-workflow-shellcheck-baseline.json +16 -16
  362. package/scripts/npm-audit-baseline.cjs +41 -7
  363. package/scripts/release-tarball-smoke.cjs +1 -0
  364. package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
  365. package/scripts/select-docs-guards.cjs +1 -1
  366. package/scripts/self-test-report-policy.cjs +350 -0
  367. package/skills/gsd-code-review/SKILL.md +8 -0
  368. package/skills/gsd-pause-work/SKILL.md +1 -1
  369. package/vscode/package.json +1 -1
@@ -30,6 +30,7 @@ exports.applyPreserveWhenUnchanged = applyPreserveWhenUnchanged;
30
30
  exports.applyStatePreservation = applyStatePreservation;
31
31
  exports.transitionCore = transitionCore;
32
32
  exports.sliceCurrentPositionSection = sliceCurrentPositionSection;
33
+ exports.isStatePastPhase = isStatePastPhase;
33
34
  // eslint-disable-next-line @typescript-eslint/no-require-imports
34
35
  const frontmatter = require("./frontmatter.cjs");
35
36
  const state_document_cjs_1 = require("./state-document.cjs");
@@ -37,6 +38,9 @@ const state_document_cjs_2 = require("./state-document.cjs");
37
38
  const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
38
39
  const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
39
40
  const pattern_cjs_1 = require("./pattern.cjs");
41
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- phase-id.cjs is an export= CommonJS module
42
+ const phaseIdMod = require("./phase-id.cjs");
43
+ const { comparePhaseNum } = phaseIdMod;
40
44
  // #4129: the completion-ratio kernel for the resync-arm ratchet's percent
41
45
  // (planning-scope's SCOPE — state-document's own dependency, no cycle here:
42
46
  // state-document never imports this module).
@@ -643,18 +647,24 @@ function mergeResyncProgressRatchet(curatedRecord, derivedRecord) {
643
647
  merged[key] = value;
644
648
  }
645
649
  }
646
- if ((0, state_document_cjs_2.toFiniteNumber)(derivedRecord.percent) !== null) {
647
- const recomputed = (0, state_document_cjs_2.computeProgressPercent)((0, state_document_cjs_2.toFiniteNumber)(merged.completed_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.total_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.completed_phases), (0, state_document_cjs_2.toFiniteNumber)(merged.total_phases), planningScopeMod.SCOPE.COMPLETE);
648
- // Same verbatim rule for percent: assign only when the recomputed value
649
- // numerically differs, so a string-spelled derived percent ("67") is not
650
- // churned into a number-spelled 67 (phantom-divergence noise, not a
651
- // change).
652
- if (recomputed !== null && recomputed !== (0, state_document_cjs_2.toFiniteNumber)(merged.percent)) {
653
- merged.percent = recomputed;
654
- }
655
- }
650
+ recomputeMergedProgressPercent(merged, derivedRecord);
656
651
  return merged;
657
652
  }
653
+ /**
654
+ * Make `merged.percent` the progress computation over the counters `merged` actually carries (#5619,
655
+ * #4129). Only when the derived side measured a percent: a derivation that withheld one (an incomplete
656
+ * scope, #1761/#3217) stays withheld, never invented. Same verbatim rule as the counters: assign only
657
+ * when the recomputed value numerically differs, so a string-spelled derived percent ("67") is not
658
+ * churned into a number-spelled 67 (phantom-divergence noise, not a change).
659
+ */
660
+ function recomputeMergedProgressPercent(merged, derivedRecord) {
661
+ if ((0, state_document_cjs_2.toFiniteNumber)(derivedRecord.percent) === null)
662
+ return;
663
+ const recomputed = (0, state_document_cjs_2.computeProgressPercent)((0, state_document_cjs_2.toFiniteNumber)(merged.completed_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.total_plans), (0, state_document_cjs_2.toFiniteNumber)(merged.completed_phases), (0, state_document_cjs_2.toFiniteNumber)(merged.total_phases), planningScopeMod.SCOPE.COMPLETE);
664
+ if (recomputed !== null && recomputed !== (0, state_document_cjs_2.toFiniteNumber)(merged.percent)) {
665
+ merged.percent = recomputed;
666
+ }
667
+ }
658
668
  /**
659
669
  * Executor for `preservation: 'preserve-always'` (ADR-3408 §8.1). Only
660
670
  * `progress` carries this policy today. Preserves #3242/#1446/#2440/#2969
@@ -719,18 +729,23 @@ function applyPreserveAlways(field, cls, ctx) {
719
729
  // completed after the plan count grew) — ratcheting UP only, never
720
730
  // deriving downward (preserves the #3242 curated-progress protection
721
731
  // for cases unrelated to plan-count growth, e.g. a deleted SUMMARY).
722
- // percent also takes the derived value — the resync recomputed it from
723
- // disk counts, and a stale curated percent would be incoherent against
724
- // the ratcheted-up completed counts (e.g. 54/54 at 93%).
732
+ // percent is recomputed over the counters actually written (#5619): the
733
+ // disk-derived percent is only coherent with the DERIVED counters, and a
734
+ // stale curated percent would be incoherent against the ratcheted-up
735
+ // completed counts (e.g. 54/54 at 93%).
725
736
  const ratchetUpKeys = new Set(['completed_plans', 'completed_phases']);
726
737
  for (const [key, value] of Object.entries(curatedRecord)) {
727
738
  if (key === 'total_plans' || key === 'total_phases' || key === 'percent')
728
739
  continue;
729
740
  if (ratchetUpKeys.has(key)) {
730
- const derivedNum = typeof derivedRecord[key] === 'number' ? derivedRecord[key] : -Infinity;
731
- const curatedNum = typeof value === 'number' ? value : -Infinity;
741
+ // Frontmatter scalars arrive as STRINGS ("2", not 2): coerce through
742
+ // `toFiniteNumber`, never a `typeof === 'number'` test (#5619 — that
743
+ // test made both sides -Infinity and the ratchet unreachable).
744
+ const derivedNum = (0, state_document_cjs_2.toFiniteNumber)(derivedRecord[key]) ?? -Infinity;
745
+ const curatedNum = (0, state_document_cjs_2.toFiniteNumber)(value) ?? -Infinity;
732
746
  // Take the derived value only when it ratchets up (strictly
733
- // greater — #2969's `>` not `>=`); else keep curated.
747
+ // greater — #2969's `>` not `>=`); else keep curated, with its
748
+ // spelling, on a tie too.
734
749
  if (derivedNum > curatedNum)
735
750
  continue;
736
751
  merged[key] = value;
@@ -740,6 +755,7 @@ function applyPreserveAlways(field, cls, ctx) {
740
755
  }
741
756
  }
742
757
  }
758
+ recomputeMergedProgressPercent(merged, derivedRecord);
743
759
  next = merged;
744
760
  }
745
761
  else {
@@ -876,7 +892,36 @@ exports.STATE_MD_SECTIONS = {
876
892
  * Phases 2–7 add cases for the remaining 9 intent kinds. A missing case is
877
893
  * a compile-time error (the function would not return on that path).
878
894
  */
895
+ /**
896
+ * The transitions that rewrite single-line body fields (`Status:`, `Current focus:`, `Plan:` …) with
897
+ * plain line-anchored patterns. Those patterns match a fenced EXAMPLE of a field as readily as the
898
+ * live line (#5460), so these run over the document body with fenced blocks hidden.
899
+ * `milestone*`, `prune` and `rebuild` restructure sections or re-derive the document and are not
900
+ * field-by-field writers.
901
+ */
902
+ const FENCE_MASKED_TRANSITIONS = new Set([
903
+ 'beginPhase', 'advancePlan', 'completePhase', 'plannedPhase', 'patch', 'update', 'sync',
904
+ ]);
879
905
  function transitionCore(content, intent, deps) {
906
+ if (!FENCE_MASKED_TRANSITIONS.has(intent.kind))
907
+ return transitionCoreUnmasked(content, intent, deps);
908
+ // Only the body is masked: a fence opener inside a frontmatter block scalar must not swallow the
909
+ // closing `---` (the frontmatter is not where the live fields are written).
910
+ const body = stripFrontmatter(content);
911
+ if (!content.endsWith(body))
912
+ return transitionCoreUnmasked(content, intent, deps);
913
+ const prefix = content.slice(0, content.length - body.length);
914
+ const fenceMask = (0, markdown_sectionizer_cjs_1.maskFences)(body);
915
+ const result = transitionCoreUnmasked(prefix + fenceMask.masked, intent, deps);
916
+ const restored = fenceMask.restore(result.content);
917
+ // Cannot happen short of a writer bug (a transition dropped or duplicated a placeholder line); a
918
+ // refusal is the one outcome that cannot report a rewrite that did not land.
919
+ if (restored === null) {
920
+ throw new Error(`${intent.kind}: fenced code blocks could not be restored after the edit; refusing to write STATE.md`);
921
+ }
922
+ return { ...result, content: restored };
923
+ }
924
+ function transitionCoreUnmasked(content, intent, deps) {
880
925
  switch (intent.kind) {
881
926
  case 'beginPhase':
882
927
  return beginPhaseCore(content, intent, deps);
@@ -922,6 +967,8 @@ function transitionCore(content, intent, deps) {
922
967
  */
923
968
  function beginPhaseCore(content, intent, deps) {
924
969
  const updated = [];
970
+ // #4945: a re-entry whose earlier plans already have summaries starts at the first plan still to run.
971
+ const startPlan = intent.startPlan && intent.startPlan > 0 ? Math.floor(intent.startPlan) : 1;
925
972
  // #1255: body-field replacements operate on body only (frontmatter stripped),
926
973
  // not on the full content. The YAML `status:` key matches `^Status:\s*`
927
974
  // before the body pipe-table row if full content is passed.
@@ -977,7 +1024,7 @@ function beginPhaseCore(content, intent, deps) {
977
1024
  if (intent.phaseName) {
978
1025
  tryField('Current Phase Name', intent.phaseName);
979
1026
  }
980
- tryField('Current Plan', '1');
1027
+ tryField('Current Plan', String(startPlan));
981
1028
  if (intent.planCount) {
982
1029
  tryField('Total Plans in Phase', String(intent.planCount));
983
1030
  }
@@ -996,14 +1043,21 @@ function beginPhaseCore(content, intent, deps) {
996
1043
  // end-of-line (inert here since `.` never crosses line terminators
997
1044
  // without `/s`, which is not set).
998
1045
  const focusPattern = /^([ \t]*\*\*Current focus:\*\*[ \t]*)(.*)$/im;
999
- if (focusPattern.test(body)) {
1000
- body = body.replace(focusPattern, (_match, prefix) => `${prefix}${focusLabel}`);
1046
+ const focusMatch = focusPattern.exec(body);
1047
+ if (focusMatch) {
1048
+ // #4945: a value an author wrapped onto further lines is replaced whole, so its tail is not
1049
+ // left behind under the new value. The lines that count are the ones `state validate` already
1050
+ // reports as a field's continuation (stops at a blank line, a heading, a list item, a table
1051
+ // row, a fence or a sibling field). An empty first line has no value to continue.
1052
+ const valueEnd = focusMatch.index + focusMatch[0].length;
1053
+ const end = focusMatch[2].trim() === '' ? valueEnd : (0, state_document_cjs_2.fieldContinuationEnd)(body, valueEnd);
1054
+ body = body.slice(0, focusMatch.index) + focusMatch[1] + focusLabel + body.slice(end);
1001
1055
  updated.push('Current focus');
1002
1056
  }
1003
1057
  // ## Current Position section mutation (#1104, #1365).
1004
1058
  // `locateCurrentPosition` (fence-aware, tokenizeHeadings-based) locates
1005
1059
  // the section; mirrors state.cts:2261-2324 byte-for-behaviour.
1006
- body = mutateCurrentPositionFirstTime(body, intent, today, updated);
1060
+ body = mutateCurrentPositionFirstTime(body, { ...intent, startPlan }, today, updated);
1007
1061
  }
1008
1062
  else {
1009
1063
  // Resume path: only update Last activity timestamp in Current Position
@@ -1095,7 +1149,9 @@ function mutateCurrentPositionFirstTime(body, intent, today, updated) {
1095
1149
  const span = locateCurrentPosition(body);
1096
1150
  if (span === null)
1097
1151
  return body;
1098
- let sectionBody = body.slice(span.start, span.end);
1152
+ // #5460: the section's fenced examples are hidden while the live lines are rewritten.
1153
+ const fenceMask = (0, markdown_sectionizer_cjs_1.maskFences)(body.slice(span.start, span.end));
1154
+ let sectionBody = fenceMask.masked;
1099
1155
  // Phase line — inline first, then pipe-table fallback (#1257).
1100
1156
  const phaseLabel = `${intent.phaseNumber}${intent.phaseName ? ` (${intent.phaseName})` : ''} — EXECUTING`;
1101
1157
  if (/^Phase:/m.test(sectionBody)) {
@@ -1107,7 +1163,7 @@ function mutateCurrentPositionFirstTime(body, intent, today, updated) {
1107
1163
  sectionBody = replaced;
1108
1164
  }
1109
1165
  // Plan line.
1110
- const planValue = `1 of ${intent.planCount || '?'}`;
1166
+ const planValue = `${intent.startPlan} of ${intent.planCount || '?'}`;
1111
1167
  if (/^Plan:/m.test(sectionBody)) {
1112
1168
  sectionBody = sectionBody.replace(/^Plan:.*$/m, `Plan: ${planValue}`);
1113
1169
  }
@@ -1137,8 +1193,11 @@ function mutateCurrentPositionFirstTime(body, intent, today, updated) {
1137
1193
  if (replaced !== null)
1138
1194
  sectionBody = replaced;
1139
1195
  }
1196
+ const restored = fenceMask.restore(sectionBody);
1197
+ if (restored === null)
1198
+ return body;
1140
1199
  updated.push('Current Position');
1141
- return body.slice(0, span.start) + sectionBody + body.slice(span.end);
1200
+ return body.slice(0, span.start) + restored + body.slice(span.end);
1142
1201
  }
1143
1202
  /**
1144
1203
  * Resume ## Current Position mutation: only update Last activity line
@@ -1149,7 +1208,8 @@ function mutateCurrentPositionResume(body, intent, today, updated) {
1149
1208
  const span = locateCurrentPosition(body);
1150
1209
  if (span === null)
1151
1210
  return body;
1152
- let sectionBody = body.slice(span.start, span.end);
1211
+ const fenceMask = (0, markdown_sectionizer_cjs_1.maskFences)(body.slice(span.start, span.end));
1212
+ let sectionBody = fenceMask.masked;
1153
1213
  const resumeActivity = `Last activity: ${today} — Phase ${intent.phaseNumber} execution resumed (wave continue)`;
1154
1214
  if (/^Last activity:/im.test(sectionBody)) {
1155
1215
  sectionBody = sectionBody.replace(/^Last activity:.*$/im, resumeActivity);
@@ -1164,7 +1224,10 @@ function mutateCurrentPositionResume(body, intent, today, updated) {
1164
1224
  updated.push('Last activity (resume)');
1165
1225
  }
1166
1226
  }
1167
- return body.slice(0, span.start) + sectionBody + body.slice(span.end);
1227
+ const restored = fenceMask.restore(sectionBody);
1228
+ if (restored === null)
1229
+ return body;
1230
+ return body.slice(0, span.start) + restored + body.slice(span.end);
1168
1231
  }
1169
1232
  const PLAN_SHAPE_N = /^(\d+)(?:\s.*)?$/;
1170
1233
  const PLAN_SHAPE_N_OF_M = /^(\d+)\s+of\s+(\d+)(?:\s.*)?$/;
@@ -1221,7 +1284,8 @@ function mutateCurrentPositionForAdvance(content, fields, statusDefaults, lastAc
1221
1284
  const span = locateCurrentPosition(content);
1222
1285
  if (span === null)
1223
1286
  return content;
1224
- let sectionBody = content.slice(span.start, span.end);
1287
+ const fenceMask = (0, markdown_sectionizer_cjs_1.maskFences)(content.slice(span.start, span.end));
1288
+ let sectionBody = fenceMask.masked;
1225
1289
  let mutated = false;
1226
1290
  // #3395: Phase is always replaced when a caller passes it — system-derived,
1227
1291
  // not executor-authored (same rule as Plan below). plannedPhaseCore uses
@@ -1334,7 +1398,10 @@ function mutateCurrentPositionForAdvance(content, fields, statusDefaults, lastAc
1334
1398
  }
1335
1399
  if (!mutated)
1336
1400
  return content;
1337
- return content.slice(0, span.start) + sectionBody + content.slice(span.end);
1401
+ const restored = fenceMask.restore(sectionBody);
1402
+ if (restored === null)
1403
+ return content;
1404
+ return content.slice(0, span.start) + restored + content.slice(span.end);
1338
1405
  }
1339
1406
  // ----------------------------------------------------------------------------
1340
1407
  // advancePlan — intent implementation (Phase 2)
@@ -1633,6 +1700,29 @@ function nextPhaseWording(disk) {
1633
1700
  return { status: 'Ready to plan', currentPlan: 'Not started', stoppedAt: 'ready to plan' };
1634
1701
  }
1635
1702
  }
1703
+ /**
1704
+ * #5165: is STATE.md already positioned PAST phase `phaseNum`? True when its
1705
+ * current phase (frontmatter `current_phase`, else the body `Current Phase` /
1706
+ * `Phase` field's leading phase token) compares greater than `phaseNum`.
1707
+ * Re-completing a phase STATE has already moved past must not rewind the
1708
+ * position; the caller combines this with "the phase is already complete in
1709
+ * ROADMAP.md" so a first-time out-of-order completion (#2028) still
1710
+ * transitions. An unparseable or absent current phase is "not past".
1711
+ */
1712
+ function isStatePastPhase(content, phaseNum, sourcePath) {
1713
+ const fm = extractFrontmatter(content, sourcePath);
1714
+ const fromFm = fm['current_phase'];
1715
+ let raw = typeof fromFm === 'string' || typeof fromFm === 'number' ? String(fromFm) : null;
1716
+ if (raw === null || raw.trim() === '') {
1717
+ const body = stripFrontmatter(content);
1718
+ raw = (0, state_document_cjs_1.stateExtractField)(body, 'Current Phase') || (0, state_document_cjs_1.stateExtractField)(body, 'Phase') || null;
1719
+ }
1720
+ // `Phase 4` / `phase 4 of 9` name phase 4 as surely as `4 of 9` does.
1721
+ const m = raw === null ? null : /^\s*(?:phase\s+)?(\d+(?:\.\d+)*)/i.exec(raw);
1722
+ if (!m)
1723
+ return false;
1724
+ return comparePhaseNum(m[1], String(phaseNum)) > 0;
1725
+ }
1636
1726
  /**
1637
1727
  * Apply a `completePhase` transition to STATE.md content.
1638
1728
  *
@@ -1660,6 +1750,12 @@ function completePhaseCore(content, intent, deps) {
1660
1750
  const updated = [];
1661
1751
  const today = deps.clock.localToday();
1662
1752
  const nextWording = nextPhaseWording(intent.isLastPhase ? null : intent.nextPhaseDisk ?? null);
1753
+ // #5165: the milestone the caller resolved (ROADMAP-bound identity first) wins;
1754
+ // else the milestone STATE asserts. It scopes the roadmap-derived counters
1755
+ // below to that milestone's Progress-table rows, the same milestone
1756
+ // `phase complete` scopes its frontmatter progress to.
1757
+ const currentMilestone = (0, phase_lifecycle_cjs_1.milestoneVersionOf)(intent.milestone)
1758
+ ?? (0, phase_lifecycle_cjs_1.milestoneVersionOf)(extractFrontmatter(content, deps.sourcePath)['milestone']);
1663
1759
  // Consult the field-classification table for the frontmatter keys this
1664
1760
  // transition touches (same guard beginPhaseCore applies). A missing row is a
1665
1761
  // substrate defect — fail loudly rather than silently re-encoding policy.
@@ -1798,15 +1894,27 @@ function completePhaseCore(content, intent, deps) {
1798
1894
  // Only runs when a Completed Phases field exists (the existing guard).
1799
1895
  const completedRaw = (0, state_document_cjs_1.stateExtractField)(body, 'Completed Phases');
1800
1896
  if (completedRaw !== null) {
1801
- let newCompleted = parseInt(completedRaw, 10);
1897
+ const recordedCompleted = parseInt(completedRaw, 10);
1898
+ let newCompleted = recordedCompleted;
1802
1899
  let derivedTotalPhases = null;
1803
1900
  const roadmapContent = deps.roadmapProvider ? deps.roadmapProvider() : null;
1804
1901
  if (roadmapContent) {
1805
- const derived = (0, phase_lifecycle_cjs_1.deriveProgressFromRoadmap)(roadmapContent);
1806
- if (derived.completedPhases !== null)
1807
- newCompleted = derived.completedPhases;
1808
- if (derived.totalPhases !== null)
1809
- derivedTotalPhases = derived.totalPhases;
1902
+ const derived = (0, phase_lifecycle_cjs_1.deriveProgressFromRoadmap)(roadmapContent, currentMilestone);
1903
+ // #4901: completed counters only ratchet up, like the frontmatter twin
1904
+ // (applyAuthoritativeProgressSubkeys, completedOnlyRaise). A derivation
1905
+ // that lands BELOW the recorded counter read a narrower scope than the
1906
+ // counter spans (e.g. the first `## Progress` section of a multi-milestone
1907
+ // roadmap), so its total is just as suspect: keep the recorded counter and
1908
+ // fall back to the recorded Total Phases for the percent below.
1909
+ const derivedLowered = derived.completedPhases !== null
1910
+ && Number.isFinite(recordedCompleted)
1911
+ && derived.completedPhases < recordedCompleted;
1912
+ if (!derivedLowered) {
1913
+ if (derived.completedPhases !== null)
1914
+ newCompleted = derived.completedPhases;
1915
+ if (derived.totalPhases !== null)
1916
+ derivedTotalPhases = derived.totalPhases;
1917
+ }
1810
1918
  }
1811
1919
  // #3057 B9: only mark 'Completed Phases' updated when the text actually
1812
1920
  // changed. `stateReplaceField` returns the full (re-)substituted content
@@ -1912,8 +2020,16 @@ function plannedPhaseCore(content, intent, deps) {
1912
2020
  // Phase is system-derived, always replaced (Knuth invariant does not apply);
1913
2021
  // Status / Last activity stay template-aware.
1914
2022
  const beforePos = body;
2023
+ // #5369: with no --name the label reuses the curated frontmatter name (when it is a real one), so the
2024
+ // body line and the frontmatter agree on it (the #3834 reassert keeps that name in frontmatter). A
2025
+ // status fragment a pre-fix write left there is never copied back into the name slot.
2026
+ const curatedName = existingFm['current_phase_name'];
2027
+ const labelName = intent.phaseName
2028
+ ?? (typeof curatedName === 'string' && curatedName.trim() !== '' && !phaseIdMod.isPlannedPhaseStatusPhrase(curatedName)
2029
+ ? curatedName.trim()
2030
+ : null);
1915
2031
  body = mutateCurrentPositionForAdvance(body, {
1916
- phase: `${intent.phaseNumber}${intent.phaseName ? ` (${intent.phaseName})` : ''} — READY TO EXECUTE`,
2032
+ phase: `${intent.phaseNumber}${labelName ? ` (${labelName})` : ''} — READY TO EXECUTE`,
1917
2033
  status: 'Ready to execute',
1918
2034
  lastActivity: `${today} — Phase ${intent.phaseNumber} planning complete`,
1919
2035
  }, statusDefaults, lastActivityDefaults);