@opengsd/gsd-core 1.18.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 (257) 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-code-fixer.compact.md +2 -2
  5. package/agents/gsd-code-fixer.md +4 -3
  6. package/agents/gsd-verifier.md +1 -1
  7. package/bin/install.js +422 -103
  8. package/gsd-core/bin/gsd-tools.cjs +106 -7
  9. package/gsd-core/bin/lib/agent-install-check.cjs +29 -3
  10. package/gsd-core/bin/lib/args-terminator.cjs +114 -0
  11. package/gsd-core/bin/lib/broken-windows.cjs +59 -1
  12. package/gsd-core/bin/lib/capability-lock.cjs +13 -2
  13. package/gsd-core/bin/lib/capability-registry.cjs +156 -74
  14. package/gsd-core/bin/lib/capability-state.cjs +14 -8
  15. package/gsd-core/bin/lib/capability-validator.cjs +17 -0
  16. package/gsd-core/bin/lib/config-loader.cjs +10 -0
  17. package/gsd-core/bin/lib/config.cjs +256 -58
  18. package/gsd-core/bin/lib/core-utils.cjs +34 -0
  19. package/gsd-core/bin/lib/decision-coverage-support.cjs +74 -0
  20. package/gsd-core/bin/lib/gate-context-drift.cjs +8 -3
  21. package/gsd-core/bin/lib/gate-decision-coverage-plan.cjs +6 -1
  22. package/gsd-core/bin/lib/gate-decision-coverage-verify.cjs +6 -1
  23. package/gsd-core/bin/lib/gate-evaluation-scope.cjs +134 -13
  24. package/gsd-core/bin/lib/gate-tdd-review-checkpoint.cjs +63 -22
  25. package/gsd-core/bin/lib/gate-ui-safety.cjs +23 -5
  26. package/gsd-core/bin/lib/git-info-exclude.cjs +57 -0
  27. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +18 -3
  28. package/gsd-core/bin/lib/health-diagnostic-types.cjs +4 -0
  29. package/gsd-core/bin/lib/health-diagnostic.cjs +52 -1
  30. package/gsd-core/bin/lib/host-integration.cjs +13 -6
  31. package/gsd-core/bin/lib/init.cjs +65 -1
  32. package/gsd-core/bin/lib/install-engine.cjs +246 -32
  33. package/gsd-core/bin/lib/install-profiles.cjs +9 -4
  34. package/gsd-core/bin/lib/installer-migration-report.cjs +2 -0
  35. package/gsd-core/bin/lib/markdown-line-diff.cjs +147 -0
  36. package/gsd-core/bin/lib/markdown-sectionizer.cjs +113 -0
  37. package/gsd-core/bin/lib/milestone-lock.cjs +8 -1
  38. package/gsd-core/bin/lib/milestone-release-map.cjs +244 -0
  39. package/gsd-core/bin/lib/milestone-release-tags.cjs +440 -0
  40. package/gsd-core/bin/lib/milestone.cjs +43 -1
  41. package/gsd-core/bin/lib/model-catalog.cjs +8 -0
  42. package/gsd-core/bin/lib/normalize-test-command.cjs +67 -0
  43. package/gsd-core/bin/lib/phase-id.cjs +21 -4
  44. package/gsd-core/bin/lib/phase-lifecycle.cjs +37 -4
  45. package/gsd-core/bin/lib/phase.cjs +115 -26
  46. package/gsd-core/bin/lib/planning-snapshot.cjs +3 -1
  47. package/gsd-core/bin/lib/planning-workspace.cjs +18 -0
  48. package/gsd-core/bin/lib/pristine-baseline.cjs +11 -3
  49. package/gsd-core/bin/lib/read-only-git-env.cjs +58 -0
  50. package/gsd-core/bin/lib/review-lane-descriptor.cjs +35 -2
  51. package/gsd-core/bin/lib/review-lane-runner.cjs +33 -4
  52. package/gsd-core/bin/lib/roadmap-parser.cjs +12 -0
  53. package/gsd-core/bin/lib/roadmap-upgrade.cjs +39 -2
  54. package/gsd-core/bin/lib/roadmap.cjs +33 -25
  55. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +381 -14
  56. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +8 -4
  57. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +60 -16
  58. package/gsd-core/bin/lib/shell-command-projection.cjs +121 -16
  59. package/gsd-core/bin/lib/smart-entry.cjs +13 -0
  60. package/gsd-core/bin/lib/state-contract.cjs +29 -9
  61. package/gsd-core/bin/lib/state-document.cjs +12 -4
  62. package/gsd-core/bin/lib/state-transition.cjs +119 -24
  63. package/gsd-core/bin/lib/state.cjs +50 -28
  64. package/gsd-core/bin/lib/surface.cjs +9 -0
  65. package/gsd-core/bin/lib/task-command-router.cjs +5 -25
  66. package/gsd-core/bin/lib/task-content-resolution.cjs +46 -1
  67. package/gsd-core/bin/lib/verification.cjs +96 -9
  68. package/gsd-core/bin/lib/verify.cjs +2 -0
  69. package/gsd-core/bin/lib/worktree-safety.cjs +22 -1
  70. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  71. package/gsd-core/bin/shared/config-schema.manifest.json +1 -0
  72. package/gsd-core/references/git-integration.md +11 -0
  73. package/gsd-core/references/loop-hook-dispatch.md +13 -6
  74. package/gsd-core/references/planning-config.md +2 -0
  75. package/gsd-core/references/tdd.md +2 -2
  76. package/gsd-core/templates/DEBUG.md +16 -0
  77. package/gsd-core/templates/config.json +2 -1
  78. package/gsd-core/templates/verification-report.md +1 -1
  79. package/gsd-core/workflows/audit-fix.md +2 -1
  80. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +10 -1
  81. package/gsd-core/workflows/code-review.md +61 -7
  82. package/gsd-core/workflows/complete-milestone/steps/project-md-evolution-review.md +145 -0
  83. package/gsd-core/workflows/complete-milestone/steps/release-map.md +80 -0
  84. package/gsd-core/workflows/complete-milestone.md +37 -150
  85. package/gsd-core/workflows/diagnose-issues.md +29 -5
  86. package/gsd-core/workflows/discuss-phase/modes/power.md +1 -1
  87. package/gsd-core/workflows/discuss-phase-assumptions.md +33 -2
  88. package/gsd-core/workflows/discuss-phase-power.md +19 -2
  89. package/gsd-core/workflows/discuss-phase.md +6 -10
  90. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +13 -7
  91. package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +7 -2
  92. package/gsd-core/workflows/execute-phase/steps/regression-gate-run.md +2 -1
  93. package/gsd-core/workflows/execute-phase/steps/verify-phase-goal.md +2 -2
  94. package/gsd-core/workflows/execute-phase/steps/wave-post-gate-hooks.md +11 -2
  95. package/gsd-core/workflows/execute-phase.md +9 -5
  96. package/gsd-core/workflows/health.md +2 -1
  97. package/gsd-core/workflows/import.md +1 -1
  98. package/gsd-core/workflows/plan-phase/steps/chunked-planning-mode.md +2 -2
  99. package/gsd-core/workflows/plan-phase.md +13 -13
  100. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +1 -1
  101. package/gsd-core/workflows/quick/steps/worktree-pre-dispatch-commit.md +8 -1
  102. package/gsd-core/workflows/quick-batch/steps/plan-checker-loop.md +2 -1
  103. package/gsd-core/workflows/quick.md +1 -1
  104. package/gsd-core/workflows/review.md +16 -13
  105. package/gsd-core/workflows/section-manifest.json +5 -0
  106. package/gsd-core/workflows/settings.md +1 -0
  107. package/gsd-core/workflows/ship.md +3 -4
  108. package/gsd-core/workflows/spec-phase.md +3 -6
  109. package/gsd-core/workflows/verify-work.md +4 -3
  110. package/hooks/dist/gsd-agent-isolation-guard.js +11 -1
  111. package/hooks/dist/gsd-cursor-subagent-start.js +6 -2
  112. package/hooks/dist/gsd-path-export.js +95 -0
  113. package/hooks/dist/gsd-secret-read-guard.js +172 -39
  114. package/hooks/dist/gsd-statusline.js +35 -2
  115. package/hooks/dist/gsd-windsurf-pre-write.js +28 -1
  116. package/hooks/dist/gsd-workflow-guard.js +1 -1
  117. package/hooks/dist/gsd-worktree-path-guard.js +28 -1
  118. package/hooks/dist/lib/isolation-sentinel.js +44 -0
  119. package/hooks/dist/managed-hooks-registry.cjs +1 -0
  120. package/hooks/gsd-agent-isolation-guard.js +11 -1
  121. package/hooks/gsd-cursor-subagent-start.js +6 -2
  122. package/hooks/gsd-path-export.js +95 -0
  123. package/hooks/gsd-secret-read-guard.js +172 -39
  124. package/hooks/gsd-statusline.js +35 -2
  125. package/hooks/gsd-windsurf-pre-write.js +28 -1
  126. package/hooks/gsd-workflow-guard.js +1 -1
  127. package/hooks/gsd-worktree-path-guard.js +28 -1
  128. package/hooks/hooks.json +1 -0
  129. package/hooks/lib/isolation-sentinel.js +44 -0
  130. package/hooks/managed-hooks-registry.cjs +1 -0
  131. package/package.json +13 -6
  132. package/pi/gsd.cjs +1047 -10
  133. package/pi/package-agents/gsd-advisor-researcher.md +113 -0
  134. package/pi/package-agents/gsd-ai-researcher.md +111 -0
  135. package/pi/package-agents/gsd-assumptions-analyzer.md +110 -0
  136. package/pi/package-agents/gsd-code-fixer.md +769 -0
  137. package/pi/package-agents/gsd-code-reviewer.md +402 -0
  138. package/pi/package-agents/gsd-codebase-mapper.md +850 -0
  139. package/pi/package-agents/gsd-debug-session-manager.md +416 -0
  140. package/pi/package-agents/gsd-debugger.md +1274 -0
  141. package/pi/package-agents/gsd-doc-classifier.md +269 -0
  142. package/pi/package-agents/gsd-doc-synthesizer.md +259 -0
  143. package/pi/package-agents/gsd-doc-verifier.md +212 -0
  144. package/pi/package-agents/gsd-doc-writer.md +626 -0
  145. package/pi/package-agents/gsd-dom-verifier.md +164 -0
  146. package/pi/package-agents/gsd-domain-researcher.md +144 -0
  147. package/pi/package-agents/gsd-eval-auditor.md +185 -0
  148. package/pi/package-agents/gsd-eval-planner.md +149 -0
  149. package/pi/package-agents/gsd-executor.md +894 -0
  150. package/pi/package-agents/gsd-framework-selector.md +159 -0
  151. package/pi/package-agents/gsd-integration-checker.md +476 -0
  152. package/pi/package-agents/gsd-intel-updater.md +338 -0
  153. package/pi/package-agents/gsd-mempalace-curator.md +49 -0
  154. package/pi/package-agents/gsd-nyquist-auditor.md +200 -0
  155. package/pi/package-agents/gsd-pattern-mapper.md +340 -0
  156. package/pi/package-agents/gsd-phase-researcher.md +897 -0
  157. package/pi/package-agents/gsd-plan-checker.md +1077 -0
  158. package/pi/package-agents/gsd-planner.md +1003 -0
  159. package/pi/package-agents/gsd-project-researcher.md +611 -0
  160. package/pi/package-agents/gsd-research-synthesizer.md +259 -0
  161. package/pi/package-agents/gsd-roadmapper.md +779 -0
  162. package/pi/package-agents/gsd-security-auditor.md +171 -0
  163. package/pi/package-agents/gsd-ui-auditor.md +581 -0
  164. package/pi/package-agents/gsd-ui-checker.md +417 -0
  165. package/pi/package-agents/gsd-ui-researcher.md +469 -0
  166. package/pi/package-agents/gsd-user-profiler.md +174 -0
  167. package/pi/package-agents/gsd-verifier.md +963 -0
  168. package/pi/package-agents/manifest.json +39 -0
  169. package/pi/package-skills/gsd-add-tests/SKILL.md +39 -0
  170. package/pi/package-skills/gsd-ai-integration-phase/SKILL.md +36 -0
  171. package/pi/package-skills/gsd-audit-fix/SKILL.md +34 -0
  172. package/pi/package-skills/gsd-audit-milestone/SKILL.md +40 -0
  173. package/pi/package-skills/gsd-audit-uat/SKILL.md +26 -0
  174. package/pi/package-skills/gsd-autonomous/SKILL.md +52 -0
  175. package/pi/package-skills/gsd-capture/SKILL.md +68 -0
  176. package/pi/package-skills/gsd-cleanup/SKILL.md +25 -0
  177. package/pi/package-skills/gsd-code-review/SKILL.md +71 -0
  178. package/pi/package-skills/gsd-complete-milestone/SKILL.md +147 -0
  179. package/pi/package-skills/gsd-config/SKILL.md +60 -0
  180. package/pi/package-skills/gsd-debug/SKILL.md +64 -0
  181. package/pi/package-skills/gsd-discuss-phase/SKILL.md +74 -0
  182. package/pi/package-skills/gsd-docs-update/SKILL.md +50 -0
  183. package/pi/package-skills/gsd-eval-review/SKILL.md +35 -0
  184. package/pi/package-skills/gsd-execute-phase/SKILL.md +62 -0
  185. package/pi/package-skills/gsd-explore/SKILL.md +26 -0
  186. package/pi/package-skills/gsd-extract-learnings/SKILL.md +25 -0
  187. package/pi/package-skills/gsd-fast/SKILL.md +33 -0
  188. package/pi/package-skills/gsd-forensics/SKILL.md +59 -0
  189. package/pi/package-skills/gsd-graphify/SKILL.md +210 -0
  190. package/pi/package-skills/gsd-health/SKILL.md +36 -0
  191. package/pi/package-skills/gsd-help/SKILL.md +37 -0
  192. package/pi/package-skills/gsd-import/SKILL.md +46 -0
  193. package/pi/package-skills/gsd-inbox/SKILL.md +42 -0
  194. package/pi/package-skills/gsd-ingest-docs/SKILL.md +43 -0
  195. package/pi/package-skills/gsd-manager/SKILL.md +46 -0
  196. package/pi/package-skills/gsd-map-codebase/SKILL.md +85 -0
  197. package/pi/package-skills/gsd-mempalace-capture/SKILL.md +111 -0
  198. package/pi/package-skills/gsd-mempalace-recall/SKILL.md +111 -0
  199. package/pi/package-skills/gsd-milestone-summary/SKILL.md +54 -0
  200. package/pi/package-skills/gsd-mvp-phase/SKILL.md +45 -0
  201. package/pi/package-skills/gsd-new-milestone/SKILL.md +49 -0
  202. package/pi/package-skills/gsd-new-project/SKILL.md +49 -0
  203. package/pi/package-skills/gsd-next/SKILL.md +34 -0
  204. package/pi/package-skills/gsd-ns-context/SKILL.md +31 -0
  205. package/pi/package-skills/gsd-ns-ideate/SKILL.md +30 -0
  206. package/pi/package-skills/gsd-ns-manage/SKILL.md +42 -0
  207. package/pi/package-skills/gsd-ns-project/SKILL.md +34 -0
  208. package/pi/package-skills/gsd-ns-review/SKILL.md +35 -0
  209. package/pi/package-skills/gsd-ns-workflow/SKILL.md +44 -0
  210. package/pi/package-skills/gsd-onboard/SKILL.md +46 -0
  211. package/pi/package-skills/gsd-pause-work/SKILL.md +48 -0
  212. package/pi/package-skills/gsd-phase/SKILL.md +61 -0
  213. package/pi/package-skills/gsd-plan-phase/SKILL.md +62 -0
  214. package/pi/package-skills/gsd-plan-review-convergence/SKILL.md +63 -0
  215. package/pi/package-skills/gsd-pr-branch/SKILL.md +31 -0
  216. package/pi/package-skills/gsd-profile-user/SKILL.md +48 -0
  217. package/pi/package-skills/gsd-progress/SKILL.md +51 -0
  218. package/pi/package-skills/gsd-quick/SKILL.md +179 -0
  219. package/pi/package-skills/gsd-quick-batch/SKILL.md +114 -0
  220. package/pi/package-skills/gsd-resume-work/SKILL.md +31 -0
  221. package/pi/package-skills/gsd-review/SKILL.md +50 -0
  222. package/pi/package-skills/gsd-review-backlog/SKILL.md +65 -0
  223. package/pi/package-skills/gsd-secure-phase/SKILL.md +37 -0
  224. package/pi/package-skills/gsd-settings/SKILL.md +30 -0
  225. package/pi/package-skills/gsd-ship/SKILL.md +27 -0
  226. package/pi/package-skills/gsd-sketch/SKILL.md +56 -0
  227. package/pi/package-skills/gsd-spec-phase/SKILL.md +63 -0
  228. package/pi/package-skills/gsd-spike/SKILL.md +53 -0
  229. package/pi/package-skills/gsd-stats/SKILL.md +22 -0
  230. package/pi/package-skills/gsd-surface/SKILL.md +177 -0
  231. package/pi/package-skills/gsd-thread/SKILL.md +29 -0
  232. package/pi/package-skills/gsd-ui-phase/SKILL.md +35 -0
  233. package/pi/package-skills/gsd-ui-review/SKILL.md +35 -0
  234. package/pi/package-skills/gsd-ultraplan-phase/SKILL.md +38 -0
  235. package/pi/package-skills/gsd-undo/SKILL.md +38 -0
  236. package/pi/package-skills/gsd-update/SKILL.md +51 -0
  237. package/pi/package-skills/gsd-validate-phase/SKILL.md +37 -0
  238. package/pi/package-skills/gsd-verify-work/SKILL.md +41 -0
  239. package/pi/package-skills/gsd-workspace/SKILL.md +57 -0
  240. package/pi/package-skills/gsd-workstreams/SKILL.md +73 -0
  241. package/scripts/build-hooks.js +4 -0
  242. package/scripts/command-contract-helpers.cjs +1 -1
  243. package/scripts/docs-guard-registry.cjs +20 -7
  244. package/scripts/gen-health-docs.cjs +13 -1
  245. package/scripts/gen-pi-package-skills.cjs +217 -0
  246. package/scripts/lib/macos-conformance-tier.generated.cjs +11 -1
  247. package/scripts/lib/platform-conformance-tier.generated.cjs +26 -1
  248. package/scripts/lint-docs-guard-registration.exempt-baseline.cjs +3 -3
  249. package/scripts/lint-retired-runtime-name.cjs +5 -0
  250. package/scripts/npm-audit-baseline.cjs +41 -7
  251. package/scripts/reviewed-or-maintainer-policy.cjs +181 -0
  252. package/scripts/select-docs-guards.cjs +1 -1
  253. package/scripts/self-test-report-policy.cjs +350 -0
  254. package/vscode/package.json +1 -1
  255. package/scripts/diagnose-validate-commit-in-tier.cjs +0 -270
  256. package/scripts/diagnose-validate-commit-phases.cjs +0 -348
  257. package/scripts/xtrace-phase-timing.cjs +0 -205
@@ -42,7 +42,7 @@
42
42
  */
43
43
  // eslint-disable-next-line @typescript-eslint/no-require-imports
44
44
  const healthDiagnosticMod = require("../health-diagnostic-types.cjs");
45
- const { SEVERITY, adviseRemedy } = healthDiagnosticMod;
45
+ const { SEVERITY, REMEDY_ACTION, REMEDY_RISK, adviseRemedy } = healthDiagnosticMod;
46
46
  // eslint-disable-next-line @typescript-eslint/no-require-imports
47
47
  const validateMod = require("../validate.cjs");
48
48
  // #612: `isPhaseDirName` is the convention-SELECTED shape test wrapping
@@ -57,6 +57,9 @@ const phaseIdMod = require("../phase-id.cjs");
57
57
  const { extractPhaseToken, normalizePhaseName, comparePhaseNum } = phaseIdMod;
58
58
  // #5060: the Phase Status Module owns the status-label ladder.
59
59
  const phase_status_cjs_1 = require("../phase-status.cjs");
60
+ // #5291: W030 asks whether a raw report status has a known repair. The lookup is
61
+ // a pure read of a frozen table, so `check` stays free of ambient I/O (§8.1 rule 1).
62
+ const verification_cjs_1 = require("../verification.cjs");
60
63
  // ─── W005 — phase directory doesn't follow NN-name format (verify.cts:1893-1902) ─
61
64
  function checkW005(snapshot) {
62
65
  const diagnostics = [];
@@ -174,11 +177,21 @@ function checkW030(snapshot) {
174
177
  const invalid = phase.verificationStatusError;
175
178
  if (!invalid)
176
179
  continue;
180
+ // #5291: a KNOWN legacy status is repairable (rewritten to its closed-set
181
+ // equivalent, original kept in `legacy_status`); any other value has no
182
+ // mapping and keeps the advise-only remedy — it stays refused.
183
+ const target = (0, verification_cjs_1.legacyStatusRepairTarget)(invalid.rawStatus);
177
184
  diagnostics.push({
178
185
  code: 'W030',
179
186
  severity: SEVERITY.WARNING,
180
187
  message: `Phase ${phase.dir}: ${invalid.message}`,
181
- remedy: adviseRemedy('Set the report frontmatter `status` to one of passed | gaps_found | human_needed, or delete the report and re-run the phase verification'),
188
+ remedy: target === null
189
+ ? adviseRemedy('Set the report frontmatter `status` to one of passed | gaps_found | human_needed, or delete the report and re-run the phase verification')
190
+ : {
191
+ action: REMEDY_ACTION.REPAIR_VERIFICATION_STATUS,
192
+ risk: REMEDY_RISK.NONE,
193
+ args: { file: invalid.file, from: invalid.rawStatus, to: target },
194
+ },
182
195
  });
183
196
  }
184
197
  return diagnostics;
@@ -217,7 +230,9 @@ const RULES = [
217
230
  code: 'W030',
218
231
  severity: SEVERITY.WARNING,
219
232
  description: 'Phase verification report status is outside the closed set',
220
- repairable: false,
233
+ // #5291: repairable per finding — a KNOWN legacy status (`pass_with_caveats`)
234
+ // is rewritten by `--repair`; any other value stays advise-only.
235
+ repairable: true,
221
236
  check: checkW030,
222
237
  },
223
238
  ];
@@ -38,6 +38,10 @@ const REMEDY_ACTION = Object.freeze({
38
38
  ADD_NYQUIST_KEY: 'addNyquistKey',
39
39
  ADD_AI_INTEGRATION_PHASE_KEY: 'addAiIntegrationPhaseKey',
40
40
  BACKFILL_MILESTONES: 'backfillMilestones',
41
+ // #5291: rewrite a KNOWN legacy verification `status` (W030) to its closed-set
42
+ // equivalent, keeping the original in `legacy_status`. Per-finding: only
43
+ // emitted when the raw value has a mapping; every other W030 stays ADVISE.
44
+ REPAIR_VERIFICATION_STATUS: 'repairVerificationStatus',
41
45
  // §8.3 rule 5 — every non-repairable finding's `fix` string becomes an
42
46
  // ADVISE payload; ADVISE never acts, only describes.
43
47
  ADVISE: 'advise',
@@ -118,6 +118,9 @@ const { getMilestoneInfo } = roadmapParserMod;
118
118
  const stateMod = require("./state.cjs");
119
119
  const { writeStateMd, assertVerificationReportsReadable } = stateMod;
120
120
  // eslint-disable-next-line @typescript-eslint/no-require-imports
121
+ const verificationMod = require("./verification.cjs");
122
+ const { repairLegacyVerificationStatus } = verificationMod;
123
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
121
124
  const frontmatter = require("./frontmatter.cjs");
122
125
  const { extractFrontmatter } = frontmatter;
123
126
  // eslint-disable-next-line @typescript-eslint/no-require-imports
@@ -252,9 +255,27 @@ function computeMissingMilestoneVersions(milestonesArchiveDir, milestonesPath) {
252
255
  * shape, collapsed to one seam here since every case now shares one
253
256
  * caller).
254
257
  */
255
- function runRepairAction(cwd, action, paths) {
258
+ function runRepairAction(cwd, action, paths, args = {}) {
256
259
  const { rootBase, configPath, statePath, milestonesPath, milestonesArchiveDir } = paths;
257
260
  switch (action) {
261
+ case REMEDY_ACTION.REPAIR_VERIFICATION_STATUS: {
262
+ // #5291: the report path comes from the finding's own remedy args, not
263
+ // from user input; `repairLegacyVerificationStatus` re-verifies that it is
264
+ // a report contained in its phase directory before it writes a byte.
265
+ const file = typeof args['file'] === 'string' ? args['file'] : '';
266
+ if (file === '')
267
+ return { success: false, error: 'no report path on the finding' };
268
+ const repaired = repairLegacyVerificationStatus(file);
269
+ if (!repaired.ok)
270
+ return { success: false, error: repaired.reason };
271
+ return {
272
+ success: true,
273
+ path: node_path_1.default.relative(cwd, file).split(node_path_1.default.sep).join('/'),
274
+ detail: repaired.legacyStatusKept
275
+ ? `status ${repaired.from} -> ${repaired.to}; the report's existing legacy_status was left as it was`
276
+ : `status ${repaired.from} -> ${repaired.to}; original kept as legacy_status`,
277
+ };
278
+ }
258
279
  case REMEDY_ACTION.CREATE_CONFIG:
259
280
  case REMEDY_ACTION.RESET_CONFIG: {
260
281
  (0, shell_command_projection_cjs_1.platformWriteSync)(configPath, JSON.stringify(defaultConfigPayload(), null, 2));
@@ -390,6 +411,34 @@ function applyRepairs(cwd, diagnostics, repair, backfill) {
390
411
  const refused = [];
391
412
  const details = [];
392
413
  const paths = repairPaths(cwd);
414
+ // #5291: a legacy-status repair is the CURE for the refusal the pre-check
415
+ // below enforces, so it runs first (a report edit is its only write and it
416
+ // validates its own target); the pre-check then sees the repaired reports.
417
+ const statusRepairs = new Set();
418
+ if (repair) {
419
+ for (const diagnostic of diagnostics) {
420
+ const { remedy, code } = diagnostic;
421
+ if (remedy.action !== REMEDY_ACTION.REPAIR_VERIFICATION_STATUS || remedy.risk === REMEDY_RISK.DESTRUCTIVE)
422
+ continue;
423
+ statusRepairs.add(diagnostic);
424
+ try {
425
+ const outcome = runRepairAction(cwd, remedy.action, paths, remedy.args);
426
+ details.push({
427
+ code,
428
+ action: remedy.action,
429
+ success: outcome.success,
430
+ ...(outcome.path ? { path: outcome.path } : {}),
431
+ ...(outcome.detail ? { detail: outcome.detail } : {}),
432
+ ...(outcome.error ? { error: outcome.error } : {}),
433
+ });
434
+ if (outcome.success)
435
+ applied.push(code);
436
+ }
437
+ catch (err) {
438
+ details.push({ code, action: remedy.action, success: false, error: err instanceof Error ? err.message : String(err) });
439
+ }
440
+ }
441
+ }
393
442
  // #5118 (no write before the error): a requested REGENERATE_STATE rewrites
394
443
  // STATE.md from every phase's report and throws on one whose `status` is
395
444
  // outside the closed set — but other repairs in the SAME run (config,
@@ -411,6 +460,8 @@ function applyRepairs(cwd, diagnostics, repair, backfill) {
411
460
  const { remedy, code } = diagnostic;
412
461
  if (remedy.action === REMEDY_ACTION.ADVISE)
413
462
  continue;
463
+ if (statusRepairs.has(diagnostic))
464
+ continue;
414
465
  const requested = remedy.action === REMEDY_ACTION.BACKFILL_MILESTONES ? repair || backfill : repair;
415
466
  if (!requested)
416
467
  continue;
@@ -620,7 +620,7 @@ function hookEventSurfaceFor(hookEvents) {
620
620
  // event subset (imperative hosts' extension API). They are not the same thing.
621
621
  //
622
622
  // Values are documentation-sourced (ADR-1239 §research): OpenCode ~25 plugin
623
- // events (session/tool/file/permission); pi ~30 fine-grained extension events;
623
+ // events (session/tool/file/permission); pi 41 fine-grained extension events (pi 1.3.0);
624
624
  // 'none' = the host exposes no extension surface and the engine owns the bus
625
625
  // (VS Code). Declarative hosts (no plugin API) do not set `extensionEvents`.
626
626
  // OpenCode's plugin event surface (ADR-1239 §research; ~25 documented events,
@@ -655,11 +655,13 @@ const EXTENSION_EVENT_SURFACES = Object.freeze({
655
655
  'pre_gateway_dispatch', 'pre_approval_request',
656
656
  'transform_tool_result',
657
657
  ]),
658
- // #2102 Stage 2 — pi's real ExtensionAPI event vocabulary (~30 fine-grained
659
- // extension events; documentation-sourced, ADR-1239 §research). Replaces the
660
- // placeholder single-event ['tool_call'] surface — the Stage 1 value only
661
- // covered the one event pi/gsd.cjs happened to bind at the time, not the
662
- // full declared surface.
658
+ // pi's real ExtensionAPI event vocabulary: the 41 `on(event: "...")` overloads
659
+ // declared by pi 1.3.0 (@earendil-works/pi-coding-agent
660
+ // dist/core/extensions/types.d.ts, sourceCommit 71023aec15, #5557). #2102
661
+ // Stage 2 declared the first 30 from pi.dev prose; the last 11 on the final
662
+ // row group were added when the host's own declarations were read. The
663
+ // pi.dev extensions page lists a lossy subset (it omits session_before_compact,
664
+ // which pi/gsd.cjs binds), so the type declarations are the source of truth.
663
665
  pi: Object.freeze([
664
666
  'session_start', 'project_trust', 'resources_discover', 'input',
665
667
  'before_agent_start', 'agent_start', 'message_start', 'message_update',
@@ -669,6 +671,11 @@ const EXTENSION_EVENT_SURFACES = Object.freeze({
669
671
  'session_before_switch', 'session_shutdown', 'session_before_fork',
670
672
  'session_info_changed', 'session_before_compact', 'session_compact',
671
673
  'session_before_tree', 'session_tree', 'thinking_level_select', 'model_select',
674
+ // Added in pi 1.3.0 (#5557):
675
+ 'agent_before_settle', 'agent_settled', 'before_provider_headers',
676
+ 'cache_warming_decision', 'context_with_system', 'mcp_servers_change',
677
+ 'provider_stream_event', 'session_compact_failed', 'ui_prompt_end',
678
+ 'ui_prompt_start', 'user_bash',
672
679
  ]),
673
680
  none: Object.freeze([]),
674
681
  });
@@ -98,7 +98,7 @@ const { getRoadmapPhaseInternal, getMilestoneInfo, stripShippedMilestones, extra
98
98
  const { pathExistsInternal, generateSlugInternal, toPosixPath } = coreUtils;
99
99
  const { comparePhaseNum, normalizePhaseName, stripProjectCodePrefix, PHASE_NUMBER_TOKEN_SOURCE, PHASE_DEP_REF_SOURCE, isForeignPrefixedPhaseQuery, isSentinelPhaseId, extractPhaseToken, scopeToPhase, renderPhaseBranchName, parsePhaseId, renderPhaseId, phaseHeadingPrefixSrcFor, PHASE_HEADING_BASELINE, buildPhaseHeadingScanRegex, } = phaseId;
100
100
  const { pruneOrphanedWorktrees } = worktreeSafety;
101
- const { planningPaths, planningDir, planningRoot, todosDir, listAvailableWorkstreams, peekActiveWorkstream, resolveEnvWorkstream, diagnoseUnresolvedActiveWorkstream, describeUnresolvedWorkstreamReason, findContextMdIn, resolvePhaseIdConvention, worktreesOptedOut, } = planningWorkspace;
101
+ const { planningPaths, planningDir, planningRoot, todosDir, listAvailableWorkstreams, peekActiveWorkstream, resolveEnvWorkstream, diagnoseUnresolvedActiveWorkstream, describeUnresolvedWorkstreamReason, findContextMdIn, findPhaseSpecIn, resolvePhaseIdConvention, worktreesOptedOut, } = planningWorkspace;
102
102
  const { extractFrontmatter, frontmatterBlock } = frontmatterMod;
103
103
  const { isPhaseComplete, resolveVerificationFile, resolveUatFile, VERIFICATION_STATUS, VerificationStatusError } = verificationMod;
104
104
  const { evaluateUatPassed } = uatPredicateMod;
@@ -177,6 +177,28 @@ function resolvePhaseDisplayName(phaseInfo, roadmapPhase) {
177
177
  || phaseInfo?.['phase_name']
178
178
  || null;
179
179
  }
180
+ /**
181
+ * #5629: the phase SPEC as init facts, for every init payload a SPEC-consuming workflow parses
182
+ * (discuss-phase via `phase-op`, discuss-phase-assumptions, plan-phase). `has_spec` is always present;
183
+ * `spec_path` (absolute, posix) only when a plain `NN-SPEC.md` exists. One predicate (`findPhaseSpecIn`, shared
184
+ * with the context-drift gate) decides, so a UI-SPEC or AI-SPEC is never mistaken for the requirements lock and
185
+ * no workflow globs for it. A phase with no directory yet, or one that cannot be read, has no SPEC.
186
+ */
187
+ function phaseSpecFacts(phaseDirAbs) {
188
+ if (!phaseDirAbs)
189
+ return { has_spec: false };
190
+ let files;
191
+ try {
192
+ files = node_fs_1.default.readdirSync(phaseDirAbs);
193
+ }
194
+ catch {
195
+ return { has_spec: false };
196
+ }
197
+ // Scoped to THIS phase's own artifacts first (#3511), like the sibling artifact lookups: a misfiled
198
+ // `02-SPEC.md` in phase 03's directory must not win (the context-drift gate scopes the same way).
199
+ const spec = findPhaseSpecIn(scopeToPhase(files, node_path_1.default.basename(phaseDirAbs)));
200
+ return spec ? { has_spec: true, spec_path: toPosixPath(node_path_1.default.join(phaseDirAbs, spec)) } : { has_spec: false };
201
+ }
180
202
  /**
181
203
  * #2994 (review finding, DEFECT.GENERATIVE-FIX): shared archived/not-found
182
204
  * fallback applied identically by `cmdInitExecutePhase`, `cmdInitPlanPhase`,
@@ -600,6 +622,28 @@ function detectFallowConfig(cwd) {
600
622
  function detectGitCreateTag(cwd) {
601
623
  return readConfigJsonValue(cwd, ['git', 'create_tag']) !== false;
602
624
  }
625
+ /**
626
+ * `git.repo_tagging` ground truth (#5706, epic #3628): the milestone tagging
627
+ * mode exposed to `complete-milestone.md`. Only the documented `per_repo`
628
+ * opts in; an absent key or any other stored value reads as the default
629
+ * `single` (today's behavior), matching `loadConfig`'s resolution.
630
+ */
631
+ function detectRepoTagging(cwd) {
632
+ return readConfigJsonValue(cwd, ['git', 'repo_tagging']) === 'per_repo' ? 'per_repo' : 'single';
633
+ }
634
+ /**
635
+ * The configured `planning.sub_repos` (#5706): an array of non-empty repo
636
+ * names, possibly empty. A legacy top-level `sub_repos` is honored when the
637
+ * nested key is absent, the same flat-then-nested order `loadConfig` applies.
638
+ * Non-string members are dropped; any degraded read yields `[]`.
639
+ */
640
+ function detectSubRepos(cwd) {
641
+ const nested = readConfigJsonValue(cwd, ['planning', 'sub_repos']);
642
+ const raw = nested !== undefined ? nested : readConfigJsonValue(cwd, ['sub_repos']);
643
+ if (!Array.isArray(raw))
644
+ return [];
645
+ return raw.filter((name) => typeof name === 'string' && name.trim() !== '');
646
+ }
603
647
  /**
604
648
  * `state:phase-mvp-mode` ground truth (design doc §Behavior table: ROADMAP.md
605
649
  * `**Mode:** mvp` for the CURRENT phase). Bounded, non-throwing — an absent
@@ -1139,6 +1183,8 @@ function cmdInitPlanPhase(cwd, phase, raw, options = {}) {
1139
1183
  state_path: node_fs_1.default.existsSync(statePath) ? toPosixPath(statePath) : null,
1140
1184
  roadmap_path: node_fs_1.default.existsSync(roadmapPath) ? toPosixPath(roadmapPath) : null,
1141
1185
  requirements_path: node_fs_1.default.existsSync(requirementsPath) ? toPosixPath(requirementsPath) : null,
1186
+ // #5629: the phase SPEC (plan-phase lifts its Edge Coverage from it; no workflow globs for it).
1187
+ ...phaseSpecFacts(phaseInfo?.['directory'] ? node_path_1.default.join(cwd, phaseInfo['directory']) : null),
1142
1188
  patterns_path: null,
1143
1189
  };
1144
1190
  if (phaseInfo?.['directory']) {
@@ -1934,6 +1980,8 @@ function cmdInitDiscussPhaseAssumptions(cwd, phase, raw, options = {}) {
1934
1980
  plan_count: phaseInfo?.['plans']?.length || 0,
1935
1981
  roadmap_exists: node_fs_1.default.existsSync(node_path_1.default.join(planningDir(cwd), 'ROADMAP.md')),
1936
1982
  planning_exists: node_fs_1.default.existsSync(planningDir(cwd)),
1983
+ // #5629: the phase SPEC, so assumptions mode honours it like the default flow does.
1984
+ ...phaseSpecFacts(phaseDir ? node_path_1.default.join(cwd, phaseDir) : null),
1937
1985
  };
1938
1986
  // #2994 (Phase 6.3): additive, optional field — degrades to null, never throws.
1939
1987
  const sectionManifestOptions = {
@@ -2065,6 +2113,8 @@ function cmdInitPhaseOp(cwd, phase, raw) {
2065
2113
  state_path: node_fs_1.default.existsSync(statePath) ? toPosixPath(statePath) : null,
2066
2114
  roadmap_path: node_fs_1.default.existsSync(roadmapPath) ? toPosixPath(roadmapPath) : null,
2067
2115
  requirements_path: node_fs_1.default.existsSync(requirementsPath) ? toPosixPath(requirementsPath) : null,
2116
+ // #5629: the phase SPEC (discuss-phase reads it from here; no workflow globs for it).
2117
+ ...phaseSpecFacts(phaseDir ? node_path_1.default.join(cwd, phaseDir) : null),
2068
2118
  };
2069
2119
  if (phaseInfo?.['directory']) {
2070
2120
  const phaseDirFull = node_path_1.default.join(cwd, phaseInfo['directory']);
@@ -3016,9 +3066,23 @@ function cmdInitCompleteMilestone(cwd, raw, options = {}) {
3016
3066
  milestones_path: node_fs_1.default.existsSync(milestonesPath) ? toPosixPath(milestonesPath) : null,
3017
3067
  project_path: node_fs_1.default.existsSync(projectPath) ? toPosixPath(projectPath) : null,
3018
3068
  requirements_path: node_fs_1.default.existsSync(requirementsPath) ? toPosixPath(requirementsPath) : null,
3069
+ // #5706 (epic #3628): the repositories configured for this project and the
3070
+ // milestone tagging mode, so the workflow reads both from one init call.
3071
+ sub_repos: detectSubRepos(cwd),
3072
+ repo_tagging: detectRepoTagging(cwd),
3019
3073
  };
3074
+ // #5195: `state:flat-mode` gates the PROJECT.md evolution review. PROJECT.md
3075
+ // is shared across workstreams (the `projectPath` comment above), so a
3076
+ // workstream's milestone close must not rewrite or stage it — the same
3077
+ // decision `cmdInitNewMilestone` applies to its Part A (#2308), resolved from
3078
+ // the same authority (`GSD_WORKSTREAM` env, else the stored pointer) so the
3079
+ // gate cannot disagree with the workstream-scoped paths returned above.
3080
+ // Read-only peek: no self-heal side effect from building a report field (#3579).
3081
+ const workstreamActive = !!(resolveEnvWorkstream() ?? peekActiveWorkstream(cwd));
3020
3082
  result['section_manifest'] = buildSectionManifestField(cwd, null, options, 'complete-milestone', {
3021
3083
  gitCreateTag,
3084
+ workstreamActive,
3085
+ flatMode: !workstreamActive,
3022
3086
  });
3023
3087
  output(withProjectRoot(cwd, result), raw);
3024
3088
  }