@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,50 @@
1
+ # Charter — <program name>
2
+
3
+ <!-- Written by $gsd-path-define program mode. Enduring program intent:
4
+ vetoes and constraints here override every milestone. Amended only by an
5
+ explicit user ruling recorded under Corrections. Lives at .project/
6
+ top level and persists across milestones; it never archives. -->
7
+
8
+ Review panel: off <!-- off | detected | claude,gpt,grok,composer,gemini,
9
+ deepseek,kimi,qwen — durable
10
+ program default for optional cross-model plan and
11
+ wave review. Milestone INTENT copies this value and
12
+ may override it. off is the default. Named values
13
+ name at most 3 families. -->
14
+
15
+ ## Vision
16
+
17
+ <2–4 sentences: the program's end state and why it matters.>
18
+
19
+ ## Full scope: in
20
+
21
+ <!-- Everything the program will deliver, grouped by capability area. The
22
+ roadmap slices this list; every item must map to at least one milestone. -->
23
+ - <capability area>: <what it includes>
24
+
25
+ ## Full scope: out (vetoes)
26
+
27
+ <!-- Hard limits. No milestone, research dispatch, plan, or task may include
28
+ these. -->
29
+ - <vetoed item> — <user's stated reason, verbatim where possible>
30
+
31
+ ## Constraints
32
+
33
+ <Program-level stack, budget, deadline, integrations, compliance.>
34
+
35
+ ## Program success criteria
36
+
37
+ <!-- Observable statements checked when the last milestone ships. -->
38
+ 1. <criterion — a thing you can run/measure/see>
39
+
40
+ ## Open questions
41
+
42
+ <!-- Unresolved at program define end. Tags: RESEARCH (program research
43
+ answers it), NEEDS-USER (a human decision, surface at next checkpoint). -->
44
+ - [RESEARCH] <question>
45
+ - [NEEDS-USER] <question>
46
+
47
+ ## Corrections
48
+
49
+ <!-- Verbatim user rulings that amend this charter. Append-only. -->
50
+ - <date>: "<what the user said>"
@@ -0,0 +1,98 @@
1
+ # Intent — <project name>
2
+
3
+ <!-- Written by $gsd-path-define. Every downstream agent reads this first.
4
+ Constraints and vetoes here override everything downstream. -->
5
+
6
+ Lane: standard <!-- standard | quick | milestone — quick: at most two
7
+ deliverable-sized tasks in one wave, no RESEARCH or
8
+ NEEDS-USER items, no cross-wave risk; set by define at
9
+ approval. Quick skips research and decide. Milestone:
10
+ derived from an approved ROADMAP.md entry in a program;
11
+ research/decide run only when the entry has open
12
+ questions. -->
13
+
14
+ Review panel: off <!-- off | detected | claude,gpt,grok,composer,gemini,deepseek,kimi,qwen — this
15
+ milestone's panel setting. In program flow, copy
16
+ CHARTER.md's durable default and override only when
17
+ the user says so. off is the default. detected uses
18
+ advertised host families except the parent, at most 3.
19
+ Named families are an assertion, at most 3. Quick
20
+ lane stays off. -->
21
+
22
+ Finding skeptics: off <!-- off | on — build spawns one read-only skeptic
23
+ per blocking deep-review finding before fix tasks
24
+ are opened; a refuted finding spawns no fix task unless
25
+ the user explicitly overrides all cycle refutations.
26
+ off is the default. Quick lane stays off. -->
27
+
28
+ Surfaces: none <!-- none | comma-separated list of the human-facing
29
+ surfaces this milestone delivers: a web app, a CLI, an
30
+ HTTP API. Anything a person opens, sees, or types into
31
+ is a surface. Use none only when nobody touches this
32
+ work directly — a library, a migration, internals.
33
+ Every named surface needs a success criterion
34
+ observable there and a PLAN.md Surface contract. -->
35
+
36
+ ## Summary
37
+
38
+ <3–5 sentences: the problem, who has it, what the first release does. This is the
39
+ paragraph the user signed off on — do not edit without a new sign-off.>
40
+
41
+ ## Problem
42
+
43
+ <What hurts today, for whom, how badly. Evidence if the user gave any.>
44
+
45
+ ## Users
46
+
47
+ <Who, how many, how technical, what they use today.>
48
+
49
+ ## Success criteria
50
+
51
+ <!-- Observable statements, numbered from 1. PLAN.md maps each to a task
52
+ AC and Verify as SC1, SC2, …. Wave review checks the SCs a wave owns.
53
+ Final review checks every SC.
54
+ Every surface named above needs at least one criterion a person can
55
+ observe at that surface — a screen reached, an output seen — never a
56
+ passing test standing in for the experience. -->
57
+ 1. <criterion — a thing you can run/measure/see>
58
+ 2. ...
59
+
60
+ ## Scope: in
61
+
62
+ <The smallest version that hits the success criteria. Bullet list.>
63
+
64
+ ## Scope: out (vetoes)
65
+
66
+ <!-- Hard constraints. Nothing in research, plans, or tasks may include these. -->
67
+ - <vetoed item> — <user's stated reason, verbatim where possible>
68
+
69
+ ## Constraints
70
+
71
+ <Stack preferences, deadline, budget, existing code, integrations, compliance.>
72
+
73
+ ## Current state (brownfield only)
74
+
75
+ <!-- Filled from evidence-codebase.md during brownfield define. Omit the
76
+ section entirely for greenfield projects. -->
77
+ - **What exists**: <stack, architecture, maturity in 2–3 sentences>
78
+ - **Must not break**: <existing behavior the user ruled protected — these are vetoes>
79
+ - **Doc-vs-code rulings**: <each DOCS-AUDIT conflict → user's ruling: fix-doc | fix-code | accept-drift>
80
+ - **Ground truth**: `<track>/research/evidence-codebase.md`, `<track>/research/DOCS-AUDIT.md`
81
+
82
+ ## Risks
83
+
84
+ <!-- What the user is most unsure about. Research prioritizes these. -->
85
+ - <risk>
86
+
87
+ ## Open questions
88
+
89
+ <!-- Unresolved at define end. Tags: RESEARCH (research phase answers it),
90
+ NEEDS-USER (a human decision, surface at next checkpoint). -->
91
+ - [RESEARCH] <question>
92
+ - [NEEDS-USER] <question>
93
+
94
+ ## Corrections
95
+
96
+ <!-- Verbatim user corrections from playback and later phases. Append-only.
97
+ These are the highest-signal intent data in the file. -->
98
+ - <date>: "<what the user said>"
@@ -0,0 +1,27 @@
1
+ ---
2
+ pipeline: gsd-path/v2
3
+ project: <slug>
4
+ milestone: null # set by define; names the archive directory at ship
5
+ phase: define # v2 tokens: inspect | define | research | decide | roadmap | plan | build | ship | shipped
6
+ # inspect only for brownfield; greenfield starts at define
7
+ # roadmap only in program flow (CHARTER.md exists)
8
+ status: active # active | done | blocked; shipped is only phase: shipped + status: done
9
+ branch: null # bound per milestone as gsd-path/M00N; after integration
10
+ # the router rebinds before any next-milestone file change
11
+ # the bound branch is never main; ship integrates it there
12
+ archive: null # persisted archive transaction path; never recomputed
13
+ integration_default: direct # direct | pull-request; project setting
14
+ integration: direct # current milestone; may override the default before build
15
+ integration_source: default # default | milestone; preserves override provenance
16
+ ---
17
+
18
+ # Project State
19
+
20
+ One file, always current. The router reads this first; every phase updates
21
+ it on completion. If this file and the artifacts disagree, the artifacts win
22
+ — fix this file.
23
+
24
+ ## Log
25
+
26
+ <!-- append one line per transition: date, phase, event -->
27
+ - YYYY-MM-DD — <phase> — project initialized
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: gsd-path-discuss
3
+ description: Hold an explicit, evidence-grounded discussion about an active GSD Path milestone from any phase, preserve the verbatim dialogue and answer records under .project/discuss/, use local code and existing artifacts before focused research, challenge unsupported assumptions, and identify the phase owner for follow-up. Use only when the user explicitly invokes $gsd-path-discuss to ask questions, explore a decision, request a progress explanation, or close a discussion without advancing the pipeline.
4
+ ---
5
+
6
+ # GSD Path Discussion
7
+
8
+ Use this skill as an interruptible sidecar to the active GSD Path pipeline. Keep
9
+ the conversation in the main user thread, ground claims in the repository and
10
+ the current phase artifacts, and save the exchange before returning the answer.
11
+
12
+ Routing instructions are caller handoffs under the AGENTS.md handoff rule;
13
+ tell the user which phase owns the follow-up and never invoke it yourself.
14
+
15
+ ## Preconditions and ownership
16
+
17
+ 1. Resolve the project root from the working directory. Read `AGENTS.md`,
18
+ `WORKFLOW.md`, and `.project/STATE.md` before answering.
19
+ 2. Require a real `.project/STATE.md` whose frontmatter contains
20
+ `pipeline: gsd-path/v2`. If it is missing, foreign, malformed, or a
21
+ symlink, stop and tell the user to invoke `$gsd-path` for ownership recovery.
22
+ Do not create state merely to hold a discussion.
23
+ 3. Accept any active milestone phase except `shipped`: inspect,
24
+ define, research, decide, roadmap, plan, build, or ship. Use the
25
+ state status currently recorded on disk. A shipped milestone is archived and must not be
26
+ reopened by this sidecar; start a new milestone first.
27
+ 4. Resolve the bundled `scripts/discussion_records.py`,
28
+ [dialogue template](templates/dialogue.md), and
29
+ [answers template](templates/answers.md) to absolute paths. Run its `prepare`
30
+ command with the absolute repository and template paths before reading any
31
+ records. This deterministic helper validates STATE ownership, locks STATE,
32
+ recovers interrupted paired appends, restores an uncommitted review archive
33
+ without editing it, creates the exact record pair when absent, and fails on
34
+ stale or malformed state. Do not reproduce those operations manually.
35
+ 5. Read only the helper-returned absolute DIALOGUE.md and ANSWERS.md paths.
36
+ 6. Do not change `STATE.md`, phase status, `INTENT.md`, `SYNTHESIS.md`,
37
+ `PLAN.md`, task frontmatter, review verdicts, or archive
38
+ contents. Discussion can propose a change and name its owner; the owning
39
+ phase must apply it through its normal gate.
40
+
41
+ The helper serializes writers and rechecks STATE immediately before a paired
42
+ publication. Never commit the records: the current phase orchestrator is their
43
+ checkpoint owner and includes them as append-only bookkeeping in its next
44
+ normal `.project/` checkpoint. The answer's named next owner separately owns
45
+ the target artifact and disposition receipt.
46
+
47
+ ## Grounding and pushback
48
+
49
+ Use the authority order from `AGENTS.md`:
50
+
51
+ - Treat the user's current words as the question, but treat intent vetoes and
52
+ recorded corrections as hard constraints.
53
+ - Treat settled synthesis decisions and the current plan/task contract as
54
+ governing phase inputs. Surface a conflict; never average sources or quietly
55
+ override a gate.
56
+ - Inspect the relevant implementation, callers, tests, and phase artifacts.
57
+ Use search to locate evidence, then read the code or run an allowed,
58
+ meaningful check before claiming behavior. Cite exact repository paths and
59
+ line numbers when practical. Never describe an unrun command as passing.
60
+ - Separate observed fact, inference, recommendation, and user decision. If the
61
+ premise is weak, push back plainly with the evidence and explain the smallest
62
+ safer alternative.
63
+
64
+ Read only the phase-specific inputs needed for the question:
65
+
66
+ | Phase | Start with |
67
+ | --- | --- |
68
+ | inspect | codebase map and docs audit |
69
+ | define | intent and inspection evidence |
70
+ | research | intent, research manifest, and relevant evidence |
71
+ | decide | intent, evidence, and synthesis |
72
+ | roadmap | charter, program synthesis, and the roadmap |
73
+ | `plan` | intent, synthesis, plan, and affected task contracts |
74
+ | `build` | intent, synthesis, plan, task frontmatter/logs, wave reviews, and STATE log |
75
+ | ship | intent, plan, task frontmatter, STATE log, and relevant review artifacts |
76
+
77
+ Then inspect the code that can prove or disprove the claim. Do not reread the
78
+ whole repository when a focused path set answers the question.
79
+
80
+ ## Focused research
81
+
82
+ Use existing `.project/research/` evidence first. If the question depends on a
83
+ current external fact, an unfamiliar library behavior, or an unresolved intent
84
+ risk, perform focused research during the discussion when the required search
85
+ or source-reading capability is available. Record the query/scope, checked
86
+ sources, and confidence in the answer record.
87
+
88
+ Do not launch the full `$gsd-path-research` phase from this sidecar. That phase
89
+ owns a legal state transition and a gated `RESEARCH.md` handoff; invoking it
90
+ from an arbitrary phase would bypass the pipeline contract. If the result must
91
+ become formal milestone evidence, record a `[RESEARCH]` follow-up and name
92
+ `gsd-path-research` as the next owner. If research is unavailable, mark the
93
+ answer `NEEDS-USER` or `unverifiable` instead of filling the gap from memory.
94
+
95
+ ## Discussion loop
96
+
97
+ For each invocation:
98
+
99
+ 1. Identify the current phase/status and discussion thread. Run the helper's
100
+ `threads` command to list existing thread ids, topics, and statuses; do not
101
+ parse DIALOGUE.md for them. Reuse a stable thread id
102
+ (`T###`) when the user is continuing a topic; request `new` for a
103
+ distinct topic and let the helper allocate its id. Classify the
104
+ request as a fact check, diagnosis, decision, challenge, progress question,
105
+ or follow-up request.
106
+ 2. Gather the smallest sufficient local evidence, then focused research only
107
+ when needed. Record conflicts and uncertainty before forming a conclusion.
108
+ 3. Answer in the main conversation. State the conclusion first, then the
109
+ reasoning, evidence, pushback or alternatives, confidence, and the phase
110
+ owner for any action. When a formal follow-up is required, tell the user to
111
+ invoke `$gsd-path`; the router will route the pending answer to that owner.
112
+ Do not leave the user with only an owner name or direct phase command. Ask
113
+ only the next question required to resolve the user's decision; use the
114
+ host's interactive input facility when available.
115
+ 4. Before returning, provide the semantic turn fields to the helper's `append`
116
+ command as one JSON object via `--input`, passing the same absolute template
117
+ paths as `prepare`. The object requires these non-empty fields:
118
+ `topic`, `user`, `assistant`,
119
+ `question`, `status`, `thread_status`, `conclusion`, `reasoning`,
120
+ `evidence`, `research`, `confidence`, `unresolved`, `next_owner`,
121
+ `target_artifact`, and `follow_up`. `thread` is optional: pass an existing
122
+ `T###` id to continue a thread, or omit it (or pass `new`) to let the
123
+ helper allocate the next thread id. An optional `date` field overrides the
124
+ record date (`YYYY-MM-DD`). Every listed field except `user` and
125
+ `assistant` must be a single line; the helper rejects an incomplete payload
126
+ and names every missing or multi-line field in one error. The helper allocates D/A ids,
127
+ reply and supersession links, records the current phase/status, and publishes
128
+ DIALOGUE.md and ANSWERS.md as a recoverable pair. Preserve the user's message
129
+ and returned assistant answer verbatim in `user` and `assistant`.
130
+ 5. Use `working` only when the answer is explicitly
131
+ provisional or asks another question, `NEEDS-USER` when a human choice or
132
+ missing evidence blocks it, and `final` when it resolves the bounded question
133
+ or the user accepts/closes the thread. Set `Follow-up: required` only when a
134
+ named phase must update the named target artifact; otherwise use `none`. A
135
+ final answer record is durable context, not approval to advance a phase.
136
+
137
+ If the user corrects a fact, sets a veto, or makes a decision, preserve the
138
+ words verbatim in both the dialogue and answer records and identify which
139
+ formal artifact the owning phase must update. Such a record uses `Follow-up:
140
+ required`; it remains pending until the owner appends a fixed-format
141
+ `Disposition X###` receipt. The discussion sidecar never writes its own
142
+ disposition. After a helper failure, do not claim the dialogue or answer was
143
+ saved; the next `prepare` recovers an interrupted paired publication before
144
+ accepting another turn.
145
+
146
+ ## Output contract
147
+
148
+ Every completed turn leaves these project-local artifacts:
149
+
150
+ - `.project/discuss/DIALOGUE.md` — append-only transcript of the exchange.
151
+ - `.project/discuss/ANSWERS.md` — append-only answer and decision records,
152
+ with final answers clearly marked `final`.
153
+
154
+ Keep answer records concise but self-contained: question, phase/status,
155
+ conclusion, reasoning or pushback, evidence/citations, research used or why it
156
+ was not needed, confidence, unresolved tags, next owner, target artifact, and
157
+ follow-up state. Do not duplicate a formal phase handoff or silently edit one
158
+ on the user's behalf. End the user response with **Outcome**, Markdown
159
+ **Review** links to the resolved absolute DIALOGUE.md and ANSWERS.md paths. For
160
+ a required follow-up, **Next** names the pending owner and tells the user to
161
+ invoke `$gsd-path`; otherwise it gives the next discussion question or says
162
+ that no action is required.
@@ -0,0 +1,6 @@
1
+ interface:
2
+ display_name: "GSD Path Discussion"
3
+ short_description: "Discuss any phase with durable answers"
4
+ default_prompt: "Use $gsd-path-discuss to reason through this GSD Path question and save the dialogue and final answer."
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