@opengsd/gsd-path 1.1.0 → 1.3.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/AGENTS.md +5 -2
- package/CHANGELOG.md +87 -0
- package/DOCS.md +73 -1
- package/FULL.md +3 -2
- package/HOOKS.md +18 -9
- package/QUICK.md +3 -4
- package/README.md +72 -5
- package/RUNTIME.md +9 -4
- package/UPDATE.md +56 -11
- package/WORKFLOW.md +5 -2
- package/package.json +9 -1
- package/platforms/claude/dispatch.md +4 -4
- package/platforms/copilot/dispatch.md +4 -4
- package/platforms/cursor/dispatch.md +5 -10
- package/platforms/grok/dispatch.md +4 -6
- package/platforms/kimi/dispatch.md +4 -4
- package/platforms/kiro/dispatch.md +4 -6
- package/platforms/opencode/dispatch.md +4 -4
- package/platforms/qwen/dispatch.md +4 -4
- package/platforms/shared-agents/dispatch.md +6 -19
- package/scripts/_common.py +5 -0
- package/scripts/archive_milestone.py +20 -6
- package/scripts/bootstrap_repository.py +8 -1
- package/scripts/build_recovery.py +5 -0
- package/scripts/build_state.py +2 -0
- package/scripts/check_docs_audit.py +2 -0
- package/scripts/check_handoffs.py +6 -0
- package/scripts/check_task_briefs.py +3 -0
- package/scripts/detect_project.py +11 -1
- package/scripts/discussion_records.py +3 -0
- package/scripts/discussion_validate.py +8 -3
- package/scripts/dispatch_driver.py +230 -21
- package/scripts/git_guard.py +12 -4
- package/scripts/guard_hook.py +11 -1
- package/scripts/install.mjs +74 -1448
- package/scripts/install.py +165 -201
- package/scripts/integration.py +28 -8
- package/scripts/isolation.py +15 -5
- package/scripts/jev_review.py +138 -0
- package/scripts/lean_verification.py +2 -0
- package/scripts/loop_run.py +2 -0
- package/scripts/model_policy.py +279 -0
- package/scripts/path_config.py +248 -0
- package/scripts/pipeline_diagnose.py +3 -0
- package/scripts/pipeline_git.py +3 -0
- package/scripts/pipeline_state.py +4 -1
- package/scripts/pipeline_undo.py +3 -0
- package/scripts/promote_lookahead.py +3 -0
- package/scripts/review_panel.py +11 -0
- package/scripts/roadmap.py +5 -0
- package/scripts/runtime_store.py +281 -0
- package/scripts/skill-resources.json +104 -4
- package/scripts/state_checkpoint.py +5 -0
- package/scripts/state_promote.py +5 -0
- package/scripts/status_runtime.py +92 -6
- package/scripts/wizard.mjs +8 -2
- package/scripts/workflow_run.py +12 -1
- package/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path/BUILD.md +7 -0
- package/skills/gsd-path/DECIDE.md +2 -0
- package/skills/gsd-path/DEFINE.md +13 -7
- package/skills/gsd-path/DOCS-AUDIT.md +2 -0
- package/skills/gsd-path/INSPECT.md +2 -0
- package/skills/gsd-path/PLAN.md +4 -2
- package/skills/gsd-path/RESEARCH.md +2 -0
- package/skills/gsd-path/ROADMAP.md +2 -0
- package/skills/gsd-path/SHIP.md +24 -13
- package/skills/gsd-path/SKILL.md +23 -9
- package/skills/gsd-path/references/build-native.md +15 -7
- package/skills/gsd-path/references/config.md +57 -0
- package/skills/gsd-path/references/dispatch.md +6 -19
- package/skills/gsd-path/references/jev-review.md +82 -0
- package/skills/gsd-path/references/model-policy.md +139 -0
- package/skills/gsd-path/references/reviewer-panel.md +1 -1
- package/skills/gsd-path/references/reviewer.md +2 -0
- package/skills/gsd-path/references/runtime-selection.md +25 -0
- 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/scripts/_common.py +5 -0
- package/skills/gsd-path/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path/scripts/bootstrap_repository.py +8 -1
- package/skills/gsd-path/scripts/build_recovery.py +5 -0
- package/skills/gsd-path/scripts/build_state.py +2 -0
- package/skills/gsd-path/scripts/check_docs_audit.py +2 -0
- package/skills/gsd-path/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path/scripts/detect_project.py +11 -1
- package/skills/gsd-path/scripts/discussion_records.py +3 -0
- package/skills/gsd-path/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path/scripts/dispatch_driver.py +230 -21
- package/skills/gsd-path/scripts/git_guard.py +768 -0
- package/skills/gsd-path/scripts/integration.py +28 -8
- package/skills/gsd-path/scripts/isolation.py +15 -5
- package/skills/gsd-path/scripts/jev_review.py +138 -0
- package/skills/gsd-path/scripts/lean_verification.py +2 -0
- package/skills/gsd-path/scripts/loop_run.py +2 -0
- package/skills/gsd-path/scripts/model_policy.py +279 -0
- package/skills/gsd-path/scripts/path_config.py +248 -0
- package/skills/gsd-path/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path/scripts/review_panel.py +11 -0
- package/skills/gsd-path/scripts/roadmap.py +5 -0
- package/skills/gsd-path/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path/scripts/state_promote.py +5 -0
- package/skills/gsd-path/scripts/status_runtime.py +208 -0
- package/skills/gsd-path/scripts/workflow_run.py +12 -1
- package/skills/gsd-path/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path/templates/skeptic.md +1 -1
- package/skills/gsd-path/templates/task.md +2 -0
- package/skills/gsd-path/templates/wave-panel.md +1 -1
- package/skills/gsd-path-build/SKILL.md +7 -0
- package/skills/gsd-path-build/references/build-native.md +15 -7
- package/skills/gsd-path-build/references/dispatch.md +6 -19
- package/skills/gsd-path-build/references/jev-review.md +82 -0
- package/skills/gsd-path-build/references/model-policy.md +139 -0
- package/skills/gsd-path-build/references/reviewer-panel.md +1 -1
- package/skills/gsd-path-build/references/reviewer.md +2 -0
- package/skills/gsd-path-build/references/runtime-selection.md +25 -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-build/scripts/_common.py +5 -0
- package/skills/gsd-path-build/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-build/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-build/scripts/build_state.py +2 -0
- package/skills/gsd-path-build/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-build/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-build/scripts/detect_project.py +11 -1
- package/skills/gsd-path-build/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-build/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-build/scripts/dispatch_driver.py +230 -21
- package/skills/gsd-path-build/scripts/integration.py +28 -8
- package/skills/gsd-path-build/scripts/isolation.py +15 -5
- package/skills/gsd-path-build/scripts/jev_review.py +138 -0
- package/skills/gsd-path-build/scripts/loop_run.py +2 -0
- package/skills/gsd-path-build/scripts/model_policy.py +279 -0
- package/skills/gsd-path-build/scripts/path_config.py +248 -0
- package/skills/gsd-path-build/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-build/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-build/scripts/review_panel.py +11 -0
- package/skills/gsd-path-build/scripts/roadmap.py +5 -0
- package/skills/gsd-path-build/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-build/scripts/state_promote.py +5 -0
- package/skills/gsd-path-build/scripts/workflow_run.py +12 -1
- package/skills/gsd-path-build/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-build/templates/skeptic.md +1 -1
- package/skills/gsd-path-build/templates/task.md +2 -0
- package/skills/gsd-path-build/templates/wave-panel.md +1 -1
- package/skills/gsd-path-decide/SKILL.md +2 -0
- package/skills/gsd-path-decide/references/dispatch.md +6 -19
- package/skills/gsd-path-decide/references/model-policy.md +139 -0
- package/skills/gsd-path-decide/references/runtime-selection.md +25 -0
- package/skills/gsd-path-decide/scripts/_common.py +5 -0
- package/skills/gsd-path-decide/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-decide/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-decide/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-decide/scripts/detect_project.py +11 -1
- package/skills/gsd-path-decide/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-decide/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-decide/scripts/integration.py +28 -8
- package/skills/gsd-path-decide/scripts/isolation.py +15 -5
- package/skills/gsd-path-decide/scripts/loop_run.py +839 -0
- package/skills/gsd-path-decide/scripts/model_policy.py +279 -0
- package/skills/gsd-path-decide/scripts/path_config.py +248 -0
- package/skills/gsd-path-decide/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-decide/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-decide/scripts/review_panel.py +11 -0
- package/skills/gsd-path-decide/scripts/roadmap.py +5 -0
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-decide/scripts/state_promote.py +5 -0
- package/skills/gsd-path-decide/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-define/SKILL.md +13 -7
- package/skills/gsd-path-define/references/runtime-selection.md +25 -0
- package/skills/gsd-path-define/scripts/_common.py +5 -0
- package/skills/gsd-path-define/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-define/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-define/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-define/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-define/scripts/detect_project.py +11 -1
- package/skills/gsd-path-define/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-define/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-define/scripts/integration.py +28 -8
- package/skills/gsd-path-define/scripts/isolation.py +15 -5
- package/skills/gsd-path-define/scripts/loop_run.py +839 -0
- package/skills/gsd-path-define/scripts/model_policy.py +279 -0
- package/skills/gsd-path-define/scripts/path_config.py +248 -0
- package/skills/gsd-path-define/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-define/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-define/scripts/review_panel.py +11 -0
- package/skills/gsd-path-define/scripts/roadmap.py +5 -0
- package/skills/gsd-path-define/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-define/scripts/state_promote.py +5 -0
- package/skills/gsd-path-define/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-discuss/SKILL.md +2 -0
- package/skills/gsd-path-discuss/references/runtime-selection.md +25 -0
- package/skills/gsd-path-discuss/scripts/_common.py +5 -0
- package/skills/gsd-path-discuss/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-discuss/scripts/loop_run.py +839 -0
- package/skills/gsd-path-discuss/scripts/model_policy.py +279 -0
- package/skills/gsd-path-discuss/scripts/path_config.py +248 -0
- package/skills/gsd-path-discuss/scripts/review_panel.py +564 -0
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-docs-audit/SKILL.md +2 -0
- package/skills/gsd-path-docs-audit/references/dispatch.md +6 -19
- package/skills/gsd-path-docs-audit/references/model-policy.md +139 -0
- package/skills/gsd-path-docs-audit/references/runtime-selection.md +25 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +5 -0
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +2 -0
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +11 -1
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-docs-audit/scripts/integration.py +28 -8
- package/skills/gsd-path-docs-audit/scripts/isolation.py +15 -5
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +839 -0
- package/skills/gsd-path-docs-audit/scripts/model_policy.py +279 -0
- package/skills/gsd-path-docs-audit/scripts/path_config.py +248 -0
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-docs-audit/scripts/review_panel.py +11 -0
- package/skills/gsd-path-docs-audit/scripts/roadmap.py +5 -0
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +5 -0
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-forensics/SKILL.md +9 -5
- package/skills/gsd-path-forensics/references/runtime-selection.md +25 -0
- package/skills/gsd-path-forensics/scripts/_common.py +5 -0
- package/skills/gsd-path-forensics/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-forensics/scripts/loop_run.py +839 -0
- package/skills/gsd-path-forensics/scripts/model_policy.py +279 -0
- package/skills/gsd-path-forensics/scripts/path_config.py +248 -0
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +3 -0
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +3 -0
- package/skills/gsd-path-forensics/scripts/review_panel.py +564 -0
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-inspect/SKILL.md +2 -0
- package/skills/gsd-path-inspect/references/dispatch.md +6 -19
- package/skills/gsd-path-inspect/references/model-policy.md +139 -0
- package/skills/gsd-path-inspect/references/runtime-selection.md +25 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/_common.py +5 -0
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-inspect/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +2 -0
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-inspect/scripts/detect_project.py +11 -1
- package/skills/gsd-path-inspect/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-inspect/scripts/integration.py +28 -8
- package/skills/gsd-path-inspect/scripts/isolation.py +15 -5
- package/skills/gsd-path-inspect/scripts/loop_run.py +839 -0
- package/skills/gsd-path-inspect/scripts/model_policy.py +279 -0
- package/skills/gsd-path-inspect/scripts/path_config.py +248 -0
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-inspect/scripts/review_panel.py +11 -0
- package/skills/gsd-path-inspect/scripts/roadmap.py +5 -0
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-inspect/scripts/state_promote.py +5 -0
- package/skills/gsd-path-inspect/scripts/workflow_run.py +12 -1
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-loop/SKILL.md +2 -0
- package/skills/gsd-path-loop/references/runtime-selection.md +25 -0
- package/skills/gsd-path-loop/scripts/_common.py +5 -0
- package/skills/gsd-path-loop/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-loop/scripts/loop_run.py +2 -0
- package/skills/gsd-path-loop/scripts/model_policy.py +279 -0
- package/skills/gsd-path-loop/scripts/path_config.py +248 -0
- package/skills/gsd-path-loop/scripts/review_panel.py +564 -0
- package/skills/gsd-path-loop/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-migrate/SKILL.md +2 -0
- package/skills/gsd-path-migrate/references/runtime-selection.md +25 -0
- package/skills/gsd-path-migrate/scripts/_common.py +185 -0
- package/skills/gsd-path-migrate/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-migrate/scripts/loop_run.py +839 -0
- package/skills/gsd-path-migrate/scripts/model_policy.py +279 -0
- package/skills/gsd-path-migrate/scripts/path_config.py +248 -0
- package/skills/gsd-path-migrate/scripts/review_panel.py +564 -0
- package/skills/gsd-path-plan/SKILL.md +4 -2
- package/skills/gsd-path-plan/references/dispatch.md +6 -19
- package/skills/gsd-path-plan/references/model-policy.md +139 -0
- package/skills/gsd-path-plan/references/runtime-selection.md +25 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/_common.py +5 -0
- package/skills/gsd-path-plan/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-plan/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-plan/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-plan/scripts/detect_project.py +11 -1
- package/skills/gsd-path-plan/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-plan/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-plan/scripts/integration.py +28 -8
- package/skills/gsd-path-plan/scripts/isolation.py +15 -5
- package/skills/gsd-path-plan/scripts/loop_run.py +839 -0
- package/skills/gsd-path-plan/scripts/model_policy.py +279 -0
- package/skills/gsd-path-plan/scripts/path_config.py +248 -0
- package/skills/gsd-path-plan/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-plan/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-plan/scripts/review_panel.py +11 -0
- package/skills/gsd-path-plan/scripts/roadmap.py +5 -0
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-plan/scripts/state_promote.py +5 -0
- package/skills/gsd-path-plan/scripts/workflow_run.py +12 -1
- package/skills/gsd-path-plan/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-plan/templates/task.md +2 -0
- package/skills/gsd-path-research/SKILL.md +2 -0
- package/skills/gsd-path-research/references/dispatch.md +6 -19
- package/skills/gsd-path-research/references/model-policy.md +139 -0
- package/skills/gsd-path-research/references/runtime-selection.md +25 -0
- package/skills/gsd-path-research/scripts/_common.py +5 -0
- package/skills/gsd-path-research/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-research/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-research/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-research/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-research/scripts/detect_project.py +11 -1
- package/skills/gsd-path-research/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-research/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-research/scripts/integration.py +28 -8
- package/skills/gsd-path-research/scripts/isolation.py +15 -5
- package/skills/gsd-path-research/scripts/loop_run.py +839 -0
- package/skills/gsd-path-research/scripts/model_policy.py +279 -0
- package/skills/gsd-path-research/scripts/path_config.py +248 -0
- package/skills/gsd-path-research/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-research/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-research/scripts/review_panel.py +11 -0
- package/skills/gsd-path-research/scripts/roadmap.py +5 -0
- package/skills/gsd-path-research/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-research/scripts/state_promote.py +5 -0
- package/skills/gsd-path-research/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-roadmap/SKILL.md +2 -0
- package/skills/gsd-path-roadmap/references/dispatch.md +6 -19
- package/skills/gsd-path-roadmap/references/model-policy.md +139 -0
- package/skills/gsd-path-roadmap/references/runtime-selection.md +25 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +5 -0
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-roadmap/scripts/detect_project.py +11 -1
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-roadmap/scripts/integration.py +28 -8
- package/skills/gsd-path-roadmap/scripts/isolation.py +15 -5
- package/skills/gsd-path-roadmap/scripts/loop_run.py +839 -0
- package/skills/gsd-path-roadmap/scripts/model_policy.py +279 -0
- package/skills/gsd-path-roadmap/scripts/path_config.py +248 -0
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-roadmap/scripts/review_panel.py +11 -0
- package/skills/gsd-path-roadmap/scripts/roadmap.py +5 -0
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-roadmap/scripts/state_promote.py +5 -0
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-ship/SKILL.md +24 -13
- package/skills/gsd-path-ship/references/dispatch.md +6 -19
- package/skills/gsd-path-ship/references/jev-review.md +82 -0
- package/skills/gsd-path-ship/references/model-policy.md +139 -0
- package/skills/gsd-path-ship/references/reviewer-panel.md +1 -1
- package/skills/gsd-path-ship/references/reviewer.md +2 -0
- package/skills/gsd-path-ship/references/runtime-selection.md +25 -0
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/_common.py +5 -0
- package/skills/gsd-path-ship/scripts/archive_milestone.py +20 -6
- package/skills/gsd-path-ship/scripts/build_recovery.py +5 -0
- package/skills/gsd-path-ship/scripts/build_state.py +2 -0
- package/skills/gsd-path-ship/scripts/check_handoffs.py +6 -0
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +3 -0
- package/skills/gsd-path-ship/scripts/detect_project.py +11 -1
- package/skills/gsd-path-ship/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-ship/scripts/discussion_validate.py +8 -3
- package/skills/gsd-path-ship/scripts/integration.py +28 -8
- package/skills/gsd-path-ship/scripts/isolation.py +15 -5
- package/skills/gsd-path-ship/scripts/jev_review.py +138 -0
- package/skills/gsd-path-ship/scripts/lean_verification.py +2 -0
- package/skills/gsd-path-ship/scripts/loop_run.py +839 -0
- package/skills/gsd-path-ship/scripts/model_policy.py +279 -0
- package/skills/gsd-path-ship/scripts/path_config.py +248 -0
- package/skills/gsd-path-ship/scripts/pipeline_git.py +3 -0
- package/skills/gsd-path-ship/scripts/pipeline_state.py +4 -1
- package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -0
- package/skills/gsd-path-ship/scripts/review_panel.py +11 -0
- package/skills/gsd-path-ship/scripts/roadmap.py +5 -0
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +5 -0
- package/skills/gsd-path-ship/scripts/state_promote.py +5 -0
- package/skills/gsd-path-ship/scripts/workflow_run.py +12 -1
- package/skills/gsd-path-ship/scripts/worktree_paths.py +94 -0
- package/skills/gsd-path-undo/SKILL.md +2 -0
- package/skills/gsd-path-undo/references/runtime-selection.md +25 -0
- package/skills/gsd-path-undo/scripts/_common.py +5 -0
- package/skills/gsd-path-undo/scripts/discussion_records.py +3 -0
- package/skills/gsd-path-undo/scripts/loop_run.py +839 -0
- package/skills/gsd-path-undo/scripts/model_policy.py +279 -0
- package/skills/gsd-path-undo/scripts/path_config.py +248 -0
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +3 -0
- package/skills/gsd-path-undo/scripts/review_panel.py +564 -0
- package/skills/gsd-path-undo/scripts/worktree_paths.py +94 -0
- package/skills/path/BUILD.md +7 -0
- package/skills/path/DECIDE.md +2 -0
- package/skills/path/DEFINE.md +13 -7
- package/skills/path/DOCS-AUDIT.md +2 -0
- package/skills/path/INSPECT.md +2 -0
- package/skills/path/PLAN.md +4 -2
- package/skills/path/RESEARCH.md +2 -0
- package/skills/path/ROADMAP.md +2 -0
- package/skills/path/SHIP.md +24 -13
- package/skills/path/SKILL.md +23 -9
- package/skills/path/references/build-native.md +15 -7
- package/skills/path/references/config.md +57 -0
- package/skills/path/references/dispatch.md +6 -19
- package/skills/path/references/jev-review.md +82 -0
- package/skills/path/references/model-policy.md +139 -0
- package/skills/path/references/reviewer-panel.md +1 -1
- package/skills/path/references/reviewer.md +2 -0
- package/skills/path/references/runtime-selection.md +25 -0
- package/skills/path/scripts/_common.py +5 -0
- package/skills/path/scripts/archive_milestone.py +20 -6
- package/skills/path/scripts/bootstrap_repository.py +8 -1
- package/skills/path/scripts/build_recovery.py +5 -0
- package/skills/path/scripts/build_state.py +2 -0
- package/skills/path/scripts/check_docs_audit.py +2 -0
- package/skills/path/scripts/check_handoffs.py +6 -0
- package/skills/path/scripts/check_task_briefs.py +3 -0
- package/skills/path/scripts/detect_project.py +11 -1
- package/skills/path/scripts/discussion_records.py +3 -0
- package/skills/path/scripts/discussion_validate.py +8 -3
- package/skills/path/scripts/dispatch_driver.py +230 -21
- package/skills/path/scripts/git_guard.py +768 -0
- package/skills/path/scripts/integration.py +28 -8
- package/skills/path/scripts/isolation.py +15 -5
- package/skills/path/scripts/jev_review.py +138 -0
- package/skills/path/scripts/lean_verification.py +2 -0
- package/skills/path/scripts/loop_run.py +2 -0
- package/skills/path/scripts/model_policy.py +279 -0
- package/skills/path/scripts/path_config.py +248 -0
- package/skills/path/scripts/pipeline_git.py +3 -0
- package/skills/path/scripts/pipeline_state.py +4 -1
- package/skills/path/scripts/promote_lookahead.py +3 -0
- package/skills/path/scripts/review_panel.py +11 -0
- package/skills/path/scripts/roadmap.py +5 -0
- package/skills/path/scripts/state_checkpoint.py +5 -0
- package/skills/path/scripts/state_promote.py +5 -0
- package/skills/path/scripts/status_runtime.py +208 -0
- package/skills/path/scripts/workflow_run.py +12 -1
- package/skills/path/scripts/worktree_paths.py +94 -0
- package/skills/path/templates/skeptic.md +1 -1
- package/skills/path/templates/task.md +2 -0
- package/skills/path/templates/wave-panel.md +1 -1
- package/skills/gsd-path/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/discussion_records.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/integration.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/loop_run.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/review_findings.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/task_context.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/workflow_run.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/loop_run.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/review_findings.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/task_context.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/workflow_run.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-decide/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-define/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-docs-audit/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-forensics/scripts/__pycache__/pipeline_undo.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-research/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-roadmap/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/archive_milestone.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/build_recovery.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/build_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/check_task_briefs.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/detect_project.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/discussion_validate.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/isolation.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/pipeline_git.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/pipeline_state.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/review_panel.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/roadmap.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/state_checkpoint.cpython-312.pyc +0 -0
package/scripts/install.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import argparse
|
|
5
5
|
import errno
|
|
6
|
+
import hashlib
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
8
9
|
import re
|
|
@@ -17,9 +18,11 @@ from typing import Callable, Iterable, List, Mapping, Optional, Sequence, Tuple,
|
|
|
17
18
|
sys.dont_write_bytecode = True
|
|
18
19
|
|
|
19
20
|
try:
|
|
20
|
-
from . import sync_skill_resources
|
|
21
|
+
from . import sync_skill_resources, runtime_store, status_runtime
|
|
21
22
|
except ImportError: # Direct execution from scripts/.
|
|
22
23
|
import sync_skill_resources # type: ignore
|
|
24
|
+
import runtime_store
|
|
25
|
+
import status_runtime
|
|
23
26
|
|
|
24
27
|
|
|
25
28
|
def skill_names_for_manifest(manifest: Mapping) -> Tuple[str, ...]:
|
|
@@ -46,27 +49,7 @@ CLAUDE_BRIDGE = "@../AGENTS.md\n@../WORKFLOW.md\n"
|
|
|
46
49
|
HOOKS_DIRECTORY = ".gsd-path"
|
|
47
50
|
GUARD_SCRIPTS = ("guard_hook.py", "git_guard.py")
|
|
48
51
|
GUARD_MARKER = "gsd-path guard"
|
|
49
|
-
PROJECT_RUNTIME_SCRIPTS =
|
|
50
|
-
"pipeline_state.py",
|
|
51
|
-
"roadmap.py",
|
|
52
|
-
"check_handoffs.py",
|
|
53
|
-
"check_task_briefs.py",
|
|
54
|
-
"isolation.py",
|
|
55
|
-
"discussion_records.py",
|
|
56
|
-
"pipeline_git.py",
|
|
57
|
-
"promote_lookahead.py",
|
|
58
|
-
"detect_project.py",
|
|
59
|
-
"pipeline_diagnose.py",
|
|
60
|
-
"pipeline_undo.py",
|
|
61
|
-
"archive_milestone.py",
|
|
62
|
-
"review_panel.py",
|
|
63
|
-
"_common.py",
|
|
64
|
-
"build_recovery.py",
|
|
65
|
-
"state_checkpoint.py",
|
|
66
|
-
"state_promote.py",
|
|
67
|
-
"discussion_validate.py",
|
|
68
|
-
"integration.py",
|
|
69
|
-
)
|
|
52
|
+
PROJECT_RUNTIME_SCRIPTS = runtime_store.RUNTIME_FILES
|
|
70
53
|
PROJECT_RUNTIME_MARKER = "gsd-path project runtime"
|
|
71
54
|
PROJECT_STATUS_LAUNCHER = "status_runtime.py"
|
|
72
55
|
PROJECT_STATUS_MARKER = "gsd-path project status launcher"
|
|
@@ -888,10 +871,15 @@ def _create_install_lock(lock: Path) -> None:
|
|
|
888
871
|
raise
|
|
889
872
|
|
|
890
873
|
|
|
874
|
+
def _install_lock_path(root: Path) -> Path:
|
|
875
|
+
identity = hashlib.sha256(os.fsencode(root.resolve())).hexdigest()
|
|
876
|
+
return Path.home() / ".gsd-path" / "install-locks" / identity / INSTALL_LOCK_NAME
|
|
877
|
+
|
|
878
|
+
|
|
891
879
|
def _acquire_install_locks(roots: Iterable[Path]) -> Tuple[List[Path], List[Path]]:
|
|
892
880
|
locks: List[Path] = []
|
|
893
881
|
for root in roots:
|
|
894
|
-
candidate = root
|
|
882
|
+
candidate = _install_lock_path(root)
|
|
895
883
|
if not any(_same_path(candidate, existing) for existing in locks):
|
|
896
884
|
locks.append(candidate)
|
|
897
885
|
locks.sort(key=lambda candidate: os.path.normcase(os.fspath(candidate)))
|
|
@@ -1030,15 +1018,7 @@ def _project_destinations(
|
|
|
1030
1018
|
False,
|
|
1031
1019
|
),
|
|
1032
1020
|
]
|
|
1033
|
-
destinations.
|
|
1034
|
-
(
|
|
1035
|
-
project / HOOKS_DIRECTORY / "runtime" / name,
|
|
1036
|
-
f"scripts/{name}",
|
|
1037
|
-
None,
|
|
1038
|
-
False,
|
|
1039
|
-
)
|
|
1040
|
-
for name in PROJECT_RUNTIME_SCRIPTS
|
|
1041
|
-
)
|
|
1021
|
+
destinations.append((project / HOOKS_DIRECTORY / "runtime.json", None, "", False))
|
|
1042
1022
|
if "claude" in selected:
|
|
1043
1023
|
destinations.append(
|
|
1044
1024
|
(project / ".claude" / "CLAUDE.md", None, CLAUDE_BRIDGE, False)
|
|
@@ -1046,7 +1026,7 @@ def _project_destinations(
|
|
|
1046
1026
|
if hooks:
|
|
1047
1027
|
for name in GUARD_SCRIPTS:
|
|
1048
1028
|
destinations.append(
|
|
1049
|
-
(project / HOOKS_DIRECTORY / name,
|
|
1029
|
+
(project / HOOKS_DIRECTORY / name, None, runtime_store.guard_launcher(name), False)
|
|
1050
1030
|
)
|
|
1051
1031
|
if "claude" in selected:
|
|
1052
1032
|
destinations.append(
|
|
@@ -1106,6 +1086,8 @@ def _update_replacement(
|
|
|
1106
1086
|
the managed-file check for a replaceable destination, or None for a
|
|
1107
1087
|
kept one."""
|
|
1108
1088
|
parent = project / HOOKS_DIRECTORY
|
|
1089
|
+
if (parent / "runtime.json").is_file() and destination.parent == parent:
|
|
1090
|
+
return None # Stable wiring and selection change only through explicit operations.
|
|
1109
1091
|
directory = destination.parent
|
|
1110
1092
|
if _same_path(directory, parent / "runtime"):
|
|
1111
1093
|
return _is_managed_project_runtime
|
|
@@ -1246,6 +1228,10 @@ def _validate_project(
|
|
|
1246
1228
|
source = source_root / source_name
|
|
1247
1229
|
if source.is_symlink() or not source.is_file():
|
|
1248
1230
|
raise InstallerError(f"missing project contract: {source}")
|
|
1231
|
+
try:
|
|
1232
|
+
runtime_store.prepare(source_root, project, dry_run=True)
|
|
1233
|
+
except (OSError, ValueError) as error:
|
|
1234
|
+
raise InstallerError(str(error)) from error
|
|
1249
1235
|
mergers = _native_settings_mergers(project, selected, hooks)
|
|
1250
1236
|
for destination, _, _, _ in _project_destinations(
|
|
1251
1237
|
project, selected, hooks, interpreter, hooks_dir
|
|
@@ -1280,11 +1266,17 @@ def _apply_project(
|
|
|
1280
1266
|
hooks_dir: Optional[Path],
|
|
1281
1267
|
update: bool = False,
|
|
1282
1268
|
) -> None:
|
|
1269
|
+
try:
|
|
1270
|
+
pin = runtime_store.prepare(source_root, project)
|
|
1271
|
+
except (OSError, ValueError) as error:
|
|
1272
|
+
raise InstallerError(str(error)) from error
|
|
1283
1273
|
_create_directory(project, transaction.created_directories)
|
|
1284
1274
|
mergers = _native_settings_mergers(project, selected, hooks)
|
|
1285
1275
|
for destination, source_name, content, executable in _project_destinations(
|
|
1286
1276
|
project, selected, hooks, interpreter, hooks_dir
|
|
1287
1277
|
):
|
|
1278
|
+
if destination.name == "runtime.json" and destination.parent == project / HOOKS_DIRECTORY:
|
|
1279
|
+
content = runtime_store.pin_text(pin)
|
|
1288
1280
|
_create_directory(destination.parent, transaction.created_directories)
|
|
1289
1281
|
merge = mergers.get(destination)
|
|
1290
1282
|
if _lexists(destination) and not destination.is_symlink():
|
|
@@ -1300,7 +1292,7 @@ def _apply_project(
|
|
|
1300
1292
|
elif source_name:
|
|
1301
1293
|
replacement = (source_root / source_name).read_bytes()
|
|
1302
1294
|
else:
|
|
1303
|
-
replacement = content or ""
|
|
1295
|
+
replacement = (content or "").encode("utf-8")
|
|
1304
1296
|
_atomic_write(
|
|
1305
1297
|
destination, replacement, 0o755 if executable else mode
|
|
1306
1298
|
)
|
|
@@ -1316,9 +1308,9 @@ def _apply_project(
|
|
|
1316
1308
|
created = True
|
|
1317
1309
|
shutil.copyfileobj(source, output)
|
|
1318
1310
|
else:
|
|
1319
|
-
with destination.open("
|
|
1311
|
+
with destination.open("xb") as output:
|
|
1320
1312
|
created = True
|
|
1321
|
-
output.write(content)
|
|
1313
|
+
output.write(content.encode("utf-8"))
|
|
1322
1314
|
if executable:
|
|
1323
1315
|
destination.chmod(0o755)
|
|
1324
1316
|
transaction.copied.append(destination)
|
|
@@ -1642,7 +1634,7 @@ def _validate_hooks_refresh(
|
|
|
1642
1634
|
project / HOOKS_DIRECTORY / "runtime", "project runtime directory"
|
|
1643
1635
|
)
|
|
1644
1636
|
refresh_guards = _refreshes_guards(project, full, initialize)
|
|
1645
|
-
runtime_exists = any(
|
|
1637
|
+
runtime_exists = (project / HOOKS_DIRECTORY / "runtime.json").is_file() or any(
|
|
1646
1638
|
_lexists(project / HOOKS_DIRECTORY / "runtime" / name)
|
|
1647
1639
|
for name in PROJECT_RUNTIME_SCRIPTS
|
|
1648
1640
|
)
|
|
@@ -1733,162 +1725,63 @@ def _validate_hooks_refresh(
|
|
|
1733
1725
|
)
|
|
1734
1726
|
|
|
1735
1727
|
|
|
1736
|
-
def _refresh_hooks_unlocked(
|
|
1737
|
-
source_root: Path,
|
|
1738
|
-
project: Path,
|
|
1739
|
-
full: bool,
|
|
1740
|
-
dry_run: bool = False,
|
|
1741
|
-
selected: Sequence[str] = (),
|
|
1742
|
-
initialize: bool = False,
|
|
1743
|
-
) -> List[str]:
|
|
1744
|
-
"""Refreshed project-relative paths; "note:"-prefixed entries are
|
|
1745
|
-
user-facing notes rather than refreshed files."""
|
|
1746
|
-
hooks_dir = _git_hooks_directory(project) if full else None
|
|
1747
|
-
interpreter: Optional[str] = None
|
|
1748
|
-
if not dry_run:
|
|
1749
|
-
if full:
|
|
1750
|
-
interpreter, hooks_dir = _required_hook_runtime(
|
|
1751
|
-
project,
|
|
1752
|
-
"--hooks-init" if initialize else "--hooks-refresh-full",
|
|
1753
|
-
selected,
|
|
1754
|
-
)
|
|
1755
|
-
else:
|
|
1756
|
-
interpreter = _required_python_runtime("--hooks-refresh", selected)
|
|
1757
|
-
_validate_hooks_refresh(
|
|
1758
|
-
source_root, project, full, hooks_dir, selected, initialize
|
|
1759
|
-
)
|
|
1760
|
-
refreshed: List[str] = []
|
|
1761
|
-
refresh_guards = _refreshes_guards(project, full, initialize)
|
|
1762
|
-
runtime = project / HOOKS_DIRECTORY / "runtime"
|
|
1763
|
-
if not dry_run:
|
|
1764
|
-
runtime.parent.mkdir(parents=True, exist_ok=True)
|
|
1765
|
-
staging = Path(tempfile.mkdtemp(prefix=".runtime-stage-", dir=runtime.parent))
|
|
1766
|
-
previous = staging.with_name(staging.name + "-previous")
|
|
1767
|
-
moved_previous = False
|
|
1768
|
-
published_runtime = False
|
|
1769
|
-
launcher = runtime.parent / PROJECT_STATUS_LAUNCHER
|
|
1770
|
-
launcher_original = launcher.read_bytes() if _lexists(launcher) else None
|
|
1771
|
-
launcher_mode = (
|
|
1772
|
-
launcher.stat().st_mode & 0o777 if launcher_original is not None else None
|
|
1773
|
-
)
|
|
1774
|
-
guard_originals: List[Tuple[Path, Optional[bytes], Optional[int]]] = []
|
|
1775
|
-
try:
|
|
1776
|
-
for name in PROJECT_RUNTIME_SCRIPTS:
|
|
1777
|
-
shutil.copy2(source_root / "scripts" / name, staging / name)
|
|
1778
|
-
_atomic_copy(source_root / "scripts" / PROJECT_STATUS_LAUNCHER, launcher)
|
|
1779
|
-
if _lexists(runtime):
|
|
1780
|
-
os.replace(runtime, previous)
|
|
1781
|
-
moved_previous = True
|
|
1782
|
-
os.replace(staging, runtime)
|
|
1783
|
-
published_runtime = True
|
|
1784
|
-
if refresh_guards:
|
|
1785
|
-
for name in GUARD_SCRIPTS:
|
|
1786
|
-
destination = project / HOOKS_DIRECTORY / name
|
|
1787
|
-
original = destination.read_bytes() if _lexists(destination) else None
|
|
1788
|
-
mode = (
|
|
1789
|
-
destination.stat().st_mode & 0o777
|
|
1790
|
-
if original is not None
|
|
1791
|
-
else None
|
|
1792
|
-
)
|
|
1793
|
-
guard_originals.append((destination, original, mode))
|
|
1794
|
-
_atomic_copy(source_root / "scripts" / name, destination)
|
|
1795
|
-
if moved_previous:
|
|
1796
|
-
_remove_path(previous)
|
|
1797
|
-
except BaseException as error:
|
|
1798
|
-
for destination, original, mode in reversed(guard_originals):
|
|
1799
|
-
if original is None:
|
|
1800
|
-
_remove_path(destination)
|
|
1801
|
-
else:
|
|
1802
|
-
_atomic_write(destination, original, mode)
|
|
1803
|
-
if launcher_original is None:
|
|
1804
|
-
_remove_path(launcher)
|
|
1805
|
-
else:
|
|
1806
|
-
_atomic_write(launcher, launcher_original, launcher_mode)
|
|
1807
|
-
if published_runtime and _lexists(runtime):
|
|
1808
|
-
_remove_path(runtime)
|
|
1809
|
-
if not _lexists(runtime) and moved_previous and _lexists(previous):
|
|
1810
|
-
os.replace(previous, runtime)
|
|
1811
|
-
if isinstance(error, Exception):
|
|
1812
|
-
raise InstallerError(
|
|
1813
|
-
f"project runtime refresh failed: {error}"
|
|
1814
|
-
) from error
|
|
1815
|
-
raise
|
|
1816
|
-
finally:
|
|
1817
|
-
_remove_path(staging)
|
|
1818
|
-
for name in PROJECT_RUNTIME_SCRIPTS:
|
|
1819
|
-
refreshed.append(_describe_project_path(project, runtime / name))
|
|
1820
|
-
refreshed.append(
|
|
1821
|
-
_describe_project_path(
|
|
1822
|
-
project, project / HOOKS_DIRECTORY / PROJECT_STATUS_LAUNCHER
|
|
1823
|
-
)
|
|
1824
|
-
)
|
|
1825
|
-
if refresh_guards:
|
|
1826
|
-
for name in GUARD_SCRIPTS:
|
|
1827
|
-
destination = project / HOOKS_DIRECTORY / name
|
|
1828
|
-
refreshed.append(_describe_project_path(project, destination))
|
|
1829
|
-
if full:
|
|
1830
|
-
for target, settings, merge, generated in (
|
|
1831
|
-
(
|
|
1832
|
-
"claude",
|
|
1833
|
-
project / ".claude" / "settings.json",
|
|
1834
|
-
_merged_claude_settings,
|
|
1835
|
-
claude_hooks_settings,
|
|
1836
|
-
),
|
|
1837
|
-
(
|
|
1838
|
-
"codex",
|
|
1839
|
-
project / ".codex" / "hooks.json",
|
|
1840
|
-
_merged_codex_settings,
|
|
1841
|
-
codex_hooks_settings,
|
|
1842
|
-
),
|
|
1843
|
-
(
|
|
1844
|
-
"cursor",
|
|
1845
|
-
project / ".cursor" / "hooks.json",
|
|
1846
|
-
_merged_cursor_settings,
|
|
1847
|
-
cursor_hooks_settings,
|
|
1848
|
-
),
|
|
1849
|
-
):
|
|
1850
|
-
if initialize and target not in selected:
|
|
1851
|
-
continue
|
|
1852
|
-
exists = _lexists(settings)
|
|
1853
|
-
if exists or target in selected:
|
|
1854
|
-
if not dry_run:
|
|
1855
|
-
settings.parent.mkdir(parents=True, exist_ok=True)
|
|
1856
|
-
content = (
|
|
1857
|
-
merge(settings, interpreter)
|
|
1858
|
-
if exists
|
|
1859
|
-
else generated(interpreter)
|
|
1860
|
-
)
|
|
1861
|
-
_atomic_write(settings, content)
|
|
1862
|
-
refreshed.append(_describe_project_path(project, settings))
|
|
1863
|
-
if hooks_dir is not None:
|
|
1864
|
-
for hook_name, generator in GIT_HOOKS:
|
|
1865
|
-
hook_path = hooks_dir / hook_name
|
|
1866
|
-
if not dry_run:
|
|
1867
|
-
content = generator(interpreter)
|
|
1868
|
-
hook_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1869
|
-
_atomic_write(hook_path, content, mode=0o755)
|
|
1870
|
-
refreshed.append(_describe_project_path(project, hook_path))
|
|
1871
|
-
return refreshed
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
1728
|
def refresh_hooks(
|
|
1875
|
-
source_root: Path,
|
|
1876
|
-
|
|
1877
|
-
full: bool,
|
|
1878
|
-
dry_run: bool = False,
|
|
1879
|
-
selected: Sequence[str] = (),
|
|
1880
|
-
initialize: bool = False,
|
|
1729
|
+
source_root: Path, project: Path, full: bool, dry_run: bool = False,
|
|
1730
|
+
selected: Sequence[str] = (), initialize: bool = False,
|
|
1881
1731
|
) -> List[str]:
|
|
1882
|
-
if dry_run:
|
|
1883
|
-
return _refresh_hooks_unlocked(
|
|
1884
|
-
source_root, project, full, True, selected, initialize
|
|
1885
|
-
)
|
|
1886
1732
|
_validate_directory_destination(project, "project path")
|
|
1733
|
+
if full and not dry_run:
|
|
1734
|
+
_required_hook_runtime(project, "--hooks-init" if initialize else "--hooks-refresh-full", selected)
|
|
1735
|
+
pinned = os.path.lexists(project / HOOKS_DIRECTORY / "runtime.json")
|
|
1736
|
+
if os.path.lexists(project / HOOKS_DIRECTORY / "runtime"):
|
|
1737
|
+
raise InstallerError("legacy runtime requires --runtime-migrate before refresh")
|
|
1738
|
+
if pinned:
|
|
1739
|
+
try:
|
|
1740
|
+
status_runtime.resolve_runtime(project)
|
|
1741
|
+
except (OSError, ValueError) as error:
|
|
1742
|
+
raise InstallerError(str(error)) from error
|
|
1743
|
+
_validate_hooks_refresh(source_root, project, full, _git_hooks_directory(project) if full else None, selected, initialize)
|
|
1744
|
+
if not dry_run:
|
|
1745
|
+
_required_python_runtime("--hooks-refresh", selected)
|
|
1746
|
+
elif not initialize and not _has_legacy_project_contracts(source_root, project):
|
|
1747
|
+
_validate_hooks_refresh(source_root, project, full, _git_hooks_directory(project) if full else None, selected, initialize)
|
|
1748
|
+
raise InstallerError(f"no managed GSD Path hooks or runtime found in project: {project}")
|
|
1749
|
+
if dry_run:
|
|
1750
|
+
if pinned:
|
|
1751
|
+
return ["note: selected runtime retained; use --runtime-upgrade for an explicit upgrade"]
|
|
1752
|
+
_validate_hooks_refresh(source_root, project, full,
|
|
1753
|
+
_git_hooks_directory(project) if full else None, selected, True)
|
|
1754
|
+
runtime_store.prepare(source_root, project, dry_run=True)
|
|
1755
|
+
return [".gsd-path/runtime.json", ".gsd-path/status_runtime.py"]
|
|
1887
1756
|
locks, created = _acquire_install_locks([project / HOOKS_DIRECTORY])
|
|
1888
1757
|
try:
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1758
|
+
if not pinned:
|
|
1759
|
+
interpreter = _required_python_runtime("--hooks-init", selected)
|
|
1760
|
+
hooks_dir = _git_hooks_directory(project) if full else None
|
|
1761
|
+
_validate_hooks_refresh(source_root, project, full, hooks_dir, selected, True)
|
|
1762
|
+
transaction = ProjectTransaction()
|
|
1763
|
+
try:
|
|
1764
|
+
_apply_project(source_root, project, selected, full, transaction, interpreter, hooks_dir, update=True)
|
|
1765
|
+
except BaseException:
|
|
1766
|
+
_rollback_project(transaction)
|
|
1767
|
+
raise
|
|
1768
|
+
return [".gsd-path/runtime.json", ".gsd-path/status_runtime.py"]
|
|
1769
|
+
if not full and not _has_managed_guard_wiring(project):
|
|
1770
|
+
return ["note: selected runtime retained; use --runtime-upgrade for an explicit upgrade"]
|
|
1771
|
+
interpreter = _required_python_runtime("--hooks-refresh", selected)
|
|
1772
|
+
hooks_dir = _git_hooks_directory(project) if full else None
|
|
1773
|
+
refresh_targets = list(selected)
|
|
1774
|
+
if full and not initialize:
|
|
1775
|
+
for target, relative in (("claude", ".claude/settings.json"), ("codex", ".codex/hooks.json"), ("cursor", ".cursor/hooks.json")):
|
|
1776
|
+
if (project / relative).exists() and target not in refresh_targets:
|
|
1777
|
+
refresh_targets.append(target)
|
|
1778
|
+
transaction = ProjectTransaction()
|
|
1779
|
+
try:
|
|
1780
|
+
_apply_project(source_root, project, refresh_targets, True, transaction, interpreter, hooks_dir, update=True)
|
|
1781
|
+
except BaseException:
|
|
1782
|
+
_rollback_project(transaction)
|
|
1783
|
+
raise
|
|
1784
|
+
return ["note: selected runtime retained; stable hooks initialized/refreshed"]
|
|
1892
1785
|
finally:
|
|
1893
1786
|
_release_install_locks(locks, created)
|
|
1894
1787
|
|
|
@@ -2037,6 +1930,11 @@ def _read_package_version(manifest: Path) -> Optional[str]:
|
|
|
2037
1930
|
|
|
2038
1931
|
def _validated_project_state(source_root: Path, project: Path) -> dict:
|
|
2039
1932
|
validator = source_root / "scripts" / "pipeline_state.py"
|
|
1933
|
+
if (project / HOOKS_DIRECTORY / "runtime.json").exists():
|
|
1934
|
+
try:
|
|
1935
|
+
validator = status_runtime.resolve_runtime(project) / "pipeline_state.py"
|
|
1936
|
+
except (OSError, ValueError) as error:
|
|
1937
|
+
raise InstallerError(str(error)) from error
|
|
2040
1938
|
if validator.is_symlink() or not validator.is_file():
|
|
2041
1939
|
raise InstallerError(f"canonical state validator is unavailable: {validator}")
|
|
2042
1940
|
interpreter = _required_python_runtime("--doctor")
|
|
@@ -2074,6 +1972,11 @@ def _validated_project_state(source_root: Path, project: Path) -> dict:
|
|
|
2074
1972
|
def _validate_project_runtime_status(source_root: Path, project: Path) -> None:
|
|
2075
1973
|
interpreter = _required_python_runtime("--doctor")
|
|
2076
1974
|
runtime = source_root / "scripts" / "pipeline_state.py"
|
|
1975
|
+
if (project / HOOKS_DIRECTORY / "runtime.json").exists():
|
|
1976
|
+
try:
|
|
1977
|
+
runtime = status_runtime.resolve_runtime(project) / "pipeline_state.py"
|
|
1978
|
+
except (OSError, ValueError) as error:
|
|
1979
|
+
raise InstallerError(f"runtime changed during doctor validation: {error}") from error
|
|
2077
1980
|
environment = os.environ.copy()
|
|
2078
1981
|
environment["GIT_OPTIONAL_LOCKS"] = "0"
|
|
2079
1982
|
try:
|
|
@@ -2099,6 +2002,13 @@ def _validate_project_runtime_status(source_root: Path, project: Path) -> None:
|
|
|
2099
2002
|
|
|
2100
2003
|
|
|
2101
2004
|
def _project_runtime_matches(source_root: Path, project: Path) -> bool:
|
|
2005
|
+
if (project / HOOKS_DIRECTORY / "runtime.json").exists():
|
|
2006
|
+
try:
|
|
2007
|
+
root = status_runtime.resolve_runtime(project)
|
|
2008
|
+
launcher = project / HOOKS_DIRECTORY / PROJECT_STATUS_LAUNCHER
|
|
2009
|
+
return not launcher.is_symlink() and launcher.read_bytes() == (root / PROJECT_STATUS_LAUNCHER).read_bytes()
|
|
2010
|
+
except (OSError, ValueError):
|
|
2011
|
+
return False
|
|
2102
2012
|
pairs = [
|
|
2103
2013
|
(
|
|
2104
2014
|
project / HOOKS_DIRECTORY / PROJECT_STATUS_LAUNCHER,
|
|
@@ -2370,7 +2280,15 @@ def doctor(
|
|
|
2370
2280
|
"project: .claude/CLAUDE.md exists but is not the managed bridge",
|
|
2371
2281
|
)
|
|
2372
2282
|
|
|
2283
|
+
pinned = os.path.lexists(project / HOOKS_DIRECTORY / "runtime.json")
|
|
2373
2284
|
runtime = project / HOOKS_DIRECTORY / "runtime"
|
|
2285
|
+
if pinned:
|
|
2286
|
+
try:
|
|
2287
|
+
runtime = status_runtime.resolve_runtime(project)
|
|
2288
|
+
push("ok", f"project: selected runtime {status_runtime.declaration(project)['version']}")
|
|
2289
|
+
except (OSError, ValueError) as error:
|
|
2290
|
+
push("fail", str(error))
|
|
2291
|
+
return findings
|
|
2374
2292
|
launcher = project / HOOKS_DIRECTORY / PROJECT_STATUS_LAUNCHER
|
|
2375
2293
|
runtime_current = True
|
|
2376
2294
|
if launcher.is_symlink():
|
|
@@ -2382,7 +2300,7 @@ def doctor(
|
|
|
2382
2300
|
else:
|
|
2383
2301
|
launcher_content = read_project_file(launcher, "project: status launcher")
|
|
2384
2302
|
launcher_source = read_project_file(
|
|
2385
|
-
source_root / "scripts" / PROJECT_STATUS_LAUNCHER,
|
|
2303
|
+
(runtime if pinned else source_root / "scripts") / PROJECT_STATUS_LAUNCHER,
|
|
2386
2304
|
"package: status launcher",
|
|
2387
2305
|
)
|
|
2388
2306
|
if launcher_content is None or launcher_source is None:
|
|
@@ -2423,7 +2341,7 @@ def doctor(
|
|
|
2423
2341
|
runtime_current = False
|
|
2424
2342
|
continue
|
|
2425
2343
|
source = read_project_file(
|
|
2426
|
-
source_root / "scripts" / name, f"package: runtime {name}"
|
|
2344
|
+
(runtime if pinned else source_root / "scripts") / name, f"package: runtime {name}"
|
|
2427
2345
|
)
|
|
2428
2346
|
if source is None:
|
|
2429
2347
|
runtime_current = False
|
|
@@ -2494,6 +2412,8 @@ def doctor(
|
|
|
2494
2412
|
source = read_project_file(
|
|
2495
2413
|
source_root / "scripts" / name, f"package: guard {name}"
|
|
2496
2414
|
)
|
|
2415
|
+
if pinned:
|
|
2416
|
+
source = runtime_store.guard_launcher(name).encode()
|
|
2497
2417
|
if source is None:
|
|
2498
2418
|
continue
|
|
2499
2419
|
if GUARD_MARKER.encode() not in content:
|
|
@@ -2721,17 +2641,16 @@ def install(
|
|
|
2721
2641
|
|
|
2722
2642
|
if project is not None:
|
|
2723
2643
|
_validate_directory_destination(project, "project path")
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
)
|
|
2644
|
+
_validate_project(
|
|
2645
|
+
source_root,
|
|
2646
|
+
project,
|
|
2647
|
+
selected,
|
|
2648
|
+
hooks,
|
|
2649
|
+
[*mutation_roots, *planned_backups],
|
|
2650
|
+
interpreter,
|
|
2651
|
+
hooks_dir,
|
|
2652
|
+
update,
|
|
2653
|
+
)
|
|
2735
2654
|
|
|
2736
2655
|
results = []
|
|
2737
2656
|
with tempfile.TemporaryDirectory(prefix="gsd-path-install-") as temporary:
|
|
@@ -2853,12 +2772,16 @@ def parser() -> argparse.ArgumentParser:
|
|
|
2853
2772
|
for target in TARGETS:
|
|
2854
2773
|
argument_parser.add_argument(f"--{target}", action="store_true")
|
|
2855
2774
|
argument_parser.add_argument(f"--{target}-root", type=Path)
|
|
2775
|
+
argument_parser.add_argument("--adapter-request", action="store_true", help=argparse.SUPPRESS)
|
|
2856
2776
|
argument_parser.add_argument("--all", action="store_true", dest="all_targets")
|
|
2857
2777
|
argument_parser.add_argument("--update", action="store_true")
|
|
2858
2778
|
argument_parser.add_argument("--local", action="store_true")
|
|
2859
2779
|
argument_parser.add_argument("--dry-run", action="store_true")
|
|
2860
2780
|
argument_parser.add_argument("--project", type=Path)
|
|
2861
2781
|
argument_parser.add_argument("--doctor", action="store_true")
|
|
2782
|
+
runtime_actions = argument_parser.add_mutually_exclusive_group()
|
|
2783
|
+
for action in ("restore", "upgrade", "migrate"):
|
|
2784
|
+
runtime_actions.add_argument(f"--runtime-{action}", action="store_true")
|
|
2862
2785
|
argument_parser.add_argument("--hooks", action="store_true")
|
|
2863
2786
|
argument_parser.add_argument("--hooks-init", action="store_true")
|
|
2864
2787
|
argument_parser.add_argument("--hooks-refresh", action="store_true")
|
|
@@ -2875,10 +2798,51 @@ def parser() -> argparse.ArgumentParser:
|
|
|
2875
2798
|
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
2876
2799
|
argument_parser = parser()
|
|
2877
2800
|
arguments = argument_parser.parse_args(argv)
|
|
2801
|
+
if arguments.adapter_request:
|
|
2802
|
+
try:
|
|
2803
|
+
request = json.load(sys.stdin)
|
|
2804
|
+
source = Path(request["source"])
|
|
2805
|
+
project = Path(request["project"])
|
|
2806
|
+
action = request["action"]
|
|
2807
|
+
if action == "install":
|
|
2808
|
+
plans = [TargetPlan(p["name"], Path(p["root"])) for p in request["plans"]]
|
|
2809
|
+
result = install(source, plans, project=project, dry_run=request["dryRun"],
|
|
2810
|
+
hooks=request["hooks"], migrate_legacy=request["migrateLegacy"],
|
|
2811
|
+
update=request["update"])
|
|
2812
|
+
elif action == "refresh":
|
|
2813
|
+
result = refresh_hooks(source, project, request["full"], request["dryRun"],
|
|
2814
|
+
request["selected"], request["initialize"])
|
|
2815
|
+
elif action == "doctor":
|
|
2816
|
+
result = doctor(source, request["targets"], lambda target: Path(request["roots"][target]), project)
|
|
2817
|
+
else:
|
|
2818
|
+
raise InstallerError("unknown installer adapter action")
|
|
2819
|
+
print(json.dumps(result))
|
|
2820
|
+
return 0
|
|
2821
|
+
except (InstallerError, OSError, ValueError, KeyError) as error:
|
|
2822
|
+
print(str(error), file=sys.stderr)
|
|
2823
|
+
return 1
|
|
2878
2824
|
source_root = absolute_path(arguments.source_root)
|
|
2879
2825
|
project = (
|
|
2880
2826
|
absolute_path(arguments.project) if arguments.project is not None else None
|
|
2881
2827
|
)
|
|
2828
|
+
runtime_action = next((action for action in ("restore", "upgrade", "migrate")
|
|
2829
|
+
if getattr(arguments, "runtime_" + action)), None)
|
|
2830
|
+
if runtime_action:
|
|
2831
|
+
if project is None:
|
|
2832
|
+
argument_parser.error(f"--runtime-{runtime_action} requires --project")
|
|
2833
|
+
try:
|
|
2834
|
+
_validate_project_git_root(project)
|
|
2835
|
+
locks, created = ([], []) if arguments.dry_run else _acquire_install_locks([project / HOOKS_DIRECTORY])
|
|
2836
|
+
try:
|
|
2837
|
+
pin = runtime_store.operate(source_root, project, runtime_action, dry_run=arguments.dry_run)
|
|
2838
|
+
finally:
|
|
2839
|
+
_release_install_locks(locks, created)
|
|
2840
|
+
print(f"runtime: {runtime_action} {pin['version']} ({pin['digest']})"
|
|
2841
|
+
+ (" (dry run)" if arguments.dry_run else ""))
|
|
2842
|
+
return 0
|
|
2843
|
+
except (InstallerError, OSError, ValueError) as error:
|
|
2844
|
+
print(f"error: {error}", file=sys.stderr)
|
|
2845
|
+
return 1
|
|
2882
2846
|
if arguments.doctor:
|
|
2883
2847
|
named = [target for target in TARGETS if getattr(arguments, target)]
|
|
2884
2848
|
selected = named if named and not arguments.all_targets else list(TARGETS)
|
package/scripts/integration.py
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
# gsd-path project runtime
|
|
3
3
|
"""Own milestone integration, publication, tags, and completion proof."""
|
|
4
4
|
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
# Runtime helpers must not modify their immutable installation.
|
|
8
|
+
sys.dont_write_bytecode = True
|
|
9
|
+
|
|
5
10
|
import json
|
|
6
11
|
import re
|
|
7
12
|
from pathlib import Path, PurePosixPath
|
|
@@ -21,6 +26,7 @@ try:
|
|
|
21
26
|
from pipeline_state import PipelineState
|
|
22
27
|
from isolation import publication_base
|
|
23
28
|
import _common
|
|
29
|
+
import worktree_paths
|
|
24
30
|
except ImportError: # pragma: no cover - package import used by tests
|
|
25
31
|
from scripts.pipeline_git import (
|
|
26
32
|
bound_branch_name,
|
|
@@ -35,6 +41,7 @@ except ImportError: # pragma: no cover - package import used by tests
|
|
|
35
41
|
from scripts.pipeline_state import PipelineState
|
|
36
42
|
from scripts.isolation import publication_base
|
|
37
43
|
from scripts import _common
|
|
44
|
+
from scripts import worktree_paths
|
|
38
45
|
|
|
39
46
|
|
|
40
47
|
if __package__:
|
|
@@ -156,10 +163,13 @@ def optional_ref(project: Path, ref: str) -> Optional[str]:
|
|
|
156
163
|
return result.stdout.strip() if result.returncode == 0 else None
|
|
157
164
|
|
|
158
165
|
|
|
159
|
-
def integration_names(project: Path, archive_name: str) -> tuple[str, Path]:
|
|
166
|
+
def integration_names(project: Path, archive_name: str, *, pin: bool = False) -> tuple[str, Path]:
|
|
160
167
|
identifier = milestone_id(milestone_number(archive_name))
|
|
161
168
|
branch = f"gsd-path-integrate/{identifier}"
|
|
162
|
-
|
|
169
|
+
try:
|
|
170
|
+
worktree = worktree_paths.worktree_path(project, "integrate", identifier, pin=pin)
|
|
171
|
+
except (ValueError, OSError) as error:
|
|
172
|
+
raise ArchiveError(str(error)) from error
|
|
163
173
|
return branch, worktree
|
|
164
174
|
|
|
165
175
|
|
|
@@ -1044,7 +1054,7 @@ def integrate(repo: Path, slug: str) -> dict:
|
|
|
1044
1054
|
ship_commit,
|
|
1045
1055
|
)
|
|
1046
1056
|
publishable_bound_branch(project, bound_branch, ship_commit)
|
|
1047
|
-
integration_branch, worktree = integration_names(project, archive_name)
|
|
1057
|
+
integration_branch, worktree = integration_names(project, archive_name, pin=True)
|
|
1048
1058
|
interrupted_worktree = registered_worktree(project, integration_branch)
|
|
1049
1059
|
if (
|
|
1050
1060
|
interrupted_worktree is not None
|
|
@@ -1222,7 +1232,9 @@ def find_integrate_commit(
|
|
|
1222
1232
|
return merge_commit
|
|
1223
1233
|
|
|
1224
1234
|
|
|
1225
|
-
def validate_integrated(
|
|
1235
|
+
def validate_integrated(
|
|
1236
|
+
repo: Path, slug: str, *, refresh: bool = True, historical: bool = False
|
|
1237
|
+
) -> dict:
|
|
1226
1238
|
project = repo.resolve()
|
|
1227
1239
|
active_root = archive_milestone.require_project_layout(project)
|
|
1228
1240
|
state, _, loaded_state_path = archive_milestone.strict_state(project)
|
|
@@ -1235,7 +1247,7 @@ def validate_integrated(repo: Path, slug: str, *, refresh: bool = True) -> dict:
|
|
|
1235
1247
|
)
|
|
1236
1248
|
|
|
1237
1249
|
# (a) The shipped transaction itself must still validate.
|
|
1238
|
-
shipped = archive_milestone.validate(repo)
|
|
1250
|
+
shipped = archive_milestone.validate(repo, historical=historical)
|
|
1239
1251
|
configured = shipped["archive"]
|
|
1240
1252
|
ship_commit = shipped["commit"]
|
|
1241
1253
|
archive_name = PurePosixPath(configured).name
|
|
@@ -1340,6 +1352,10 @@ def validate_integrated(repo: Path, slug: str, *, refresh: bool = True) -> dict:
|
|
|
1340
1352
|
contains = run_git(project, "merge-base", "--is-ancestor", merge_commit, remote_default)
|
|
1341
1353
|
if contains.returncode != 0:
|
|
1342
1354
|
raise ArchiveError(f"{remote_default} does not contain the integration merge")
|
|
1355
|
+
if (historical
|
|
1356
|
+
and run_git(project, "branch", "--show-current").stdout.strip() != bound_branch
|
|
1357
|
+
and run_git(project, "merge-base", "--is-ancestor", merge_commit, "HEAD").returncode):
|
|
1358
|
+
raise ArchiveError("HEAD does not contain the integration merge")
|
|
1343
1359
|
|
|
1344
1360
|
# (e) The bound branch tip and annotated tag must be published on origin.
|
|
1345
1361
|
require_published_integration(
|
|
@@ -1348,7 +1364,8 @@ def validate_integrated(repo: Path, slug: str, *, refresh: bool = True) -> dict:
|
|
|
1348
1364
|
ship_commit,
|
|
1349
1365
|
tag_name,
|
|
1350
1366
|
merge_commit,
|
|
1351
|
-
allow_missing_bound=state.integration == "pull-request",
|
|
1367
|
+
allow_missing_bound=state.integration == "pull-request" or (historical and has_origin),
|
|
1368
|
+
retired=historical,
|
|
1352
1369
|
)
|
|
1353
1370
|
|
|
1354
1371
|
result = {
|
|
@@ -1369,7 +1386,9 @@ def validate_integrated(repo: Path, slug: str, *, refresh: bool = True) -> dict:
|
|
|
1369
1386
|
refs = [(f"refs/heads/{default_name}", result["base"]),
|
|
1370
1387
|
(f"refs/tags/{tag_name}", optional_ref(project, tag_ref))]
|
|
1371
1388
|
if state.integration == "direct":
|
|
1372
|
-
|
|
1389
|
+
bound_ref = f"refs/heads/{bound_branch}"
|
|
1390
|
+
if not historical or live_remote_ref(project, bound_ref) is not None:
|
|
1391
|
+
refs.append((bound_ref, ship_commit))
|
|
1373
1392
|
for ref, expected in refs:
|
|
1374
1393
|
if live_remote_ref(project, ref) != expected:
|
|
1375
1394
|
raise ArchiveError(f"published {ref} differs from local integration evidence")
|
|
@@ -1385,6 +1404,7 @@ def require_published_integration(
|
|
|
1385
1404
|
tag_name: str,
|
|
1386
1405
|
merge_commit: str,
|
|
1387
1406
|
allow_missing_bound: bool = False,
|
|
1407
|
+
retired: bool = False,
|
|
1388
1408
|
) -> None:
|
|
1389
1409
|
if allow_missing_bound:
|
|
1390
1410
|
published_ship = live_remote_ref(project, f"refs/heads/{bound_branch}")
|
|
@@ -1408,7 +1428,7 @@ def require_published_integration(
|
|
|
1408
1428
|
|
|
1409
1429
|
bound_ref = f"refs/remotes/origin/{bound_branch}"
|
|
1410
1430
|
if run_git(project, "rev-parse", "--verify", "--quiet", bound_ref).returncode != 0:
|
|
1411
|
-
if not
|
|
1431
|
+
if not retired:
|
|
1412
1432
|
raise ArchiveError(f"missing published bound branch: origin/{bound_branch}")
|
|
1413
1433
|
else:
|
|
1414
1434
|
published_ship = archive_milestone.require_git_success(
|