@opengsd/gsd-path 1.0.0 → 1.1.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 (395) hide show
  1. package/AGENTS.md +28 -11
  2. package/DOCS.md +6 -5
  3. package/FULL.md +9 -13
  4. package/QUICK.md +3 -3
  5. package/README.md +151 -14
  6. package/RUNTIME.md +7 -1
  7. package/WORKFLOW.md +30 -14
  8. package/package.json +15 -1
  9. package/platforms/shared-agents/dispatch.md +6 -0
  10. package/scripts/archive_milestone.py +10 -118
  11. package/scripts/bootstrap_repository.py +25 -3
  12. package/scripts/build_recovery.py +287 -0
  13. package/scripts/check_docs_audit.py +5 -3
  14. package/scripts/check_handoffs.py +1 -1
  15. package/scripts/detect_project.py +11 -2
  16. package/scripts/dispatch_driver.py +4 -2
  17. package/scripts/git_guard.py +2 -1
  18. package/scripts/install.mjs +2 -0
  19. package/scripts/install.py +2 -0
  20. package/scripts/integration.py +28 -22
  21. package/scripts/isolation.py +9 -1
  22. package/scripts/lean_verification.py +1 -1
  23. package/scripts/pipeline_diagnose.py +12 -3
  24. package/scripts/pipeline_state.py +114 -186
  25. package/scripts/pipeline_undo.py +11 -7
  26. package/scripts/promote_lookahead.py +30 -162
  27. package/scripts/roadmap.py +321 -0
  28. package/scripts/skill-resources.json +79 -1
  29. package/scripts/state_checkpoint.py +109 -72
  30. package/scripts/state_promote.py +42 -44
  31. package/scripts/task_context.py +73 -0
  32. package/scripts/token_budget.py +40 -1
  33. package/scripts/workflow_run.py +116 -7
  34. package/skills/gsd-path/BUILD.md +47 -575
  35. package/skills/gsd-path/DECIDE.md +2 -6
  36. package/skills/gsd-path/DEFINE.md +10 -14
  37. package/skills/gsd-path/INSPECT.md +30 -8
  38. package/skills/gsd-path/PLAN.md +25 -17
  39. package/skills/gsd-path/RESEARCH.md +3 -6
  40. package/skills/gsd-path/ROADMAP.md +22 -58
  41. package/skills/gsd-path/SHIP.md +5 -4
  42. package/skills/gsd-path/SKILL.md +24 -14
  43. package/skills/gsd-path/references/build-abandon.md +33 -0
  44. package/skills/gsd-path/references/build-native.md +494 -0
  45. package/skills/gsd-path/references/build-recovery.md +78 -0
  46. package/skills/gsd-path/references/coder.md +8 -3
  47. package/skills/gsd-path/references/dispatch.md +6 -0
  48. package/skills/gsd-path/references/docs-auditor.md +14 -0
  49. package/skills/gsd-path/references/reviewer-final.md +21 -0
  50. package/skills/gsd-path/references/reviewer-panel.md +17 -0
  51. package/skills/gsd-path/references/reviewer-skeptic.md +20 -0
  52. package/skills/gsd-path/references/reviewer-wave.md +89 -0
  53. package/skills/gsd-path/references/reviewer.md +12 -150
  54. package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  55. package/skills/gsd-path/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  56. package/skills/gsd-path/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
  57. package/skills/gsd-path/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
  58. package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  59. package/skills/gsd-path/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
  60. package/skills/gsd-path/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  61. package/skills/gsd-path/scripts/__pycache__/discussion_records.cpython-312.pyc +0 -0
  62. package/skills/gsd-path/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  63. package/skills/gsd-path/scripts/__pycache__/integration.cpython-312.pyc +0 -0
  64. package/skills/gsd-path/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  65. package/skills/gsd-path/scripts/__pycache__/loop_run.cpython-312.pyc +0 -0
  66. package/skills/gsd-path/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  67. package/skills/gsd-path/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  68. package/skills/gsd-path/scripts/__pycache__/review_findings.cpython-312.pyc +0 -0
  69. package/skills/gsd-path/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  70. package/skills/gsd-path/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  71. package/skills/gsd-path/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  72. package/skills/gsd-path/scripts/__pycache__/task_context.cpython-312.pyc +0 -0
  73. package/skills/gsd-path/scripts/__pycache__/workflow_run.cpython-312.pyc +0 -0
  74. package/skills/gsd-path/scripts/archive_milestone.py +10 -118
  75. package/skills/gsd-path/scripts/bootstrap_repository.py +25 -3
  76. package/skills/gsd-path/scripts/build_recovery.py +287 -0
  77. package/skills/gsd-path/scripts/check_docs_audit.py +5 -3
  78. package/skills/gsd-path/scripts/check_handoffs.py +1 -1
  79. package/skills/gsd-path/scripts/detect_project.py +11 -2
  80. package/skills/gsd-path/scripts/dispatch_driver.py +4 -2
  81. package/skills/gsd-path/scripts/integration.py +28 -22
  82. package/skills/gsd-path/scripts/isolation.py +9 -1
  83. package/skills/gsd-path/scripts/lean_verification.py +1 -1
  84. package/skills/gsd-path/scripts/pipeline_state.py +114 -186
  85. package/skills/gsd-path/scripts/promote_lookahead.py +30 -162
  86. package/skills/gsd-path/scripts/roadmap.py +321 -0
  87. package/skills/gsd-path/scripts/state_checkpoint.py +109 -72
  88. package/skills/gsd-path/scripts/state_promote.py +42 -44
  89. package/skills/gsd-path/scripts/task_context.py +73 -0
  90. package/skills/gsd-path/scripts/token_budget.py +40 -1
  91. package/skills/gsd-path/scripts/workflow_run.py +116 -7
  92. package/skills/gsd-path/templates/wave-review.md +1 -1
  93. package/skills/gsd-path-build/SKILL.md +47 -575
  94. package/skills/gsd-path-build/references/build-abandon.md +33 -0
  95. package/skills/gsd-path-build/references/build-native.md +494 -0
  96. package/skills/gsd-path-build/references/build-recovery.md +78 -0
  97. package/skills/gsd-path-build/references/coder.md +8 -3
  98. package/skills/gsd-path-build/references/dispatch.md +6 -0
  99. package/skills/gsd-path-build/references/reviewer-final.md +21 -0
  100. package/skills/gsd-path-build/references/reviewer-panel.md +17 -0
  101. package/skills/gsd-path-build/references/reviewer-skeptic.md +20 -0
  102. package/skills/gsd-path-build/references/reviewer-wave.md +89 -0
  103. package/skills/gsd-path-build/references/reviewer.md +12 -150
  104. package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  105. package/skills/gsd-path-build/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  106. package/skills/gsd-path-build/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
  107. package/skills/gsd-path-build/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
  108. package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  109. package/skills/gsd-path-build/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
  110. package/skills/gsd-path-build/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  111. package/skills/gsd-path-build/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  112. package/skills/gsd-path-build/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  113. package/skills/gsd-path-build/scripts/__pycache__/loop_run.cpython-312.pyc +0 -0
  114. package/skills/gsd-path-build/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  115. package/skills/gsd-path-build/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  116. package/skills/gsd-path-build/scripts/__pycache__/review_findings.cpython-312.pyc +0 -0
  117. package/skills/gsd-path-build/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  118. package/skills/gsd-path-build/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  119. package/skills/gsd-path-build/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  120. package/skills/gsd-path-build/scripts/__pycache__/task_context.cpython-312.pyc +0 -0
  121. package/skills/gsd-path-build/scripts/__pycache__/workflow_run.cpython-312.pyc +0 -0
  122. package/skills/gsd-path-build/scripts/archive_milestone.py +10 -118
  123. package/skills/gsd-path-build/scripts/build_recovery.py +287 -0
  124. package/skills/gsd-path-build/scripts/check_handoffs.py +1 -1
  125. package/skills/gsd-path-build/scripts/detect_project.py +1526 -0
  126. package/skills/gsd-path-build/scripts/dispatch_driver.py +4 -2
  127. package/skills/gsd-path-build/scripts/integration.py +28 -22
  128. package/skills/gsd-path-build/scripts/isolation.py +9 -1
  129. package/skills/gsd-path-build/scripts/pipeline_state.py +114 -186
  130. package/skills/gsd-path-build/scripts/promote_lookahead.py +283 -0
  131. package/skills/gsd-path-build/scripts/roadmap.py +321 -0
  132. package/skills/gsd-path-build/scripts/state_checkpoint.py +109 -72
  133. package/skills/gsd-path-build/scripts/state_promote.py +42 -44
  134. package/skills/gsd-path-build/scripts/task_context.py +73 -0
  135. package/skills/gsd-path-build/scripts/token_budget.py +40 -1
  136. package/skills/gsd-path-build/scripts/workflow_run.py +116 -7
  137. package/skills/gsd-path-build/templates/wave-review.md +1 -1
  138. package/skills/gsd-path-decide/SKILL.md +2 -6
  139. package/skills/gsd-path-decide/references/dispatch.md +6 -0
  140. package/skills/gsd-path-decide/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  141. package/skills/gsd-path-decide/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  142. package/skills/gsd-path-decide/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  143. package/skills/gsd-path-decide/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  144. package/skills/gsd-path-decide/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  145. package/skills/gsd-path-decide/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  146. package/skills/gsd-path-decide/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  147. package/skills/gsd-path-decide/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  148. package/skills/gsd-path-decide/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  149. package/skills/gsd-path-decide/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  150. package/skills/gsd-path-decide/scripts/archive_milestone.py +2157 -0
  151. package/skills/gsd-path-decide/scripts/build_recovery.py +287 -0
  152. package/skills/gsd-path-decide/scripts/check_handoffs.py +1 -1
  153. package/skills/gsd-path-decide/scripts/detect_project.py +1526 -0
  154. package/skills/gsd-path-decide/scripts/discussion_validate.py +1321 -0
  155. package/skills/gsd-path-decide/scripts/integration.py +1439 -0
  156. package/skills/gsd-path-decide/scripts/isolation.py +9 -1
  157. package/skills/gsd-path-decide/scripts/pipeline_state.py +114 -186
  158. package/skills/gsd-path-decide/scripts/promote_lookahead.py +283 -0
  159. package/skills/gsd-path-decide/scripts/review_panel.py +553 -0
  160. package/skills/gsd-path-decide/scripts/roadmap.py +321 -0
  161. package/skills/gsd-path-decide/scripts/state_checkpoint.py +109 -72
  162. package/skills/gsd-path-decide/scripts/state_promote.py +42 -44
  163. package/skills/gsd-path-define/SKILL.md +10 -14
  164. package/skills/gsd-path-define/references/build-recovery.md +78 -0
  165. package/skills/gsd-path-define/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  166. package/skills/gsd-path-define/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  167. package/skills/gsd-path-define/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  168. package/skills/gsd-path-define/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  169. package/skills/gsd-path-define/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  170. package/skills/gsd-path-define/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  171. package/skills/gsd-path-define/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  172. package/skills/gsd-path-define/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  173. package/skills/gsd-path-define/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  174. package/skills/gsd-path-define/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  175. package/skills/gsd-path-define/scripts/archive_milestone.py +2157 -0
  176. package/skills/gsd-path-define/scripts/build_recovery.py +287 -0
  177. package/skills/gsd-path-define/scripts/check_handoffs.py +1 -1
  178. package/skills/gsd-path-define/scripts/detect_project.py +11 -2
  179. package/skills/gsd-path-define/scripts/discussion_validate.py +1321 -0
  180. package/skills/gsd-path-define/scripts/integration.py +1439 -0
  181. package/skills/gsd-path-define/scripts/isolation.py +9 -1
  182. package/skills/gsd-path-define/scripts/pipeline_state.py +114 -186
  183. package/skills/gsd-path-define/scripts/promote_lookahead.py +283 -0
  184. package/skills/gsd-path-define/scripts/review_panel.py +553 -0
  185. package/skills/gsd-path-define/scripts/roadmap.py +321 -0
  186. package/skills/gsd-path-define/scripts/state_checkpoint.py +109 -72
  187. package/skills/gsd-path-define/scripts/state_promote.py +42 -44
  188. package/skills/gsd-path-docs-audit/references/dispatch.md +6 -0
  189. package/skills/gsd-path-docs-audit/references/docs-auditor.md +14 -0
  190. package/skills/gsd-path-docs-audit/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  191. package/skills/gsd-path-docs-audit/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  192. package/skills/gsd-path-docs-audit/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
  193. package/skills/gsd-path-docs-audit/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  194. package/skills/gsd-path-docs-audit/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  195. package/skills/gsd-path-docs-audit/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  196. package/skills/gsd-path-docs-audit/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  197. package/skills/gsd-path-docs-audit/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  198. package/skills/gsd-path-docs-audit/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  199. package/skills/gsd-path-docs-audit/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  200. package/skills/gsd-path-docs-audit/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  201. package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +2157 -0
  202. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +287 -0
  203. package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +5 -3
  204. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +1 -1
  205. package/skills/gsd-path-docs-audit/scripts/detect_project.py +1526 -0
  206. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +1321 -0
  207. package/skills/gsd-path-docs-audit/scripts/integration.py +1439 -0
  208. package/skills/gsd-path-docs-audit/scripts/isolation.py +9 -1
  209. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +114 -186
  210. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +283 -0
  211. package/skills/gsd-path-docs-audit/scripts/review_panel.py +553 -0
  212. package/skills/gsd-path-docs-audit/scripts/roadmap.py +321 -0
  213. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +109 -72
  214. package/skills/gsd-path-docs-audit/scripts/state_promote.py +42 -44
  215. package/skills/gsd-path-forensics/scripts/__pycache__/pipeline_undo.cpython-312.pyc +0 -0
  216. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +12 -3
  217. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +11 -7
  218. package/skills/gsd-path-inspect/SKILL.md +30 -8
  219. package/skills/gsd-path-inspect/references/dispatch.md +6 -0
  220. package/skills/gsd-path-inspect/references/docs-auditor.md +14 -0
  221. package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  222. package/skills/gsd-path-inspect/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  223. package/skills/gsd-path-inspect/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
  224. package/skills/gsd-path-inspect/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  225. package/skills/gsd-path-inspect/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  226. package/skills/gsd-path-inspect/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  227. package/skills/gsd-path-inspect/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  228. package/skills/gsd-path-inspect/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  229. package/skills/gsd-path-inspect/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  230. package/skills/gsd-path-inspect/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  231. package/skills/gsd-path-inspect/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  232. package/skills/gsd-path-inspect/scripts/archive_milestone.py +2157 -0
  233. package/skills/gsd-path-inspect/scripts/build_recovery.py +287 -0
  234. package/skills/gsd-path-inspect/scripts/check_docs_audit.py +5 -3
  235. package/skills/gsd-path-inspect/scripts/check_handoffs.py +1 -1
  236. package/skills/gsd-path-inspect/scripts/detect_project.py +11 -2
  237. package/skills/gsd-path-inspect/scripts/discussion_validate.py +1321 -0
  238. package/skills/gsd-path-inspect/scripts/integration.py +1439 -0
  239. package/skills/gsd-path-inspect/scripts/isolation.py +9 -1
  240. package/skills/gsd-path-inspect/scripts/pipeline_state.py +114 -186
  241. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +283 -0
  242. package/skills/gsd-path-inspect/scripts/review_panel.py +553 -0
  243. package/skills/gsd-path-inspect/scripts/roadmap.py +321 -0
  244. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +109 -72
  245. package/skills/gsd-path-inspect/scripts/state_promote.py +42 -44
  246. package/skills/gsd-path-inspect/scripts/workflow_run.py +226 -0
  247. package/skills/gsd-path-plan/SKILL.md +25 -17
  248. package/skills/gsd-path-plan/references/build-recovery.md +78 -0
  249. package/skills/gsd-path-plan/references/dispatch.md +6 -0
  250. package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  251. package/skills/gsd-path-plan/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  252. package/skills/gsd-path-plan/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  253. package/skills/gsd-path-plan/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  254. package/skills/gsd-path-plan/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  255. package/skills/gsd-path-plan/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  256. package/skills/gsd-path-plan/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  257. package/skills/gsd-path-plan/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  258. package/skills/gsd-path-plan/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  259. package/skills/gsd-path-plan/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  260. package/skills/gsd-path-plan/scripts/archive_milestone.py +2157 -0
  261. package/skills/gsd-path-plan/scripts/build_recovery.py +287 -0
  262. package/skills/gsd-path-plan/scripts/check_handoffs.py +1 -1
  263. package/skills/gsd-path-plan/scripts/detect_project.py +1526 -0
  264. package/skills/gsd-path-plan/scripts/discussion_validate.py +1321 -0
  265. package/skills/gsd-path-plan/scripts/integration.py +1439 -0
  266. package/skills/gsd-path-plan/scripts/isolation.py +9 -1
  267. package/skills/gsd-path-plan/scripts/pipeline_state.py +114 -186
  268. package/skills/gsd-path-plan/scripts/promote_lookahead.py +283 -0
  269. package/skills/gsd-path-plan/scripts/roadmap.py +321 -0
  270. package/skills/gsd-path-plan/scripts/state_checkpoint.py +109 -72
  271. package/skills/gsd-path-plan/scripts/state_promote.py +42 -44
  272. package/skills/gsd-path-plan/scripts/workflow_run.py +116 -7
  273. package/skills/gsd-path-research/SKILL.md +3 -6
  274. package/skills/gsd-path-research/references/dispatch.md +6 -0
  275. package/skills/gsd-path-research/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  276. package/skills/gsd-path-research/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  277. package/skills/gsd-path-research/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  278. package/skills/gsd-path-research/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  279. package/skills/gsd-path-research/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  280. package/skills/gsd-path-research/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  281. package/skills/gsd-path-research/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  282. package/skills/gsd-path-research/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  283. package/skills/gsd-path-research/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  284. package/skills/gsd-path-research/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  285. package/skills/gsd-path-research/scripts/archive_milestone.py +2157 -0
  286. package/skills/gsd-path-research/scripts/build_recovery.py +287 -0
  287. package/skills/gsd-path-research/scripts/check_handoffs.py +1 -1
  288. package/skills/gsd-path-research/scripts/detect_project.py +1526 -0
  289. package/skills/gsd-path-research/scripts/discussion_validate.py +1321 -0
  290. package/skills/gsd-path-research/scripts/integration.py +1439 -0
  291. package/skills/gsd-path-research/scripts/isolation.py +9 -1
  292. package/skills/gsd-path-research/scripts/pipeline_state.py +114 -186
  293. package/skills/gsd-path-research/scripts/promote_lookahead.py +283 -0
  294. package/skills/gsd-path-research/scripts/review_panel.py +553 -0
  295. package/skills/gsd-path-research/scripts/roadmap.py +321 -0
  296. package/skills/gsd-path-research/scripts/state_checkpoint.py +109 -72
  297. package/skills/gsd-path-research/scripts/state_promote.py +42 -44
  298. package/skills/gsd-path-roadmap/SKILL.md +22 -58
  299. package/skills/gsd-path-roadmap/references/dispatch.md +6 -0
  300. package/skills/gsd-path-roadmap/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  301. package/skills/gsd-path-roadmap/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  302. package/skills/gsd-path-roadmap/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  303. package/skills/gsd-path-roadmap/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  304. package/skills/gsd-path-roadmap/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  305. package/skills/gsd-path-roadmap/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  306. package/skills/gsd-path-roadmap/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  307. package/skills/gsd-path-roadmap/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  308. package/skills/gsd-path-roadmap/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  309. package/skills/gsd-path-roadmap/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  310. package/skills/gsd-path-roadmap/scripts/archive_milestone.py +10 -118
  311. package/skills/gsd-path-roadmap/scripts/build_recovery.py +287 -0
  312. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +1 -1
  313. package/skills/gsd-path-roadmap/scripts/detect_project.py +11 -2
  314. package/skills/gsd-path-roadmap/scripts/integration.py +28 -22
  315. package/skills/gsd-path-roadmap/scripts/isolation.py +9 -1
  316. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +114 -186
  317. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +30 -162
  318. package/skills/gsd-path-roadmap/scripts/roadmap.py +321 -0
  319. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +109 -72
  320. package/skills/gsd-path-roadmap/scripts/state_promote.py +42 -44
  321. package/skills/gsd-path-ship/SKILL.md +5 -4
  322. package/skills/gsd-path-ship/references/dispatch.md +6 -0
  323. package/skills/gsd-path-ship/references/reviewer-final.md +21 -0
  324. package/skills/gsd-path-ship/references/reviewer-panel.md +17 -0
  325. package/skills/gsd-path-ship/references/reviewer-skeptic.md +20 -0
  326. package/skills/gsd-path-ship/references/reviewer-wave.md +89 -0
  327. package/skills/gsd-path-ship/references/reviewer.md +12 -150
  328. package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
  329. package/skills/gsd-path-ship/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
  330. package/skills/gsd-path-ship/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
  331. package/skills/gsd-path-ship/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
  332. package/skills/gsd-path-ship/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
  333. package/skills/gsd-path-ship/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
  334. package/skills/gsd-path-ship/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
  335. package/skills/gsd-path-ship/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
  336. package/skills/gsd-path-ship/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
  337. package/skills/gsd-path-ship/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
  338. package/skills/gsd-path-ship/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
  339. package/skills/gsd-path-ship/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
  340. package/skills/gsd-path-ship/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
  341. package/skills/gsd-path-ship/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
  342. package/skills/gsd-path-ship/scripts/archive_milestone.py +10 -118
  343. package/skills/gsd-path-ship/scripts/build_recovery.py +287 -0
  344. package/skills/gsd-path-ship/scripts/check_handoffs.py +1 -1
  345. package/skills/gsd-path-ship/scripts/detect_project.py +1526 -0
  346. package/skills/gsd-path-ship/scripts/integration.py +28 -22
  347. package/skills/gsd-path-ship/scripts/isolation.py +9 -1
  348. package/skills/gsd-path-ship/scripts/lean_verification.py +1 -1
  349. package/skills/gsd-path-ship/scripts/pipeline_state.py +114 -186
  350. package/skills/gsd-path-ship/scripts/promote_lookahead.py +283 -0
  351. package/skills/gsd-path-ship/scripts/roadmap.py +321 -0
  352. package/skills/gsd-path-ship/scripts/state_checkpoint.py +109 -72
  353. package/skills/gsd-path-ship/scripts/state_promote.py +42 -44
  354. package/skills/gsd-path-ship/scripts/workflow_run.py +116 -7
  355. package/skills/gsd-path-ship/templates/wave-review.md +1 -1
  356. package/skills/gsd-path-undo/scripts/pipeline_undo.py +11 -7
  357. package/skills/path/BUILD.md +47 -575
  358. package/skills/path/DECIDE.md +2 -6
  359. package/skills/path/DEFINE.md +10 -14
  360. package/skills/path/INSPECT.md +30 -8
  361. package/skills/path/PLAN.md +25 -17
  362. package/skills/path/RESEARCH.md +3 -6
  363. package/skills/path/ROADMAP.md +22 -58
  364. package/skills/path/SHIP.md +5 -4
  365. package/skills/path/SKILL.md +24 -14
  366. package/skills/path/references/build-abandon.md +33 -0
  367. package/skills/path/references/build-native.md +494 -0
  368. package/skills/path/references/build-recovery.md +78 -0
  369. package/skills/path/references/coder.md +8 -3
  370. package/skills/path/references/dispatch.md +6 -0
  371. package/skills/path/references/docs-auditor.md +14 -0
  372. package/skills/path/references/reviewer-final.md +21 -0
  373. package/skills/path/references/reviewer-panel.md +17 -0
  374. package/skills/path/references/reviewer-skeptic.md +20 -0
  375. package/skills/path/references/reviewer-wave.md +89 -0
  376. package/skills/path/references/reviewer.md +12 -150
  377. package/skills/path/scripts/archive_milestone.py +10 -118
  378. package/skills/path/scripts/bootstrap_repository.py +25 -3
  379. package/skills/path/scripts/build_recovery.py +287 -0
  380. package/skills/path/scripts/check_docs_audit.py +5 -3
  381. package/skills/path/scripts/check_handoffs.py +1 -1
  382. package/skills/path/scripts/detect_project.py +11 -2
  383. package/skills/path/scripts/dispatch_driver.py +4 -2
  384. package/skills/path/scripts/integration.py +28 -22
  385. package/skills/path/scripts/isolation.py +9 -1
  386. package/skills/path/scripts/lean_verification.py +1 -1
  387. package/skills/path/scripts/pipeline_state.py +114 -186
  388. package/skills/path/scripts/promote_lookahead.py +30 -162
  389. package/skills/path/scripts/roadmap.py +321 -0
  390. package/skills/path/scripts/state_checkpoint.py +109 -72
  391. package/skills/path/scripts/state_promote.py +42 -44
  392. package/skills/path/scripts/task_context.py +73 -0
  393. package/skills/path/scripts/token_budget.py +40 -1
  394. package/skills/path/scripts/workflow_run.py +116 -7
  395. package/skills/path/templates/wave-review.md +1 -1
@@ -0,0 +1,287 @@
1
+ # gsd-path project runtime
2
+ """Guard a blocked build's return to Define or Plan using its committed base."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+
10
+
11
+ EVENTS = {
12
+ "define": "build intent corrections requested",
13
+ "plan": "build plan repair requested",
14
+ }
15
+ MARKER = "build recovery: "
16
+
17
+
18
+ def runtime():
19
+ if __package__:
20
+ from scripts import pipeline_state
21
+ else:
22
+ import pipeline_state
23
+ return pipeline_state
24
+
25
+
26
+ def checkpoint_runtime():
27
+ if __package__:
28
+ from scripts import state_checkpoint
29
+ else:
30
+ import state_checkpoint
31
+ return state_checkpoint
32
+
33
+
34
+ def context(repo: Path, text: str | None = None) -> dict | None:
35
+ state = runtime()
36
+ current, loaded, _ = state.load_state(repo)
37
+ text = loaded if text is None else text
38
+ recovery = None
39
+ for line in text.splitlines():
40
+ if " — " not in line:
41
+ continue
42
+ event = line.split(" — ", 2)[-1]
43
+ if event.startswith(MARKER):
44
+ try:
45
+ value = json.loads(event[len(MARKER):])
46
+ except ValueError as error:
47
+ raise state.PipelineStateError("invalid build recovery record") from error
48
+ if (not isinstance(value, dict) or set(value) != {"base", "branch", "kind"}
49
+ or value["kind"] not in EVENTS
50
+ or not isinstance(value["base"], str)
51
+ or not re.fullmatch(r"[0-9a-f]{40}", value["base"])):
52
+ raise state.PipelineStateError("invalid build recovery record")
53
+ recovery = {**value, "active": True} if value["branch"] == current.branch else None
54
+ elif event == "build started" and recovery:
55
+ recovery["active"] = False
56
+ if recovery:
57
+ if not state._is_ancestor(repo, recovery["base"], "HEAD"):
58
+ raise state.PipelineStateError("build recovery base is not an ancestor of HEAD")
59
+ source = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/STATE.md")
60
+ if source is None:
61
+ raise state.PipelineStateError("build recovery base has no STATE.md")
62
+ before = state._state_from_text(source)
63
+ if ((before.phase, before.status) != ("build", "blocked")
64
+ or before.branch != current.branch or before.milestone != current.milestone):
65
+ raise state.PipelineStateError("build recovery base does not prove this blocked milestone")
66
+ return recovery
67
+
68
+
69
+ def task_fields(text: str, label: str) -> dict:
70
+ if __package__:
71
+ from scripts.isolation import task_frontmatter
72
+ else:
73
+ from isolation import task_frontmatter
74
+ fields, error = task_frontmatter(text)
75
+ if fields is None:
76
+ raise runtime().PipelineStateError(f"{label}: {error}")
77
+ return fields
78
+
79
+
80
+ def settled_tasks(repo: Path) -> dict[str, tuple[str, dict]]:
81
+ """Read task ownership without requiring the graph that Plan must repair."""
82
+ state = runtime()
83
+ directory = repo / ".project/tasks"
84
+ if directory.is_symlink() or not directory.is_dir():
85
+ raise state.PipelineStateError("build recovery requires real task artifacts")
86
+ tasks = {}
87
+ for path in sorted(directory.iterdir()):
88
+ if not re.fullmatch(r"T[0-9]{3}-[a-z0-9][a-z0-9-]*\.md", path.name):
89
+ raise state.PipelineStateError(f"invalid recovery task path: {path.name}")
90
+ text = state._read_real_file(path, path.name)
91
+ fields = task_fields(text, path.name)
92
+ if fields.get("status") not in {"pending", "done"}:
93
+ raise state.PipelineStateError(f"settle task ownership before recovery: {path.name}")
94
+ if fields["status"] == "pending" and any(
95
+ fields.get(key) != "null" for key in ("agent", "base", "worktree", "task_branch")
96
+ ):
97
+ raise state.PipelineStateError(f"pending task retains dispatch metadata: {path.name}")
98
+ tasks[path.name] = (text, fields)
99
+ if not tasks:
100
+ raise state.PipelineStateError("build recovery requires task artifacts")
101
+ return tasks
102
+
103
+
104
+ def begin(repo: Path, before, after, event: str) -> dict:
105
+ state = runtime()
106
+ if (before.phase, before.status) != ("build", "blocked") or after.phase not in EVENTS:
107
+ raise state.PipelineStateError("build recovery requires build/blocked")
108
+ if event != EVENTS[after.phase]:
109
+ raise state.PipelineStateError(f"state transition requires event: {EVENTS[after.phase]}")
110
+ if before.archive is not None or before.branch != state._current_branch(repo):
111
+ raise state.PipelineStateError("build recovery requires the active bound branch")
112
+ if state._worktree_changes(repo):
113
+ raise state.PipelineStateError("checkpoint the blocked build before recovery")
114
+ if any(state.transaction_journals(repo).values()):
115
+ raise state.PipelineStateError("finish pending transactions before build recovery")
116
+ records = records_root(repo)
117
+ for directory in {path.parent.parent for path in records.rglob("attempt-*/state.json")}:
118
+ latest = max(directory.glob("attempt-*/state.json"), key=lambda path: int(path.parent.name.split("-")[1]))
119
+ record = state._read_json(latest)
120
+ if (record.get("cleanup_pending")
121
+ or (record.get("worktree") and record.get("branch") and not record.get("cleanup_complete"))
122
+ or record.get("outcome") not in {"landed", "collected", "blocked", "resolved", "redispatched"}):
123
+ raise state.PipelineStateError(f"settle dispatch records before recovery: {latest}")
124
+ tasks = settled_tasks(repo)
125
+ state._read_real_file(repo / ".project/plan/PLAN.md", "PLAN.md")
126
+ state._read_real_file(repo / ".project/intent/INTENT.md", "INTENT.md")
127
+ base = state._run_git(repo, "rev-parse", "HEAD").stdout.strip()
128
+ done = [repo / ".project/tasks" / name for name, (_, fields) in tasks.items()
129
+ if fields["status"] == "done"]
130
+ if done:
131
+ if __package__:
132
+ from scripts.isolation import verify_landed_task_files
133
+ else:
134
+ from isolation import verify_landed_task_files
135
+ verify_landed_task_files(repo, done, ".project/tasks", base)
136
+ return {"kind": after.phase, "base": base, "branch": before.branch}
137
+
138
+
139
+ def records_root(repo: Path) -> Path:
140
+ if __package__:
141
+ from scripts import isolation
142
+ else:
143
+ import isolation
144
+ root = isolation.common_git_dir(repo) / "gsd-path/dispatch" / isolation.require_bound(repo).replace("/", "-")
145
+ recovery = context(repo)
146
+ return root / recovery["base"] if recovery else root
147
+
148
+
149
+ def review_backup(repo: Path, recovery: dict) -> Path:
150
+ return repo / ".project/plan" / f"build-recovery-{recovery['base']}" / "review"
151
+
152
+
153
+ def validate_review_backup(repo: Path, recovery: dict, directory: Path) -> None:
154
+ state = runtime()
155
+ if directory.exists():
156
+ checkpoint_runtime()._tree_digest(directory) # Reject symlinks and special files before reading.
157
+ expected = {}
158
+ for path in state._run_git(repo, "ls-tree", "-r", "--name-only", "-z",
159
+ recovery["base"], "--", ".project/review").stdout.split("\0"):
160
+ if path:
161
+ expected[str(Path(path).relative_to(".project/review"))] = checkpoint_runtime()._git_text_at(repo, recovery["base"], path)
162
+ actual = {str(path.relative_to(directory)): path.read_text(encoding="utf-8")
163
+ for path in directory.rglob("*") if path.is_file()} if directory.exists() else {}
164
+ if actual != expected:
165
+ raise state.PipelineStateError("review backup differs from the recovery base")
166
+
167
+
168
+ def prepare(repo: Path) -> dict:
169
+ """Move old reviews once; the durable STATE record owns interruption recovery."""
170
+ state = runtime()
171
+ repo = state._repo_root(repo)
172
+ with state._state_lock(repo / ".project"):
173
+ recovery = context(repo)
174
+ if not recovery or not recovery["active"]:
175
+ raise state.PipelineStateError("no active build recovery")
176
+ target = review_backup(repo, recovery)
177
+ if (repo / ".project/plan").is_symlink() or target.parent.is_symlink() or target.is_symlink():
178
+ raise state.PipelineStateError("unsafe recovery review backup")
179
+ source = repo / ".project/review"
180
+ if source.is_symlink():
181
+ raise state.PipelineStateError("unsafe recovery review directory")
182
+ if not target.exists():
183
+ validate_review_backup(repo, recovery, source)
184
+ target.parent.mkdir(exist_ok=True)
185
+ if source.exists():
186
+ source.rename(target)
187
+ else:
188
+ target.mkdir()
189
+ validate_review_backup(repo, recovery, target)
190
+ source.mkdir(exist_ok=True)
191
+ return {"status": "prepared", "recovery": recovery, "path": str(target)}
192
+
193
+
194
+ def validate_plan(repo: Path) -> None:
195
+ state = runtime()
196
+ recovery = context(repo)
197
+ if not recovery or not recovery["active"]:
198
+ return
199
+ if not review_backup(repo, recovery).is_dir():
200
+ raise state.PipelineStateError("run prepare-build-recovery before planning")
201
+ validate_review_backup(repo, recovery, review_backup(repo, recovery))
202
+ source = checkpoint_runtime()._task_contracts_at(repo, recovery["base"], ".project/tasks")
203
+ current = settled_tasks(repo)
204
+ done = set()
205
+ for _, (path, text) in source.items():
206
+ fields = task_fields(text, path)
207
+ if fields.get("status") == "done":
208
+ name = Path(path).name
209
+ done.add(name)
210
+ if name not in current or current[name][0] != text:
211
+ raise state.PipelineStateError(f"build recovery must preserve landed task: {name}")
212
+ if any(fields["status"] == "done" and name not in done
213
+ for name, (_, fields) in current.items()):
214
+ raise state.PipelineStateError("build recovery cannot manufacture landed tasks")
215
+ if recovery["kind"] == "plan":
216
+ intent = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/intent/INTENT.md")
217
+ if state._read_real_file(repo / ".project/intent/INTENT.md", "INTENT.md") != intent:
218
+ raise state.PipelineStateError("plan repair cannot change approved intent")
219
+ unchanged = unchanged_waves(repo, recovery)
220
+ for path in (repo / ".project/review").iterdir():
221
+ match = re.match(r"wave-([1-9]\d*)[.]", path.name)
222
+ if match and int(match[1]) not in unchanged:
223
+ raise state.PipelineStateError("changed wave must be reviewed after build resumes")
224
+
225
+
226
+ def unchanged_waves(repo: Path, recovery: dict) -> set[int]:
227
+ """Reuse evidence only when its intent, wave contract, and task bytes match."""
228
+ state = runtime()
229
+ project = repo / ".project"
230
+ old_intent = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/intent/INTENT.md")
231
+ if state._read_real_file(project / "intent/INTENT.md", "INTENT.md") != old_intent:
232
+ return set()
233
+ old_plan = checkpoint_runtime()._git_text_at(repo, recovery["base"], ".project/plan/PLAN.md") or ""
234
+ new_plan = state._read_real_file(project / "plan/PLAN.md", "PLAN.md")
235
+
236
+ def sections(text):
237
+ return {match[1]: match[2] for match in re.finditer(
238
+ r"(?ms)^## ([^\n]+)\n(.*?)(?=^## |\Z)", text,
239
+ )}
240
+
241
+ old_sections, new_sections = sections(old_plan), sections(new_plan)
242
+ # Non-wave settings govern every wave, including coverage and surfaces.
243
+ if ({k: v for k, v in old_sections.items() if not k.startswith("Wave ")}
244
+ != {k: v for k, v in new_sections.items() if not k.startswith("Wave ")}):
245
+ return set()
246
+ old_tasks = checkpoint_runtime()._task_contracts_at(repo, recovery["base"], ".project/tasks")
247
+ current = settled_tasks(repo)
248
+ unchanged = set()
249
+ for title, body in new_sections.items():
250
+ match = re.match(r"Wave ([1-9]\d*)\b", title)
251
+ if not match or old_sections.get(title) != body:
252
+ continue
253
+ wave = match[1]
254
+ before = {Path(path).name: text for path, text in old_tasks.values()
255
+ if task_fields(text, path).get("wave") == wave}
256
+ after = {name: text for name, (text, fields) in current.items() if fields.get("wave") == wave}
257
+ if before and before == after:
258
+ unchanged.add(int(wave))
259
+ return unchanged
260
+
261
+
262
+ def restore_unchanged_reviews(repo: Path) -> None:
263
+ recovery = context(repo)
264
+ if not recovery or not recovery["active"]:
265
+ return
266
+ unchanged = unchanged_waves(repo, recovery)
267
+ for path in review_backup(repo, recovery).iterdir():
268
+ match = re.match(r"wave-([1-9]\d*)[.]", path.name)
269
+ if match and int(match[1]) in unchanged:
270
+ destination = repo / ".project/review" / path.name
271
+ content = path.read_text(encoding="utf-8")
272
+ if not destination.exists() or runtime()._read_real_file(destination, destination.name) != content:
273
+ runtime()._atomic_write(destination, content)
274
+
275
+
276
+ def inventory_checkpoint(repo: Path, head: str) -> bool:
277
+ state = runtime()
278
+ if state._run_git(repo, "show", "-s", "--format=%s", head).stdout.strip() != state.PLAN_APPROVAL_SUBJECT:
279
+ return False
280
+ text = checkpoint_runtime()._git_text_at(repo, head, ".project/STATE.md")
281
+ if text is None:
282
+ return False
283
+ approved = state._state_from_text(text)
284
+ if (approved.phase, approved.status) != ("plan", "done"):
285
+ return False
286
+ recovery = context(repo, text)
287
+ return bool(recovery and recovery["active"])
@@ -21,7 +21,8 @@ are rejected.
21
21
  The frozen inventory travels in the dispatch brief; pass it with
22
22
  `--inventory FILE` (one POSIX path per line, `-` for stdin). Without it the
23
23
  gate derives the inventory from tracked Markdown files, excluding `.git`,
24
- `node_modules`, `.project/archive/**`, installed `*/skills/gsd-path*` bundles,
24
+ `node_modules`, `.project/archive/**`, installed `*/skills/gsd-path*` and
25
+ `*/skills/path` bundles,
25
26
  the audit itself, and — unless the
26
27
  audit declares `Alignment mode: yes` — everything else under `.project/`.
27
28
  """
@@ -100,9 +101,10 @@ def _not_placeholder(value: str, label: str) -> None:
100
101
 
101
102
 
102
103
  def _installed_skill(parts: Sequence[str]) -> bool:
103
- """True for files inside an installed GSD Path skill bundle (<host>/skills/gsd-path*/…)."""
104
+ """Exclude installed GSD Path bundles, including the path router alias."""
104
105
  return any(
105
- parts[index] == "skills" and parts[index + 1].startswith("gsd-path")
106
+ parts[index] == "skills" and
107
+ (parts[index + 1].startswith("gsd-path") or parts[index + 1] == "path")
106
108
  for index in range(len(parts) - 2)
107
109
  )
108
110
 
@@ -1462,7 +1462,7 @@ def validate_wave_evidence(
1462
1462
  raise HandoffError(f"{name} Cycle field does not match its filename")
1463
1463
  if _line_value(text, "Depth:") != expected_depth:
1464
1464
  raise HandoffError(f"{name} Depth does not match PLAN.md")
1465
- lens_fields = re.findall(r"(?m)^Lens:\s*(\S.*?)\s*$", text)
1465
+ lens_fields = re.findall(r"(?m)^Lens:[ \t]*(\S.*?)[ \t]*$", text)
1466
1466
  if lens is None and lens_fields:
1467
1467
  raise HandoffError(f"{name} must not declare a review lens")
1468
1468
  if lens is not None and lens_fields != [lens]:
@@ -1439,7 +1439,7 @@ def write_state_anchored(
1439
1439
 
1440
1440
 
1441
1441
  def initialize(
1442
- repo: Path, template: Path, phase: Optional[str] = None
1442
+ repo: Path, template: Path, phase: Optional[str] = None, *, require_git: bool = False
1443
1443
  ) -> dict:
1444
1444
  if phase is not None and phase not in {"inspect", "define"}:
1445
1445
  raise DetectError(f"initialize phase must be inspect or define: {phase}")
@@ -1458,6 +1458,13 @@ def initialize(
1458
1458
  if payload["verdict"] not in {"brownfield", "greenfield"}:
1459
1459
  payload["wrote_state"] = False
1460
1460
  return payload
1461
+ if require_git:
1462
+ git = subprocess.run(
1463
+ ["git", "-C", str(root), "rev-parse", "--is-inside-work-tree"],
1464
+ env=git_environment(), capture_output=True, text=True, check=False,
1465
+ )
1466
+ if git.returncode != 0 or git.stdout.strip() != "true":
1467
+ return {**payload, "route": "setup-repository", "wrote_state": False}
1461
1468
  expected = "inspect" if payload["verdict"] == "brownfield" else "define"
1462
1469
  if phase is None:
1463
1470
  phase = expected
@@ -1491,6 +1498,7 @@ def parser() -> argparse.ArgumentParser:
1491
1498
  result.add_argument("--repo", type=Path, required=True)
1492
1499
  result.add_argument("--template", type=Path)
1493
1500
  result.add_argument("--phase", choices=("inspect", "define"))
1501
+ result.add_argument("--require-git", action="store_true")
1494
1502
  return result
1495
1503
 
1496
1504
 
@@ -1503,7 +1511,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
1503
1511
  if arguments.template is None:
1504
1512
  raise DetectError("initialize requires --template")
1505
1513
  payload = initialize(
1506
- arguments.repo, arguments.template, arguments.phase
1514
+ arguments.repo, arguments.template, arguments.phase,
1515
+ require_git=arguments.require_git
1507
1516
  )
1508
1517
  return emit(payload, 2 if payload.get("error") else 0)
1509
1518
  raise DetectError(f"unknown command: {arguments.command}")