@opengsd/gsd-path 1.5.0 → 1.6.1
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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +169 -0
- package/DOCS.md +4 -3
- package/FULL.md +68 -7
- package/HOOKS.md +81 -4
- package/MIGRATE.md +12 -0
- package/QUICK.md +4 -2
- package/README.md +69 -16
- package/RUNTIME.md +23 -5
- package/UPDATE.md +35 -0
- package/WORKFLOW.md +66 -7
- package/package.json +1 -1
- package/scripts/_common.py +150 -1
- package/scripts/build_recovery.py +62 -30
- package/scripts/build_state.py +195 -5
- package/scripts/check_handoffs.py +92 -30
- package/scripts/check_task_briefs.py +27 -19
- package/scripts/detect_project.py +17 -2
- package/scripts/discussion_records.py +9 -1
- package/scripts/discussion_validate.py +7 -6
- package/scripts/dispatch_driver.py +174 -36
- package/scripts/git_guard.py +42 -7
- package/scripts/guard_hook.py +1216 -47
- package/scripts/install.mjs +76 -3
- package/scripts/install.py +182 -37
- package/scripts/integration.py +115 -68
- package/scripts/isolation.py +192 -23
- package/scripts/members.py +68 -25
- package/scripts/migrate_core.py +2 -0
- package/scripts/model_policy.py +13 -2
- package/scripts/pipeline_diagnose.py +17 -2
- package/scripts/pipeline_git.py +87 -35
- package/scripts/pipeline_state.py +31 -7
- package/scripts/pipeline_undo.py +17 -8
- package/scripts/promote_lookahead.py +3 -3
- package/scripts/review_findings.py +180 -44
- package/scripts/roadmap.py +9 -1
- package/scripts/runtime_store.py +1 -0
- package/scripts/state_checkpoint.py +30 -9
- package/scripts/state_promote.py +92 -5
- package/scripts/task_context.py +2 -0
- package/scripts/workflow_run.py +9 -2
- package/skills/gsd-path/DEFINE.md +6 -2
- package/skills/gsd-path/PLAN.md +6 -2
- package/skills/gsd-path/ROADMAP.md +16 -6
- package/skills/gsd-path/SHIP.md +38 -11
- package/skills/gsd-path/SKILL.md +52 -24
- package/skills/gsd-path/references/build-native.md +96 -9
- package/skills/gsd-path/references/build-recovery.md +13 -0
- package/skills/gsd-path/references/coder.md +7 -3
- package/skills/gsd-path/references/model-policy.md +3 -1
- package/skills/gsd-path/references/operating-rules.md +14 -5
- package/skills/gsd-path/references/planner.md +13 -1
- package/skills/gsd-path/references/reviewer-final.md +5 -5
- package/skills/gsd-path/references/reviewer-wave.md +46 -13
- package/skills/gsd-path/references/runtime-selection.md +10 -0
- package/skills/gsd-path/scripts/_common.py +150 -1
- package/skills/gsd-path/scripts/build_recovery.py +62 -30
- package/skills/gsd-path/scripts/build_state.py +195 -5
- package/skills/gsd-path/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path/scripts/detect_project.py +17 -2
- package/skills/gsd-path/scripts/discussion_records.py +9 -1
- package/skills/gsd-path/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path/scripts/dispatch_driver.py +174 -36
- package/skills/gsd-path/scripts/git_guard.py +42 -7
- package/skills/gsd-path/scripts/integration.py +115 -68
- package/skills/gsd-path/scripts/isolation.py +192 -23
- package/skills/gsd-path/scripts/members.py +68 -25
- package/skills/gsd-path/scripts/model_policy.py +13 -2
- package/skills/gsd-path/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path/scripts/review_findings.py +180 -44
- package/skills/gsd-path/scripts/roadmap.py +9 -1
- package/skills/gsd-path/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path/scripts/state_promote.py +92 -5
- package/skills/gsd-path/scripts/task_context.py +2 -0
- package/skills/gsd-path/scripts/workflow_run.py +9 -2
- package/skills/gsd-path/templates/final-review.md +5 -5
- package/skills/gsd-path/templates/state.md +1 -0
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +18 -9
- package/skills/gsd-path-build/references/build-native.md +96 -9
- package/skills/gsd-path-build/references/build-recovery.md +13 -0
- package/skills/gsd-path-build/references/coder.md +7 -3
- package/skills/gsd-path-build/references/model-policy.md +3 -1
- package/skills/gsd-path-build/references/operating-rules.md +14 -5
- package/skills/gsd-path-build/references/reviewer-final.md +5 -5
- package/skills/gsd-path-build/references/reviewer-wave.md +46 -13
- package/skills/gsd-path-build/references/runtime-selection.md +10 -0
- package/skills/gsd-path-build/scripts/_common.py +150 -1
- package/skills/gsd-path-build/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-build/scripts/build_state.py +195 -5
- package/skills/gsd-path-build/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-build/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-build/scripts/detect_project.py +17 -2
- package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-build/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-build/scripts/dispatch_driver.py +174 -36
- package/skills/gsd-path-build/scripts/integration.py +115 -68
- package/skills/gsd-path-build/scripts/isolation.py +192 -23
- package/skills/gsd-path-build/scripts/members.py +68 -25
- package/skills/gsd-path-build/scripts/model_policy.py +13 -2
- package/skills/gsd-path-build/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-build/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-build/scripts/review_findings.py +180 -44
- package/skills/gsd-path-build/scripts/roadmap.py +9 -1
- package/skills/gsd-path-build/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-build/scripts/state_promote.py +92 -5
- package/skills/gsd-path-build/scripts/task_context.py +2 -0
- package/skills/gsd-path-build/scripts/workflow_run.py +9 -2
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +18 -9
- package/skills/gsd-path-decide/references/model-policy.md +3 -1
- package/skills/gsd-path-decide/references/operating-rules.md +14 -5
- package/skills/gsd-path-decide/references/runtime-selection.md +10 -0
- package/skills/gsd-path-decide/scripts/_common.py +150 -1
- package/skills/gsd-path-decide/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-decide/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-decide/scripts/detect_project.py +17 -2
- package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-decide/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-decide/scripts/integration.py +115 -68
- package/skills/gsd-path-decide/scripts/isolation.py +192 -23
- package/skills/gsd-path-decide/scripts/members.py +68 -25
- package/skills/gsd-path-decide/scripts/model_policy.py +13 -2
- package/skills/gsd-path-decide/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-decide/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-decide/scripts/state_promote.py +92 -5
- package/skills/gsd-path-define/SKILL.md +6 -2
- package/skills/gsd-path-define/references/build-recovery.md +13 -0
- package/skills/gsd-path-define/references/operating-rules.md +14 -5
- package/skills/gsd-path-define/references/runtime-selection.md +10 -0
- package/skills/gsd-path-define/scripts/_common.py +150 -1
- package/skills/gsd-path-define/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-define/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-define/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-define/scripts/detect_project.py +17 -2
- package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-define/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-define/scripts/integration.py +115 -68
- package/skills/gsd-path-define/scripts/isolation.py +192 -23
- package/skills/gsd-path-define/scripts/members.py +68 -25
- package/skills/gsd-path-define/scripts/model_policy.py +13 -2
- package/skills/gsd-path-define/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-define/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-define/scripts/roadmap.py +9 -1
- package/skills/gsd-path-define/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-define/scripts/state_promote.py +92 -5
- package/skills/gsd-path-define/templates/state.md +1 -0
- package/skills/gsd-path-discuss/references/operating-rules.md +14 -5
- package/skills/gsd-path-discuss/references/runtime-selection.md +10 -0
- package/skills/gsd-path-discuss/scripts/_common.py +150 -1
- package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-discuss/scripts/model_policy.py +13 -2
- package/skills/gsd-path-docs-audit/references/model-policy.md +3 -1
- package/skills/gsd-path-docs-audit/references/operating-rules.md +14 -5
- package/skills/gsd-path-docs-audit/references/runtime-selection.md +10 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +150 -1
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +17 -2
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-docs-audit/scripts/integration.py +115 -68
- package/skills/gsd-path-docs-audit/scripts/isolation.py +192 -23
- package/skills/gsd-path-docs-audit/scripts/members.py +68 -25
- package/skills/gsd-path-docs-audit/scripts/model_policy.py +13 -2
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +92 -5
- package/skills/gsd-path-forensics/references/operating-rules.md +14 -5
- package/skills/gsd-path-forensics/references/runtime-selection.md +10 -0
- package/skills/gsd-path-forensics/scripts/_common.py +150 -1
- package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-forensics/scripts/model_policy.py +13 -2
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +17 -8
- package/skills/gsd-path-inspect/references/model-policy.md +3 -1
- package/skills/gsd-path-inspect/references/operating-rules.md +14 -5
- package/skills/gsd-path-inspect/references/runtime-selection.md +10 -0
- package/skills/gsd-path-inspect/scripts/_common.py +150 -1
- package/skills/gsd-path-inspect/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-inspect/scripts/detect_project.py +17 -2
- package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-inspect/scripts/integration.py +115 -68
- package/skills/gsd-path-inspect/scripts/isolation.py +192 -23
- package/skills/gsd-path-inspect/scripts/members.py +68 -25
- package/skills/gsd-path-inspect/scripts/model_policy.py +13 -2
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-inspect/scripts/state_promote.py +92 -5
- package/skills/gsd-path-inspect/scripts/workflow_run.py +9 -2
- package/skills/gsd-path-inspect/templates/state.md +1 -0
- package/skills/gsd-path-loop/references/operating-rules.md +14 -5
- package/skills/gsd-path-loop/references/runtime-selection.md +10 -0
- package/skills/gsd-path-loop/scripts/_common.py +150 -1
- package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-loop/scripts/model_policy.py +13 -2
- package/skills/gsd-path-migrate/SKILL.md +8 -0
- package/skills/gsd-path-migrate/references/operating-rules.md +14 -5
- package/skills/gsd-path-migrate/references/runtime-selection.md +10 -0
- package/skills/gsd-path-migrate/scripts/_common.py +150 -1
- package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
- package/skills/gsd-path-migrate/scripts/model_policy.py +13 -2
- package/skills/gsd-path-plan/SKILL.md +6 -2
- package/skills/gsd-path-plan/references/build-recovery.md +13 -0
- package/skills/gsd-path-plan/references/model-policy.md +3 -1
- package/skills/gsd-path-plan/references/operating-rules.md +14 -5
- package/skills/gsd-path-plan/references/planner.md +13 -1
- package/skills/gsd-path-plan/references/runtime-selection.md +10 -0
- package/skills/gsd-path-plan/scripts/_common.py +150 -1
- package/skills/gsd-path-plan/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-plan/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-plan/scripts/detect_project.py +17 -2
- package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-plan/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-plan/scripts/integration.py +115 -68
- package/skills/gsd-path-plan/scripts/isolation.py +192 -23
- package/skills/gsd-path-plan/scripts/members.py +68 -25
- package/skills/gsd-path-plan/scripts/model_policy.py +13 -2
- package/skills/gsd-path-plan/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-plan/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-plan/scripts/state_promote.py +92 -5
- package/skills/gsd-path-plan/scripts/workflow_run.py +9 -2
- package/skills/gsd-path-plan/templates/task.md +1 -0
- package/skills/gsd-path-research/references/model-policy.md +3 -1
- package/skills/gsd-path-research/references/operating-rules.md +14 -5
- package/skills/gsd-path-research/references/runtime-selection.md +10 -0
- package/skills/gsd-path-research/scripts/_common.py +150 -1
- package/skills/gsd-path-research/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-research/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-research/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-research/scripts/detect_project.py +17 -2
- package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-research/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-research/scripts/integration.py +115 -68
- package/skills/gsd-path-research/scripts/isolation.py +192 -23
- package/skills/gsd-path-research/scripts/members.py +68 -25
- package/skills/gsd-path-research/scripts/model_policy.py +13 -2
- package/skills/gsd-path-research/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-research/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-research/scripts/roadmap.py +9 -1
- package/skills/gsd-path-research/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-research/scripts/state_promote.py +92 -5
- package/skills/gsd-path-roadmap/SKILL.md +16 -6
- package/skills/gsd-path-roadmap/references/model-policy.md +3 -1
- package/skills/gsd-path-roadmap/references/operating-rules.md +14 -5
- package/skills/gsd-path-roadmap/references/runtime-selection.md +10 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +150 -1
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-roadmap/scripts/detect_project.py +17 -2
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-roadmap/scripts/integration.py +115 -68
- package/skills/gsd-path-roadmap/scripts/isolation.py +192 -23
- package/skills/gsd-path-roadmap/scripts/members.py +68 -25
- package/skills/gsd-path-roadmap/scripts/model_policy.py +13 -2
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-roadmap/scripts/state_promote.py +92 -5
- package/skills/gsd-path-ship/SKILL.md +38 -11
- package/skills/gsd-path-ship/references/model-policy.md +3 -1
- package/skills/gsd-path-ship/references/operating-rules.md +14 -5
- package/skills/gsd-path-ship/references/reviewer-final.md +5 -5
- package/skills/gsd-path-ship/references/reviewer-wave.md +46 -13
- package/skills/gsd-path-ship/references/runtime-selection.md +10 -0
- package/skills/gsd-path-ship/scripts/_common.py +150 -1
- package/skills/gsd-path-ship/scripts/build_recovery.py +62 -30
- package/skills/gsd-path-ship/scripts/build_state.py +195 -5
- package/skills/gsd-path-ship/scripts/check_handoffs.py +92 -30
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +27 -19
- package/skills/gsd-path-ship/scripts/detect_project.py +17 -2
- package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-ship/scripts/discussion_validate.py +7 -6
- package/skills/gsd-path-ship/scripts/integration.py +115 -68
- package/skills/gsd-path-ship/scripts/isolation.py +192 -23
- package/skills/gsd-path-ship/scripts/members.py +68 -25
- package/skills/gsd-path-ship/scripts/model_policy.py +13 -2
- package/skills/gsd-path-ship/scripts/pipeline_git.py +87 -35
- package/skills/gsd-path-ship/scripts/pipeline_state.py +31 -7
- package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +30 -9
- package/skills/gsd-path-ship/scripts/state_promote.py +92 -5
- package/skills/gsd-path-ship/scripts/workflow_run.py +9 -2
- package/skills/gsd-path-ship/templates/final-review.md +5 -5
- package/skills/gsd-path-ship/templates/wave-review.md +18 -9
- package/skills/gsd-path-undo/references/operating-rules.md +14 -5
- package/skills/gsd-path-undo/references/runtime-selection.md +10 -0
- package/skills/gsd-path-undo/scripts/_common.py +150 -1
- package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-undo/scripts/model_policy.py +13 -2
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +17 -8
- package/skills/path/DEFINE.md +6 -2
- package/skills/path/PLAN.md +6 -2
- package/skills/path/ROADMAP.md +16 -6
- package/skills/path/SHIP.md +38 -11
- package/skills/path/SKILL.md +52 -24
- package/skills/path/references/build-native.md +96 -9
- package/skills/path/references/build-recovery.md +13 -0
- package/skills/path/references/coder.md +7 -3
- package/skills/path/references/model-policy.md +3 -1
- package/skills/path/references/operating-rules.md +14 -5
- package/skills/path/references/planner.md +13 -1
- package/skills/path/references/reviewer-final.md +5 -5
- package/skills/path/references/reviewer-wave.md +46 -13
- package/skills/path/references/runtime-selection.md +10 -0
- package/skills/path/scripts/_common.py +150 -1
- package/skills/path/scripts/build_recovery.py +62 -30
- package/skills/path/scripts/build_state.py +195 -5
- package/skills/path/scripts/check_handoffs.py +92 -30
- package/skills/path/scripts/check_task_briefs.py +27 -19
- package/skills/path/scripts/detect_project.py +17 -2
- package/skills/path/scripts/discussion_records.py +9 -1
- package/skills/path/scripts/discussion_validate.py +7 -6
- package/skills/path/scripts/dispatch_driver.py +174 -36
- package/skills/path/scripts/git_guard.py +42 -7
- package/skills/path/scripts/integration.py +115 -68
- package/skills/path/scripts/isolation.py +192 -23
- package/skills/path/scripts/members.py +68 -25
- package/skills/path/scripts/model_policy.py +13 -2
- package/skills/path/scripts/pipeline_git.py +87 -35
- package/skills/path/scripts/pipeline_state.py +31 -7
- package/skills/path/scripts/promote_lookahead.py +3 -3
- package/skills/path/scripts/review_findings.py +180 -44
- package/skills/path/scripts/roadmap.py +9 -1
- package/skills/path/scripts/state_checkpoint.py +30 -9
- package/skills/path/scripts/state_promote.py +92 -5
- package/skills/path/scripts/task_context.py +2 -0
- package/skills/path/scripts/workflow_run.py +9 -2
- package/skills/path/templates/final-review.md +5 -5
- package/skills/path/templates/state.md +1 -0
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +18 -9
package/scripts/install.mjs
CHANGED
|
@@ -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
|
|
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
|
|
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.";
|
package/scripts/install.py
CHANGED
|
@@ -220,30 +220,52 @@ def _cursor_guard_entry(interpreter: str) -> dict:
|
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
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
|
|
233
|
-
return (
|
|
234
|
-
"
|
|
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
|
|
242
|
-
return (
|
|
243
|
-
"
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1272
|
-
|
|
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
|
|
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(
|
|
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,
|