@opengsd/gsd-core 1.10.0 → 1.11.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 (328) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/agents/gsd-debug-session-manager.md +11 -0
  4. package/agents/gsd-doc-synthesizer.md +2 -4
  5. package/agents/gsd-executor.md +5 -5
  6. package/agents/gsd-mempalace-curator.md +5 -2
  7. package/agents/gsd-phase-researcher.md +20 -1
  8. package/agents/gsd-plan-checker.md +37 -0
  9. package/agents/gsd-planner.md +44 -46
  10. package/agents/gsd-user-profiler.md +3 -0
  11. package/agents/gsd-verifier.md +12 -3
  12. package/bin/install.js +841 -971
  13. package/bin/lib/ui-safety-gate.cjs +2 -0
  14. package/commands/gsd/code-review.md +1 -1
  15. package/commands/gsd/execute-phase.md +1 -1
  16. package/commands/gsd/map-codebase.md +1 -1
  17. package/commands/gsd/mempalace-capture.md +1 -1
  18. package/commands/gsd/mempalace-recall.md +1 -1
  19. package/commands/gsd/new-milestone.md +1 -1
  20. package/commands/gsd/quick.md +1 -1
  21. package/commands/gsd/review-backlog.md +2 -1
  22. package/commands/gsd/verify-work.md +1 -1
  23. package/gsd-core/bin/gsd-tools.cjs +469 -88
  24. package/gsd-core/bin/lib/active-workstream-store.cjs +138 -22
  25. package/gsd-core/bin/lib/agent-install-check.cjs +230 -32
  26. package/gsd-core/bin/lib/api-coverage.cjs +3 -5
  27. package/gsd-core/bin/lib/artifacts.cjs +3 -0
  28. package/gsd-core/bin/lib/assumption-delta.cjs +2 -4
  29. package/gsd-core/bin/lib/audit-command-router.cjs +9 -2
  30. package/gsd-core/bin/lib/audit.cjs +876 -240
  31. package/gsd-core/bin/lib/broken-windows.cjs +1 -1
  32. package/gsd-core/bin/lib/capability-consent.cjs +149 -15
  33. package/gsd-core/bin/lib/capability-lifecycle.cjs +45 -0
  34. package/gsd-core/bin/lib/capability-registry.cjs +575 -101
  35. package/gsd-core/bin/lib/capability-source.cjs +92 -0
  36. package/gsd-core/bin/lib/capability-trust.cjs +444 -25
  37. package/gsd-core/bin/lib/capability-validator.cjs +495 -22
  38. package/gsd-core/bin/lib/capability-writer.cjs +3 -2
  39. package/gsd-core/bin/lib/check-command-router.cjs +71 -37
  40. package/gsd-core/bin/lib/claude-orchestration.cjs +56 -3
  41. package/gsd-core/bin/lib/codex-agent-toml.cjs +329 -0
  42. package/gsd-core/bin/lib/command-aliases.cjs +22 -0
  43. package/gsd-core/bin/lib/command-roster.cjs +44 -1
  44. package/gsd-core/bin/lib/commands.cjs +651 -86
  45. package/gsd-core/bin/lib/commonjs-marker.cjs +12 -6
  46. package/gsd-core/bin/lib/complexity-trigger.cjs +1172 -0
  47. package/gsd-core/bin/lib/config-loader.cjs +75 -0
  48. package/gsd-core/bin/lib/config.cjs +10 -1
  49. package/gsd-core/bin/lib/core-utils.cjs +127 -29
  50. package/gsd-core/bin/lib/decisions.cjs +23 -0
  51. package/gsd-core/bin/lib/fallow-runner.cjs +20 -44
  52. package/gsd-core/bin/lib/frontmatter.cjs +155 -20
  53. package/gsd-core/bin/lib/gap-checker.cjs +68 -7
  54. package/gsd-core/bin/lib/git-base-branch.cjs +102 -0
  55. package/gsd-core/bin/lib/gsd2-import.cjs +10 -1
  56. package/gsd-core/bin/lib/health-diagnostic-rules/agent-install.cjs +101 -0
  57. package/gsd-core/bin/lib/health-diagnostic-rules/config-validation.cjs +348 -0
  58. package/gsd-core/bin/lib/health-diagnostic-rules/consistency.cjs +145 -0
  59. package/gsd-core/bin/lib/health-diagnostic-rules/install-surface-shadowing.cjs +98 -0
  60. package/gsd-core/bin/lib/health-diagnostic-rules/milestone-archive-hygiene.cjs +100 -0
  61. package/gsd-core/bin/lib/health-diagnostic-rules/phase-structure.cjs +222 -0
  62. package/gsd-core/bin/lib/health-diagnostic-rules/roadmap-disk-consistency.cjs +265 -0
  63. package/gsd-core/bin/lib/health-diagnostic-rules/root-existence.cjs +161 -0
  64. package/gsd-core/bin/lib/health-diagnostic-rules/state-consistency.cjs +303 -0
  65. package/gsd-core/bin/lib/health-diagnostic-rules/worktree-health.cjs +173 -0
  66. package/gsd-core/bin/lib/health-diagnostic-types.cjs +68 -0
  67. package/gsd-core/bin/lib/health-diagnostic.cjs +431 -0
  68. package/gsd-core/bin/lib/host-runtime-detection.cjs +134 -0
  69. package/gsd-core/bin/lib/init.cjs +321 -129
  70. package/gsd-core/bin/lib/install-effort-resolver.cjs +73 -30
  71. package/gsd-core/bin/lib/install-engine.cjs +745 -258
  72. package/gsd-core/bin/lib/install-fs-adapter.cjs +262 -0
  73. package/gsd-core/bin/lib/install-model-override-resolver.cjs +203 -0
  74. package/gsd-core/bin/lib/install-profiles.cjs +134 -57
  75. package/gsd-core/bin/lib/install-scope.cjs +270 -0
  76. package/gsd-core/bin/lib/install-shadow-report.cjs +385 -0
  77. package/gsd-core/bin/lib/installed-surface-resolver.cjs +381 -0
  78. package/gsd-core/bin/lib/installer-migrations.cjs +138 -31
  79. package/gsd-core/bin/lib/io.cjs +10 -0
  80. package/gsd-core/bin/lib/markdown-sectionizer.cjs +2 -1
  81. package/gsd-core/bin/lib/markdown-table.cjs +133 -20
  82. package/gsd-core/bin/lib/milestone-lock.cjs +248 -0
  83. package/gsd-core/bin/lib/milestone.cjs +754 -70
  84. package/gsd-core/bin/lib/model-catalog.cjs +59 -1
  85. package/gsd-core/bin/lib/model-resolver.cjs +183 -40
  86. package/gsd-core/bin/lib/normalize-test-command.cjs +1 -1
  87. package/gsd-core/bin/lib/pattern.cjs +122 -0
  88. package/gsd-core/bin/lib/phase-estimation.cjs +1 -1
  89. package/gsd-core/bin/lib/phase-id.cjs +444 -36
  90. package/gsd-core/bin/lib/phase-lifecycle.cjs +28 -3
  91. package/gsd-core/bin/lib/phase-locator.cjs +125 -18
  92. package/gsd-core/bin/lib/phase.cjs +646 -143
  93. package/gsd-core/bin/lib/plan-dependency-graph.cjs +72 -1
  94. package/gsd-core/bin/lib/plan-drift-guard.cjs +120 -0
  95. package/gsd-core/bin/lib/plan-scan.cjs +86 -2
  96. package/gsd-core/bin/lib/planning-scope.cjs +31 -0
  97. package/gsd-core/bin/lib/planning-snapshot.cjs +890 -0
  98. package/gsd-core/bin/lib/planning-workspace.cjs +56 -6
  99. package/gsd-core/bin/lib/probe-core.cjs +1 -1
  100. package/gsd-core/bin/lib/profile-output.cjs +1 -1
  101. package/gsd-core/bin/lib/refactor-trigger-command-router.cjs +740 -0
  102. package/gsd-core/bin/lib/retired-artifact-cleanup.cjs +11 -6
  103. package/gsd-core/bin/lib/review-lane-descriptor.cjs +13 -4
  104. package/gsd-core/bin/lib/review-lane-invocation.cjs +30 -0
  105. package/gsd-core/bin/lib/review-lane-runner.cjs +421 -66
  106. package/gsd-core/bin/lib/review-reviewer-selection.cjs +13 -18
  107. package/gsd-core/bin/lib/roadmap-command-router.cjs +34 -0
  108. package/gsd-core/bin/lib/roadmap-parser.cjs +943 -184
  109. package/gsd-core/bin/lib/roadmap-upgrade.cjs +37 -10
  110. package/gsd-core/bin/lib/roadmap.cjs +385 -94
  111. package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +608 -46
  112. package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +14 -2
  113. package/gsd-core/bin/lib/runtime-artifact-layout.cjs +426 -55
  114. package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +3 -2
  115. package/gsd-core/bin/lib/runtime-homes.cjs +69 -3
  116. package/gsd-core/bin/lib/runtime-hooks-surface.cjs +115 -3
  117. package/gsd-core/bin/lib/runtime-name-policy.cjs +3 -1
  118. package/gsd-core/bin/lib/runtime-slash.cjs +27 -9
  119. package/gsd-core/bin/lib/security.cjs +104 -5
  120. package/gsd-core/bin/lib/shell-command-projection.cjs +275 -3
  121. package/gsd-core/bin/lib/smart-entry.cjs +142 -22
  122. package/gsd-core/bin/lib/state-command-router.cjs +5 -1
  123. package/gsd-core/bin/lib/state-document.cjs +152 -8
  124. package/gsd-core/bin/lib/state-transition.cjs +371 -117
  125. package/gsd-core/bin/lib/state.cjs +1794 -357
  126. package/gsd-core/bin/lib/surface.cjs +23 -9
  127. package/gsd-core/bin/lib/text-lines.cjs +80 -0
  128. package/gsd-core/bin/lib/token-scanner.cjs +76 -0
  129. package/gsd-core/bin/lib/uat-predicate.cjs +9 -3
  130. package/gsd-core/bin/lib/uat.cjs +399 -56
  131. package/gsd-core/bin/lib/ui-frontend-evidence.cjs +157 -0
  132. package/gsd-core/bin/lib/ui-safety-gate.cjs +14 -5
  133. package/gsd-core/bin/lib/unusable-input.cjs +24 -0
  134. package/gsd-core/bin/lib/update-context.cjs +8 -2
  135. package/gsd-core/bin/lib/user-artifact-staging.cjs +705 -0
  136. package/gsd-core/bin/lib/validate.cjs +20 -6
  137. package/gsd-core/bin/lib/vendor/README.md +37 -0
  138. package/gsd-core/bin/lib/vendor/re2js.cjs +6480 -0
  139. package/gsd-core/bin/lib/vendor/re2js.d.cts +938 -0
  140. package/gsd-core/bin/lib/verification-command-router.cjs +2 -1
  141. package/gsd-core/bin/lib/verification.cjs +258 -8
  142. package/gsd-core/bin/lib/verify.cjs +368 -888
  143. package/gsd-core/bin/lib/workstream-inventory-builder.cjs +53 -32
  144. package/gsd-core/bin/lib/workstream-inventory.cjs +63 -10
  145. package/gsd-core/bin/lib/workstream.cjs +2 -2
  146. package/gsd-core/bin/lib/worktree-safety.cjs +176 -9
  147. package/gsd-core/bin/shared/config-defaults.manifest.json +1 -0
  148. package/gsd-core/bin/shared/config-schema.manifest.json +7 -1
  149. package/gsd-core/references/agent-contracts.md +43 -26
  150. package/gsd-core/references/checkpoints.md +2 -2
  151. package/gsd-core/references/context-budget.md +1 -1
  152. package/gsd-core/references/dispatch-isolation-gate.md +138 -0
  153. package/gsd-core/references/doc-conflict-engine.md +1 -1
  154. package/gsd-core/references/execute-mvp-tdd.md +3 -3
  155. package/gsd-core/references/execute-phase-between-wave-reset.md +6 -2
  156. package/gsd-core/references/execute-phase-context-guard.md +1 -1
  157. package/gsd-core/references/execute-phase-response-language.md +1 -1
  158. package/gsd-core/references/execute-phase-wave-guard.md +6 -2
  159. package/gsd-core/references/gate-prompts.md +1 -1
  160. package/gsd-core/references/git-planning-commit.md +2 -1
  161. package/gsd-core/references/loop-hook-dispatch.md +39 -2
  162. package/gsd-core/references/model-profiles.md +12 -4
  163. package/gsd-core/references/mvp-concepts.md +9 -9
  164. package/gsd-core/references/planner-guidance.md +3 -9
  165. package/gsd-core/references/planner-preconditions.md +1 -1
  166. package/gsd-core/references/planner-reviews.md +1 -1
  167. package/gsd-core/references/planning-config.md +8 -6
  168. package/gsd-core/references/revision-loop.md +1 -1
  169. package/gsd-core/references/specless-probe-fallback.md +1 -1
  170. package/gsd-core/references/universal-anti-patterns.md +3 -3
  171. package/gsd-core/references/verifier-phase-gates.md +192 -0
  172. package/gsd-core/references/verify-mvp-mode.md +1 -1
  173. package/gsd-core/references/workstream-flag.md +22 -6
  174. package/gsd-core/templates/discussion-log.md +1 -1
  175. package/gsd-core/templates/phase-prompt.md +2 -4
  176. package/gsd-core/templates/state.md +4 -4
  177. package/gsd-core/templates/verification-report.md +9 -1
  178. package/gsd-core/workflows/ai-integration-phase.md +9 -11
  179. package/gsd-core/workflows/autonomous.md +1 -1
  180. package/gsd-core/workflows/cleanup.md +62 -3
  181. package/gsd-core/workflows/code-review/steps/structural-pre-pass.md +13 -3
  182. package/gsd-core/workflows/code-review-fix.md +37 -10
  183. package/gsd-core/workflows/code-review.md +38 -12
  184. package/gsd-core/workflows/complete-milestone.md +141 -18
  185. package/gsd-core/workflows/debug.md +7 -5
  186. package/gsd-core/workflows/diagnose-issues.md +35 -9
  187. package/gsd-core/workflows/discuss-phase/modes/chain.md +2 -1
  188. package/gsd-core/workflows/discuss-phase/modes/default.md +1 -1
  189. package/gsd-core/workflows/discuss-phase-assumptions.md +2 -1
  190. package/gsd-core/workflows/edit-phase.md +26 -1
  191. package/gsd-core/workflows/eval-review.md +3 -5
  192. package/gsd-core/workflows/execute-phase/steps/executor-isolation-dispatch.md +31 -6
  193. package/gsd-core/workflows/execute-phase/steps/per-plan-executor-routing.md +77 -0
  194. package/gsd-core/workflows/execute-phase/steps/per-plan-worktree-gate.md +2 -0
  195. package/gsd-core/workflows/execute-phase.md +38 -50
  196. package/gsd-core/workflows/execute-plan.md +36 -4
  197. package/gsd-core/workflows/explore.md +131 -4
  198. package/gsd-core/workflows/fast.md +10 -2
  199. package/gsd-core/workflows/health.md +73 -4
  200. package/gsd-core/workflows/import.md +4 -4
  201. package/gsd-core/workflows/ingest-docs.md +5 -5
  202. package/gsd-core/workflows/mvp-phase.md +6 -3
  203. package/gsd-core/workflows/new-milestone.md +14 -9
  204. package/gsd-core/workflows/new-project.md +14 -14
  205. package/gsd-core/workflows/next.md +12 -0
  206. package/gsd-core/workflows/plan-phase.md +41 -17
  207. package/gsd-core/workflows/plan-review-convergence.md +50 -2
  208. package/gsd-core/workflows/progress.md +34 -6
  209. package/gsd-core/workflows/quick/steps/plan-checker-loop.md +4 -4
  210. package/gsd-core/workflows/quick/steps/quick-verification.md +27 -6
  211. package/gsd-core/workflows/quick/steps/research-phase.md +2 -2
  212. package/gsd-core/workflows/quick.md +35 -15
  213. package/gsd-core/workflows/review.md +26 -5
  214. package/gsd-core/workflows/secure-phase.md +1 -1
  215. package/gsd-core/workflows/session-report.md +2 -1
  216. package/gsd-core/workflows/settings.md +66 -2
  217. package/gsd-core/workflows/ship.md +104 -44
  218. package/gsd-core/workflows/spec-phase.md +30 -12
  219. package/gsd-core/workflows/sync-skills.md +63 -8
  220. package/gsd-core/workflows/transition.md +46 -11
  221. package/gsd-core/workflows/ui-phase.md +5 -5
  222. package/gsd-core/workflows/ui-review.md +2 -2
  223. package/gsd-core/workflows/update.md +1 -1
  224. package/gsd-core/workflows/validate-phase.md +1 -1
  225. package/gsd-core/workflows/verify-work.md +9 -7
  226. package/hooks/dist/gsd-agent-isolation-guard.js +103 -14
  227. package/hooks/dist/gsd-check-update-worker.js +56 -13
  228. package/hooks/dist/gsd-check-update.js +19 -1
  229. package/hooks/dist/gsd-cursor-pre-tool.js +0 -3
  230. package/hooks/dist/gsd-cursor-subagent-start.js +77 -2
  231. package/hooks/dist/gsd-cursor-subagent-stop.js +3 -2
  232. package/hooks/dist/gsd-prompt-guard.js +21 -20
  233. package/hooks/dist/gsd-read-injection-scanner.js +38 -24
  234. package/hooks/dist/gsd-statusline.js +18 -0
  235. package/hooks/dist/gsd-update-banner.js +22 -1
  236. package/hooks/dist/gsd-workflow-guard.js +134 -36
  237. package/hooks/dist/lib/git-cmd.js +92 -59
  238. package/hooks/dist/lib/injection-patterns.js +45 -0
  239. package/hooks/dist/lib/isolation-deny-reason.js +39 -0
  240. package/hooks/dist/lib/isolation-sentinel.js +9 -0
  241. package/hooks/gsd-agent-isolation-guard.js +103 -14
  242. package/hooks/gsd-check-update-worker.js +56 -13
  243. package/hooks/gsd-check-update.js +19 -1
  244. package/hooks/gsd-cursor-pre-tool.js +0 -3
  245. package/hooks/gsd-cursor-subagent-start.js +77 -2
  246. package/hooks/gsd-cursor-subagent-stop.js +3 -2
  247. package/hooks/gsd-prompt-guard.js +21 -20
  248. package/hooks/gsd-read-injection-scanner.js +38 -24
  249. package/hooks/gsd-statusline.js +18 -0
  250. package/hooks/gsd-update-banner.js +22 -1
  251. package/hooks/gsd-workflow-guard.js +134 -36
  252. package/hooks/lib/git-cmd.js +92 -59
  253. package/hooks/lib/injection-patterns.js +45 -0
  254. package/hooks/lib/isolation-deny-reason.js +39 -0
  255. package/hooks/lib/isolation-sentinel.js +9 -0
  256. package/package.json +21 -9
  257. package/pi/gsd.cjs +19 -5
  258. package/scripts/baselines/planning-prompt-drift-baseline.json +4 -0
  259. package/scripts/baselines/planning-snapshot-bypass-baseline.json +12 -0
  260. package/scripts/baselines/unreachable-guard-drift-baseline.json +4 -0
  261. package/scripts/changeset/lint.cjs +60 -5
  262. package/scripts/check-alias-drift.cjs +7 -43
  263. package/scripts/check-contract-drift.cjs +297 -0
  264. package/scripts/ci-test-scope.cjs +19 -2
  265. package/scripts/command-contract-helpers.cjs +903 -1
  266. package/scripts/gen-adr-index.cjs +728 -38
  267. package/scripts/gen-capability-registry.cjs +3 -15
  268. package/scripts/gen-context-index.cjs +2 -11
  269. package/scripts/gen-health-docs.cjs +390 -0
  270. package/scripts/gen-inventory-manifest.cjs +50 -4
  271. package/scripts/gen-loop-host-contract.cjs +4 -24
  272. package/scripts/gen-registry.cjs +3 -14
  273. package/scripts/lib/alias-drift-families.cjs +46 -0
  274. package/scripts/lib/drift-scan.cjs +278 -0
  275. package/scripts/lint-allow-test-rule-refs.allowlist.json +1 -26
  276. package/scripts/lint-allow-test-rule-refs.effective-ceiling.json +4 -0
  277. package/scripts/lint-allow-test-rule-refs.unverified-ceiling.json +3 -0
  278. package/scripts/lint-canary-version-leak.cjs +73 -0
  279. package/scripts/lint-command-contract.cjs +96 -13
  280. package/scripts/lint-completion-predicate-drift.cjs +933 -0
  281. package/scripts/lint-completion-ratio-drift.cjs +214 -0
  282. package/scripts/lint-default-flip-documentation.cjs +193 -0
  283. package/scripts/lint-eslint-glob-coverage.allowlist.json +34 -0
  284. package/scripts/lint-eslint-glob-coverage.cjs +340 -0
  285. package/scripts/lint-frontmatter-scalar-broad-grep.cjs +237 -0
  286. package/scripts/lint-health-diagnostic-rule-table.cjs +404 -0
  287. package/scripts/lint-hooks-runtime-build-seam.cjs +262 -0
  288. package/scripts/lint-milestone-window-drift.cjs +468 -0
  289. package/scripts/lint-phase-enumeration-drift.cjs +479 -0
  290. package/scripts/lint-plan-count-drift.cjs +318 -0
  291. package/scripts/lint-planning-artifact-writer-drift.cjs +398 -0
  292. package/scripts/lint-planning-prompt-drift.cjs +434 -0
  293. package/scripts/lint-planning-snapshot-bypass-drift.cjs +544 -0
  294. package/scripts/lint-regression-test-names.cjs +15 -13
  295. package/scripts/lint-removed-but-needed.cjs +320 -0
  296. package/scripts/lint-state-field-drift.cjs +805 -0
  297. package/scripts/lint-state-write-path-drift.cjs +1045 -0
  298. package/scripts/lint-test-file-count.allowlist.json +21 -10
  299. package/scripts/lint-unreachable-guard-drift.cjs +843 -0
  300. package/scripts/lint-vendored-deps.cjs +124 -0
  301. package/scripts/pr-changed-files.cjs +63 -0
  302. package/scripts/pr-template-policy.cjs +14 -4
  303. package/scripts/prompt-injection-scan.sh +25 -0
  304. package/scripts/require-issue-link-policy.cjs +192 -0
  305. package/scripts/state-write-path-drift-baseline.json +19 -0
  306. package/scripts/sync-runtime-launcher.cjs +2 -4
  307. package/skills/gsd-autonomous/SKILL.md +0 -1
  308. package/skills/gsd-code-review/SKILL.md +1 -1
  309. package/skills/gsd-execute-phase/SKILL.md +1 -2
  310. package/skills/gsd-map-codebase/SKILL.md +1 -1
  311. package/skills/gsd-mempalace-capture/SKILL.md +1 -1
  312. package/skills/gsd-mempalace-recall/SKILL.md +1 -1
  313. package/skills/gsd-new-milestone/SKILL.md +1 -1
  314. package/skills/gsd-next/SKILL.md +0 -1
  315. package/skills/gsd-plan-phase/SKILL.md +0 -1
  316. package/skills/gsd-progress/SKILL.md +0 -1
  317. package/skills/gsd-quick/SKILL.md +1 -1
  318. package/skills/gsd-review-backlog/SKILL.md +2 -1
  319. package/skills/gsd-stats/SKILL.md +0 -1
  320. package/skills/gsd-verify-work/SKILL.md +1 -1
  321. package/vscode/package.json +1 -1
  322. package/gsd-core/workflows/discovery-phase.md +0 -298
  323. package/gsd-core/workflows/plan-milestone-gaps.md +0 -281
  324. package/gsd-core/workflows/verify-phase.md +0 -574
  325. package/scripts/affected-tests-lib.cjs +0 -554
  326. package/scripts/lint-allow-test-rule-refs.cjs +0 -162
  327. package/scripts/run-affected-tests.cjs +0 -7
  328. package/scripts/run-tests.cjs +0 -1051
@@ -10,8 +10,11 @@
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.KNOWN_STATUS_PATTERNS = exports.KNOWN_TEMPLATE_DEFAULTS = void 0;
12
12
  exports.stateExtractField = stateExtractField;
13
+ exports.stateFieldValue = stateFieldValue;
14
+ exports.stateCurrentPositionSlice = stateCurrentPositionSlice;
13
15
  exports.stateReplaceField = stateReplaceField;
14
16
  exports.stateReplaceFieldWithFallback = stateReplaceFieldWithFallback;
17
+ exports.stateReplaceFieldInSession = stateReplaceFieldInSession;
15
18
  exports.normalizeStateStatus = normalizeStateStatus;
16
19
  exports.computeProgressPercent = computeProgressPercent;
17
20
  exports.shouldPreserveExistingProgress = shouldPreserveExistingProgress;
@@ -19,10 +22,12 @@ exports.normalizeProgressNumbers = normalizeProgressNumbers;
19
22
  exports.isStateTemplateDefault = isStateTemplateDefault;
20
23
  exports.stateReplaceFieldIfTemplate = stateReplaceFieldIfTemplate;
21
24
  const markdown_table_cjs_1 = require("./markdown-table.cjs");
22
- // Internal helpers
23
- function escapeRegex(str) {
24
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
25
- }
25
+ const phase_lifecycle_cjs_1 = require("./phase-lifecycle.cjs");
26
+ const markdown_sectionizer_cjs_1 = require("./markdown-sectionizer.cjs");
27
+ const pattern_cjs_1 = require("./pattern.cjs");
28
+ // eslint-disable-next-line @typescript-eslint/no-require-imports -- planning-scope.cjs is an export= CommonJS module
29
+ const planningScopeMod = require("./planning-scope.cjs");
30
+ const { SCOPE } = planningScopeMod;
26
31
  function toFiniteNumber(value) {
27
32
  const number = Number(value);
28
33
  return Number.isFinite(number) ? number : null;
@@ -204,7 +209,7 @@ function locateFieldRow(content, fieldName) {
204
209
  return null;
205
210
  }
206
211
  function stateExtractField(content, fieldName) {
207
- const escaped = escapeRegex(fieldName);
212
+ const escaped = (0, pattern_cjs_1.escapeRegex)(fieldName);
208
213
  // Bold inline format: **FieldName:** value
209
214
  const boldPattern = new RegExp(`\\*\\*${escaped}:\\*\\*[ \\t]*(.+)`, 'i');
210
215
  const boldMatch = content.match(boldPattern);
@@ -222,8 +227,107 @@ function stateExtractField(content, fieldName) {
222
227
  return hit.rawValue.trim();
223
228
  return null;
224
229
  }
230
+ /**
231
+ * Single owner of the #1760 STATE.md field-extraction fallback chain: "read
232
+ * field F, preferring the YAML frontmatter scalar, falling back to the body
233
+ * field." Added for #3187 (epic #3180, ADR-3180 §7.7) to collapse three
234
+ * independent re-derivations of this chain — `src/smart-entry.cts`'s
235
+ * `fmScalar` closure, and `src/state.cts`'s `cmdStateSnapshot` and
236
+ * `cmdStatePrune` — onto one function, per ADR-3180 Decision 1 ("keep N
237
+ * copies with a parity test" is rejected: a parity test proves today's
238
+ * agreement, not that copy N+1 won't happen).
239
+ *
240
+ * Takes ALREADY-PARSED `fm` and `body` rather than raw STATE.md content: the
241
+ * heaviest caller, `cmdStateSnapshot`, reads roughly ten fields off one parse
242
+ * and must not re-parse frontmatter per field.
243
+ *
244
+ * `stateExtractField` (above) is deliberately left untouched — it has 20
245
+ * direct callers and a CRITICAL blast radius (ADR-3180 §7.7's Rejected #1) —
246
+ * so this function is additive: it calls `stateExtractField` rather than
247
+ * replacing it or changing its signature.
248
+ *
249
+ * Fallback ladder (unchanged from every prior copy this replaces):
250
+ * 1. `fm[fmKey]` is a non-empty (post-`.trim()`) string → that trimmed
251
+ * string.
252
+ * 2. `fm[fmKey]` is a `number` or `boolean` → `String(fm[fmKey])`, so `0`
253
+ * and `false` are VALUES, not absence.
254
+ * 3. Anything else (`null`, `undefined`, an object, an array, or an
255
+ * empty/whitespace-only string) → fall through to
256
+ * `stateExtractField(body, bodyField)`.
257
+ *
258
+ * `fmKey === null` skips steps 1–2 outright: for a caller whose chain has no
259
+ * frontmatter side for this particular field (e.g. `state.cts`'s body-only
260
+ * `Last Activity` / `Last activity` case-variant pair, which sits inside a
261
+ * function that DOES own a ladder for its other fields, so per this phase's
262
+ * function-scoped guard it must still route through this owner).
263
+ * `bodyField === null` skips step 3: for a caller whose "no frontmatter
264
+ * value" case falls through to an already-computed value instead of a fresh
265
+ * extractor call (e.g. `cmdStateSnapshot`'s `last_activity`, which falls to
266
+ * its already-parsed prose date rather than re-extracting the body).
267
+ *
268
+ * `scope` reports whether the chain ran over inputs it could actually
269
+ * consult (ADR-3180 Decision 2/§7.7 — mirrors `scanPhasePlans`'s
270
+ * scope-carrying result in `plan-scan.cts`; see `planning-scope.cjs`). This
271
+ * function's own ladder always runs to completion on whatever `fm`/`body` it
272
+ * is given, INCLUDING when the answer is `null` — a genuinely absent field is
273
+ * a real answer, not a failure to look (§7.7 behavior table row 4). So
274
+ * `scope` defaults to `SCOPE.COMPLETE` and is only ever something else when
275
+ * the CALLER passes `opts.scope`, because only the caller knows whether an
276
+ * input it handed in was itself degraded — e.g. `fm` came back `{}` from an
277
+ * unterminated frontmatter fence (`extractFrontmatter` swallows that parse
278
+ * failure), or `body` is an unscoped whole-document fallback because a
279
+ * required `## Current Position` section was not found (#2956). This
280
+ * function never invents a new `SCOPE` member — the enum is frozen at
281
+ * COMPLETE/TRUNCATED/UNSCOPED/UNREADABLE (`planning-scope.cjs`).
282
+ *
283
+ * #1760 is the fallback chain's origin.
284
+ */
285
+ function stateFieldValue(fm, body, fmKey, bodyField, opts) {
286
+ const v = fmKey === null ? undefined : fm[fmKey];
287
+ let value;
288
+ if (typeof v === 'string' && v.trim()) {
289
+ value = v.trim();
290
+ }
291
+ else if (typeof v === 'number' || typeof v === 'boolean') {
292
+ value = String(v);
293
+ }
294
+ else {
295
+ value = bodyField === null ? null : stateExtractField(body, bodyField);
296
+ }
297
+ return { value, scope: opts?.scope ?? SCOPE.COMPLETE };
298
+ }
299
+ /**
300
+ * Match the "Current Position" section body from a STATE.md body. #2956: this
301
+ * is the Phase analogue of state.cts's matchSessionSection. `Phase` canonically
302
+ * lives under `## Current Position` (gsd-core/templates/state.md), so — like
303
+ * Stopped At / Paused At under `## Session` — it must be extracted from THAT
304
+ * section, not from the first `Phase:` / `**Phase:**` line anywhere in the
305
+ * body. Without the scope, a historical `Phase:` line in an archive section
306
+ * silently shadows the real one on every read/write, and because callers use
307
+ * this for routing (state.cts's current_phase) and for drift detection
308
+ * (gsd-tools.cjs's `drift-guard phase-status` CLI seam), a stale match either
309
+ * routes work to the wrong phase or fabricates a drift finding.
310
+ *
311
+ * Level-flexible: the canonical template uses an h2 `## Current Position`, the
312
+ * bootstrap template an h3 `### Current Position` (templates/state.md). Both
313
+ * must match — mirroring how matchSessionSection recognises `## Session` and
314
+ * `## Session Continuity`. Exact 'current position' text match (case-
315
+ * insensitive) excludes unrelated headings. Built on the `collectSection`
316
+ * seam, so it inherits that seam's CRLF tolerance (#2444 fix).
317
+ *
318
+ * This is the single owner of the scope — state.cts's private
319
+ * `matchCurrentPositionSection` delegates here rather than duplicating the
320
+ * logic, so the two consumers cannot drift apart.
321
+ *
322
+ * Returns the section body, or null (caller falls back to full-body search).
323
+ */
324
+ function stateCurrentPositionSlice(body) {
325
+ const isCurrentPosition = (h) => (h.level === 2 || h.level === 3) && h.text.trim().toLowerCase() === 'current position';
326
+ const section = (0, markdown_sectionizer_cjs_1.collectSection)(body, isCurrentPosition, { levelBounded: true });
327
+ return section ? section.body : null;
328
+ }
225
329
  function stateReplaceField(content, fieldName, newValue) {
226
- const escaped = escapeRegex(fieldName);
330
+ const escaped = (0, pattern_cjs_1.escapeRegex)(fieldName);
227
331
  // Bold inline format: **FieldName:** value
228
332
  const boldPattern = new RegExp(`(\\*\\*${escaped}:\\*\\*\\s*)(.*)`, 'i');
229
333
  if (boldPattern.test(content)) {
@@ -253,6 +357,33 @@ function stateReplaceFieldWithFallback(content, primary, fallback, value) {
253
357
  }
254
358
  return content;
255
359
  }
360
+ /**
361
+ * #3374: session-scoped variant of stateReplaceFieldWithFallback for the
362
+ * `## Session` continuity fields. The post-sync harvest (state.cts's
363
+ * matchSessionSection → buildStateFrontmatter) reads these fields ONLY from
364
+ * the session section, so a writer that refreshes one must target the same
365
+ * scope — a whole-body replace lets a decoy `**Stopped at:**` line in an
366
+ * unrelated (e.g. archive) section absorb the refresh while the harvested
367
+ * session value stays stale.
368
+ *
369
+ * Section preference mirrors the reader exactly: the normalized `## Session`
370
+ * block wins over the bootstrap `## Session Continuity` heading when both
371
+ * exist (legacy duplicate files); the continuity heading is only consulted
372
+ * when no canonical `## Session` section exists. `levelBounded` heading
373
+ * matching also excludes `## Session Continuity Archive` (the #2444 scoping).
374
+ *
375
+ * Replace-only (no insertion): returns `content` unchanged when no session
376
+ * section exists or the field is absent from it, so a STATE.md layout without
377
+ * the line keeps its shape and the post-sync preservation pass decides the
378
+ * frontmatter value (see #3374).
379
+ */
380
+ function stateReplaceFieldInSession(content, primary, fallback, value) {
381
+ const isSession = (h) => h.level === 2 && h.text.trim().toLowerCase() === 'session';
382
+ const isSessionContinuity = (h) => h.level === 2 && h.text.trim().toLowerCase() === 'session continuity';
383
+ const hasCanonicalSession = (0, markdown_sectionizer_cjs_1.collectSection)(content, isSession, { levelBounded: true }) !== null;
384
+ const target = hasCanonicalSession ? isSession : isSessionContinuity;
385
+ return (0, markdown_sectionizer_cjs_1.withSection)(content, target, (sectionBody) => stateReplaceFieldWithFallback(sectionBody, primary, fallback, value));
386
+ }
256
387
  function normalizeStateStatus(status, pausedAt) {
257
388
  let normalizedStatus = status || 'unknown';
258
389
  const statusLower = (status || '').toLowerCase();
@@ -279,7 +410,20 @@ function normalizeStateStatus(status, pausedAt) {
279
410
  }
280
411
  return normalizedStatus;
281
412
  }
282
- function computeProgressPercent(completedPlans, totalPlans, completedPhases, totalPhases) {
413
+ /**
414
+ * ADR-3180 §7.6 rule 4 (#3217): `scope` is the `listMilestonePhaseDirs`-owner
415
+ * discriminator for the phase/plan set these four counts were derived from.
416
+ * A caller that cannot vouch for `scope === SCOPE.COMPLETE` must pass the
417
+ * scope it actually has — this function refuses to compose a percentage
418
+ * from counts whose scope says they are not a trustworthy answer, returning
419
+ * `null` (never `0`; see the module's already-existing "no data" `null`
420
+ * below, which this generalizes) exactly like its pre-existing "no data"
421
+ * case. `scope` is REQUIRED (no default) so a caller cannot silently opt out
422
+ * of rule 4 by omission.
423
+ */
424
+ function computeProgressPercent(completedPlans, totalPlans, completedPhases, totalPhases, scope) {
425
+ if (scope !== SCOPE.COMPLETE)
426
+ return null;
283
427
  const hasPlanData = totalPlans !== null && totalPlans > 0 && completedPlans !== null;
284
428
  const hasPhaseData = totalPhases !== null && totalPhases > 0 && completedPhases !== null;
285
429
  if (!hasPlanData && !hasPhaseData)
@@ -288,7 +432,7 @@ function computeProgressPercent(completedPlans, totalPlans, completedPhases, tot
288
432
  // cannot track through intermediate boolean variables).
289
433
  const planFraction = hasPlanData ? (completedPlans ?? 0) / (totalPlans ?? 1) : 1;
290
434
  const phaseFraction = hasPhaseData ? (completedPhases ?? 0) / (totalPhases ?? 1) : 1;
291
- return Math.min(100, Math.round(Math.min(planFraction, phaseFraction) * 100));
435
+ return (0, phase_lifecycle_cjs_1.clampPercentFromFraction)(Math.min(planFraction, phaseFraction));
292
436
  }
293
437
  function shouldPreserveExistingProgress(existingProgress, derivedProgress) {
294
438
  if (!existingProgress || typeof existingProgress !== 'object')