@opengsd/gsd-path 1.4.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.
- package/CHANGELOG.md +460 -341
- package/DOCS.md +16 -5
- package/FULL.md +67 -6
- package/HOOKS.md +158 -10
- package/MIGRATE.md +12 -0
- package/QUICK.md +4 -2
- package/README.md +136 -116
- package/RUNTIME.md +24 -6
- package/UPDATE.md +39 -3
- package/WORKFLOW.md +80 -4
- package/package.json +5 -2
- package/platforms/shared-agents/dispatch.md +13 -0
- package/scripts/_common.py +256 -2
- package/scripts/archive_milestone.py +14 -13
- package/scripts/build_recovery.py +155 -58
- package/scripts/build_state.py +274 -8
- package/scripts/check_docs_audit.py +77 -4
- package/scripts/check_handoffs.py +635 -57
- package/scripts/check_task_briefs.py +293 -32
- package/scripts/detect_project.py +260 -20
- package/scripts/discussion_records.py +9 -1
- package/scripts/discussion_validate.py +93 -35
- package/scripts/dispatch_driver.py +549 -53
- package/scripts/git_guard.py +27 -8
- package/scripts/guard_hook.py +2630 -210
- package/scripts/install.mjs +99 -11
- package/scripts/install.py +231 -46
- package/scripts/integration.py +244 -65
- package/scripts/isolation.py +539 -70
- package/scripts/loop_run.py +16 -4
- package/scripts/members.py +77 -32
- package/scripts/migrate_core.py +2 -0
- package/scripts/model_policy.py +5 -1
- package/scripts/path_config.py +3 -3
- package/scripts/pipeline_diagnose.py +17 -2
- package/scripts/pipeline_git.py +131 -42
- package/scripts/pipeline_state.py +139 -39
- package/scripts/pipeline_undo.py +118 -16
- 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 +21 -2
- package/scripts/skill-resources.json +9 -2
- package/scripts/state_checkpoint.py +39 -36
- package/scripts/state_promote.py +15 -4
- package/scripts/status_runtime.py +22 -4
- package/scripts/task_context.py +14 -3
- package/scripts/wizard.mjs +1 -0
- package/scripts/workflow_run.py +14 -4
- package/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path/DEFINE.md +34 -5
- package/skills/gsd-path/PLAN.md +14 -3
- package/skills/gsd-path/RESEARCH.md +11 -0
- package/skills/gsd-path/ROADMAP.md +16 -6
- package/skills/gsd-path/SHIP.md +32 -5
- package/skills/gsd-path/SKILL.md +52 -24
- package/skills/gsd-path/references/build-native.md +112 -10
- package/skills/gsd-path/references/build-recovery.md +13 -0
- package/skills/gsd-path/references/coder.md +7 -3
- package/skills/gsd-path/references/dispatch.md +13 -0
- package/skills/gsd-path/references/docs-auditor.md +5 -0
- package/skills/gsd-path/references/operating-rules.md +11 -3
- package/skills/gsd-path/references/planner.md +26 -4
- package/skills/gsd-path/references/reviewer-final.md +20 -2
- package/skills/gsd-path/references/reviewer-wave.md +56 -12
- package/skills/gsd-path/references/reviewer.md +3 -1
- package/skills/gsd-path/references/runtime-selection.md +9 -0
- package/skills/gsd-path/references/spec-probes.md +150 -0
- package/skills/gsd-path/scripts/_common.py +256 -2
- package/skills/gsd-path/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path/scripts/build_recovery.py +155 -58
- package/skills/gsd-path/scripts/build_state.py +274 -8
- package/skills/gsd-path/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path/scripts/detect_project.py +260 -20
- package/skills/gsd-path/scripts/discussion_records.py +9 -1
- package/skills/gsd-path/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path/scripts/dispatch_driver.py +549 -53
- package/skills/gsd-path/scripts/git_guard.py +27 -8
- package/skills/gsd-path/scripts/integration.py +244 -65
- package/skills/gsd-path/scripts/isolation.py +539 -70
- package/skills/gsd-path/scripts/loop_run.py +16 -4
- package/skills/gsd-path/scripts/members.py +77 -32
- package/skills/gsd-path/scripts/model_policy.py +5 -1
- package/skills/gsd-path/scripts/path_config.py +3 -3
- package/skills/gsd-path/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path/scripts/state_promote.py +15 -4
- package/skills/gsd-path/scripts/status_runtime.py +22 -4
- package/skills/gsd-path/scripts/task_context.py +14 -3
- package/skills/gsd-path/scripts/workflow_run.py +14 -4
- package/skills/gsd-path/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path/templates/docs-audit.md +5 -1
- package/skills/gsd-path/templates/final-review.md +11 -2
- package/skills/gsd-path/templates/intent.md +30 -0
- package/skills/gsd-path/templates/patch-findings.md +3 -3
- package/skills/gsd-path/templates/plan.md +17 -2
- package/skills/gsd-path/templates/research-handoff.md +14 -3
- package/skills/gsd-path/templates/state.md +2 -1
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +28 -9
- package/skills/gsd-path-build/references/build-native.md +112 -10
- 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/dispatch.md +13 -0
- package/skills/gsd-path-build/references/operating-rules.md +11 -3
- package/skills/gsd-path-build/references/reviewer-final.md +20 -2
- package/skills/gsd-path-build/references/reviewer-wave.md +56 -12
- package/skills/gsd-path-build/references/reviewer.md +3 -1
- package/skills/gsd-path-build/references/runtime-selection.md +9 -0
- package/skills/gsd-path-build/references/spec-probes.md +150 -0
- package/skills/gsd-path-build/scripts/_common.py +256 -2
- package/skills/gsd-path-build/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-build/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-build/scripts/build_state.py +274 -8
- package/skills/gsd-path-build/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-build/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-build/scripts/detect_project.py +260 -20
- package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-build/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-build/scripts/dispatch_driver.py +549 -53
- package/skills/gsd-path-build/scripts/integration.py +244 -65
- package/skills/gsd-path-build/scripts/isolation.py +539 -70
- package/skills/gsd-path-build/scripts/loop_run.py +16 -4
- package/skills/gsd-path-build/scripts/members.py +77 -32
- package/skills/gsd-path-build/scripts/model_policy.py +5 -1
- package/skills/gsd-path-build/scripts/path_config.py +3 -3
- package/skills/gsd-path-build/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-build/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-build/scripts/state_promote.py +15 -4
- package/skills/gsd-path-build/scripts/task_context.py +14 -3
- package/skills/gsd-path-build/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-build/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +28 -9
- package/skills/gsd-path-decide/references/dispatch.md +13 -0
- package/skills/gsd-path-decide/references/operating-rules.md +11 -3
- package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
- package/skills/gsd-path-decide/scripts/_common.py +256 -2
- package/skills/gsd-path-decide/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-decide/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-decide/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-decide/scripts/detect_project.py +260 -20
- package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-decide/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-decide/scripts/integration.py +244 -65
- package/skills/gsd-path-decide/scripts/isolation.py +539 -70
- package/skills/gsd-path-decide/scripts/loop_run.py +16 -4
- package/skills/gsd-path-decide/scripts/members.py +77 -32
- package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
- package/skills/gsd-path-decide/scripts/path_config.py +3 -3
- package/skills/gsd-path-decide/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-decide/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
- package/skills/gsd-path-decide/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-define/SKILL.md +34 -5
- package/skills/gsd-path-define/references/build-recovery.md +13 -0
- package/skills/gsd-path-define/references/operating-rules.md +11 -3
- package/skills/gsd-path-define/references/runtime-selection.md +9 -0
- package/skills/gsd-path-define/references/spec-probes.md +150 -0
- package/skills/gsd-path-define/scripts/_common.py +256 -2
- package/skills/gsd-path-define/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-define/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-define/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-define/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-define/scripts/detect_project.py +260 -20
- package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-define/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-define/scripts/integration.py +244 -65
- package/skills/gsd-path-define/scripts/isolation.py +539 -70
- package/skills/gsd-path-define/scripts/loop_run.py +16 -4
- package/skills/gsd-path-define/scripts/members.py +77 -32
- package/skills/gsd-path-define/scripts/model_policy.py +5 -1
- package/skills/gsd-path-define/scripts/path_config.py +3 -3
- package/skills/gsd-path-define/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-define/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-define/scripts/state_promote.py +15 -4
- package/skills/gsd-path-define/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-define/templates/intent.md +30 -0
- package/skills/gsd-path-define/templates/state.md +2 -1
- package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
- package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
- package/skills/gsd-path-discuss/scripts/_common.py +256 -2
- package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-discuss/scripts/loop_run.py +16 -4
- package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
- package/skills/gsd-path-discuss/scripts/path_config.py +3 -3
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +5 -0
- package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
- package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +256 -2
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +260 -20
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-docs-audit/scripts/integration.py +244 -65
- package/skills/gsd-path-docs-audit/scripts/isolation.py +539 -70
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +16 -4
- package/skills/gsd-path-docs-audit/scripts/members.py +77 -32
- package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
- package/skills/gsd-path-docs-audit/scripts/path_config.py +3 -3
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +5 -1
- package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
- package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
- package/skills/gsd-path-forensics/scripts/_common.py +256 -2
- package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-forensics/scripts/loop_run.py +16 -4
- package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
- package/skills/gsd-path-forensics/scripts/path_config.py +3 -3
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +118 -16
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-inspect/references/dispatch.md +13 -0
- package/skills/gsd-path-inspect/references/docs-auditor.md +5 -0
- package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
- package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
- package/skills/gsd-path-inspect/scripts/_common.py +256 -2
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-inspect/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-inspect/scripts/detect_project.py +260 -20
- package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-inspect/scripts/integration.py +244 -65
- package/skills/gsd-path-inspect/scripts/isolation.py +539 -70
- package/skills/gsd-path-inspect/scripts/loop_run.py +16 -4
- package/skills/gsd-path-inspect/scripts/members.py +77 -32
- package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
- package/skills/gsd-path-inspect/scripts/path_config.py +3 -3
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
- package/skills/gsd-path-inspect/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-inspect/templates/docs-audit.md +5 -1
- package/skills/gsd-path-inspect/templates/state.md +2 -1
- package/skills/gsd-path-loop/references/operating-rules.md +11 -3
- package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
- package/skills/gsd-path-loop/scripts/_common.py +256 -2
- package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-loop/scripts/loop_run.py +16 -4
- package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
- package/skills/gsd-path-loop/scripts/path_config.py +3 -3
- package/skills/gsd-path-loop/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-migrate/SKILL.md +8 -0
- package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
- package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
- package/skills/gsd-path-migrate/scripts/_common.py +256 -2
- package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-migrate/scripts/loop_run.py +16 -4
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
- package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
- package/skills/gsd-path-migrate/scripts/path_config.py +3 -3
- package/skills/gsd-path-plan/SKILL.md +14 -3
- package/skills/gsd-path-plan/references/build-recovery.md +13 -0
- package/skills/gsd-path-plan/references/dispatch.md +13 -0
- package/skills/gsd-path-plan/references/operating-rules.md +11 -3
- package/skills/gsd-path-plan/references/planner.md +26 -4
- package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
- package/skills/gsd-path-plan/references/spec-probes.md +150 -0
- package/skills/gsd-path-plan/scripts/_common.py +256 -2
- package/skills/gsd-path-plan/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-plan/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-plan/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-plan/scripts/detect_project.py +260 -20
- package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-plan/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-plan/scripts/integration.py +244 -65
- package/skills/gsd-path-plan/scripts/isolation.py +539 -70
- package/skills/gsd-path-plan/scripts/loop_run.py +16 -4
- package/skills/gsd-path-plan/scripts/members.py +77 -32
- package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
- package/skills/gsd-path-plan/scripts/path_config.py +3 -3
- package/skills/gsd-path-plan/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-plan/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
- package/skills/gsd-path-plan/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-plan/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
- package/skills/gsd-path-plan/templates/plan.md +17 -2
- package/skills/gsd-path-plan/templates/task.md +1 -0
- package/skills/gsd-path-research/SKILL.md +11 -0
- package/skills/gsd-path-research/references/dispatch.md +13 -0
- package/skills/gsd-path-research/references/operating-rules.md +11 -3
- package/skills/gsd-path-research/references/runtime-selection.md +9 -0
- package/skills/gsd-path-research/scripts/_common.py +256 -2
- package/skills/gsd-path-research/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-research/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-research/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-research/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-research/scripts/detect_project.py +260 -20
- package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-research/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-research/scripts/integration.py +244 -65
- package/skills/gsd-path-research/scripts/isolation.py +539 -70
- package/skills/gsd-path-research/scripts/loop_run.py +16 -4
- package/skills/gsd-path-research/scripts/members.py +77 -32
- package/skills/gsd-path-research/scripts/model_policy.py +5 -1
- package/skills/gsd-path-research/scripts/path_config.py +3 -3
- package/skills/gsd-path-research/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-research/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-research/scripts/state_promote.py +15 -4
- package/skills/gsd-path-research/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-research/templates/research-handoff.md +14 -3
- package/skills/gsd-path-roadmap/SKILL.md +16 -6
- package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
- package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
- package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +256 -2
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-roadmap/scripts/detect_project.py +260 -20
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-roadmap/scripts/integration.py +244 -65
- package/skills/gsd-path-roadmap/scripts/isolation.py +539 -70
- package/skills/gsd-path-roadmap/scripts/loop_run.py +16 -4
- package/skills/gsd-path-roadmap/scripts/members.py +77 -32
- package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
- package/skills/gsd-path-roadmap/scripts/path_config.py +3 -3
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-ship/SKILL.md +32 -5
- package/skills/gsd-path-ship/references/dispatch.md +13 -0
- package/skills/gsd-path-ship/references/operating-rules.md +11 -3
- package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
- package/skills/gsd-path-ship/references/reviewer-wave.md +56 -12
- package/skills/gsd-path-ship/references/reviewer.md +3 -1
- package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
- package/skills/gsd-path-ship/references/spec-probes.md +150 -0
- package/skills/gsd-path-ship/scripts/_common.py +256 -2
- package/skills/gsd-path-ship/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-ship/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-ship/scripts/build_state.py +274 -8
- package/skills/gsd-path-ship/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-ship/scripts/detect_project.py +260 -20
- package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-ship/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-ship/scripts/integration.py +244 -65
- package/skills/gsd-path-ship/scripts/isolation.py +539 -70
- package/skills/gsd-path-ship/scripts/loop_run.py +16 -4
- package/skills/gsd-path-ship/scripts/members.py +77 -32
- package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
- package/skills/gsd-path-ship/scripts/path_config.py +3 -3
- package/skills/gsd-path-ship/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-ship/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
- package/skills/gsd-path-ship/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-ship/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-ship/templates/final-review.md +11 -2
- package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
- package/skills/gsd-path-ship/templates/wave-review.md +28 -9
- package/skills/gsd-path-undo/references/operating-rules.md +11 -3
- package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
- package/skills/gsd-path-undo/scripts/_common.py +256 -2
- package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-undo/scripts/loop_run.py +16 -4
- package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
- package/skills/gsd-path-undo/scripts/path_config.py +3 -3
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +118 -16
- package/skills/gsd-path-undo/scripts/worktree_paths.py +54 -2
- package/skills/path/DEFINE.md +34 -5
- package/skills/path/PLAN.md +14 -3
- package/skills/path/RESEARCH.md +11 -0
- package/skills/path/ROADMAP.md +16 -6
- package/skills/path/SHIP.md +32 -5
- package/skills/path/SKILL.md +52 -24
- package/skills/path/references/build-native.md +112 -10
- package/skills/path/references/build-recovery.md +13 -0
- package/skills/path/references/coder.md +7 -3
- package/skills/path/references/dispatch.md +13 -0
- package/skills/path/references/docs-auditor.md +5 -0
- package/skills/path/references/operating-rules.md +11 -3
- package/skills/path/references/planner.md +26 -4
- package/skills/path/references/reviewer-final.md +20 -2
- package/skills/path/references/reviewer-wave.md +56 -12
- package/skills/path/references/reviewer.md +3 -1
- package/skills/path/references/runtime-selection.md +9 -0
- package/skills/path/references/spec-probes.md +150 -0
- package/skills/path/scripts/_common.py +256 -2
- package/skills/path/scripts/archive_milestone.py +14 -13
- package/skills/path/scripts/build_recovery.py +155 -58
- package/skills/path/scripts/build_state.py +274 -8
- package/skills/path/scripts/check_docs_audit.py +77 -4
- package/skills/path/scripts/check_handoffs.py +635 -57
- package/skills/path/scripts/check_task_briefs.py +293 -32
- package/skills/path/scripts/detect_project.py +260 -20
- package/skills/path/scripts/discussion_records.py +9 -1
- package/skills/path/scripts/discussion_validate.py +93 -35
- package/skills/path/scripts/dispatch_driver.py +549 -53
- package/skills/path/scripts/git_guard.py +27 -8
- package/skills/path/scripts/integration.py +244 -65
- package/skills/path/scripts/isolation.py +539 -70
- package/skills/path/scripts/loop_run.py +16 -4
- package/skills/path/scripts/members.py +77 -32
- package/skills/path/scripts/model_policy.py +5 -1
- package/skills/path/scripts/path_config.py +3 -3
- package/skills/path/scripts/pipeline_git.py +131 -42
- package/skills/path/scripts/pipeline_state.py +139 -39
- 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 +39 -36
- package/skills/path/scripts/state_promote.py +15 -4
- package/skills/path/scripts/status_runtime.py +22 -4
- package/skills/path/scripts/task_context.py +14 -3
- package/skills/path/scripts/workflow_run.py +14 -4
- package/skills/path/scripts/worktree_paths.py +54 -2
- package/skills/path/templates/docs-audit.md +5 -1
- package/skills/path/templates/final-review.md +11 -2
- package/skills/path/templates/intent.md +30 -0
- package/skills/path/templates/patch-findings.md +3 -3
- package/skills/path/templates/plan.md +17 -2
- package/skills/path/templates/research-handoff.md +14 -3
- package/skills/path/templates/state.md +2 -1
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +28 -9
- package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
package/scripts/install.mjs
CHANGED
|
@@ -212,9 +212,10 @@ export const EXPLICIT_ONLY_TARGETS = new Set([
|
|
|
212
212
|
"cursor",
|
|
213
213
|
"zed",
|
|
214
214
|
"kimi",
|
|
215
|
+
"muse",
|
|
215
216
|
"shared-agents",
|
|
216
217
|
]);
|
|
217
|
-
const SHARED_AGENT_TARGETS = new Set(["codex", "antigravity", "zed"]);
|
|
218
|
+
const SHARED_AGENT_TARGETS = new Set(["codex", "antigravity", "zed", "muse"]);
|
|
218
219
|
export const SHARED_AGENT_PROFILE = "shared-agents";
|
|
219
220
|
export const CURSOR_AGENT_FILENAME = "gsd-path.md";
|
|
220
221
|
export const CURSOR_AGENT_BACKUP_NAME = "cursor-agent-gsd-path.md";
|
|
@@ -228,7 +229,7 @@ const MANIFEST = JSON.parse(
|
|
|
228
229
|
);
|
|
229
230
|
|
|
230
231
|
function sharedInvocations(text) {
|
|
231
|
-
const pattern = /(`?)(\$gsd-path(?:-[a-z0-9]+)*|\$path)( status)?\1(?: \(Codex\) (?:and|or) (`?)\/(gsd-path(?:-[a-z0-9]+)*|path)( status)?\4 \((?:other hosts|Antigravity\/Zed)\))?/g;
|
|
232
|
+
const pattern = /(`?)(\$gsd-path(?:-[a-z0-9]+)*|\$path)( status)?\1(?: \(Codex\) (?:and|or) (`?)\/(gsd-path(?:-[a-z0-9]+)*|path)( status)?\4 \((?:other hosts|Antigravity\/Zed\/Muse)\))?/g;
|
|
232
233
|
return text.replace(pattern, (_match, quote, token, arguments_, pairedQuote, pairedSkill, pairedArguments) => {
|
|
233
234
|
const skill = token.slice(1);
|
|
234
235
|
const argumentsText = arguments_ || "";
|
|
@@ -237,7 +238,7 @@ function sharedInvocations(text) {
|
|
|
237
238
|
}
|
|
238
239
|
const codex = `${MANIFEST.hosts.codex.invocation_prefix}${skill}`;
|
|
239
240
|
const others = `${MANIFEST.hosts.antigravity.invocation_prefix}${skill}`;
|
|
240
|
-
return `${quote}${codex}${argumentsText}${quote} (Codex) or ${quote}${others}${argumentsText}${quote} (Antigravity/Zed)`;
|
|
241
|
+
return `${quote}${codex}${argumentsText}${quote} (Codex) or ${quote}${others}${argumentsText}${quote} (Antigravity/Zed/Muse)`;
|
|
241
242
|
});
|
|
242
243
|
}
|
|
243
244
|
export function skillNamesForManifest(manifest) {
|
|
@@ -355,7 +356,7 @@ export function defaultRoot(target, env = process.env) {
|
|
|
355
356
|
}
|
|
356
357
|
if (target === "antigravity") return absolutePath("~/.gemini/antigravity-cli/skills");
|
|
357
358
|
if (target === "cursor") return absolutePath("~/.cursor/skills");
|
|
358
|
-
if (target === "zed") return absolutePath("~/.agents/skills");
|
|
359
|
+
if (target === "zed" || target === "muse") return absolutePath("~/.agents/skills");
|
|
359
360
|
if (target === "kiro") {
|
|
360
361
|
return absolutePath(path.join(env.KIRO_HOME || expandUser("~/.kiro"), "skills"));
|
|
361
362
|
}
|
|
@@ -386,7 +387,9 @@ function isOwnedRouterAlias(skillDir) {
|
|
|
386
387
|
const versionFile = path.join(skillDir, "VERSION");
|
|
387
388
|
if (!isFile(versionFile)) return isManagedProjectRuntime(runtime); // installs before alias version stamping
|
|
388
389
|
try {
|
|
389
|
-
return /^[0-9]+(?:\.[0-9]+)
|
|
390
|
+
return /^[0-9]+(?:\.[0-9]+)+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.test(
|
|
391
|
+
fs.readFileSync(versionFile, "utf8").trim()
|
|
392
|
+
);
|
|
390
393
|
} catch {
|
|
391
394
|
return false;
|
|
392
395
|
}
|
|
@@ -1037,7 +1040,7 @@ async function applyTarget(plan, stagedRoot, transaction) {
|
|
|
1037
1040
|
const destination = path.join(plan.root, name);
|
|
1038
1041
|
hooks.reserveDirectory(destination);
|
|
1039
1042
|
transaction.installed.push(destination);
|
|
1040
|
-
|
|
1043
|
+
copyIntoReservedDirectory(path.join(stagedRoot, name), destination);
|
|
1041
1044
|
await tick();
|
|
1042
1045
|
}
|
|
1043
1046
|
if (cursorAgent !== null) {
|
|
@@ -1051,6 +1054,18 @@ function reserveDirectory(destination) {
|
|
|
1051
1054
|
fs.mkdirSync(destination);
|
|
1052
1055
|
}
|
|
1053
1056
|
|
|
1057
|
+
// Node 26 rejects recursive cpSync when the destination directory already exists
|
|
1058
|
+
// and errorOnExist is set. Reserve the skill directory, then copy each staged entry.
|
|
1059
|
+
export function copyIntoReservedDirectory(source, destination) {
|
|
1060
|
+
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
|
|
1061
|
+
fs.cpSync(path.join(source, entry.name), path.join(destination, entry.name), {
|
|
1062
|
+
recursive: true,
|
|
1063
|
+
errorOnExist: true,
|
|
1064
|
+
force: false,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1054
1069
|
function reserveFile(destination) {
|
|
1055
1070
|
const descriptor = fs.openSync(destination, "wx", 0o644);
|
|
1056
1071
|
try {
|
|
@@ -1192,7 +1207,7 @@ export function deploymentPlans(plans) {
|
|
|
1192
1207
|
if (group.length > 1) {
|
|
1193
1208
|
if (!targets.every((name) => SHARED_AGENT_TARGETS.has(name))) {
|
|
1194
1209
|
throw new InstallerError(
|
|
1195
|
-
`only Codex, Antigravity, and
|
|
1210
|
+
`only Codex, Antigravity, Zed, and Muse may share a skills root: ${targets.join(", ")}`
|
|
1196
1211
|
);
|
|
1197
1212
|
}
|
|
1198
1213
|
profile = SHARED_AGENT_PROFILE;
|
|
@@ -1545,8 +1560,53 @@ export async function install(sourceRoot, plans, options = {}) {
|
|
|
1545
1560
|
return results;
|
|
1546
1561
|
}
|
|
1547
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
|
+
|
|
1548
1608
|
// Documented project-relative skill roots (verified against each host's
|
|
1549
|
-
// official skills docs). Codex, Zed, and Antigravity all discover the
|
|
1609
|
+
// official skills docs). Codex, Zed, Muse, and Antigravity all discover the
|
|
1550
1610
|
// project-level .agents/skills standard directory.
|
|
1551
1611
|
export function localRoot(target, projectDir) {
|
|
1552
1612
|
const relative = LOCAL_ROOTS[target];
|
|
@@ -1565,10 +1625,16 @@ export function detectInstalls(targets, rootFor) {
|
|
|
1565
1625
|
return plans;
|
|
1566
1626
|
}
|
|
1567
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
|
+
|
|
1568
1633
|
export function parseCli(argv) {
|
|
1569
1634
|
const options = {
|
|
1570
1635
|
all: { type: "boolean", default: false },
|
|
1571
1636
|
update: { type: "boolean", default: false },
|
|
1637
|
+
uninstall: { type: "boolean", default: false },
|
|
1572
1638
|
"dry-run": { type: "boolean", default: false },
|
|
1573
1639
|
local: { type: "boolean", default: false },
|
|
1574
1640
|
project: { type: "string" },
|
|
@@ -1655,13 +1721,16 @@ function usage() {
|
|
|
1655
1721
|
"Docs: DOCS.md (hub) · QUICK.md (first run) · FULL.md · UPDATE.md\n\n" +
|
|
1656
1722
|
"usage: gsd-path (no flags on a terminal opens the interactive wizard)\n" +
|
|
1657
1723
|
" gsd-path [--all] [--update] [--local] [--dry-run] [--project PATH]\n" +
|
|
1658
|
-
" [--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" +
|
|
1659
1726
|
" First install: gsd-path --all --dry-run && gsd-path --all\n" +
|
|
1660
1727
|
" New repo: gsd-path --all --project /path/to/repo\n" +
|
|
1661
1728
|
" Update skills: gsd-path --update (or npx @opengsd/gsd-path@latest --update)\n\n" +
|
|
1662
1729
|
`targets: ${flags}\n` +
|
|
1663
1730
|
" --update refresh existing installs in place; with --project also\n" +
|
|
1664
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" +
|
|
1665
1734
|
" --local install into this project's per-host skill dirs\n" +
|
|
1666
1735
|
" --project PATH write project contracts and status runtime; requires Python 3.9+\n" +
|
|
1667
1736
|
" --doctor read-only health check of installs, hooks, and state\n" +
|
|
@@ -1712,6 +1781,20 @@ export async function main(argv, env = process.env) {
|
|
|
1712
1781
|
: path.resolve(SCRIPT_DIRECTORY, "..");
|
|
1713
1782
|
const project =
|
|
1714
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
|
+
}
|
|
1715
1798
|
const migrateAndUpdate = values["runtime-migrate"] && values.update;
|
|
1716
1799
|
if (migrateAndUpdate && (project === null || values["runtime-restore"] || values["runtime-upgrade"] || values.doctor || values["hooks-init"] || values["hooks-refresh"] || values["hooks-refresh-full"])) {
|
|
1717
1800
|
ui.error("--runtime-migrate --update requires --project and cannot be combined with another runtime, doctor, or hook operation");
|
|
@@ -1807,7 +1890,10 @@ export async function main(argv, env = process.env) {
|
|
|
1807
1890
|
}
|
|
1808
1891
|
}
|
|
1809
1892
|
const sourceRootForInstall = sourceRoot;
|
|
1810
|
-
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}`;
|
|
1811
1897
|
const mode = scope + (values["dry-run"] ? " · dry run" : "");
|
|
1812
1898
|
ui.banner(mode);
|
|
1813
1899
|
let plans;
|
|
@@ -1840,7 +1926,7 @@ export async function main(argv, env = process.env) {
|
|
|
1840
1926
|
}
|
|
1841
1927
|
const spin = ui.spinner("Preparing");
|
|
1842
1928
|
try {
|
|
1843
|
-
const results = await install(sourceRootForInstall, plans, {
|
|
1929
|
+
const results = values.uninstall ? uninstall(plans, { dryRun: values["dry-run"] }) : await install(sourceRootForInstall, plans, {
|
|
1844
1930
|
project,
|
|
1845
1931
|
dryRun: values["dry-run"],
|
|
1846
1932
|
env,
|
|
@@ -1855,6 +1941,8 @@ export async function main(argv, env = process.env) {
|
|
|
1855
1941
|
}
|
|
1856
1942
|
const closing = values["dry-run"]
|
|
1857
1943
|
? "Dry run — nothing was written."
|
|
1944
|
+
: values.uninstall
|
|
1945
|
+
? "Done. Restart active agent sessions."
|
|
1858
1946
|
: values.update
|
|
1859
1947
|
? "Updated. Previous copies are in each root's disabled-gsd-skills backup."
|
|
1860
1948
|
: "Done. Restart active agent sessions, then invoke the router explicitly.";
|
package/scripts/install.py
CHANGED
|
@@ -124,7 +124,7 @@ STATUS_STATE_FIELDS = frozenset(
|
|
|
124
124
|
"integration_source",
|
|
125
125
|
}
|
|
126
126
|
)
|
|
127
|
-
STATUS_INTEGRATION_MODES = frozenset({"direct", "pull-request"})
|
|
127
|
+
STATUS_INTEGRATION_MODES = frozenset({"direct", "pull-request", "external-landing"})
|
|
128
128
|
STATUS_INTEGRATION_SOURCES = frozenset({"default", "milestone"})
|
|
129
129
|
STATUS_SLUG = re.compile(r"^[a-z0-9][a-z0-9-]*$")
|
|
130
130
|
STATUS_BRANCH = re.compile(r"^gsd-path/M(\d{3,})$")
|
|
@@ -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]:
|
|
@@ -505,9 +515,9 @@ HOST_NOTES = {
|
|
|
505
515
|
"kiro": KIRO_NOTE,
|
|
506
516
|
}
|
|
507
517
|
EXPLICIT_ONLY_TARGETS = frozenset(
|
|
508
|
-
{"claude", "grok", "copilot", "qwen", "cursor", "zed", "kimi", "shared-agents"}
|
|
518
|
+
{"claude", "grok", "copilot", "qwen", "cursor", "zed", "kimi", "muse", "shared-agents"}
|
|
509
519
|
)
|
|
510
|
-
SHARED_AGENT_TARGETS = frozenset({"codex", "antigravity", "zed"})
|
|
520
|
+
SHARED_AGENT_TARGETS = frozenset({"codex", "antigravity", "zed", "muse"})
|
|
511
521
|
SHARED_AGENT_PROFILE = "shared-agents"
|
|
512
522
|
CURSOR_AGENT_FILENAME = "gsd-path.md"
|
|
513
523
|
CURSOR_AGENT_BACKUP_NAME = "cursor-agent-gsd-path.md"
|
|
@@ -533,7 +543,7 @@ def _shared_invocations(text: str) -> str:
|
|
|
533
543
|
others = f"{hosts['antigravity']['invocation_prefix']}{skill}"
|
|
534
544
|
return (
|
|
535
545
|
f"{quote}{codex}{arguments}{quote} (Codex) or "
|
|
536
|
-
f"{quote}{others}{arguments}{quote} (Antigravity/Zed)"
|
|
546
|
+
f"{quote}{others}{arguments}{quote} (Antigravity/Zed/Muse)"
|
|
537
547
|
)
|
|
538
548
|
|
|
539
549
|
return re.sub(
|
|
@@ -542,7 +552,7 @@ def _shared_invocations(text: str) -> str:
|
|
|
542
552
|
r"(?: \(Codex\) (?:and|or) (?P<paired_quote>`?)/"
|
|
543
553
|
r"(?P<paired_skill>gsd-path(?:-[a-z0-9]+)*|path)"
|
|
544
554
|
r"(?P<paired_arguments> status)?(?P=paired_quote)"
|
|
545
|
-
r" \((?:other hosts|Antigravity/Zed)\))?",
|
|
555
|
+
r" \((?:other hosts|Antigravity/Zed/Muse)\))?",
|
|
546
556
|
replace,
|
|
547
557
|
text,
|
|
548
558
|
)
|
|
@@ -620,7 +630,7 @@ def default_root(target: str, environ: Optional[Mapping[str, str]] = None) -> Pa
|
|
|
620
630
|
return absolute_path(Path("~/.gemini/antigravity-cli/skills"))
|
|
621
631
|
if target == "cursor":
|
|
622
632
|
return absolute_path(Path("~/.cursor/skills"))
|
|
623
|
-
if target
|
|
633
|
+
if target in ("zed", "muse"):
|
|
624
634
|
return absolute_path(Path("~/.agents/skills"))
|
|
625
635
|
if target == "kiro":
|
|
626
636
|
return absolute_path(Path(env.get("KIRO_HOME") or "~/.kiro") / "skills")
|
|
@@ -656,7 +666,15 @@ def _is_owned_router_alias(skill_dir: Path) -> bool:
|
|
|
656
666
|
version = version_file.read_text(encoding="utf-8").strip()
|
|
657
667
|
except (OSError, UnicodeError):
|
|
658
668
|
return False
|
|
659
|
-
return
|
|
669
|
+
return (
|
|
670
|
+
re.fullmatch(
|
|
671
|
+
r"[0-9]+(?:\.[0-9]+)+"
|
|
672
|
+
r"(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?"
|
|
673
|
+
r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?",
|
|
674
|
+
version,
|
|
675
|
+
)
|
|
676
|
+
is not None
|
|
677
|
+
)
|
|
660
678
|
|
|
661
679
|
|
|
662
680
|
def _is_managed_install_entry(root: Path, name: str) -> bool:
|
|
@@ -1199,6 +1217,35 @@ def _rollback_target(transaction: TargetTransaction) -> None:
|
|
|
1199
1217
|
_remove_empty_directories(transaction.created_directories)
|
|
1200
1218
|
|
|
1201
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
|
+
|
|
1202
1249
|
def _project_destinations(
|
|
1203
1250
|
project: Path,
|
|
1204
1251
|
selected: Sequence[str],
|
|
@@ -1260,9 +1307,9 @@ def _project_destinations(
|
|
|
1260
1307
|
)
|
|
1261
1308
|
if hooks_dir is not None:
|
|
1262
1309
|
for hook_name, generator in GIT_HOOKS:
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
)
|
|
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))
|
|
1266
1313
|
return destinations
|
|
1267
1314
|
|
|
1268
1315
|
|
|
@@ -1664,6 +1711,13 @@ def _validate_project(
|
|
|
1664
1711
|
managed = (
|
|
1665
1712
|
_update_replacement(project, destination, hooks_dir) if update else None
|
|
1666
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
|
|
1667
1721
|
if destination.is_symlink() or (merge is None and not update):
|
|
1668
1722
|
raise _existing_contract_error(destination)
|
|
1669
1723
|
if merge is not None:
|
|
@@ -1710,6 +1764,21 @@ def _apply_project(
|
|
|
1710
1764
|
_apply_agents(source_root, destination, transaction)
|
|
1711
1765
|
continue
|
|
1712
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
|
|
1713
1782
|
if _lexists(destination) and not destination.is_symlink():
|
|
1714
1783
|
replaceable = (
|
|
1715
1784
|
update
|
|
@@ -2151,7 +2220,9 @@ def _validate_hooks_refresh(
|
|
|
2151
2220
|
raise InstallerError(
|
|
2152
2221
|
f"refusing to refresh a symlink: {hook_path}"
|
|
2153
2222
|
)
|
|
2154
|
-
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):
|
|
2155
2226
|
raise InstallerError(
|
|
2156
2227
|
f"not a managed GSD Path git hook: {hook_path}"
|
|
2157
2228
|
)
|
|
@@ -2259,7 +2330,7 @@ def _deployment_plans(plans: Sequence[TargetPlan]) -> List[DeploymentPlan]:
|
|
|
2259
2330
|
if not target_set <= SHARED_AGENT_TARGETS:
|
|
2260
2331
|
labels = ", ".join(targets)
|
|
2261
2332
|
raise InstallerError(
|
|
2262
|
-
"only Codex, Antigravity, and
|
|
2333
|
+
"only Codex, Antigravity, Zed, and Muse may share a skills root: "
|
|
2263
2334
|
f"{labels}"
|
|
2264
2335
|
)
|
|
2265
2336
|
profile = SHARED_AGENT_PROFILE
|
|
@@ -2836,6 +2907,8 @@ def doctor(
|
|
|
2836
2907
|
else:
|
|
2837
2908
|
for name in PROJECT_RUNTIME_SCRIPTS:
|
|
2838
2909
|
destination = runtime / name
|
|
2910
|
+
if pinned and not _lexists(destination):
|
|
2911
|
+
continue # a valid older selected runtime lacks helpers added later
|
|
2839
2912
|
if destination.is_symlink():
|
|
2840
2913
|
push("fail", f"project: runtime {name} is a symlink")
|
|
2841
2914
|
runtime_current = False
|
|
@@ -2995,7 +3068,9 @@ def doctor(
|
|
|
2995
3068
|
if not _is_managed_git_hook_content(hook_text):
|
|
2996
3069
|
push("warn", f"hooks: {label} is not a managed GSD Path git hook")
|
|
2997
3070
|
elif not any(
|
|
2998
|
-
hook_text == generator(
|
|
3071
|
+
hook_text == generator(
|
|
3072
|
+
candidate, _lexists(_chained_hook_path(hook_path))
|
|
3073
|
+
)
|
|
2999
3074
|
for candidate in INTERPRETER_CANDIDATES
|
|
3000
3075
|
):
|
|
3001
3076
|
push("warn", f"hooks: {label} is stale — run --hooks-refresh-full")
|
|
@@ -3275,6 +3350,87 @@ def install(
|
|
|
3275
3350
|
return results
|
|
3276
3351
|
|
|
3277
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
|
+
|
|
3403
|
+
def _runtime_provenance(arguments, source_root: Path):
|
|
3404
|
+
"""Owner-recorded provenance from --runtime-provenance-* upgrade flags.
|
|
3405
|
+
|
|
3406
|
+
When the supplied source root is a git checkout and no patch reference
|
|
3407
|
+
was given, its HEAD sha is recorded with one best-effort rev-parse.
|
|
3408
|
+
Provenance is display/audit metadata on the runtime declaration only; it
|
|
3409
|
+
never joins the pinned digest or runtime validation.
|
|
3410
|
+
"""
|
|
3411
|
+
supplied = (arguments.runtime_provenance_source, arguments.runtime_provenance_patch,
|
|
3412
|
+
arguments.runtime_provenance_note)
|
|
3413
|
+
recorded = {key: value for key, value in zip(runtime_store.PROVENANCE_KEYS, supplied) if value}
|
|
3414
|
+
if not recorded:
|
|
3415
|
+
return None
|
|
3416
|
+
if "patch_ref" not in recorded:
|
|
3417
|
+
try:
|
|
3418
|
+
head = subprocess.run(["git", "rev-parse", "--show-toplevel", "HEAD"], cwd=source_root,
|
|
3419
|
+
capture_output=True, encoding="utf-8", check=True)
|
|
3420
|
+
toplevel, _, sha = head.stdout.strip().partition("\n")
|
|
3421
|
+
if sha and Path(toplevel).resolve() == Path(source_root).resolve():
|
|
3422
|
+
recorded["patch_ref"] = sha
|
|
3423
|
+
except (OSError, subprocess.CalledProcessError):
|
|
3424
|
+
pass
|
|
3425
|
+
return recorded
|
|
3426
|
+
|
|
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
|
+
|
|
3278
3434
|
def parser() -> argparse.ArgumentParser:
|
|
3279
3435
|
argument_parser = argparse.ArgumentParser(description=__doc__)
|
|
3280
3436
|
for target in TARGETS:
|
|
@@ -3283,6 +3439,12 @@ def parser() -> argparse.ArgumentParser:
|
|
|
3283
3439
|
argument_parser.add_argument("--adapter-request", action="store_true", help=argparse.SUPPRESS)
|
|
3284
3440
|
argument_parser.add_argument("--all", action="store_true", dest="all_targets")
|
|
3285
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
|
+
)
|
|
3286
3448
|
argument_parser.add_argument("--local", action="store_true")
|
|
3287
3449
|
argument_parser.add_argument("--dry-run", action="store_true")
|
|
3288
3450
|
argument_parser.add_argument("--project", type=Path)
|
|
@@ -3291,6 +3453,9 @@ def parser() -> argparse.ArgumentParser:
|
|
|
3291
3453
|
runtime_actions = argument_parser.add_mutually_exclusive_group()
|
|
3292
3454
|
for action in ("restore", "upgrade", "migrate"):
|
|
3293
3455
|
runtime_actions.add_argument(f"--runtime-{action}", action="store_true")
|
|
3456
|
+
argument_parser.add_argument("--runtime-provenance-source")
|
|
3457
|
+
argument_parser.add_argument("--runtime-provenance-patch")
|
|
3458
|
+
argument_parser.add_argument("--runtime-provenance-note")
|
|
3294
3459
|
argument_parser.add_argument("--hooks", action="store_true")
|
|
3295
3460
|
argument_parser.add_argument("--hooks-init", action="store_true")
|
|
3296
3461
|
argument_parser.add_argument("--hooks-refresh", action="store_true")
|
|
@@ -3334,8 +3499,27 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
3334
3499
|
project = (
|
|
3335
3500
|
absolute_path(arguments.project) if arguments.project is not None else None
|
|
3336
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
|
|
3337
3518
|
runtime_action = next((action for action in ("restore", "upgrade", "migrate")
|
|
3338
3519
|
if getattr(arguments, "runtime_" + action)), None)
|
|
3520
|
+
provenance = _runtime_provenance(arguments, source_root)
|
|
3521
|
+
if provenance is not None and runtime_action != "upgrade":
|
|
3522
|
+
argument_parser.error("--runtime-provenance-* requires --runtime-upgrade")
|
|
3339
3523
|
if runtime_action:
|
|
3340
3524
|
if project is None:
|
|
3341
3525
|
argument_parser.error(f"--runtime-{runtime_action} requires --project")
|
|
@@ -3343,7 +3527,8 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
3343
3527
|
_validate_project_git_root(project)
|
|
3344
3528
|
locks, created = ([], []) if arguments.dry_run else _acquire_install_locks([project / HOOKS_DIRECTORY])
|
|
3345
3529
|
try:
|
|
3346
|
-
pin = runtime_store.operate(source_root, project, runtime_action,
|
|
3530
|
+
pin = runtime_store.operate(source_root, project, runtime_action,
|
|
3531
|
+
dry_run=arguments.dry_run, provenance=provenance)
|
|
3347
3532
|
finally:
|
|
3348
3533
|
_release_install_locks(locks, created)
|
|
3349
3534
|
print(f"runtime: {runtime_action} {pin['version']} ({pin['digest']})"
|
|
@@ -3477,7 +3662,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
|
3477
3662
|
)
|
|
3478
3663
|
return 1
|
|
3479
3664
|
try:
|
|
3480
|
-
for result in install(
|
|
3665
|
+
for result in uninstall(plans, arguments.dry_run) if arguments.uninstall else install(
|
|
3481
3666
|
source_root,
|
|
3482
3667
|
plans,
|
|
3483
3668
|
project,
|