@opengsd/gsd-path 1.5.0 → 1.6.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 (352) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/DOCS.md +4 -3
  3. package/FULL.md +64 -4
  4. package/HOOKS.md +63 -2
  5. package/MIGRATE.md +12 -0
  6. package/QUICK.md +4 -2
  7. package/README.md +67 -15
  8. package/RUNTIME.md +23 -5
  9. package/UPDATE.md +35 -0
  10. package/WORKFLOW.md +58 -3
  11. package/package.json +1 -1
  12. package/scripts/_common.py +107 -1
  13. package/scripts/build_recovery.py +62 -30
  14. package/scripts/build_state.py +195 -5
  15. package/scripts/check_handoffs.py +92 -30
  16. package/scripts/check_task_briefs.py +19 -14
  17. package/scripts/detect_project.py +17 -2
  18. package/scripts/discussion_records.py +9 -1
  19. package/scripts/discussion_validate.py +7 -6
  20. package/scripts/dispatch_driver.py +157 -31
  21. package/scripts/git_guard.py +24 -5
  22. package/scripts/guard_hook.py +1216 -47
  23. package/scripts/install.mjs +76 -3
  24. package/scripts/install.py +182 -37
  25. package/scripts/integration.py +98 -64
  26. package/scripts/isolation.py +148 -11
  27. package/scripts/members.py +68 -25
  28. package/scripts/migrate_core.py +2 -0
  29. package/scripts/model_policy.py +5 -1
  30. package/scripts/pipeline_diagnose.py +17 -2
  31. package/scripts/pipeline_git.py +68 -30
  32. package/scripts/pipeline_state.py +28 -6
  33. package/scripts/pipeline_undo.py +17 -8
  34. package/scripts/promote_lookahead.py +3 -3
  35. package/scripts/review_findings.py +180 -44
  36. package/scripts/roadmap.py +9 -1
  37. package/scripts/runtime_store.py +1 -0
  38. package/scripts/state_checkpoint.py +30 -9
  39. package/scripts/state_promote.py +15 -4
  40. package/scripts/task_context.py +2 -0
  41. package/scripts/workflow_run.py +9 -2
  42. package/skills/gsd-path/DEFINE.md +6 -2
  43. package/skills/gsd-path/PLAN.md +3 -0
  44. package/skills/gsd-path/ROADMAP.md +16 -6
  45. package/skills/gsd-path/SHIP.md +26 -4
  46. package/skills/gsd-path/SKILL.md +52 -24
  47. package/skills/gsd-path/references/build-native.md +96 -9
  48. package/skills/gsd-path/references/build-recovery.md +13 -0
  49. package/skills/gsd-path/references/coder.md +7 -3
  50. package/skills/gsd-path/references/operating-rules.md +11 -3
  51. package/skills/gsd-path/references/planner.md +13 -1
  52. package/skills/gsd-path/references/reviewer-final.md +5 -5
  53. package/skills/gsd-path/references/reviewer-wave.md +46 -13
  54. package/skills/gsd-path/references/runtime-selection.md +9 -0
  55. package/skills/gsd-path/scripts/_common.py +107 -1
  56. package/skills/gsd-path/scripts/build_recovery.py +62 -30
  57. package/skills/gsd-path/scripts/build_state.py +195 -5
  58. package/skills/gsd-path/scripts/check_handoffs.py +92 -30
  59. package/skills/gsd-path/scripts/check_task_briefs.py +19 -14
  60. package/skills/gsd-path/scripts/detect_project.py +17 -2
  61. package/skills/gsd-path/scripts/discussion_records.py +9 -1
  62. package/skills/gsd-path/scripts/discussion_validate.py +7 -6
  63. package/skills/gsd-path/scripts/dispatch_driver.py +157 -31
  64. package/skills/gsd-path/scripts/git_guard.py +24 -5
  65. package/skills/gsd-path/scripts/integration.py +98 -64
  66. package/skills/gsd-path/scripts/isolation.py +148 -11
  67. package/skills/gsd-path/scripts/members.py +68 -25
  68. package/skills/gsd-path/scripts/model_policy.py +5 -1
  69. package/skills/gsd-path/scripts/pipeline_git.py +68 -30
  70. package/skills/gsd-path/scripts/pipeline_state.py +28 -6
  71. package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
  72. package/skills/gsd-path/scripts/review_findings.py +180 -44
  73. package/skills/gsd-path/scripts/roadmap.py +9 -1
  74. package/skills/gsd-path/scripts/state_checkpoint.py +30 -9
  75. package/skills/gsd-path/scripts/state_promote.py +15 -4
  76. package/skills/gsd-path/scripts/task_context.py +2 -0
  77. package/skills/gsd-path/scripts/workflow_run.py +9 -2
  78. package/skills/gsd-path/templates/final-review.md +5 -5
  79. package/skills/gsd-path/templates/state.md +1 -0
  80. package/skills/gsd-path/templates/task.md +1 -0
  81. package/skills/gsd-path/templates/wave-review.md +18 -9
  82. package/skills/gsd-path-build/references/build-native.md +96 -9
  83. package/skills/gsd-path-build/references/build-recovery.md +13 -0
  84. package/skills/gsd-path-build/references/coder.md +7 -3
  85. package/skills/gsd-path-build/references/operating-rules.md +11 -3
  86. package/skills/gsd-path-build/references/reviewer-final.md +5 -5
  87. package/skills/gsd-path-build/references/reviewer-wave.md +46 -13
  88. package/skills/gsd-path-build/references/runtime-selection.md +9 -0
  89. package/skills/gsd-path-build/scripts/_common.py +107 -1
  90. package/skills/gsd-path-build/scripts/build_recovery.py +62 -30
  91. package/skills/gsd-path-build/scripts/build_state.py +195 -5
  92. package/skills/gsd-path-build/scripts/check_handoffs.py +92 -30
  93. package/skills/gsd-path-build/scripts/check_task_briefs.py +19 -14
  94. package/skills/gsd-path-build/scripts/detect_project.py +17 -2
  95. package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
  96. package/skills/gsd-path-build/scripts/discussion_validate.py +7 -6
  97. package/skills/gsd-path-build/scripts/dispatch_driver.py +157 -31
  98. package/skills/gsd-path-build/scripts/integration.py +98 -64
  99. package/skills/gsd-path-build/scripts/isolation.py +148 -11
  100. package/skills/gsd-path-build/scripts/members.py +68 -25
  101. package/skills/gsd-path-build/scripts/model_policy.py +5 -1
  102. package/skills/gsd-path-build/scripts/pipeline_git.py +68 -30
  103. package/skills/gsd-path-build/scripts/pipeline_state.py +28 -6
  104. package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
  105. package/skills/gsd-path-build/scripts/review_findings.py +180 -44
  106. package/skills/gsd-path-build/scripts/roadmap.py +9 -1
  107. package/skills/gsd-path-build/scripts/state_checkpoint.py +30 -9
  108. package/skills/gsd-path-build/scripts/state_promote.py +15 -4
  109. package/skills/gsd-path-build/scripts/task_context.py +2 -0
  110. package/skills/gsd-path-build/scripts/workflow_run.py +9 -2
  111. package/skills/gsd-path-build/templates/task.md +1 -0
  112. package/skills/gsd-path-build/templates/wave-review.md +18 -9
  113. package/skills/gsd-path-decide/references/operating-rules.md +11 -3
  114. package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
  115. package/skills/gsd-path-decide/scripts/_common.py +107 -1
  116. package/skills/gsd-path-decide/scripts/build_recovery.py +62 -30
  117. package/skills/gsd-path-decide/scripts/check_handoffs.py +92 -30
  118. package/skills/gsd-path-decide/scripts/check_task_briefs.py +19 -14
  119. package/skills/gsd-path-decide/scripts/detect_project.py +17 -2
  120. package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
  121. package/skills/gsd-path-decide/scripts/discussion_validate.py +7 -6
  122. package/skills/gsd-path-decide/scripts/integration.py +98 -64
  123. package/skills/gsd-path-decide/scripts/isolation.py +148 -11
  124. package/skills/gsd-path-decide/scripts/members.py +68 -25
  125. package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
  126. package/skills/gsd-path-decide/scripts/pipeline_git.py +68 -30
  127. package/skills/gsd-path-decide/scripts/pipeline_state.py +28 -6
  128. package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
  129. package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
  130. package/skills/gsd-path-decide/scripts/state_checkpoint.py +30 -9
  131. package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
  132. package/skills/gsd-path-define/SKILL.md +6 -2
  133. package/skills/gsd-path-define/references/build-recovery.md +13 -0
  134. package/skills/gsd-path-define/references/operating-rules.md +11 -3
  135. package/skills/gsd-path-define/references/runtime-selection.md +9 -0
  136. package/skills/gsd-path-define/scripts/_common.py +107 -1
  137. package/skills/gsd-path-define/scripts/build_recovery.py +62 -30
  138. package/skills/gsd-path-define/scripts/check_handoffs.py +92 -30
  139. package/skills/gsd-path-define/scripts/check_task_briefs.py +19 -14
  140. package/skills/gsd-path-define/scripts/detect_project.py +17 -2
  141. package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
  142. package/skills/gsd-path-define/scripts/discussion_validate.py +7 -6
  143. package/skills/gsd-path-define/scripts/integration.py +98 -64
  144. package/skills/gsd-path-define/scripts/isolation.py +148 -11
  145. package/skills/gsd-path-define/scripts/members.py +68 -25
  146. package/skills/gsd-path-define/scripts/model_policy.py +5 -1
  147. package/skills/gsd-path-define/scripts/pipeline_git.py +68 -30
  148. package/skills/gsd-path-define/scripts/pipeline_state.py +28 -6
  149. package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
  150. package/skills/gsd-path-define/scripts/roadmap.py +9 -1
  151. package/skills/gsd-path-define/scripts/state_checkpoint.py +30 -9
  152. package/skills/gsd-path-define/scripts/state_promote.py +15 -4
  153. package/skills/gsd-path-define/templates/state.md +1 -0
  154. package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
  155. package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
  156. package/skills/gsd-path-discuss/scripts/_common.py +107 -1
  157. package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
  158. package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
  159. package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
  160. package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
  161. package/skills/gsd-path-docs-audit/scripts/_common.py +107 -1
  162. package/skills/gsd-path-docs-audit/scripts/build_recovery.py +62 -30
  163. package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +92 -30
  164. package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +19 -14
  165. package/skills/gsd-path-docs-audit/scripts/detect_project.py +17 -2
  166. package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
  167. package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +7 -6
  168. package/skills/gsd-path-docs-audit/scripts/integration.py +98 -64
  169. package/skills/gsd-path-docs-audit/scripts/isolation.py +148 -11
  170. package/skills/gsd-path-docs-audit/scripts/members.py +68 -25
  171. package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
  172. package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +68 -30
  173. package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +28 -6
  174. package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
  175. package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
  176. package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +30 -9
  177. package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
  178. package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
  179. package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
  180. package/skills/gsd-path-forensics/scripts/_common.py +107 -1
  181. package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
  182. package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
  183. package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
  184. package/skills/gsd-path-forensics/scripts/pipeline_undo.py +17 -8
  185. package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
  186. package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
  187. package/skills/gsd-path-inspect/scripts/_common.py +107 -1
  188. package/skills/gsd-path-inspect/scripts/build_recovery.py +62 -30
  189. package/skills/gsd-path-inspect/scripts/check_handoffs.py +92 -30
  190. package/skills/gsd-path-inspect/scripts/check_task_briefs.py +19 -14
  191. package/skills/gsd-path-inspect/scripts/detect_project.py +17 -2
  192. package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
  193. package/skills/gsd-path-inspect/scripts/discussion_validate.py +7 -6
  194. package/skills/gsd-path-inspect/scripts/integration.py +98 -64
  195. package/skills/gsd-path-inspect/scripts/isolation.py +148 -11
  196. package/skills/gsd-path-inspect/scripts/members.py +68 -25
  197. package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
  198. package/skills/gsd-path-inspect/scripts/pipeline_git.py +68 -30
  199. package/skills/gsd-path-inspect/scripts/pipeline_state.py +28 -6
  200. package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
  201. package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
  202. package/skills/gsd-path-inspect/scripts/state_checkpoint.py +30 -9
  203. package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
  204. package/skills/gsd-path-inspect/scripts/workflow_run.py +9 -2
  205. package/skills/gsd-path-inspect/templates/state.md +1 -0
  206. package/skills/gsd-path-loop/references/operating-rules.md +11 -3
  207. package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
  208. package/skills/gsd-path-loop/scripts/_common.py +107 -1
  209. package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
  210. package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
  211. package/skills/gsd-path-migrate/SKILL.md +8 -0
  212. package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
  213. package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
  214. package/skills/gsd-path-migrate/scripts/_common.py +107 -1
  215. package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
  216. package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
  217. package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
  218. package/skills/gsd-path-plan/SKILL.md +3 -0
  219. package/skills/gsd-path-plan/references/build-recovery.md +13 -0
  220. package/skills/gsd-path-plan/references/operating-rules.md +11 -3
  221. package/skills/gsd-path-plan/references/planner.md +13 -1
  222. package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
  223. package/skills/gsd-path-plan/scripts/_common.py +107 -1
  224. package/skills/gsd-path-plan/scripts/build_recovery.py +62 -30
  225. package/skills/gsd-path-plan/scripts/check_handoffs.py +92 -30
  226. package/skills/gsd-path-plan/scripts/check_task_briefs.py +19 -14
  227. package/skills/gsd-path-plan/scripts/detect_project.py +17 -2
  228. package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
  229. package/skills/gsd-path-plan/scripts/discussion_validate.py +7 -6
  230. package/skills/gsd-path-plan/scripts/integration.py +98 -64
  231. package/skills/gsd-path-plan/scripts/isolation.py +148 -11
  232. package/skills/gsd-path-plan/scripts/members.py +68 -25
  233. package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
  234. package/skills/gsd-path-plan/scripts/pipeline_git.py +68 -30
  235. package/skills/gsd-path-plan/scripts/pipeline_state.py +28 -6
  236. package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
  237. package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
  238. package/skills/gsd-path-plan/scripts/state_checkpoint.py +30 -9
  239. package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
  240. package/skills/gsd-path-plan/scripts/workflow_run.py +9 -2
  241. package/skills/gsd-path-plan/templates/task.md +1 -0
  242. package/skills/gsd-path-research/references/operating-rules.md +11 -3
  243. package/skills/gsd-path-research/references/runtime-selection.md +9 -0
  244. package/skills/gsd-path-research/scripts/_common.py +107 -1
  245. package/skills/gsd-path-research/scripts/build_recovery.py +62 -30
  246. package/skills/gsd-path-research/scripts/check_handoffs.py +92 -30
  247. package/skills/gsd-path-research/scripts/check_task_briefs.py +19 -14
  248. package/skills/gsd-path-research/scripts/detect_project.py +17 -2
  249. package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
  250. package/skills/gsd-path-research/scripts/discussion_validate.py +7 -6
  251. package/skills/gsd-path-research/scripts/integration.py +98 -64
  252. package/skills/gsd-path-research/scripts/isolation.py +148 -11
  253. package/skills/gsd-path-research/scripts/members.py +68 -25
  254. package/skills/gsd-path-research/scripts/model_policy.py +5 -1
  255. package/skills/gsd-path-research/scripts/pipeline_git.py +68 -30
  256. package/skills/gsd-path-research/scripts/pipeline_state.py +28 -6
  257. package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
  258. package/skills/gsd-path-research/scripts/roadmap.py +9 -1
  259. package/skills/gsd-path-research/scripts/state_checkpoint.py +30 -9
  260. package/skills/gsd-path-research/scripts/state_promote.py +15 -4
  261. package/skills/gsd-path-roadmap/SKILL.md +16 -6
  262. package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
  263. package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
  264. package/skills/gsd-path-roadmap/scripts/_common.py +107 -1
  265. package/skills/gsd-path-roadmap/scripts/build_recovery.py +62 -30
  266. package/skills/gsd-path-roadmap/scripts/check_handoffs.py +92 -30
  267. package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +19 -14
  268. package/skills/gsd-path-roadmap/scripts/detect_project.py +17 -2
  269. package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
  270. package/skills/gsd-path-roadmap/scripts/discussion_validate.py +7 -6
  271. package/skills/gsd-path-roadmap/scripts/integration.py +98 -64
  272. package/skills/gsd-path-roadmap/scripts/isolation.py +148 -11
  273. package/skills/gsd-path-roadmap/scripts/members.py +68 -25
  274. package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
  275. package/skills/gsd-path-roadmap/scripts/pipeline_git.py +68 -30
  276. package/skills/gsd-path-roadmap/scripts/pipeline_state.py +28 -6
  277. package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
  278. package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
  279. package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +30 -9
  280. package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
  281. package/skills/gsd-path-ship/SKILL.md +26 -4
  282. package/skills/gsd-path-ship/references/operating-rules.md +11 -3
  283. package/skills/gsd-path-ship/references/reviewer-final.md +5 -5
  284. package/skills/gsd-path-ship/references/reviewer-wave.md +46 -13
  285. package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
  286. package/skills/gsd-path-ship/scripts/_common.py +107 -1
  287. package/skills/gsd-path-ship/scripts/build_recovery.py +62 -30
  288. package/skills/gsd-path-ship/scripts/build_state.py +195 -5
  289. package/skills/gsd-path-ship/scripts/check_handoffs.py +92 -30
  290. package/skills/gsd-path-ship/scripts/check_task_briefs.py +19 -14
  291. package/skills/gsd-path-ship/scripts/detect_project.py +17 -2
  292. package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
  293. package/skills/gsd-path-ship/scripts/discussion_validate.py +7 -6
  294. package/skills/gsd-path-ship/scripts/integration.py +98 -64
  295. package/skills/gsd-path-ship/scripts/isolation.py +148 -11
  296. package/skills/gsd-path-ship/scripts/members.py +68 -25
  297. package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
  298. package/skills/gsd-path-ship/scripts/pipeline_git.py +68 -30
  299. package/skills/gsd-path-ship/scripts/pipeline_state.py +28 -6
  300. package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
  301. package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
  302. package/skills/gsd-path-ship/scripts/state_checkpoint.py +30 -9
  303. package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
  304. package/skills/gsd-path-ship/scripts/workflow_run.py +9 -2
  305. package/skills/gsd-path-ship/templates/final-review.md +5 -5
  306. package/skills/gsd-path-ship/templates/wave-review.md +18 -9
  307. package/skills/gsd-path-undo/references/operating-rules.md +11 -3
  308. package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
  309. package/skills/gsd-path-undo/scripts/_common.py +107 -1
  310. package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
  311. package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
  312. package/skills/gsd-path-undo/scripts/pipeline_undo.py +17 -8
  313. package/skills/path/DEFINE.md +6 -2
  314. package/skills/path/PLAN.md +3 -0
  315. package/skills/path/ROADMAP.md +16 -6
  316. package/skills/path/SHIP.md +26 -4
  317. package/skills/path/SKILL.md +52 -24
  318. package/skills/path/references/build-native.md +96 -9
  319. package/skills/path/references/build-recovery.md +13 -0
  320. package/skills/path/references/coder.md +7 -3
  321. package/skills/path/references/operating-rules.md +11 -3
  322. package/skills/path/references/planner.md +13 -1
  323. package/skills/path/references/reviewer-final.md +5 -5
  324. package/skills/path/references/reviewer-wave.md +46 -13
  325. package/skills/path/references/runtime-selection.md +9 -0
  326. package/skills/path/scripts/_common.py +107 -1
  327. package/skills/path/scripts/build_recovery.py +62 -30
  328. package/skills/path/scripts/build_state.py +195 -5
  329. package/skills/path/scripts/check_handoffs.py +92 -30
  330. package/skills/path/scripts/check_task_briefs.py +19 -14
  331. package/skills/path/scripts/detect_project.py +17 -2
  332. package/skills/path/scripts/discussion_records.py +9 -1
  333. package/skills/path/scripts/discussion_validate.py +7 -6
  334. package/skills/path/scripts/dispatch_driver.py +157 -31
  335. package/skills/path/scripts/git_guard.py +24 -5
  336. package/skills/path/scripts/integration.py +98 -64
  337. package/skills/path/scripts/isolation.py +148 -11
  338. package/skills/path/scripts/members.py +68 -25
  339. package/skills/path/scripts/model_policy.py +5 -1
  340. package/skills/path/scripts/pipeline_git.py +68 -30
  341. package/skills/path/scripts/pipeline_state.py +28 -6
  342. package/skills/path/scripts/promote_lookahead.py +3 -3
  343. package/skills/path/scripts/review_findings.py +180 -44
  344. package/skills/path/scripts/roadmap.py +9 -1
  345. package/skills/path/scripts/state_checkpoint.py +30 -9
  346. package/skills/path/scripts/state_promote.py +15 -4
  347. package/skills/path/scripts/task_context.py +2 -0
  348. package/skills/path/scripts/workflow_run.py +9 -2
  349. package/skills/path/templates/final-review.md +5 -5
  350. package/skills/path/templates/state.md +1 -0
  351. package/skills/path/templates/task.md +1 -0
  352. package/skills/path/templates/wave-review.md +18 -9
@@ -1560,6 +1560,51 @@ export async function install(sourceRoot, plans, options = {}) {
1560
1560
  return results;
1561
1561
  }
1562
1562
 
1563
+ // The desktop app's rule: a VERSION stamp or a SKILL.md that names gsd-path.
1564
+ function isInstalledSkill(skillDir) {
1565
+ if (isFile(path.join(skillDir, "VERSION"))) return true;
1566
+ try {
1567
+ return fs.readFileSync(path.join(skillDir, "SKILL.md"), "utf8").includes("gsd-path");
1568
+ } catch {
1569
+ return false;
1570
+ }
1571
+ }
1572
+
1573
+ // Removes installed skills only. Project contracts and hooks stay.
1574
+ export function uninstall(plans, { dryRun = false } = {}) {
1575
+ const found = deploymentPlans(plans).map((plan) => {
1576
+ const owned = [];
1577
+ const kept = [];
1578
+ for (const name of isDirectory(plan.root) ? fs.readdirSync(plan.root).sort() : []) {
1579
+ if (!isManagedName(name)) continue;
1580
+ const entry = path.join(plan.root, name);
1581
+ (isManagedInstallEntry(plan.root, name) && isInstalledSkill(entry) ? owned : kept).push(entry);
1582
+ }
1583
+ const agent = path.join(path.dirname(plan.root), "agents", CURSOR_AGENT_FILENAME);
1584
+ if (plan.profile === "cursor" && isFile(agent)) owned.push(agent);
1585
+ return { label: plan.targets.join("+"), root: plan.root, owned, kept };
1586
+ });
1587
+ const results = [];
1588
+ const ownership = acquireInstallLocks(
1589
+ dryRun ? [] : found.filter(({ owned }) => owned.length).map(({ root }) => root)
1590
+ );
1591
+ try {
1592
+ for (const { label, root, owned, kept } of found) {
1593
+ for (const entry of kept) results.push(`${label}: kept ${entry} (not owned by GSD Path)`);
1594
+ for (const entry of owned) {
1595
+ if (!dryRun) removePath(entry);
1596
+ results.push(`${label}: ${dryRun ? "would remove" : "removed"} ${entry}`);
1597
+ }
1598
+ if (!owned.length) results.push(`${label}: nothing to remove (${root})`);
1599
+ }
1600
+ } catch (error) {
1601
+ throw new InstallerError(`uninstall stopped: ${messageOf(error)}; fix the cause and run it again`);
1602
+ } finally {
1603
+ releaseInstallLocks(ownership.locks, ownership.createdDirectories);
1604
+ }
1605
+ return results;
1606
+ }
1607
+
1563
1608
  // Documented project-relative skill roots (verified against each host's
1564
1609
  // official skills docs). Codex, Zed, Muse, and Antigravity all discover the
1565
1610
  // project-level .agents/skills standard directory.
@@ -1580,10 +1625,16 @@ export function detectInstalls(targets, rootFor) {
1580
1625
  return plans;
1581
1626
  }
1582
1627
 
1628
+ const UNINSTALL_CONFLICTS = [
1629
+ "update", "hooks", "hooks-init", "hooks-refresh", "hooks-refresh-full",
1630
+ "runtime-restore", "runtime-upgrade", "runtime-migrate", "doctor", "member-of",
1631
+ ];
1632
+
1583
1633
  export function parseCli(argv) {
1584
1634
  const options = {
1585
1635
  all: { type: "boolean", default: false },
1586
1636
  update: { type: "boolean", default: false },
1637
+ uninstall: { type: "boolean", default: false },
1587
1638
  "dry-run": { type: "boolean", default: false },
1588
1639
  local: { type: "boolean", default: false },
1589
1640
  project: { type: "string" },
@@ -1670,13 +1721,16 @@ function usage() {
1670
1721
  "Docs: DOCS.md (hub) · QUICK.md (first run) · FULL.md · UPDATE.md\n\n" +
1671
1722
  "usage: gsd-path (no flags on a terminal opens the interactive wizard)\n" +
1672
1723
  " gsd-path [--all] [--update] [--local] [--dry-run] [--project PATH]\n" +
1673
- " [--hooks] [--hooks-init] [--hooks-refresh] [--hooks-refresh-full] [target flags]\n\n" +
1724
+ " [--hooks] [--hooks-init] [--hooks-refresh] [--hooks-refresh-full] [target flags]\n" +
1725
+ " gsd-path --uninstall [--all] [--local] [--dry-run] [target flags]\n\n" +
1674
1726
  " First install: gsd-path --all --dry-run && gsd-path --all\n" +
1675
1727
  " New repo: gsd-path --all --project /path/to/repo\n" +
1676
1728
  " Update skills: gsd-path --update (or npx @opengsd/gsd-path@latest --update)\n\n" +
1677
1729
  `targets: ${flags}\n` +
1678
1730
  " --update refresh existing installs in place; with --project also\n" +
1679
1731
  " keeps its selected runtime and project contracts\n" +
1732
+ " --uninstall remove installed GSD Path skills from the selected targets;\n" +
1733
+ " keeps other skills, host settings, project contracts, and hooks\n" +
1680
1734
  " --local install into this project's per-host skill dirs\n" +
1681
1735
  " --project PATH write project contracts and status runtime; requires Python 3.9+\n" +
1682
1736
  " --doctor read-only health check of installs, hooks, and state\n" +
@@ -1727,6 +1781,20 @@ export async function main(argv, env = process.env) {
1727
1781
  : path.resolve(SCRIPT_DIRECTORY, "..");
1728
1782
  const project =
1729
1783
  values.project !== undefined ? absolutePath(values.project) : null;
1784
+ if (values.uninstall) {
1785
+ const conflicts = UNINSTALL_CONFLICTS.filter((name) => values[name]).map((name) => `--${name}`);
1786
+ if (conflicts.length) {
1787
+ ui.error(`--uninstall cannot be combined with ${conflicts.join(", ")}`);
1788
+ return 2;
1789
+ }
1790
+ if (project !== null) {
1791
+ ui.error(
1792
+ "--uninstall removes installed skills only; project contracts and hooks are not removed " +
1793
+ "(.project/, .gsd-path/, the AGENTS.md block, guard hooks). Run it without --project."
1794
+ );
1795
+ return 2;
1796
+ }
1797
+ }
1730
1798
  const migrateAndUpdate = values["runtime-migrate"] && values.update;
1731
1799
  if (migrateAndUpdate && (project === null || values["runtime-restore"] || values["runtime-upgrade"] || values.doctor || values["hooks-init"] || values["hooks-refresh"] || values["hooks-refresh-full"])) {
1732
1800
  ui.error("--runtime-migrate --update requires --project and cannot be combined with another runtime, doctor, or hook operation");
@@ -1822,7 +1890,10 @@ export async function main(argv, env = process.env) {
1822
1890
  }
1823
1891
  }
1824
1892
  const sourceRootForInstall = sourceRoot;
1825
- const scope = local ? `project ${values.update ? "update in" : "install into"} ${process.cwd()}` : `global ${values.update ? "update" : "install"}`;
1893
+ const [verb, localVerb] = values.uninstall
1894
+ ? ["uninstall", "uninstall from"]
1895
+ : values.update ? ["update", "update in"] : ["install", "install into"];
1896
+ const scope = local ? `project ${localVerb} ${process.cwd()}` : `global ${verb}`;
1826
1897
  const mode = scope + (values["dry-run"] ? " · dry run" : "");
1827
1898
  ui.banner(mode);
1828
1899
  let plans;
@@ -1855,7 +1926,7 @@ export async function main(argv, env = process.env) {
1855
1926
  }
1856
1927
  const spin = ui.spinner("Preparing");
1857
1928
  try {
1858
- const results = await install(sourceRootForInstall, plans, {
1929
+ const results = values.uninstall ? uninstall(plans, { dryRun: values["dry-run"] }) : await install(sourceRootForInstall, plans, {
1859
1930
  project,
1860
1931
  dryRun: values["dry-run"],
1861
1932
  env,
@@ -1870,6 +1941,8 @@ export async function main(argv, env = process.env) {
1870
1941
  }
1871
1942
  const closing = values["dry-run"]
1872
1943
  ? "Dry run — nothing was written."
1944
+ : values.uninstall
1945
+ ? "Done. Restart active agent sessions."
1873
1946
  : values.update
1874
1947
  ? "Updated. Previous copies are in each root's disabled-gsd-skills backup."
1875
1948
  : "Done. Restart active agent sessions, then invoke the router explicitly.";
@@ -220,30 +220,52 @@ def _cursor_guard_entry(interpreter: str) -> dict:
220
220
  }
221
221
 
222
222
 
223
- def pre_commit_hook(interpreter: str) -> str:
224
- return (
225
- "#!/bin/sh\n"
226
- "# gsd-path guard: archive immutability before commit.\n"
227
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
228
- f"{HOOKS_DIRECTORY}/git_guard.py\" pre-commit\n"
223
+ CHAINED_HOOK_SUFFIX = ".gsd-path-chained"
224
+
225
+
226
+ def _chained_hook_lines(name: str, guard: str) -> List[str]:
227
+ """Shell lines that run the guard, then the hook that was there before it."""
228
+ lines = [f'chained="$(dirname "$0")/{name}{CHAINED_HOOK_SUFFIX}"']
229
+ if name == "pre-push":
230
+ # Git gives pre-push its ref updates on stdin; both hooks need them.
231
+ return lines + [
232
+ "input=$(cat)",
233
+ '[ -n "$input" ] && input="$input\n"',
234
+ f'printf %s "$input" | {guard} || exit 1',
235
+ 'if [ -x "$chained" ]; then printf %s "$input" | exec "$chained" "$@"; fi',
236
+ ]
237
+ return lines + [f"{guard} || exit 1", 'if [ -x "$chained" ]; then exec "$chained" "$@"; fi']
238
+
239
+
240
+ def _git_hook(name: str, purpose: str, arguments: str, interpreter: str, chained: bool) -> str:
241
+ """chained=True also runs `<hook>.gsd-path-chained`, the user's own hook."""
242
+ guard = (
243
+ f"{interpreter} \"$(git rev-parse --show-toplevel)/"
244
+ f"{HOOKS_DIRECTORY}/git_guard.py\" {name}{arguments}"
229
245
  )
246
+ head = f"#!/bin/sh\n# gsd-path guard: {purpose}\n"
247
+ if not chained:
248
+ return f"{head}exec {guard}\n"
249
+ return head + "\n".join(_chained_hook_lines(name, guard)) + "\n"
230
250
 
231
251
 
232
- def commit_msg_hook(interpreter: str) -> str:
233
- return (
234
- "#!/bin/sh\n"
235
- "# gsd-path guard: archive immutability and ship-commit purity.\n"
236
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
237
- f"{HOOKS_DIRECTORY}/git_guard.py\" commit-msg \"$1\"\n"
252
+ def pre_commit_hook(interpreter: str, chained: bool = False) -> str:
253
+ return _git_hook(
254
+ "pre-commit", "archive immutability before commit.", "", interpreter, chained
238
255
  )
239
256
 
240
257
 
241
- def pre_push_hook(interpreter: str) -> str:
242
- return (
243
- "#!/bin/sh\n"
244
- "# gsd-path guard: bound branches publish only as ship commits.\n"
245
- f"exec {interpreter} \"$(git rev-parse --show-toplevel)/"
246
- f"{HOOKS_DIRECTORY}/git_guard.py\" pre-push \"$@\"\n"
258
+ def commit_msg_hook(interpreter: str, chained: bool = False) -> str:
259
+ return _git_hook(
260
+ "commit-msg", "archive immutability and ship-commit purity.", ' "$1"',
261
+ interpreter, chained,
262
+ )
263
+
264
+
265
+ def pre_push_hook(interpreter: str, chained: bool = False) -> str:
266
+ return _git_hook(
267
+ "pre-push", "bound branches publish only as ship commits.", ' "$@"',
268
+ interpreter, chained,
247
269
  )
248
270
 
249
271
 
@@ -254,7 +276,6 @@ GIT_HOOKS = (
254
276
  )
255
277
  GIT_HOOK_NAMES = tuple(name for name, _ in GIT_HOOKS)
256
278
  MEMBER_HOOK_MARKER = "gsd-path member guard"
257
- CHAINED_HOOK_SUFFIX = ".gsd-path-chained"
258
279
 
259
280
 
260
281
  def member_hook(interpreter: str, name: str) -> str:
@@ -271,19 +292,8 @@ def member_hook(interpreter: str, name: str) -> str:
271
292
  ' echo "gsd-path guard: member marker is unreadable; run members.py repair --repo <coordinator>" >&2',
272
293
  " exit 1",
273
294
  "}",
274
- f'chained="$(dirname "$0")/{name}{CHAINED_HOOK_SUFFIX}"',
275
295
  ]
276
- if name == "pre-push":
277
- # Git gives pre-push its ref updates on stdin; both hooks need them.
278
- lines += [
279
- "input=$(cat)",
280
- '[ -n "$input" ] && input="$input\n"',
281
- f'printf %s "$input" | {guard} || exit 1',
282
- 'if [ -x "$chained" ]; then printf %s "$input" | exec "$chained" "$@"; fi',
283
- ]
284
- else:
285
- lines += [f"{guard} || exit 1", 'if [ -x "$chained" ]; then exec "$chained" "$@"; fi']
286
- return "\n".join(lines) + "\n"
296
+ return "\n".join(lines + _chained_hook_lines(name, guard)) + "\n"
287
297
 
288
298
 
289
299
  def install_member_hooks(coordinator: Path, member: Path, dry_run: bool = False) -> List[str]:
@@ -1207,6 +1217,35 @@ def _rollback_target(transaction: TargetTransaction) -> None:
1207
1217
  _remove_empty_directories(transaction.created_directories)
1208
1218
 
1209
1219
 
1220
+ def _chained_hook_path(hook: Path) -> Path:
1221
+ return hook.with_name(f"{hook.name}{CHAINED_HOOK_SUFFIX}")
1222
+
1223
+
1224
+ def _foreign_git_hook(hook: Path) -> bool:
1225
+ """A regular hook file that no GSD Path installer wrote."""
1226
+ if hook.is_symlink() or not hook.is_file():
1227
+ return False
1228
+ text = hook.read_text(encoding="utf-8", errors="replace")
1229
+ return MEMBER_HOOK_MARKER not in text and not _is_managed_git_hook_content(text)
1230
+
1231
+
1232
+ def _require_chainable_git_hook(project: Path, hook: Path) -> None:
1233
+ """A foreign hook is kept as `<hook>.gsd-path-chained` and runs after the guard."""
1234
+ chained = _chained_hook_path(hook)
1235
+ if _lexists(chained):
1236
+ raise InstallerError(f"cannot chain {hook}: {chained} already exists")
1237
+ # ponytail: only the repository's own .git/hooks. A core.hooksPath directory
1238
+ # can be tracked (Husky) or shared by other repositories, so a rename there
1239
+ # reaches other people; chain it when a design for tracked hooks exists.
1240
+ if not _same_path(hook.parent, project / ".git" / "hooks"):
1241
+ raise InstallerError(
1242
+ f"cannot chain {hook}: its hooks directory is not this repository's "
1243
+ ".git/hooks (core.hooksPath or a linked worktree). Rename it to "
1244
+ f"{chained.name} yourself, then rerun: the guard runs it after its own "
1245
+ "check. See HOOKS.md."
1246
+ )
1247
+
1248
+
1210
1249
  def _project_destinations(
1211
1250
  project: Path,
1212
1251
  selected: Sequence[str],
@@ -1268,9 +1307,9 @@ def _project_destinations(
1268
1307
  )
1269
1308
  if hooks_dir is not None:
1270
1309
  for hook_name, generator in GIT_HOOKS:
1271
- destinations.append(
1272
- (hooks_dir / hook_name, None, generator(interpreter), True)
1273
- )
1310
+ hook = hooks_dir / hook_name
1311
+ chained = _lexists(_chained_hook_path(hook)) or _foreign_git_hook(hook)
1312
+ destinations.append((hook, None, generator(interpreter, chained), True))
1274
1313
  return destinations
1275
1314
 
1276
1315
 
@@ -1672,6 +1711,13 @@ def _validate_project(
1672
1711
  managed = (
1673
1712
  _update_replacement(project, destination, hooks_dir) if update else None
1674
1713
  )
1714
+ if (
1715
+ hooks_dir is not None
1716
+ and _same_path(destination.parent, hooks_dir)
1717
+ and _foreign_git_hook(destination)
1718
+ ):
1719
+ _require_chainable_git_hook(project, destination)
1720
+ continue
1675
1721
  if destination.is_symlink() or (merge is None and not update):
1676
1722
  raise _existing_contract_error(destination)
1677
1723
  if merge is not None:
@@ -1718,6 +1764,21 @@ def _apply_project(
1718
1764
  _apply_agents(source_root, destination, transaction)
1719
1765
  continue
1720
1766
  merge = mergers.get(destination)
1767
+ if (
1768
+ hooks_dir is not None
1769
+ and _same_path(destination.parent, hooks_dir)
1770
+ and _foreign_git_hook(destination)
1771
+ ):
1772
+ original = destination.read_bytes()
1773
+ mode = destination.stat().st_mode & 0o777
1774
+ chained = _chained_hook_path(destination)
1775
+ with chained.open("xb") as output:
1776
+ transaction.copied.append(chained)
1777
+ output.write(original)
1778
+ chained.chmod(mode)
1779
+ _atomic_write(destination, (content or "").encode("utf-8"), 0o755)
1780
+ transaction.replaced.append((destination, original, mode))
1781
+ continue
1721
1782
  if _lexists(destination) and not destination.is_symlink():
1722
1783
  replaceable = (
1723
1784
  update
@@ -2159,7 +2220,9 @@ def _validate_hooks_refresh(
2159
2220
  raise InstallerError(
2160
2221
  f"refusing to refresh a symlink: {hook_path}"
2161
2222
  )
2162
- if _lexists(hook_path) and not _is_managed_git_hook(hook_path):
2223
+ if _foreign_git_hook(hook_path):
2224
+ _require_chainable_git_hook(project, hook_path)
2225
+ elif _lexists(hook_path) and not _is_managed_git_hook(hook_path):
2163
2226
  raise InstallerError(
2164
2227
  f"not a managed GSD Path git hook: {hook_path}"
2165
2228
  )
@@ -2844,6 +2907,8 @@ def doctor(
2844
2907
  else:
2845
2908
  for name in PROJECT_RUNTIME_SCRIPTS:
2846
2909
  destination = runtime / name
2910
+ if pinned and not _lexists(destination):
2911
+ continue # a valid older selected runtime lacks helpers added later
2847
2912
  if destination.is_symlink():
2848
2913
  push("fail", f"project: runtime {name} is a symlink")
2849
2914
  runtime_current = False
@@ -3003,7 +3068,9 @@ def doctor(
3003
3068
  if not _is_managed_git_hook_content(hook_text):
3004
3069
  push("warn", f"hooks: {label} is not a managed GSD Path git hook")
3005
3070
  elif not any(
3006
- hook_text == generator(candidate)
3071
+ hook_text == generator(
3072
+ candidate, _lexists(_chained_hook_path(hook_path))
3073
+ )
3007
3074
  for candidate in INTERPRETER_CANDIDATES
3008
3075
  ):
3009
3076
  push("warn", f"hooks: {label} is stale — run --hooks-refresh-full")
@@ -3283,6 +3350,56 @@ def install(
3283
3350
  return results
3284
3351
 
3285
3352
 
3353
+ def _is_installed_skill(skill_dir: Path) -> bool:
3354
+ """The desktop app's rule: a VERSION stamp or a SKILL.md that names gsd-path."""
3355
+ if (skill_dir / "VERSION").is_file():
3356
+ return True
3357
+ try:
3358
+ return "gsd-path" in (skill_dir / "SKILL.md").read_text(encoding="utf-8", errors="replace")
3359
+ except OSError:
3360
+ return False
3361
+
3362
+
3363
+ def uninstall(plans: Sequence[TargetPlan], dry_run: bool = False) -> List[str]:
3364
+ """Remove installed skills only. Project contracts and hooks stay."""
3365
+ found = []
3366
+ for plan in _deployment_plans(plans):
3367
+ owned, kept = [], []
3368
+ names = sorted(entry.name for entry in plan.root.iterdir()) if plan.root.is_dir() else []
3369
+ for name in names:
3370
+ if not _is_managed_name(name):
3371
+ continue
3372
+ entry = plan.root / name
3373
+ if _is_managed_install_entry(plan.root, name) and _is_installed_skill(entry):
3374
+ owned.append(entry)
3375
+ else:
3376
+ kept.append(entry)
3377
+ agent = plan.root.parent / "agents" / CURSOR_AGENT_FILENAME
3378
+ if plan.profile == "cursor" and agent.is_file():
3379
+ owned.append(agent)
3380
+ found.append(("+".join(plan.targets), plan.root, owned, kept))
3381
+ results = []
3382
+ locks, created = _acquire_install_locks(
3383
+ [] if dry_run else [root for _, root, owned, _ in found if owned]
3384
+ )
3385
+ try:
3386
+ for label, root, owned, kept in found:
3387
+ results.extend(f"{label}: kept {entry} (not owned by GSD Path)" for entry in kept)
3388
+ for entry in owned:
3389
+ if not dry_run:
3390
+ _remove_path(entry)
3391
+ results.append(f"{label}: {'would remove' if dry_run else 'removed'} {entry}")
3392
+ if not owned:
3393
+ results.append(f"{label}: nothing to remove ({root})")
3394
+ except OSError as error:
3395
+ raise InstallerError(
3396
+ f"uninstall stopped: {error}; fix the cause and run it again"
3397
+ ) from error
3398
+ finally:
3399
+ _release_install_locks(locks, created)
3400
+ return results
3401
+
3402
+
3286
3403
  def _runtime_provenance(arguments, source_root: Path):
3287
3404
  """Owner-recorded provenance from --runtime-provenance-* upgrade flags.
3288
3405
 
@@ -3308,6 +3425,12 @@ def _runtime_provenance(arguments, source_root: Path):
3308
3425
  return recorded
3309
3426
 
3310
3427
 
3428
+ UNINSTALL_CONFLICTS = (
3429
+ "update", "hooks", "hooks-init", "hooks-refresh", "hooks-refresh-full",
3430
+ "runtime-restore", "runtime-upgrade", "runtime-migrate", "doctor", "member-of",
3431
+ )
3432
+
3433
+
3311
3434
  def parser() -> argparse.ArgumentParser:
3312
3435
  argument_parser = argparse.ArgumentParser(description=__doc__)
3313
3436
  for target in TARGETS:
@@ -3316,6 +3439,12 @@ def parser() -> argparse.ArgumentParser:
3316
3439
  argument_parser.add_argument("--adapter-request", action="store_true", help=argparse.SUPPRESS)
3317
3440
  argument_parser.add_argument("--all", action="store_true", dest="all_targets")
3318
3441
  argument_parser.add_argument("--update", action="store_true")
3442
+ argument_parser.add_argument(
3443
+ "--uninstall",
3444
+ action="store_true",
3445
+ help="remove installed GSD Path skills from the selected targets; "
3446
+ "keeps other skills, host settings, project contracts, and hooks",
3447
+ )
3319
3448
  argument_parser.add_argument("--local", action="store_true")
3320
3449
  argument_parser.add_argument("--dry-run", action="store_true")
3321
3450
  argument_parser.add_argument("--project", type=Path)
@@ -3370,6 +3499,22 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
3370
3499
  project = (
3371
3500
  absolute_path(arguments.project) if arguments.project is not None else None
3372
3501
  )
3502
+ if arguments.uninstall:
3503
+ conflicts = [
3504
+ f"--{name}" for name in UNINSTALL_CONFLICTS
3505
+ if getattr(arguments, name.replace("-", "_"))
3506
+ ]
3507
+ if conflicts:
3508
+ print(f"error: --uninstall cannot be combined with {', '.join(conflicts)}", file=sys.stderr)
3509
+ return 2
3510
+ if project is not None:
3511
+ print(
3512
+ "error: --uninstall removes installed skills only; project contracts and hooks "
3513
+ "are not removed (.project/, .gsd-path/, the AGENTS.md block, guard hooks). "
3514
+ "Run it without --project.",
3515
+ file=sys.stderr,
3516
+ )
3517
+ return 2
3373
3518
  runtime_action = next((action for action in ("restore", "upgrade", "migrate")
3374
3519
  if getattr(arguments, "runtime_" + action)), None)
3375
3520
  provenance = _runtime_provenance(arguments, source_root)
@@ -3517,7 +3662,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
3517
3662
  )
3518
3663
  return 1
3519
3664
  try:
3520
- for result in install(
3665
+ for result in uninstall(plans, arguments.dry_run) if arguments.uninstall else install(
3521
3666
  source_root,
3522
3667
  plans,
3523
3668
  project,