@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
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# gsd-path project runtime
|
|
3
|
+
"""Resolve optional GSD Path cross-model review panels without model reasoning.
|
|
4
|
+
|
|
5
|
+
The orchestrator inspects the host's advertised child-model slugs and passes
|
|
6
|
+
them here. This helper parses PLAN.md / INTENT.md / CHARTER.md (PLAN wins,
|
|
7
|
+
then INTENT, then CHARTER, else off), groups slugs into families, skips the
|
|
8
|
+
parent family, caps the panel at three, and merges family artifacts. It never
|
|
9
|
+
probes a host or overrides the canonical inherit reviewer.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
# Runtime helpers must not modify their immutable installation.
|
|
20
|
+
sys.dont_write_bytecode = True
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from typing import Iterable, Optional, Sequence
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
KNOWN_FAMILIES = (
|
|
26
|
+
"claude",
|
|
27
|
+
"gpt",
|
|
28
|
+
"grok",
|
|
29
|
+
"composer",
|
|
30
|
+
"gemini",
|
|
31
|
+
"deepseek",
|
|
32
|
+
"kimi",
|
|
33
|
+
"qwen",
|
|
34
|
+
)
|
|
35
|
+
FAMILY_ALIASES = {
|
|
36
|
+
"claude": "claude",
|
|
37
|
+
"opus": "claude",
|
|
38
|
+
"sonnet": "claude",
|
|
39
|
+
"haiku": "claude",
|
|
40
|
+
"gpt": "gpt",
|
|
41
|
+
"openai": "gpt",
|
|
42
|
+
"grok": "grok",
|
|
43
|
+
"composer": "composer",
|
|
44
|
+
"gemini": "gemini",
|
|
45
|
+
"deepseek": "deepseek",
|
|
46
|
+
"kimi": "kimi",
|
|
47
|
+
"moonshot": "kimi",
|
|
48
|
+
"qwen": "qwen",
|
|
49
|
+
}
|
|
50
|
+
MAX_FAMILIES = 3
|
|
51
|
+
PLAN_LINE = re.compile(
|
|
52
|
+
r"^-\s*review_panel:\s*(\S.*?)\s*(?:<!--.*-->)?\s*$", re.MULTILINE
|
|
53
|
+
)
|
|
54
|
+
INTENT_LINE = re.compile(
|
|
55
|
+
r"^Review panel:\s*(\S.*?)\s*(?:<!--.*-->)?\s*$", re.MULTILINE
|
|
56
|
+
)
|
|
57
|
+
VERSION_NUMBERS = re.compile(r"\d+")
|
|
58
|
+
TOKEN_SPLIT = re.compile(r"[^a-z0-9]+")
|
|
59
|
+
FINDING_BLOCK = re.compile(
|
|
60
|
+
r"^###\s+(?P<id>F\d+)\s*$"
|
|
61
|
+
r"(?P<body>.*?)(?=^###\s+F\d+\s*$|\Z)",
|
|
62
|
+
re.MULTILINE | re.DOTALL,
|
|
63
|
+
)
|
|
64
|
+
FIELD_LINE = re.compile(r"^-\s*(?P<key>[A-Za-z][A-Za-z ]*):\s*(?P<value>.*)\s*$")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ReviewPanelError(RuntimeError):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _first_token(value: str) -> str:
|
|
72
|
+
return value.strip().split()[0].strip().strip("`")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _split_families(value: str) -> tuple[str, ...]:
|
|
76
|
+
tokens = [token.strip().casefold() for token in value.split(",") if token.strip()]
|
|
77
|
+
if not tokens:
|
|
78
|
+
raise ReviewPanelError("review_panel named list is empty")
|
|
79
|
+
unknown = [token for token in tokens if token not in KNOWN_FAMILIES]
|
|
80
|
+
if unknown:
|
|
81
|
+
raise ReviewPanelError(
|
|
82
|
+
f"unknown review_panel families: {', '.join(unknown)}"
|
|
83
|
+
)
|
|
84
|
+
seen = []
|
|
85
|
+
for token in tokens:
|
|
86
|
+
if token not in seen:
|
|
87
|
+
seen.append(token)
|
|
88
|
+
if len(seen) > MAX_FAMILIES:
|
|
89
|
+
raise ReviewPanelError(
|
|
90
|
+
f"review_panel names at most {MAX_FAMILIES} families"
|
|
91
|
+
)
|
|
92
|
+
return tuple(seen)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def parse_review_panel_value(raw: str) -> dict:
|
|
96
|
+
value = raw.strip()
|
|
97
|
+
if not value:
|
|
98
|
+
raise ReviewPanelError("review_panel value is empty")
|
|
99
|
+
token = _first_token(value).casefold()
|
|
100
|
+
if token == "off":
|
|
101
|
+
return {"mode": "off", "families": ()}
|
|
102
|
+
if token == "detected":
|
|
103
|
+
return {"mode": "detected", "families": ()}
|
|
104
|
+
families = _split_families(value)
|
|
105
|
+
return {"mode": "named", "families": families}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def extract_config_value(text: str, pattern: re.Pattern[str], source: str) -> Optional[str]:
|
|
109
|
+
matches = pattern.findall(text)
|
|
110
|
+
if not matches:
|
|
111
|
+
return None
|
|
112
|
+
if len(matches) > 1:
|
|
113
|
+
raise ReviewPanelError(f"{source} has multiple review_panel values")
|
|
114
|
+
return matches[0]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def parse_sources(
|
|
118
|
+
plan_text: Optional[str],
|
|
119
|
+
intent_text: Optional[str],
|
|
120
|
+
charter_text: Optional[str] = None,
|
|
121
|
+
) -> dict:
|
|
122
|
+
if plan_text is not None:
|
|
123
|
+
plan_value = extract_config_value(plan_text, PLAN_LINE, "PLAN.md")
|
|
124
|
+
if plan_value is not None:
|
|
125
|
+
parsed = parse_review_panel_value(plan_value)
|
|
126
|
+
parsed["source"] = "plan"
|
|
127
|
+
return parsed
|
|
128
|
+
if intent_text is not None:
|
|
129
|
+
intent_value = extract_config_value(intent_text, INTENT_LINE, "INTENT.md")
|
|
130
|
+
if intent_value is not None:
|
|
131
|
+
parsed = parse_review_panel_value(intent_value)
|
|
132
|
+
parsed["source"] = "intent"
|
|
133
|
+
return parsed
|
|
134
|
+
if charter_text is not None:
|
|
135
|
+
charter_value = extract_config_value(charter_text, INTENT_LINE, "CHARTER.md")
|
|
136
|
+
if charter_value is not None:
|
|
137
|
+
parsed = parse_review_panel_value(charter_value)
|
|
138
|
+
parsed["source"] = "charter"
|
|
139
|
+
return parsed
|
|
140
|
+
return {"mode": "off", "families": (), "source": "default"}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def read_optional(path: Optional[Path]) -> Optional[str]:
|
|
144
|
+
if path is None:
|
|
145
|
+
return None
|
|
146
|
+
resolved = path.resolve()
|
|
147
|
+
if resolved.is_symlink() or not resolved.is_file():
|
|
148
|
+
raise ReviewPanelError(f"path must be a real file: {resolved}")
|
|
149
|
+
return resolved.read_text(encoding="utf-8")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def parse_files(
|
|
153
|
+
plan: Optional[Path],
|
|
154
|
+
intent: Optional[Path],
|
|
155
|
+
charter: Optional[Path] = None,
|
|
156
|
+
) -> dict:
|
|
157
|
+
return parse_sources(
|
|
158
|
+
read_optional(plan), read_optional(intent), read_optional(charter)
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def plan_review_panel_enabled(plan_text: str) -> bool:
|
|
163
|
+
"""Archive-safe enabled check: anything other than absent/off is on."""
|
|
164
|
+
try:
|
|
165
|
+
parsed = parse_sources(plan_text, None)
|
|
166
|
+
except ReviewPanelError:
|
|
167
|
+
return True
|
|
168
|
+
return parsed["mode"] != "off"
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def family_of_slug(slug: str) -> Optional[str]:
|
|
172
|
+
normalized = slug.strip().casefold()
|
|
173
|
+
if not normalized or normalized == "inherit":
|
|
174
|
+
return None
|
|
175
|
+
tokens = TOKEN_SPLIT.split(normalized)
|
|
176
|
+
for token in tokens:
|
|
177
|
+
if token in FAMILY_ALIASES:
|
|
178
|
+
return FAMILY_ALIASES[token]
|
|
179
|
+
for token in tokens:
|
|
180
|
+
stem = token.rstrip("0123456789")
|
|
181
|
+
if stem and stem in FAMILY_ALIASES:
|
|
182
|
+
return FAMILY_ALIASES[stem]
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def version_key(slug: str) -> tuple[int, ...]:
|
|
187
|
+
numbers = tuple(int(part) for part in VERSION_NUMBERS.findall(slug))
|
|
188
|
+
return numbers if numbers else (0,)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def latest_slug(slugs: Sequence[str]) -> str:
|
|
192
|
+
return max(slugs, key=lambda slug: (version_key(slug), len(slug), slug))
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def group_advertised(slugs: Iterable[str]) -> dict[str, list[str]]:
|
|
196
|
+
grouped: dict[str, list[str]] = {family: [] for family in KNOWN_FAMILIES}
|
|
197
|
+
for slug in slugs:
|
|
198
|
+
cleaned = slug.strip()
|
|
199
|
+
if not cleaned:
|
|
200
|
+
continue
|
|
201
|
+
family = family_of_slug(cleaned)
|
|
202
|
+
if family is None:
|
|
203
|
+
continue
|
|
204
|
+
if cleaned not in grouped[family]:
|
|
205
|
+
grouped[family].append(cleaned)
|
|
206
|
+
return {family: values for family, values in grouped.items() if values}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def split_csv(raw: Optional[str]) -> tuple[str, ...]:
|
|
210
|
+
if not raw:
|
|
211
|
+
return ()
|
|
212
|
+
return tuple(part.strip() for part in raw.split(",") if part.strip())
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def resolve_panel(
|
|
216
|
+
config: dict,
|
|
217
|
+
advertised: Sequence[str],
|
|
218
|
+
parent_family: Optional[str] = None,
|
|
219
|
+
parent_slug: Optional[str] = None,
|
|
220
|
+
excluded_families: Sequence[str] = (),
|
|
221
|
+
) -> dict:
|
|
222
|
+
inferred_parent = parent_family or (
|
|
223
|
+
family_of_slug(parent_slug) if parent_slug else None
|
|
224
|
+
)
|
|
225
|
+
grouped = group_advertised(advertised)
|
|
226
|
+
skipped = []
|
|
227
|
+
selected = []
|
|
228
|
+
|
|
229
|
+
if config["mode"] == "off":
|
|
230
|
+
return {
|
|
231
|
+
"mode": "off",
|
|
232
|
+
"status": "off",
|
|
233
|
+
"reason": "review_panel is off",
|
|
234
|
+
"parent_family": inferred_parent,
|
|
235
|
+
"selected": [],
|
|
236
|
+
"skipped": [],
|
|
237
|
+
"missing": [],
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
wanted = (
|
|
241
|
+
list(config["families"])
|
|
242
|
+
if config["mode"] == "named"
|
|
243
|
+
else [family for family in KNOWN_FAMILIES if family in grouped]
|
|
244
|
+
)
|
|
245
|
+
missing = [family for family in wanted if family not in grouped]
|
|
246
|
+
if config["mode"] == "named" and missing:
|
|
247
|
+
raise ReviewPanelError(
|
|
248
|
+
"named review_panel families are not advertised: " + ", ".join(missing)
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if config["mode"] == "named" and set(wanted) & set(excluded_families):
|
|
252
|
+
raise ReviewPanelError("named review_panel must use an independent family")
|
|
253
|
+
for family in wanted:
|
|
254
|
+
if family in excluded_families:
|
|
255
|
+
skipped.append({"family": family, "reason": "excluded reviewer family"})
|
|
256
|
+
continue
|
|
257
|
+
if family == inferred_parent:
|
|
258
|
+
skipped.append({"family": family, "reason": "parent family"})
|
|
259
|
+
continue
|
|
260
|
+
slugs = grouped.get(family)
|
|
261
|
+
if not slugs:
|
|
262
|
+
skipped.append({"family": family, "reason": "not advertised"})
|
|
263
|
+
continue
|
|
264
|
+
selected.append({"family": family, "slug": latest_slug(slugs)})
|
|
265
|
+
if len(selected) >= MAX_FAMILIES:
|
|
266
|
+
overflow = wanted[wanted.index(family) + 1 :]
|
|
267
|
+
for extra in overflow:
|
|
268
|
+
if extra != inferred_parent and extra in grouped:
|
|
269
|
+
skipped.append({"family": extra, "reason": "cap"})
|
|
270
|
+
break
|
|
271
|
+
|
|
272
|
+
if selected:
|
|
273
|
+
return {
|
|
274
|
+
"mode": config["mode"],
|
|
275
|
+
"status": "ready",
|
|
276
|
+
"reason": "panel resolved",
|
|
277
|
+
"parent_family": inferred_parent,
|
|
278
|
+
"selected": selected,
|
|
279
|
+
"skipped": skipped,
|
|
280
|
+
"missing": missing if config["mode"] == "detected" else [],
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if config["mode"] == "named":
|
|
284
|
+
raise ReviewPanelError(
|
|
285
|
+
"named review_panel would only repeat the parent family or is empty"
|
|
286
|
+
)
|
|
287
|
+
return {
|
|
288
|
+
"mode": config["mode"],
|
|
289
|
+
"status": "skipped",
|
|
290
|
+
"reason": "no advertised cross-model families",
|
|
291
|
+
"parent_family": inferred_parent,
|
|
292
|
+
"selected": [],
|
|
293
|
+
"skipped": skipped,
|
|
294
|
+
"missing": missing,
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _require_field(body: str, key: str, source: str) -> str:
|
|
299
|
+
for line in body.splitlines():
|
|
300
|
+
match = FIELD_LINE.fullmatch(line.strip())
|
|
301
|
+
if match and match.group("key").casefold() == key.casefold():
|
|
302
|
+
value = match.group("value").strip()
|
|
303
|
+
if not value:
|
|
304
|
+
raise ReviewPanelError(f"{source} has an empty {key} field")
|
|
305
|
+
return value
|
|
306
|
+
raise ReviewPanelError(f"{source} is missing the {key} field")
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def parse_findings(text: str, source: str) -> list[dict]:
|
|
310
|
+
findings = []
|
|
311
|
+
for match in FINDING_BLOCK.finditer(text):
|
|
312
|
+
body = match.group("body")
|
|
313
|
+
severity = _require_field(body, "Severity", f"{source} {match.group('id')}").casefold()
|
|
314
|
+
kind = _require_field(body, "Kind", f"{source} {match.group('id')}").casefold()
|
|
315
|
+
criterion = _require_field(body, "Criterion", f"{source} {match.group('id')}")
|
|
316
|
+
evidence = _require_field(body, "Evidence", f"{source} {match.group('id')}")
|
|
317
|
+
found = _require_field(body, "Found", f"{source} {match.group('id')}")
|
|
318
|
+
fix = _require_field(body, "Fix direction", f"{source} {match.group('id')}")
|
|
319
|
+
if severity not in {"high", "medium", "low"}:
|
|
320
|
+
raise ReviewPanelError(f"{source} {match.group('id')} has an invalid Severity")
|
|
321
|
+
if kind not in {"criterion", "preference"}:
|
|
322
|
+
raise ReviewPanelError(f"{source} {match.group('id')} has an invalid Kind")
|
|
323
|
+
if kind == "criterion" and criterion.casefold() == "none":
|
|
324
|
+
raise ReviewPanelError(
|
|
325
|
+
f"{source} {match.group('id')} criterion findings must name a criterion"
|
|
326
|
+
)
|
|
327
|
+
findings.append(
|
|
328
|
+
{
|
|
329
|
+
"id": match.group("id"),
|
|
330
|
+
"severity": severity,
|
|
331
|
+
"kind": kind,
|
|
332
|
+
"criterion": criterion,
|
|
333
|
+
"evidence": evidence,
|
|
334
|
+
"found": found,
|
|
335
|
+
"fix": fix,
|
|
336
|
+
"source": source,
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
if not findings:
|
|
340
|
+
findings_heading = re.search(r"^## Findings\s*$", text, re.MULTILINE)
|
|
341
|
+
if findings_heading:
|
|
342
|
+
rest = text[findings_heading.end() :]
|
|
343
|
+
next_heading = re.search(r"^## ", rest, re.MULTILINE)
|
|
344
|
+
section = rest[: next_heading.start()] if next_heading else rest
|
|
345
|
+
if re.search(r"^-\s*none\s*$", section, re.MULTILINE):
|
|
346
|
+
return []
|
|
347
|
+
raise ReviewPanelError(f"{source} has no findings")
|
|
348
|
+
return findings
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def parse_family_artifact(path: Path, expected_kind: str) -> dict:
|
|
352
|
+
if path.is_symlink() or not path.is_file():
|
|
353
|
+
raise ReviewPanelError(f"panel artifact must be a real file: {path}")
|
|
354
|
+
text = path.read_text(encoding="utf-8")
|
|
355
|
+
lines = text.splitlines()
|
|
356
|
+
if expected_kind == "plan":
|
|
357
|
+
if not lines or not lines[0].startswith("# Plan panel — "):
|
|
358
|
+
raise ReviewPanelError(f"{path.name} heading must start with '# Plan panel — '")
|
|
359
|
+
elif expected_kind == "wave":
|
|
360
|
+
if not lines or not lines[0].startswith("# Panel — wave "):
|
|
361
|
+
raise ReviewPanelError(f"{path.name} heading must start with '# Panel — wave '")
|
|
362
|
+
else:
|
|
363
|
+
raise ReviewPanelError(f"unknown panel kind: {expected_kind}")
|
|
364
|
+
family = _require_field(text, "Family", path.name).casefold()
|
|
365
|
+
model = _require_field(text, "Model", path.name)
|
|
366
|
+
if family not in KNOWN_FAMILIES:
|
|
367
|
+
raise ReviewPanelError(f"{path.name} has an unknown Family")
|
|
368
|
+
if "## Findings" not in text:
|
|
369
|
+
raise ReviewPanelError(f"{path.name} is missing ## Findings")
|
|
370
|
+
findings = parse_findings(text, path.name)
|
|
371
|
+
return {
|
|
372
|
+
"path": str(path),
|
|
373
|
+
"family": family,
|
|
374
|
+
"model": model,
|
|
375
|
+
"text": text.rstrip() + "\n",
|
|
376
|
+
"findings": findings,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
def actionable(finding: dict) -> bool:
|
|
381
|
+
return finding["kind"] == "criterion" and finding["severity"] == "high"
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def detect_conflicts(findings: Sequence[dict]) -> list[dict]:
|
|
385
|
+
by_criterion: dict[str, list[dict]] = {}
|
|
386
|
+
for finding in findings:
|
|
387
|
+
key = finding["criterion"].strip().casefold()
|
|
388
|
+
if key in {"", "none"}:
|
|
389
|
+
continue
|
|
390
|
+
by_criterion.setdefault(key, []).append(finding)
|
|
391
|
+
conflicts = []
|
|
392
|
+
for criterion, group in by_criterion.items():
|
|
393
|
+
severities = {item["severity"] for item in group}
|
|
394
|
+
# A conflict is families disagreeing on whether the criterion needs a
|
|
395
|
+
# fix; wording differences in Found are not conflicts.
|
|
396
|
+
if len({actionable(item) for item in group}) > 1:
|
|
397
|
+
conflicts.append(
|
|
398
|
+
{
|
|
399
|
+
"criterion": group[0]["criterion"],
|
|
400
|
+
"families": [item["source"] for item in group],
|
|
401
|
+
"severities": sorted(severities),
|
|
402
|
+
}
|
|
403
|
+
)
|
|
404
|
+
return conflicts
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
def render_finding(finding: dict) -> str:
|
|
408
|
+
return (
|
|
409
|
+
f"- {finding['severity']} / {finding['kind']} — {finding['criterion']}\n"
|
|
410
|
+
f" evidence: {finding['evidence']}\n"
|
|
411
|
+
f" found: {finding['found']}\n"
|
|
412
|
+
f" fix: {finding['fix']}\n"
|
|
413
|
+
f" source: {finding['source']}\n"
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def merge_artifacts(
|
|
418
|
+
kind: str,
|
|
419
|
+
inputs: Sequence[Path],
|
|
420
|
+
output: Path,
|
|
421
|
+
header_fields: Sequence[tuple[str, str]],
|
|
422
|
+
) -> dict:
|
|
423
|
+
artifacts = [parse_family_artifact(path, kind) for path in inputs]
|
|
424
|
+
families = [artifact["family"] for artifact in artifacts]
|
|
425
|
+
if len(families) != len(set(families)):
|
|
426
|
+
raise ReviewPanelError("panel merge repeats a family")
|
|
427
|
+
findings = [finding for artifact in artifacts for finding in artifact["findings"]]
|
|
428
|
+
action = [finding for finding in findings if actionable(finding)]
|
|
429
|
+
warnings = [finding for finding in findings if not actionable(finding)]
|
|
430
|
+
conflicts = detect_conflicts(findings)
|
|
431
|
+
title = "# Plan panel" if kind == "plan" else "# Wave panel"
|
|
432
|
+
lines = [title, ""]
|
|
433
|
+
for key, value in header_fields:
|
|
434
|
+
lines.append(f"{key}: {value}")
|
|
435
|
+
lines.extend(
|
|
436
|
+
[
|
|
437
|
+
f"Families: {', '.join(families)}",
|
|
438
|
+
f"Actionable: {len(action)}",
|
|
439
|
+
f"Warnings: {len(warnings)}",
|
|
440
|
+
f"Conflicts: {len(conflicts)}",
|
|
441
|
+
"",
|
|
442
|
+
"## Actionable",
|
|
443
|
+
"",
|
|
444
|
+
]
|
|
445
|
+
)
|
|
446
|
+
if action:
|
|
447
|
+
lines.extend(render_finding(finding) for finding in action)
|
|
448
|
+
else:
|
|
449
|
+
lines.append("- none")
|
|
450
|
+
lines.append("")
|
|
451
|
+
lines.extend(["## Warnings", ""])
|
|
452
|
+
if warnings:
|
|
453
|
+
lines.extend(render_finding(finding) for finding in warnings)
|
|
454
|
+
else:
|
|
455
|
+
lines.append("- none")
|
|
456
|
+
lines.append("")
|
|
457
|
+
lines.extend(["## Conflicts", ""])
|
|
458
|
+
if conflicts:
|
|
459
|
+
for conflict in conflicts:
|
|
460
|
+
lines.append(
|
|
461
|
+
f"- {conflict['criterion']} — families {', '.join(conflict['families'])}; "
|
|
462
|
+
f"severities {', '.join(conflict['severities'])}"
|
|
463
|
+
)
|
|
464
|
+
lines.append("")
|
|
465
|
+
else:
|
|
466
|
+
lines.append("- none")
|
|
467
|
+
lines.append("")
|
|
468
|
+
lines.extend(["## By family", ""])
|
|
469
|
+
for artifact in artifacts:
|
|
470
|
+
lines.append(artifact["text"].rstrip())
|
|
471
|
+
lines.append("")
|
|
472
|
+
output.parent.mkdir(parents=True, exist_ok=True)
|
|
473
|
+
output.write_text("\n".join(lines).rstrip() + "\n", encoding="utf-8")
|
|
474
|
+
return {
|
|
475
|
+
"output": str(output.resolve()),
|
|
476
|
+
"families": families,
|
|
477
|
+
"actionable": len(action),
|
|
478
|
+
"warnings": len(warnings),
|
|
479
|
+
"conflicts": len(conflicts),
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
def emit(payload: dict) -> int:
|
|
484
|
+
json.dump(payload, sys.stdout, indent=2, sort_keys=True)
|
|
485
|
+
sys.stdout.write("\n")
|
|
486
|
+
return 0
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def parser() -> argparse.ArgumentParser:
|
|
490
|
+
result = argparse.ArgumentParser(description=__doc__)
|
|
491
|
+
result.add_argument(
|
|
492
|
+
"command", choices=("parse", "resolve", "families", "merge", "validate-plan")
|
|
493
|
+
)
|
|
494
|
+
result.add_argument("--plan", type=Path)
|
|
495
|
+
result.add_argument("--intent", type=Path)
|
|
496
|
+
result.add_argument("--charter", type=Path)
|
|
497
|
+
result.add_argument("--advertised", default="")
|
|
498
|
+
result.add_argument("--parent-family")
|
|
499
|
+
result.add_argument("--parent-slug")
|
|
500
|
+
result.add_argument("--exclude-family", action="append", choices=KNOWN_FAMILIES, default=[])
|
|
501
|
+
result.add_argument("--kind", choices=("plan", "wave"))
|
|
502
|
+
result.add_argument("--inputs", default="")
|
|
503
|
+
result.add_argument("--output", type=Path)
|
|
504
|
+
result.add_argument("--wave")
|
|
505
|
+
result.add_argument("--cycle")
|
|
506
|
+
result.add_argument("--mode")
|
|
507
|
+
return result
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
511
|
+
arguments = parser().parse_args(argv)
|
|
512
|
+
try:
|
|
513
|
+
if arguments.command == "families":
|
|
514
|
+
grouped = group_advertised(split_csv(arguments.advertised))
|
|
515
|
+
return emit(
|
|
516
|
+
{
|
|
517
|
+
"families": {
|
|
518
|
+
family: {"slugs": slugs, "latest": latest_slug(slugs)}
|
|
519
|
+
for family, slugs in grouped.items()
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
if arguments.command == "merge":
|
|
524
|
+
if arguments.kind is None or arguments.output is None:
|
|
525
|
+
raise ReviewPanelError("merge requires --kind and --output")
|
|
526
|
+
inputs = [Path(part) for part in split_csv(arguments.inputs)]
|
|
527
|
+
if not inputs:
|
|
528
|
+
raise ReviewPanelError("merge requires --inputs")
|
|
529
|
+
header = []
|
|
530
|
+
if arguments.mode:
|
|
531
|
+
header.append(("Mode", arguments.mode))
|
|
532
|
+
if arguments.kind == "wave":
|
|
533
|
+
if not arguments.wave or not arguments.cycle:
|
|
534
|
+
raise ReviewPanelError("wave merge requires --wave and --cycle")
|
|
535
|
+
header.extend(
|
|
536
|
+
(("Wave", arguments.wave), ("Cycle", arguments.cycle))
|
|
537
|
+
)
|
|
538
|
+
return emit(merge_artifacts(arguments.kind, inputs, arguments.output, header))
|
|
539
|
+
if arguments.plan is None and arguments.command in {"parse", "resolve", "validate-plan"}:
|
|
540
|
+
if arguments.command != "parse" or (
|
|
541
|
+
arguments.intent is None and arguments.charter is None
|
|
542
|
+
):
|
|
543
|
+
raise ReviewPanelError(
|
|
544
|
+
f"{arguments.command} requires --plan, --intent, or --charter"
|
|
545
|
+
)
|
|
546
|
+
config = parse_files(arguments.plan, arguments.intent, arguments.charter)
|
|
547
|
+
if arguments.command in {"parse", "validate-plan"}:
|
|
548
|
+
return emit(config)
|
|
549
|
+
resolved = resolve_panel(
|
|
550
|
+
config,
|
|
551
|
+
split_csv(arguments.advertised),
|
|
552
|
+
arguments.parent_family,
|
|
553
|
+
arguments.parent_slug,
|
|
554
|
+
arguments.exclude_family,
|
|
555
|
+
)
|
|
556
|
+
return emit(resolved)
|
|
557
|
+
except ReviewPanelError as error:
|
|
558
|
+
json.dump({"status": "error", "error": str(error)}, sys.stdout, indent=2)
|
|
559
|
+
sys.stdout.write("\n")
|
|
560
|
+
return 2
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
if __name__ == "__main__":
|
|
564
|
+
sys.exit(main())
|
|
@@ -3,6 +3,8 @@ name: gsd-path-plan
|
|
|
3
3
|
description: Create and validate dependency-ordered GSD Path build waves and complete task contracts. Use only when the user explicitly invokes $gsd-path-plan or an active $gsd-path router explicitly routes to this phase.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
+
Before executing project helpers, read [runtime selection](references/runtime-selection.md).
|
|
7
|
+
|
|
6
8
|
# GSD Path Planning Phase
|
|
7
9
|
|
|
8
10
|
Dispatch one planner, gate its artifacts, and obtain the single approval that
|
|
@@ -214,8 +216,8 @@ as stated in Lookahead mode.
|
|
|
214
216
|
statuses do not load this template. For each selected family, spawn one independent child
|
|
215
217
|
with logical task name `review_plan_panel_<family>`, the reviewer role
|
|
216
218
|
in plan-panel mode, the plan-panel template, and the exact helper-returned
|
|
217
|
-
model slug
|
|
218
|
-
|
|
219
|
+
model slug through the dispatch model-policy contract. Planner choices
|
|
220
|
+
use that same contract. Each child stages its family file under a
|
|
219
221
|
disposable root; the parent validates and copies those files, removes
|
|
220
222
|
any stale `<track>/review/PLAN-PANEL.skipped.json`, then runs
|
|
221
223
|
`python3 <absolute review_panel.py> merge --kind plan --inputs <family
|
|
@@ -7,10 +7,7 @@ use exactly one matching branch:
|
|
|
7
7
|
- A `spawn_agent` tool exposing `task_name`, `agent_type`, and `fork_turns` is
|
|
8
8
|
Codex. Use `fork_turns: "none"`; coders use the built-in `worker` type and
|
|
9
9
|
every other role uses `default`. Reuse a completed logical target with
|
|
10
|
-
`followup_task`.
|
|
11
|
-
`heavy` tier and `low` for the portable `light` tier; leave reasoning effort
|
|
12
|
-
unset for the session-default tier, and never pass `heavy` or `light` as a
|
|
13
|
-
literal Codex value.
|
|
10
|
+
`followup_task`.
|
|
14
11
|
- A `spawn_agent` tool without those Codex fields is Zed. Spawn one isolated,
|
|
15
12
|
full-capability child per brief. Zed children are not resumable, so retries
|
|
16
13
|
use a fresh child and a complete prompt.
|
|
@@ -26,7 +23,7 @@ use exactly one matching branch:
|
|
|
26
23
|
the complete new prompt for later work. Wait for a colliding active child and
|
|
27
24
|
collect results with `wait_commands_or_subagents`.
|
|
28
25
|
- A `Task` tool advertising the custom `gsd-path` subagent is Cursor. Use that
|
|
29
|
-
|
|
26
|
+
full-capability child. Resume it by returned agent ID when
|
|
30
27
|
available; otherwise retry with a fresh child and a complete prompt.
|
|
31
28
|
- A `Task` tool advertising the built-in `general` subagent is OpenCode. Use
|
|
32
29
|
that child; if an installed OpenCode v2 host exposes the renamed `subagent`
|
|
@@ -65,20 +62,10 @@ For every branch:
|
|
|
65
62
|
- Resolve the phase's linked role brief to an absolute path, include it in the
|
|
66
63
|
prompt, and require the child to read it before acting. The role brief
|
|
67
64
|
supplies the read-only boundary for auditors and reviewers.
|
|
68
|
-
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
host, use only an exact native equivalent advertised by that host; otherwise
|
|
73
|
-
do not override the model or reasoning effort. The only exception is a
|
|
74
|
-
review-panel child: when the host advertises model selection, pass the exact
|
|
75
|
-
slug returned by `scripts/review_panel.py resolve` for that family. Never
|
|
76
|
-
override the model on the canonical reviewer, planner, coder, or any other
|
|
77
|
-
role.
|
|
78
|
-
Host isolation: none. The child's working directory is the exact absolute
|
|
79
|
-
root GSD Path supplied; a host SHA checkout or extra worktree is a contract
|
|
80
|
-
failure. Never ask the host to create a worktree. Give the child the exact
|
|
81
|
-
repository or linked-worktree root supplied by GSD Path.
|
|
65
|
+
- Model selection: before every child launch or continuation, follow
|
|
66
|
+
[the model-policy contract](model-policy.md) and apply its recorded
|
|
67
|
+
native arguments. It owns defaults, project settings, task overrides,
|
|
68
|
+
capability failures, and reassignment. Host isolation: none. Use the exact GSD Path supplied root; create no extra checkout.
|
|
82
69
|
- Send a self-contained prompt with absolute input, template, and output paths
|
|
83
70
|
plus the child's bounded responsibility. Every brief also names the absolute
|
|
84
71
|
`AGENTS.md` and `WORKFLOW.md` paths (or explicitly says they are absent), the
|