@opengsd/gsd-path 1.0.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 (398) hide show
  1. package/AGENTS.md +397 -0
  2. package/DOCS.md +341 -0
  3. package/FULL.md +475 -0
  4. package/GUIDE.md +23 -0
  5. package/HOOKS.md +273 -0
  6. package/LICENSE +21 -0
  7. package/MIGRATE.md +100 -0
  8. package/QUICK.md +146 -0
  9. package/README.md +280 -0
  10. package/RUNTIME.md +229 -0
  11. package/UPDATE.md +196 -0
  12. package/WORKFLOW.md +683 -0
  13. package/package.json +80 -0
  14. package/platforms/claude/dispatch.md +63 -0
  15. package/platforms/copilot/dispatch.md +61 -0
  16. package/platforms/cursor/agent.md +17 -0
  17. package/platforms/cursor/dispatch.md +63 -0
  18. package/platforms/grok/dispatch.md +61 -0
  19. package/platforms/kimi/dispatch.md +64 -0
  20. package/platforms/kiro/dispatch.md +58 -0
  21. package/platforms/opencode/dispatch.md +62 -0
  22. package/platforms/qwen/dispatch.md +60 -0
  23. package/platforms/shared-agents/dispatch.md +131 -0
  24. package/plugin.json +14 -0
  25. package/scripts/_common.py +180 -0
  26. package/scripts/archive_milestone.py +2265 -0
  27. package/scripts/bootstrap_repository.py +710 -0
  28. package/scripts/build_state.py +854 -0
  29. package/scripts/check_docs_audit.py +463 -0
  30. package/scripts/check_handoffs.py +1855 -0
  31. package/scripts/check_task_briefs.py +376 -0
  32. package/scripts/check_update.py +93 -0
  33. package/scripts/core_hook_gate.py +34 -0
  34. package/scripts/core_hook_settings.py +119 -0
  35. package/scripts/detect_project.py +1517 -0
  36. package/scripts/discussion_records.py +619 -0
  37. package/scripts/discussion_validate.py +1321 -0
  38. package/scripts/dispatch_driver.py +1812 -0
  39. package/scripts/git_guard.py +759 -0
  40. package/scripts/guard_hook.py +2124 -0
  41. package/scripts/install.mjs +3239 -0
  42. package/scripts/install.py +3008 -0
  43. package/scripts/integration.py +1433 -0
  44. package/scripts/isolation.py +3538 -0
  45. package/scripts/lean_verification.py +256 -0
  46. package/scripts/loop_run.py +837 -0
  47. package/scripts/migrate_core.py +169 -0
  48. package/scripts/pipeline_diagnose.py +715 -0
  49. package/scripts/pipeline_git.py +940 -0
  50. package/scripts/pipeline_state.py +2291 -0
  51. package/scripts/pipeline_undo.py +1039 -0
  52. package/scripts/promote_lookahead.py +415 -0
  53. package/scripts/review_findings.py +714 -0
  54. package/scripts/review_panel.py +553 -0
  55. package/scripts/skill-resources.json +340 -0
  56. package/scripts/state_checkpoint.py +1039 -0
  57. package/scripts/state_promote.py +743 -0
  58. package/scripts/status_runtime.py +122 -0
  59. package/scripts/sync_skill_resources.py +259 -0
  60. package/scripts/token_budget.py +146 -0
  61. package/scripts/wizard.mjs +179 -0
  62. package/scripts/workflow_run.py +117 -0
  63. package/skills/gsd-path/BUILD.md +700 -0
  64. package/skills/gsd-path/DECIDE.md +115 -0
  65. package/skills/gsd-path/DEFINE.md +297 -0
  66. package/skills/gsd-path/DOCS-AUDIT.md +190 -0
  67. package/skills/gsd-path/INSPECT.md +167 -0
  68. package/skills/gsd-path/PLAN.md +411 -0
  69. package/skills/gsd-path/RESEARCH.md +159 -0
  70. package/skills/gsd-path/ROADMAP.md +215 -0
  71. package/skills/gsd-path/SHIP.md +412 -0
  72. package/skills/gsd-path/SKILL.md +471 -0
  73. package/skills/gsd-path/agents/openai.yaml +6 -0
  74. package/skills/gsd-path/references/codebase-mapper.md +52 -0
  75. package/skills/gsd-path/references/coder.md +90 -0
  76. package/skills/gsd-path/references/decider.md +36 -0
  77. package/skills/gsd-path/references/dispatch.md +131 -0
  78. package/skills/gsd-path/references/docs-auditor.md +60 -0
  79. package/skills/gsd-path/references/planner.md +104 -0
  80. package/skills/gsd-path/references/researcher.md +42 -0
  81. package/skills/gsd-path/references/reviewer.md +188 -0
  82. package/skills/gsd-path/references/roadmapper.md +48 -0
  83. package/skills/gsd-path/scripts/_common.py +180 -0
  84. package/skills/gsd-path/scripts/archive_milestone.py +2265 -0
  85. package/skills/gsd-path/scripts/bootstrap_repository.py +710 -0
  86. package/skills/gsd-path/scripts/build_state.py +854 -0
  87. package/skills/gsd-path/scripts/check_docs_audit.py +463 -0
  88. package/skills/gsd-path/scripts/check_handoffs.py +1855 -0
  89. package/skills/gsd-path/scripts/check_task_briefs.py +376 -0
  90. package/skills/gsd-path/scripts/check_update.py +93 -0
  91. package/skills/gsd-path/scripts/detect_project.py +1517 -0
  92. package/skills/gsd-path/scripts/discussion_records.py +619 -0
  93. package/skills/gsd-path/scripts/discussion_validate.py +1321 -0
  94. package/skills/gsd-path/scripts/dispatch_driver.py +1812 -0
  95. package/skills/gsd-path/scripts/integration.py +1433 -0
  96. package/skills/gsd-path/scripts/isolation.py +3538 -0
  97. package/skills/gsd-path/scripts/lean_verification.py +256 -0
  98. package/skills/gsd-path/scripts/loop_run.py +837 -0
  99. package/skills/gsd-path/scripts/pipeline_git.py +940 -0
  100. package/skills/gsd-path/scripts/pipeline_state.py +2291 -0
  101. package/skills/gsd-path/scripts/promote_lookahead.py +415 -0
  102. package/skills/gsd-path/scripts/review_findings.py +714 -0
  103. package/skills/gsd-path/scripts/review_panel.py +553 -0
  104. package/skills/gsd-path/scripts/state_checkpoint.py +1039 -0
  105. package/skills/gsd-path/scripts/state_promote.py +743 -0
  106. package/skills/gsd-path/scripts/token_budget.py +146 -0
  107. package/skills/gsd-path/scripts/workflow_run.py +117 -0
  108. package/skills/gsd-path/templates/answers.md +29 -0
  109. package/skills/gsd-path/templates/archive-manifest.md +37 -0
  110. package/skills/gsd-path/templates/charter.md +50 -0
  111. package/skills/gsd-path/templates/codebase.md +46 -0
  112. package/skills/gsd-path/templates/dialogue.md +21 -0
  113. package/skills/gsd-path/templates/docs-audit.md +69 -0
  114. package/skills/gsd-path/templates/evidence.md +24 -0
  115. package/skills/gsd-path/templates/final-review.md +27 -0
  116. package/skills/gsd-path/templates/gap-review.md +20 -0
  117. package/skills/gsd-path/templates/intent.md +98 -0
  118. package/skills/gsd-path/templates/loop.md +59 -0
  119. package/skills/gsd-path/templates/patch-findings.md +16 -0
  120. package/skills/gsd-path/templates/plan-panel.md +25 -0
  121. package/skills/gsd-path/templates/plan.md +89 -0
  122. package/skills/gsd-path/templates/repository.md +16 -0
  123. package/skills/gsd-path/templates/research-handoff.md +25 -0
  124. package/skills/gsd-path/templates/roadmap.md +38 -0
  125. package/skills/gsd-path/templates/skeptic.md +36 -0
  126. package/skills/gsd-path/templates/state.md +27 -0
  127. package/skills/gsd-path/templates/synthesis.md +36 -0
  128. package/skills/gsd-path/templates/task.md +74 -0
  129. package/skills/gsd-path/templates/wave-panel.md +25 -0
  130. package/skills/gsd-path/templates/wave-review.md +64 -0
  131. package/skills/gsd-path-build/SKILL.md +700 -0
  132. package/skills/gsd-path-build/agents/openai.yaml +6 -0
  133. package/skills/gsd-path-build/references/coder.md +90 -0
  134. package/skills/gsd-path-build/references/dispatch.md +131 -0
  135. package/skills/gsd-path-build/references/reviewer.md +188 -0
  136. package/skills/gsd-path-build/scripts/_common.py +180 -0
  137. package/skills/gsd-path-build/scripts/archive_milestone.py +2265 -0
  138. package/skills/gsd-path-build/scripts/build_state.py +854 -0
  139. package/skills/gsd-path-build/scripts/check_handoffs.py +1855 -0
  140. package/skills/gsd-path-build/scripts/check_task_briefs.py +376 -0
  141. package/skills/gsd-path-build/scripts/discussion_records.py +619 -0
  142. package/skills/gsd-path-build/scripts/discussion_validate.py +1321 -0
  143. package/skills/gsd-path-build/scripts/dispatch_driver.py +1812 -0
  144. package/skills/gsd-path-build/scripts/integration.py +1433 -0
  145. package/skills/gsd-path-build/scripts/isolation.py +3538 -0
  146. package/skills/gsd-path-build/scripts/loop_run.py +837 -0
  147. package/skills/gsd-path-build/scripts/pipeline_git.py +940 -0
  148. package/skills/gsd-path-build/scripts/pipeline_state.py +2291 -0
  149. package/skills/gsd-path-build/scripts/review_findings.py +714 -0
  150. package/skills/gsd-path-build/scripts/review_panel.py +553 -0
  151. package/skills/gsd-path-build/scripts/state_checkpoint.py +1039 -0
  152. package/skills/gsd-path-build/scripts/state_promote.py +743 -0
  153. package/skills/gsd-path-build/scripts/token_budget.py +146 -0
  154. package/skills/gsd-path-build/scripts/workflow_run.py +117 -0
  155. package/skills/gsd-path-build/templates/skeptic.md +36 -0
  156. package/skills/gsd-path-build/templates/task.md +74 -0
  157. package/skills/gsd-path-build/templates/wave-panel.md +25 -0
  158. package/skills/gsd-path-build/templates/wave-review.md +64 -0
  159. package/skills/gsd-path-decide/SKILL.md +115 -0
  160. package/skills/gsd-path-decide/agents/openai.yaml +6 -0
  161. package/skills/gsd-path-decide/references/decider.md +36 -0
  162. package/skills/gsd-path-decide/references/dispatch.md +131 -0
  163. package/skills/gsd-path-decide/scripts/_common.py +180 -0
  164. package/skills/gsd-path-decide/scripts/check_handoffs.py +1855 -0
  165. package/skills/gsd-path-decide/scripts/check_task_briefs.py +376 -0
  166. package/skills/gsd-path-decide/scripts/discussion_records.py +619 -0
  167. package/skills/gsd-path-decide/scripts/isolation.py +3538 -0
  168. package/skills/gsd-path-decide/scripts/pipeline_git.py +940 -0
  169. package/skills/gsd-path-decide/scripts/pipeline_state.py +2291 -0
  170. package/skills/gsd-path-decide/scripts/state_checkpoint.py +1039 -0
  171. package/skills/gsd-path-decide/scripts/state_promote.py +743 -0
  172. package/skills/gsd-path-decide/templates/synthesis.md +36 -0
  173. package/skills/gsd-path-define/SKILL.md +297 -0
  174. package/skills/gsd-path-define/agents/openai.yaml +6 -0
  175. package/skills/gsd-path-define/scripts/_common.py +180 -0
  176. package/skills/gsd-path-define/scripts/check_handoffs.py +1855 -0
  177. package/skills/gsd-path-define/scripts/check_task_briefs.py +376 -0
  178. package/skills/gsd-path-define/scripts/detect_project.py +1517 -0
  179. package/skills/gsd-path-define/scripts/discussion_records.py +619 -0
  180. package/skills/gsd-path-define/scripts/isolation.py +3538 -0
  181. package/skills/gsd-path-define/scripts/pipeline_git.py +940 -0
  182. package/skills/gsd-path-define/scripts/pipeline_state.py +2291 -0
  183. package/skills/gsd-path-define/scripts/state_checkpoint.py +1039 -0
  184. package/skills/gsd-path-define/scripts/state_promote.py +743 -0
  185. package/skills/gsd-path-define/templates/charter.md +50 -0
  186. package/skills/gsd-path-define/templates/intent.md +98 -0
  187. package/skills/gsd-path-define/templates/state.md +27 -0
  188. package/skills/gsd-path-discuss/SKILL.md +162 -0
  189. package/skills/gsd-path-discuss/agents/openai.yaml +6 -0
  190. package/skills/gsd-path-discuss/scripts/_common.py +180 -0
  191. package/skills/gsd-path-discuss/scripts/discussion_records.py +619 -0
  192. package/skills/gsd-path-discuss/templates/answers.md +29 -0
  193. package/skills/gsd-path-discuss/templates/dialogue.md +21 -0
  194. package/skills/gsd-path-docs-audit/SKILL.md +190 -0
  195. package/skills/gsd-path-docs-audit/agents/openai.yaml +6 -0
  196. package/skills/gsd-path-docs-audit/references/dispatch.md +131 -0
  197. package/skills/gsd-path-docs-audit/references/docs-auditor.md +60 -0
  198. package/skills/gsd-path-docs-audit/scripts/_common.py +180 -0
  199. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +463 -0
  200. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +1855 -0
  201. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +376 -0
  202. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +619 -0
  203. package/skills/gsd-path-docs-audit/scripts/isolation.py +3538 -0
  204. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +940 -0
  205. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +2291 -0
  206. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +1039 -0
  207. package/skills/gsd-path-docs-audit/scripts/state_promote.py +743 -0
  208. package/skills/gsd-path-docs-audit/templates/docs-audit.md +69 -0
  209. package/skills/gsd-path-forensics/SKILL.md +39 -0
  210. package/skills/gsd-path-forensics/agents/openai.yaml +6 -0
  211. package/skills/gsd-path-forensics/scripts/_common.py +180 -0
  212. package/skills/gsd-path-forensics/scripts/discussion_records.py +619 -0
  213. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +715 -0
  214. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +1039 -0
  215. package/skills/gsd-path-inspect/SKILL.md +167 -0
  216. package/skills/gsd-path-inspect/agents/openai.yaml +6 -0
  217. package/skills/gsd-path-inspect/references/codebase-mapper.md +52 -0
  218. package/skills/gsd-path-inspect/references/dispatch.md +131 -0
  219. package/skills/gsd-path-inspect/references/docs-auditor.md +60 -0
  220. package/skills/gsd-path-inspect/scripts/_common.py +180 -0
  221. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +463 -0
  222. package/skills/gsd-path-inspect/scripts/check_handoffs.py +1855 -0
  223. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +376 -0
  224. package/skills/gsd-path-inspect/scripts/detect_project.py +1517 -0
  225. package/skills/gsd-path-inspect/scripts/discussion_records.py +619 -0
  226. package/skills/gsd-path-inspect/scripts/isolation.py +3538 -0
  227. package/skills/gsd-path-inspect/scripts/pipeline_git.py +940 -0
  228. package/skills/gsd-path-inspect/scripts/pipeline_state.py +2291 -0
  229. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +1039 -0
  230. package/skills/gsd-path-inspect/scripts/state_promote.py +743 -0
  231. package/skills/gsd-path-inspect/templates/codebase.md +46 -0
  232. package/skills/gsd-path-inspect/templates/docs-audit.md +69 -0
  233. package/skills/gsd-path-inspect/templates/state.md +27 -0
  234. package/skills/gsd-path-loop/SKILL.md +98 -0
  235. package/skills/gsd-path-loop/agents/openai.yaml +6 -0
  236. package/skills/gsd-path-loop/examples/ci-repair.LOOP.md +61 -0
  237. package/skills/gsd-path-loop/scripts/_common.py +180 -0
  238. package/skills/gsd-path-loop/scripts/discussion_records.py +619 -0
  239. package/skills/gsd-path-loop/scripts/loop_run.py +837 -0
  240. package/skills/gsd-path-loop/templates/loop.md +59 -0
  241. package/skills/gsd-path-migrate/SKILL.md +134 -0
  242. package/skills/gsd-path-migrate/agents/openai.yaml +6 -0
  243. package/skills/gsd-path-migrate/scripts/core_hook_gate.py +34 -0
  244. package/skills/gsd-path-migrate/scripts/core_hook_settings.py +119 -0
  245. package/skills/gsd-path-migrate/scripts/discussion_records.py +619 -0
  246. package/skills/gsd-path-migrate/scripts/migrate_core.py +169 -0
  247. package/skills/gsd-path-plan/SKILL.md +411 -0
  248. package/skills/gsd-path-plan/agents/openai.yaml +6 -0
  249. package/skills/gsd-path-plan/references/dispatch.md +131 -0
  250. package/skills/gsd-path-plan/references/planner.md +104 -0
  251. package/skills/gsd-path-plan/scripts/_common.py +180 -0
  252. package/skills/gsd-path-plan/scripts/check_handoffs.py +1855 -0
  253. package/skills/gsd-path-plan/scripts/check_task_briefs.py +376 -0
  254. package/skills/gsd-path-plan/scripts/discussion_records.py +619 -0
  255. package/skills/gsd-path-plan/scripts/isolation.py +3538 -0
  256. package/skills/gsd-path-plan/scripts/pipeline_git.py +940 -0
  257. package/skills/gsd-path-plan/scripts/pipeline_state.py +2291 -0
  258. package/skills/gsd-path-plan/scripts/review_panel.py +553 -0
  259. package/skills/gsd-path-plan/scripts/state_checkpoint.py +1039 -0
  260. package/skills/gsd-path-plan/scripts/state_promote.py +743 -0
  261. package/skills/gsd-path-plan/scripts/workflow_run.py +117 -0
  262. package/skills/gsd-path-plan/templates/patch-findings.md +16 -0
  263. package/skills/gsd-path-plan/templates/plan-panel.md +25 -0
  264. package/skills/gsd-path-plan/templates/plan.md +89 -0
  265. package/skills/gsd-path-plan/templates/task.md +74 -0
  266. package/skills/gsd-path-research/SKILL.md +159 -0
  267. package/skills/gsd-path-research/agents/openai.yaml +6 -0
  268. package/skills/gsd-path-research/references/dispatch.md +131 -0
  269. package/skills/gsd-path-research/references/researcher.md +42 -0
  270. package/skills/gsd-path-research/scripts/_common.py +180 -0
  271. package/skills/gsd-path-research/scripts/check_handoffs.py +1855 -0
  272. package/skills/gsd-path-research/scripts/check_task_briefs.py +376 -0
  273. package/skills/gsd-path-research/scripts/discussion_records.py +619 -0
  274. package/skills/gsd-path-research/scripts/isolation.py +3538 -0
  275. package/skills/gsd-path-research/scripts/pipeline_git.py +940 -0
  276. package/skills/gsd-path-research/scripts/pipeline_state.py +2291 -0
  277. package/skills/gsd-path-research/scripts/state_checkpoint.py +1039 -0
  278. package/skills/gsd-path-research/scripts/state_promote.py +743 -0
  279. package/skills/gsd-path-research/templates/evidence.md +24 -0
  280. package/skills/gsd-path-research/templates/research-handoff.md +25 -0
  281. package/skills/gsd-path-roadmap/SKILL.md +215 -0
  282. package/skills/gsd-path-roadmap/agents/openai.yaml +6 -0
  283. package/skills/gsd-path-roadmap/references/dispatch.md +131 -0
  284. package/skills/gsd-path-roadmap/references/roadmapper.md +48 -0
  285. package/skills/gsd-path-roadmap/scripts/_common.py +180 -0
  286. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +2265 -0
  287. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +1855 -0
  288. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +376 -0
  289. package/skills/gsd-path-roadmap/scripts/detect_project.py +1517 -0
  290. package/skills/gsd-path-roadmap/scripts/discussion_records.py +619 -0
  291. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +1321 -0
  292. package/skills/gsd-path-roadmap/scripts/integration.py +1433 -0
  293. package/skills/gsd-path-roadmap/scripts/isolation.py +3538 -0
  294. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +940 -0
  295. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +2291 -0
  296. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +415 -0
  297. package/skills/gsd-path-roadmap/scripts/review_panel.py +553 -0
  298. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +1039 -0
  299. package/skills/gsd-path-roadmap/scripts/state_promote.py +743 -0
  300. package/skills/gsd-path-roadmap/templates/roadmap.md +38 -0
  301. package/skills/gsd-path-ship/SKILL.md +412 -0
  302. package/skills/gsd-path-ship/agents/openai.yaml +6 -0
  303. package/skills/gsd-path-ship/references/dispatch.md +131 -0
  304. package/skills/gsd-path-ship/references/reviewer.md +188 -0
  305. package/skills/gsd-path-ship/scripts/_common.py +180 -0
  306. package/skills/gsd-path-ship/scripts/archive_milestone.py +2265 -0
  307. package/skills/gsd-path-ship/scripts/build_state.py +854 -0
  308. package/skills/gsd-path-ship/scripts/check_handoffs.py +1855 -0
  309. package/skills/gsd-path-ship/scripts/check_task_briefs.py +376 -0
  310. package/skills/gsd-path-ship/scripts/discussion_records.py +619 -0
  311. package/skills/gsd-path-ship/scripts/discussion_validate.py +1321 -0
  312. package/skills/gsd-path-ship/scripts/integration.py +1433 -0
  313. package/skills/gsd-path-ship/scripts/isolation.py +3538 -0
  314. package/skills/gsd-path-ship/scripts/lean_verification.py +256 -0
  315. package/skills/gsd-path-ship/scripts/pipeline_git.py +940 -0
  316. package/skills/gsd-path-ship/scripts/pipeline_state.py +2291 -0
  317. package/skills/gsd-path-ship/scripts/review_panel.py +553 -0
  318. package/skills/gsd-path-ship/scripts/state_checkpoint.py +1039 -0
  319. package/skills/gsd-path-ship/scripts/state_promote.py +743 -0
  320. package/skills/gsd-path-ship/scripts/workflow_run.py +117 -0
  321. package/skills/gsd-path-ship/templates/archive-manifest.md +37 -0
  322. package/skills/gsd-path-ship/templates/final-review.md +27 -0
  323. package/skills/gsd-path-ship/templates/gap-review.md +20 -0
  324. package/skills/gsd-path-ship/templates/patch-findings.md +16 -0
  325. package/skills/gsd-path-ship/templates/wave-review.md +64 -0
  326. package/skills/gsd-path-undo/SKILL.md +45 -0
  327. package/skills/gsd-path-undo/agents/openai.yaml +6 -0
  328. package/skills/gsd-path-undo/scripts/_common.py +180 -0
  329. package/skills/gsd-path-undo/scripts/discussion_records.py +619 -0
  330. package/skills/gsd-path-undo/scripts/pipeline_undo.py +1039 -0
  331. package/skills/path/BUILD.md +700 -0
  332. package/skills/path/DECIDE.md +115 -0
  333. package/skills/path/DEFINE.md +297 -0
  334. package/skills/path/DOCS-AUDIT.md +190 -0
  335. package/skills/path/INSPECT.md +167 -0
  336. package/skills/path/PLAN.md +411 -0
  337. package/skills/path/RESEARCH.md +159 -0
  338. package/skills/path/ROADMAP.md +215 -0
  339. package/skills/path/SHIP.md +412 -0
  340. package/skills/path/SKILL.md +471 -0
  341. package/skills/path/agents/openai.yaml +6 -0
  342. package/skills/path/references/codebase-mapper.md +52 -0
  343. package/skills/path/references/coder.md +90 -0
  344. package/skills/path/references/decider.md +36 -0
  345. package/skills/path/references/dispatch.md +131 -0
  346. package/skills/path/references/docs-auditor.md +60 -0
  347. package/skills/path/references/planner.md +104 -0
  348. package/skills/path/references/researcher.md +42 -0
  349. package/skills/path/references/reviewer.md +188 -0
  350. package/skills/path/references/roadmapper.md +48 -0
  351. package/skills/path/scripts/_common.py +180 -0
  352. package/skills/path/scripts/archive_milestone.py +2265 -0
  353. package/skills/path/scripts/bootstrap_repository.py +710 -0
  354. package/skills/path/scripts/build_state.py +854 -0
  355. package/skills/path/scripts/check_docs_audit.py +463 -0
  356. package/skills/path/scripts/check_handoffs.py +1855 -0
  357. package/skills/path/scripts/check_task_briefs.py +376 -0
  358. package/skills/path/scripts/check_update.py +93 -0
  359. package/skills/path/scripts/detect_project.py +1517 -0
  360. package/skills/path/scripts/discussion_records.py +619 -0
  361. package/skills/path/scripts/discussion_validate.py +1321 -0
  362. package/skills/path/scripts/dispatch_driver.py +1812 -0
  363. package/skills/path/scripts/integration.py +1433 -0
  364. package/skills/path/scripts/isolation.py +3538 -0
  365. package/skills/path/scripts/lean_verification.py +256 -0
  366. package/skills/path/scripts/loop_run.py +837 -0
  367. package/skills/path/scripts/pipeline_git.py +940 -0
  368. package/skills/path/scripts/pipeline_state.py +2291 -0
  369. package/skills/path/scripts/promote_lookahead.py +415 -0
  370. package/skills/path/scripts/review_findings.py +714 -0
  371. package/skills/path/scripts/review_panel.py +553 -0
  372. package/skills/path/scripts/state_checkpoint.py +1039 -0
  373. package/skills/path/scripts/state_promote.py +743 -0
  374. package/skills/path/scripts/token_budget.py +146 -0
  375. package/skills/path/scripts/workflow_run.py +117 -0
  376. package/skills/path/templates/answers.md +29 -0
  377. package/skills/path/templates/archive-manifest.md +37 -0
  378. package/skills/path/templates/charter.md +50 -0
  379. package/skills/path/templates/codebase.md +46 -0
  380. package/skills/path/templates/dialogue.md +21 -0
  381. package/skills/path/templates/docs-audit.md +69 -0
  382. package/skills/path/templates/evidence.md +24 -0
  383. package/skills/path/templates/final-review.md +27 -0
  384. package/skills/path/templates/gap-review.md +20 -0
  385. package/skills/path/templates/intent.md +98 -0
  386. package/skills/path/templates/loop.md +59 -0
  387. package/skills/path/templates/patch-findings.md +16 -0
  388. package/skills/path/templates/plan-panel.md +25 -0
  389. package/skills/path/templates/plan.md +89 -0
  390. package/skills/path/templates/repository.md +16 -0
  391. package/skills/path/templates/research-handoff.md +25 -0
  392. package/skills/path/templates/roadmap.md +38 -0
  393. package/skills/path/templates/skeptic.md +36 -0
  394. package/skills/path/templates/state.md +27 -0
  395. package/skills/path/templates/synthesis.md +36 -0
  396. package/skills/path/templates/task.md +74 -0
  397. package/skills/path/templates/wave-panel.md +25 -0
  398. package/skills/path/templates/wave-review.md +64 -0
@@ -0,0 +1,36 @@
1
+ # Synthesis
2
+
3
+ <!-- Written by the decider role. The planner treats Decisions as settled. -->
4
+
5
+ ## Settled
6
+
7
+ <!-- Choices closed by an intent constraint or the existing codebase.
8
+ One line each, citing the settling source. No invented runner-ups. -->
9
+ - <area> — <what stands> (<settling source>)
10
+
11
+ ## Decisions
12
+
13
+ <!-- One block per genuinely open choice the evidence resolved. -->
14
+ ### <decision area, e.g. Stack>
15
+
16
+ - **Decision**: <what we're doing>
17
+ - **Runner-up**: <what lost, and why>
18
+ - **Evidence**: <evidence-file.md § finding heading, ...>
19
+ - **Confidence**: <high | medium | low — low ⇒ verify in wave 1>
20
+
21
+ ## For the planner
22
+
23
+ <!-- The shape of the build. -->
24
+ - **Wave-1 blockers**: <riskiest assumptions to burn down first>
25
+ - **Walking skeleton**: <the thinnest end-to-end slice>
26
+ - **Pitfalls → tasks**: <known trap → which future task must dodge it>
27
+
28
+ ## User rulings
29
+
30
+ <!-- NEEDS-USER items answered at the synthesis checkpoint. Verbatim-ish. -->
31
+ - <question> → <ruling>
32
+
33
+ ## Still unknown
34
+
35
+ <!-- Carried-forward gaps. Never let a question vanish between phases. -->
36
+ - <gap> — <plan: wave-1 spike | accept risk | NEEDS-USER>
@@ -0,0 +1,297 @@
1
+ ---
2
+ name: gsd-path-define
3
+ description: Define and approve project or milestone intent through an interview or milestone confirmation, writing .project/CHARTER.md or .project/intent/INTENT.md. Use only when the user explicitly invokes $gsd-path-define or an active $gsd-path router explicitly routes to this phase.
4
+ ---
5
+
6
+ # GSD Path Define Phase
7
+
8
+ Turn a project idea or approved roadmap entry into an approved intent artifact.
9
+ Run this phase in the main conversation; never delegate its interview or
10
+ confirmation.
11
+
12
+ Primary modes: **standard** (single milestone, below), **program** (a
13
+ multi-milestone program — interview into `.project/CHARTER.md`), and
14
+ **milestone** (derive one milestone's INTENT.md from the approved roadmap; no
15
+ re-interview). Modifiers: **brownfield** when the track's
16
+ `research/evidence-codebase.md` exists, and **supplied-spec** when the user
17
+ hands in a PRD, issue, or design doc. Apply every matching modifier on top of
18
+ the primary mode.
19
+
20
+ Routing instructions below are caller handoffs under the AGENTS.md handoff
21
+ rule; never invoke an explicit-only sibling skill yourself.
22
+
23
+ Before interview work and again before approval, apply the AGENTS.md
24
+ pending-answer rule with the bundled `scripts/discussion_records.py`; a
25
+ follow-up owned by define is resolved in INTENT.md, or the phase blocks.
26
+
27
+ ## State ownership
28
+
29
+ If STATE.md exists, require `pipeline_state.py validate --repo <absolute root>
30
+ [--project-dir .project/next]` to pass; otherwise return to `$gsd-path` for
31
+ ownership checking. Legal existing-state
32
+ entry is `inspect/done` (transition to `define/active`; milestone mode when
33
+ ROADMAP.md exists), `roadmap/done`
34
+ (transition to `define/active`, milestone mode), or
35
+ `define/active|blocked`. When ROADMAP.md exists, a later milestone or
36
+ lookahead track at `define/active|blocked` also requires both current-track
37
+ inspection artifacts and a Log entry proving `inspect/done` for the same
38
+ milestone after its latest activation; otherwise route to inspect.
39
+ `define/done` or any later phase blocks rather than overwriting approved
40
+ intent and leaving downstream artifacts stale. When an active router supplies
41
+ the lookahead track root `.project/next/`, require its STATE.md to be a regular
42
+ non-symlink file and evaluate this section against that track's state and
43
+ paths; see Lookahead mode. If STATE.md is missing, run the bundled
44
+ `python3 <absolute-bundled-script> initialize --repo <absolute-root>
45
+ --template <absolute-state-template>` helper (`scripts/detect_project.py`) and
46
+ follow its returned JSON `verdict` / `route`. This is the only no-state
47
+ boundary; do not run `classify` first or classify from a directory listing or
48
+ conversation. If the command exits nonzero, returns `error`, or returns
49
+ `wrote_state: false`, report the error and block without routing or claiming
50
+ STATE.md was written.
51
+ - `owned` — continue under the existing-state rules above.
52
+ - `orphan` — return to `$gsd-path` for orphaned-state recovery; existing
53
+ evidence does not prove its pipeline version or phase and must not be reused
54
+ or overwritten by inference.
55
+ - `brownfield` — the helper writes STATE.md at `inspect/active`; route to
56
+ `$gsd-path-inspect` from this returned verdict.
57
+ - `greenfield` — require `wrote_state: true`, then continue with the helper's
58
+ STATE.md at `define/active`. Do not create STATE.md yourself.
59
+
60
+ Enter from `inspect/done` or `roadmap/done` only with `pipeline_state.py
61
+ transition`: pass the exact expected phase/status/branch/archive values, event
62
+ `definition started`, and `--set-phase define --set-status active` (plus
63
+ `--project-dir .project/next` for lookahead). This helper is the only ordinary
64
+ STATE mutation; direct template writing is limited to the missing-state
65
+ greenfield initialization above.
66
+
67
+ The router's verified new-GitHub-repository transaction is the sole greenfield
68
+ exception: STATE.md already exists at `define/active`, `branch` is the approved
69
+ `gsd-path/M001` branch, and `.project/REPOSITORY.md` contains the
70
+ fixed-format remote, remote-default SHA, clean default checkout, branch, and
71
+ primary worktree. Verify that artifact and the current branch/worktree before
72
+ interviewing. The required classifier returns `owned` before signal scanning,
73
+ so the bootstrap README is not a brownfield signal. A missing or mismatched binding
74
+ returns to `$gsd-path`; never infer it from STATE log prose or repair it
75
+ inside define.
76
+
77
+ ## Coverage checklist
78
+
79
+ Obtain a confident answer in every area before finishing:
80
+
81
+ 1. **Problem** — what hurts, for whom, and how badly.
82
+ 2. **Users** — who uses this, how many, how technical, and what they use now.
83
+ 3. **Success** — what observable result makes the first release complete.
84
+ 4. **Scope in** — the smallest version that achieves that result.
85
+ 5. **Scope out** — explicit vetoes that downstream phases must not include.
86
+ 6. **Constraints** — stack, deadline, budget, code, integrations, compliance.
87
+ 7. **Risks** — the assumptions and unknowns research must investigate.
88
+ 8. **Surfaces** — what a person opens, sees, or types into to get the
89
+ result: screens, commands, endpoints. Record them on INTENT.md
90
+ `Surfaces:` (`none` only when nobody touches this work directly), and
91
+ give every named surface at least one success criterion observable
92
+ there. A criterion satisfied by a passing test alone does not cover a
93
+ surface.
94
+
95
+ ## Program mode
96
+
97
+ When the user frames the work as a large multi-milestone program — or the
98
+ interview reveals scope that cannot ship as one milestone — interview against
99
+ the charter instead of the single-milestone checklist:
100
+
101
+ 1. **Vision** — the program's end state and why it matters.
102
+ 2. **Full scope in** — every capability area the program will deliver.
103
+ 3. **Vetoes** — what no milestone may include.
104
+ 4. **Constraints** — program-level stack, budget, deadline, integrations.
105
+ 5. **Program success criteria** — observable when the last milestone ships.
106
+ 6. **Review panel** — optional durable default (`off` | `detected` | named
107
+ families). Default `off`. This value persists on CHARTER.md; later
108
+ milestone INTENT files copy it and may override.
109
+
110
+ Read the local [charter template](templates/charter.md), write the approval
111
+ draft to `.project/CHARTER.md` including `Review panel:` (default `off`;
112
+ never invent `detected` or a named list), and run the same playback-approval
113
+ loop as the standard Process. On approval, retain the reviewed
114
+ `Review panel:` value on CHARTER.md, run `pipeline_state.py transition` with
115
+ expected `define/active`, milestone/branch/archive all at their exact current
116
+ values, event `program charter approved`, and `--set-phase define --set-status
117
+ done`; require milestone to remain null. Report that research (program
118
+ scope) is next. Research, decide, and the roadmap phase slice the program;
119
+ per-milestone INTENT.md files come later, in milestone mode. Do not write
120
+ INTENT.md in program mode.
121
+
122
+ ## Milestone mode
123
+
124
+ Legal entry: `roadmap/done` only for the first milestone after initial roadmap
125
+ approval, or `inspect/done` when `.project/ROADMAP.md` exists. Recovery from
126
+ `define/active|blocked` follows the current inspection-evidence requirement in
127
+ State ownership. There is no re-interview of charter or roadmap scope:
128
+ 1. Read the applicable track STATE.md, `.project/CHARTER.md`, and
129
+ `.project/ROADMAP.md`. Select the entry whose slug matches `STATE.milestone`.
130
+ Require exactly one match. In ordinary milestone mode,
131
+ require that entry to be `active`; in lookahead mode, require it to be
132
+ `pending`. A missing, duplicate, or wrong-status match blocks: record the
133
+ failure in the applicable STATE.md and return to the router. When
134
+ brownfield, also read the track's
135
+ `research/evidence-codebase.md` and `research/DOCS-AUDIT.md` first.
136
+ 2. Draft INTENT.md from the resolved entry: Summary from its Goal, Scope
137
+ in/out and Success criteria from the entry, Constraints inherited from the charter,
138
+ Risks and Open questions from the entry (tagged `RESEARCH`/`NEEDS-USER`),
139
+ `Lane: milestone`, `Surfaces:` copied verbatim from the entry, and
140
+ `Review panel:` copied from CHARTER.md (default
141
+ `off` when CHARTER omits it). The confirmation may override the copied
142
+ panel value; do not invent `detected` or a named list. When brownfield,
143
+ fill `## Current state` from the map, record doc-vs-code rulings as in
144
+ Brownfield mode, and add protected existing behavior under Scope out.
145
+ Write Ground truth paths from the track root: `.project` normally, or
146
+ `.project/next` in Lookahead mode — never the building milestone's
147
+ active `research/` paths.
148
+ 3. Present one confirmation, not an interview: playback the derivation (and
149
+ brownfield ground truth when present), link the resolved absolute INTENT.md
150
+ path, and ask approve or adjust. A requested change that contradicts the
151
+ charter or the resolved roadmap entry is a scope change — this phase never
152
+ edits the roadmap; surface it to the user for a `$gsd-path-roadmap` re-slice
153
+ at the next milestone boundary.
154
+ 4. On approval, finalize per the Output contract, setting `milestone` to the
155
+ resolved entry's slug. The router continues with milestone-scoped research
156
+ when the entry lists open questions, otherwise planning.
157
+
158
+ ## Lookahead mode
159
+
160
+ Entered only when an active router supplies the lookahead track root
161
+ `.project/next/` while the active STATE.md is `build/active` in program
162
+ flow. Evaluate every state and artifact precondition in this contract
163
+ against the track — `.project/next/STATE.md` is the state file and
164
+ INTENT.md is `.project/next/intent/INTENT.md` — never against active-path
165
+ artifacts. This is milestone mode run against the track, with two
166
+ differences:
167
+
168
+ - Read CHARTER.md and ROADMAP.md from their active `.project/` paths, but
169
+ resolve the milestone only from `.project/next/STATE.md` as described above;
170
+ never use the building milestone's `active` entry and never create or modify
171
+ any active-path artifact.
172
+ - Never mark the lookahead milestone's roadmap entry `active`; the router
173
+ does that at promotion.
174
+
175
+ All other milestone-mode rules apply unchanged. Brownfield evidence for
176
+ this track is `.project/next/research/evidence-codebase.md`.
177
+
178
+ ## Supplied-spec mode
179
+
180
+ When the user supplies a document at entry — a PRD, issue, or design doc —
181
+ read it fully before the first question and map it against the coverage
182
+ checklist. Present what the document settles per checklist area for
183
+ correction — stated, not asked, exactly like brownfield ground truth — then
184
+ interview only the gaps and contradictions. Note the source document path in
185
+ INTENT.md's Summary. A supplied spec composes with brownfield mode: ground
186
+ truth first, then the spec, then delta questions only.
187
+
188
+ ## Brownfield mode
189
+
190
+ When the track's `research/evidence-codebase.md` exists (inspect already
191
+ ran), read it and the matching `research/DOCS-AUDIT.md` before the first
192
+ question. The rules change for every primary mode:
193
+
194
+ - Established facts are not questions. Never ask what the stack is or what
195
+ the code does — the map answers that. State it and let the user correct.
196
+ - Standard and program interviews cover only deltas: what should change, what
197
+ must not break, and — standard — the goal of THIS milestone against the
198
+ code that already exists. Program interviews still use the charter
199
+ checklist, but skip any area the map already settled.
200
+ - Milestone mode still does not re-interview; it still collects the rulings
201
+ below before confirmation.
202
+ - Work through the mapper's `## Open questions for define` and the
203
+ audit's `NEEDS-USER` remediation rows — each doc-vs-code conflict gets a
204
+ ruling (`fix-doc`, `fix-code`, or `accept-drift`) recorded verbatim in
205
+ INTENT.md and appended to DOCS-AUDIT.md's `## User rulings` table.
206
+ `fix-doc` and `fix-code` rows receive `planned: no`; `accept-drift` receives
207
+ `planned: n/a (accept-drift)`. Never leave the durable alignment queue only
208
+ in INTENT.md. Program mode records those rulings on CHARTER.md Constraints
209
+ or Corrections and still writes the DOCS-AUDIT.md table.
210
+ - Existing behavior the user wants preserved is recorded under Scope out as
211
+ a veto ("do not break X"); accepted `fix-code` items become scope.
212
+ - Fill INTENT.md's `## Current state` from the codebase map so downstream
213
+ phases inherit ground truth without re-scanning. Set Ground truth to the
214
+ track's `research/evidence-codebase.md` and `research/DOCS-AUDIT.md`
215
+ (`.project/next/research/` in Lookahead mode). Omit that section for
216
+ greenfield. Do not add it to CHARTER.md.
217
+
218
+ ## Process
219
+
220
+ 1. Open in this order, then stop for the reply:
221
+ - **Brownfield (any primary):** present the one-screen ground truth from
222
+ inspect before any question.
223
+ - **Standard, no brownfield:** ask for a one-paragraph idea if missing.
224
+ - **Program, no brownfield:** ask for the program vision if missing.
225
+ - **Milestone:** do not ask for an idea; continue at Milestone mode
226
+ (ground truth already presented when brownfield).
227
+ - **Supplied spec:** after the opening above, present settled coverage
228
+ for correction, then interview only its gaps.
229
+ - **Standard + brownfield:** after ground truth, ask what this milestone
230
+ should achieve against the code that exists.
231
+ 2. For standard and program modes, ask small rounds of questions aimed at the
232
+ weakest checklist areas that the opening did not already settle. Never ask
233
+ a fact the map, audit, or supplied spec already answered. Use an
234
+ interactive user-input tool when available. Otherwise ask concise numbered
235
+ questions in chat and stop for the reply. Keep each round small enough to
236
+ answer in one reply. When a question offers options, list the recommended
237
+ one first marked `(recommended)` with a one-line reason; leave open
238
+ questions open. Milestone mode skips this step; collect brownfield rulings
239
+ if brownfield, then use the Milestone mode confirmation.
240
+ 3. Surface contradictions immediately and ask the user to choose. Never
241
+ average incompatible answers.
242
+ 4. In standard and program modes, challenge the largest remaining assumption
243
+ at least once: ask what happens if it is false. Do not challenge a fact
244
+ the brownfield map already established. Milestone mode skips this step.
245
+ 5. Stop when coverage is complete or the user says `enough`. Record remaining
246
+ uncertainty under `## Open questions` with `RESEARCH` or `NEEDS-USER`.
247
+ 6. Classify the proposed milestone lane before writing the approval draft.
248
+ Milestone mode keeps `Lane: milestone` and skips this classification.
249
+ Program mode writes CHARTER.md instead of INTENT.md. Otherwise choose
250
+ `quick` when scope fits at most two deliverable-sized tasks (project
251
+ policy) in one wave with
252
+ no `RESEARCH` or `NEEDS-USER` items and no cross-wave integration risk;
253
+ otherwise `standard`. Read the local [intent template](templates/intent.md),
254
+ write that proposed lane and the complete draft to
255
+ `.project/intent/INTENT.md`, then ask for approval. Present an
256
+ **Outcome** playback of the Summary and proposed lane, a **Review** Markdown
257
+ link to the resolved absolute INTENT.md path, and one **Next** approval
258
+ question with approve first as `(recommended)` only when the evidence
259
+ supports it. Record corrections verbatim under `## Corrections`, update the
260
+ file, and present the new link before asking again. When STATE records a new
261
+ new-GitHub REPOSITORY.md binding, include its remote, default checkout, GSD
262
+ Path branch, and primary worktree under `## Constraints`. Recompute and write
263
+ the lane after every correction before relinking the file.
264
+
265
+ ## Output contract
266
+
267
+ At approval, retain the already reviewed `Lane:` value and its one-line reason.
268
+ Retain `Review panel:` as reviewed: the CHARTER copy or the user's override
269
+ in milestone/lookahead mode, the CHARTER value in program mode, or `off`
270
+ when the user did not choose a panel and no CHARTER default exists.
271
+
272
+ After approval, finalize `.project/intent/INTENT.md` and run
273
+ `pipeline_state.py transition` with expected `define/active`, the exact
274
+ current milestone/branch/archive values, event `milestone intent approved`,
275
+ `--set-phase define --set-status done --set-milestone <milestone slug>`, and
276
+ `--project-dir .project/next` in lookahead. Require returned `define/done` and
277
+ the exact milestone. Report the next phase
278
+ from the approved lane. For `Lane: standard`, research is next. For
279
+ `Lane: quick`, planning is next and research and decide are skipped. For
280
+ `Lane: milestone`, use the resolved roadmap entry matching the track STATE's
281
+ `milestone`: milestone-scoped research is next when that entry lists open
282
+ questions; otherwise planning is next and research and decide are skipped.
283
+ Confirm the approved outcome, link the final INTENT.md again, and name that
284
+ next phase before routing. When routed by an active `$gsd-path`, return control
285
+ to that router so its bundled next contract can auto-advance to the named
286
+ phase. When invoked directly, stop and tell the user to explicitly invoke
287
+ `$gsd-path`, which selects that next phase; do not invoke an explicit-only
288
+ sibling skill yourself.
289
+
290
+ ## Rules
291
+
292
+ - Trace every question to a checklist gap; omit curiosity questions.
293
+ - In brownfield mode, state mapped facts for correction; never re-ask them.
294
+ - Treat solution-shaped problems as hypotheses and uncover the underlying pain.
295
+ - Preserve vetoes and corrections verbatim.
296
+ - Wrap up when every coverage-checklist area is answered or the user signals
297
+ done, and tag remaining gaps.
@@ -0,0 +1,6 @@
1
+ interface:
2
+ display_name: "GSD Path Define"
3
+ short_description: "Turn an idea into approved intent"
4
+ default_prompt: "Use $gsd-path-define to define and approve this project's intent."
5
+ policy:
6
+ allow_implicit_invocation: false
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python3
2
+ # gsd-path project runtime
3
+ """Helpers shared by the gsd-path scripts.
4
+
5
+ Every consuming script binds the names it used before (for example
6
+ ``run_git = _common.run_git``) so callers and tests that patch the name on the
7
+ consuming module keep working.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import json
13
+ import os
14
+ import re
15
+ import subprocess
16
+ from pathlib import Path
17
+ from typing import Optional
18
+
19
+ PIPELINE_MARKER = "gsd-path/v2"
20
+ BOUND_BRANCH_RE = re.compile(r"^gsd-path/M(\d{3,})$")
21
+
22
+ FIELD_PATTERN = re.compile(r"^(?P<key>[a-z_]+):\s*(?P<value>.*)$")
23
+ INLINE_LIST_PATTERN = re.compile(r"^\[(?P<body>.*)\]$")
24
+ LIST_ITEM_PATTERN = re.compile(r"^\s*-\s+(?P<value>.*)$")
25
+ VERIFY_LEDGER_PATH = ".project/build/verify-ledger.jsonl"
26
+ VERIFY_RESULTS = ("pass", "fail")
27
+ VERIFY_LEDGER_SCHEMA = "gsd-path/verify-ledger/v2"
28
+ VERIFY_BLOCK_PATTERN = re.compile(r"```bash[ \t]*\n(?P<block>.*?)```", re.DOTALL)
29
+
30
+
31
+ def section_body(text: str, heading: str) -> Optional[str]:
32
+ """The text under `## <heading>` up to the next `## `, or None when absent."""
33
+ match = re.search(
34
+ rf"(?ms)^## {re.escape(heading)}\s*\n(?P<body>.*?)(?=^## |\Z)", text
35
+ )
36
+ return match.group("body") if match else None
37
+
38
+
39
+ def task_verify_command(task_text: str) -> str:
40
+ """The Verify shell text, excluding the closing fence's separator newline."""
41
+ body = section_body(task_text, "Verify")
42
+ block = VERIFY_BLOCK_PATTERN.search(body) if body is not None else None
43
+ return block.group("block").removesuffix("\n") if block else ""
44
+
45
+
46
+ def latest_verify_entry(entries: list, command: str, commit: str) -> Optional[dict]:
47
+ for entry in reversed(entries):
48
+ if (entry.get("schema") == VERIFY_LEDGER_SCHEMA
49
+ and entry["command"] == command and entry["commit"] == commit):
50
+ return entry
51
+ return None
52
+
53
+
54
+ def verify_ledger_entries(path: Path) -> list:
55
+ """Parsed verify-ledger rows; raises ValueError on a malformed line."""
56
+ if not path.exists():
57
+ return []
58
+ return parse_verify_ledger(path.read_text(encoding="utf-8"))
59
+
60
+
61
+ def parse_verify_ledger(text: str) -> list:
62
+ entries = []
63
+ for number, line in enumerate(text.splitlines(), start=1):
64
+ if not line.strip():
65
+ continue
66
+ try:
67
+ entry = json.loads(line)
68
+ except json.JSONDecodeError as error:
69
+ raise ValueError(f"{VERIFY_LEDGER_PATH} line {number} is not JSON: {error}") from error
70
+ if (
71
+ not isinstance(entry, dict)
72
+ or not isinstance(entry.get("command"), str)
73
+ or not isinstance(entry.get("commit"), str)
74
+ or entry.get("result") not in VERIFY_RESULTS
75
+ or not isinstance(entry.get("recorded_at"), str)
76
+ ):
77
+ raise ValueError(f"{VERIFY_LEDGER_PATH} line {number} has invalid fields")
78
+ entries.append(entry)
79
+ return entries
80
+
81
+
82
+ def run_command(
83
+ *arguments: str, cwd: Optional[Path] = None
84
+ ) -> subprocess.CompletedProcess[str]:
85
+ return subprocess.run(
86
+ arguments,
87
+ cwd=cwd,
88
+ text=True,
89
+ capture_output=True,
90
+ check=False,
91
+ )
92
+
93
+
94
+ def run_git(
95
+ repo: Path, *arguments: str, input: Optional[str] = None
96
+ ) -> subprocess.CompletedProcess[str]:
97
+ return subprocess.run(
98
+ ("git", "-C", str(repo), *arguments),
99
+ input=input,
100
+ text=True,
101
+ capture_output=True,
102
+ check=False,
103
+ )
104
+
105
+
106
+ def atomic_replace(path: Path, temporary_path: Path, content: str) -> None:
107
+ temporary_path.parent.mkdir(parents=True, exist_ok=True)
108
+ descriptor = None
109
+ try:
110
+ if temporary_path.exists() or temporary_path.is_symlink():
111
+ temporary_path.unlink()
112
+ descriptor = os.open(
113
+ temporary_path,
114
+ os.O_WRONLY | os.O_CREAT | os.O_EXCL,
115
+ 0o666,
116
+ )
117
+ handle = os.fdopen(descriptor, "w", encoding="utf-8")
118
+ descriptor = None
119
+ with handle:
120
+ handle.write(content)
121
+ os.replace(temporary_path, path)
122
+ finally:
123
+ if descriptor is not None:
124
+ os.close(descriptor)
125
+ if temporary_path.exists() or temporary_path.is_symlink():
126
+ temporary_path.unlink()
127
+
128
+
129
+ def atomic_write(path: Path, content: str) -> None:
130
+ atomic_replace(path, path.parent / f".{path.name}.gsd-path-tmp", content)
131
+
132
+
133
+ def strip_yaml_comment(value: str) -> str:
134
+ quote = None
135
+ previous_significant = None
136
+ inline_list = value.lstrip().startswith("[")
137
+ index = 0
138
+ while index < len(value):
139
+ character = value[index]
140
+ if quote == '"':
141
+ if character == "\\" and index + 1 < len(value):
142
+ index += 2
143
+ continue
144
+ if character == quote:
145
+ quote = None
146
+ elif quote == "'":
147
+ if (
148
+ character == quote
149
+ and index + 1 < len(value)
150
+ and value[index + 1] == quote
151
+ ):
152
+ index += 2
153
+ continue
154
+ if character == quote:
155
+ quote = None
156
+ else:
157
+ if character in {"'", '"'} and (
158
+ previous_significant is None
159
+ or (inline_list and previous_significant in {"[", ","})
160
+ ):
161
+ quote = character
162
+ elif character == "#" and (
163
+ index == 0 or value[index - 1].isspace()
164
+ ):
165
+ return value[:index].rstrip()
166
+ if quote is None and not character.isspace():
167
+ previous_significant = character
168
+ index += 1
169
+ return value.strip()
170
+
171
+
172
+ def unquote(value: str) -> str:
173
+ cleaned = strip_yaml_comment(value).strip()
174
+ if (
175
+ len(cleaned) >= 2
176
+ and cleaned[0] == cleaned[-1]
177
+ and cleaned[0] in {"'", '"'}
178
+ ):
179
+ return cleaned[1:-1]
180
+ return cleaned