@opengsd/gsd-path 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +460 -341
- package/DOCS.md +16 -5
- package/FULL.md +67 -6
- package/HOOKS.md +158 -10
- package/MIGRATE.md +12 -0
- package/QUICK.md +4 -2
- package/README.md +136 -116
- package/RUNTIME.md +24 -6
- package/UPDATE.md +39 -3
- package/WORKFLOW.md +80 -4
- package/package.json +5 -2
- package/platforms/shared-agents/dispatch.md +13 -0
- package/scripts/_common.py +256 -2
- package/scripts/archive_milestone.py +14 -13
- package/scripts/build_recovery.py +155 -58
- package/scripts/build_state.py +274 -8
- package/scripts/check_docs_audit.py +77 -4
- package/scripts/check_handoffs.py +635 -57
- package/scripts/check_task_briefs.py +293 -32
- package/scripts/detect_project.py +260 -20
- package/scripts/discussion_records.py +9 -1
- package/scripts/discussion_validate.py +93 -35
- package/scripts/dispatch_driver.py +549 -53
- package/scripts/git_guard.py +27 -8
- package/scripts/guard_hook.py +2630 -210
- package/scripts/install.mjs +99 -11
- package/scripts/install.py +231 -46
- package/scripts/integration.py +244 -65
- package/scripts/isolation.py +539 -70
- package/scripts/loop_run.py +16 -4
- package/scripts/members.py +77 -32
- package/scripts/migrate_core.py +2 -0
- package/scripts/model_policy.py +5 -1
- package/scripts/path_config.py +3 -3
- package/scripts/pipeline_diagnose.py +17 -2
- package/scripts/pipeline_git.py +131 -42
- package/scripts/pipeline_state.py +139 -39
- package/scripts/pipeline_undo.py +118 -16
- package/scripts/promote_lookahead.py +3 -3
- package/scripts/review_findings.py +180 -44
- package/scripts/roadmap.py +9 -1
- package/scripts/runtime_store.py +21 -2
- package/scripts/skill-resources.json +9 -2
- package/scripts/state_checkpoint.py +39 -36
- package/scripts/state_promote.py +15 -4
- package/scripts/status_runtime.py +22 -4
- package/scripts/task_context.py +14 -3
- package/scripts/wizard.mjs +1 -0
- package/scripts/workflow_run.py +14 -4
- package/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path/DEFINE.md +34 -5
- package/skills/gsd-path/PLAN.md +14 -3
- package/skills/gsd-path/RESEARCH.md +11 -0
- package/skills/gsd-path/ROADMAP.md +16 -6
- package/skills/gsd-path/SHIP.md +32 -5
- package/skills/gsd-path/SKILL.md +52 -24
- package/skills/gsd-path/references/build-native.md +112 -10
- package/skills/gsd-path/references/build-recovery.md +13 -0
- package/skills/gsd-path/references/coder.md +7 -3
- package/skills/gsd-path/references/dispatch.md +13 -0
- package/skills/gsd-path/references/docs-auditor.md +5 -0
- package/skills/gsd-path/references/operating-rules.md +11 -3
- package/skills/gsd-path/references/planner.md +26 -4
- package/skills/gsd-path/references/reviewer-final.md +20 -2
- package/skills/gsd-path/references/reviewer-wave.md +56 -12
- package/skills/gsd-path/references/reviewer.md +3 -1
- package/skills/gsd-path/references/runtime-selection.md +9 -0
- package/skills/gsd-path/references/spec-probes.md +150 -0
- package/skills/gsd-path/scripts/_common.py +256 -2
- package/skills/gsd-path/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path/scripts/build_recovery.py +155 -58
- package/skills/gsd-path/scripts/build_state.py +274 -8
- package/skills/gsd-path/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path/scripts/detect_project.py +260 -20
- package/skills/gsd-path/scripts/discussion_records.py +9 -1
- package/skills/gsd-path/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path/scripts/dispatch_driver.py +549 -53
- package/skills/gsd-path/scripts/git_guard.py +27 -8
- package/skills/gsd-path/scripts/integration.py +244 -65
- package/skills/gsd-path/scripts/isolation.py +539 -70
- package/skills/gsd-path/scripts/loop_run.py +16 -4
- package/skills/gsd-path/scripts/members.py +77 -32
- package/skills/gsd-path/scripts/model_policy.py +5 -1
- package/skills/gsd-path/scripts/path_config.py +3 -3
- package/skills/gsd-path/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path/scripts/review_findings.py +180 -44
- package/skills/gsd-path/scripts/roadmap.py +9 -1
- package/skills/gsd-path/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path/scripts/state_promote.py +15 -4
- package/skills/gsd-path/scripts/status_runtime.py +22 -4
- package/skills/gsd-path/scripts/task_context.py +14 -3
- package/skills/gsd-path/scripts/workflow_run.py +14 -4
- package/skills/gsd-path/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path/templates/docs-audit.md +5 -1
- package/skills/gsd-path/templates/final-review.md +11 -2
- package/skills/gsd-path/templates/intent.md +30 -0
- package/skills/gsd-path/templates/patch-findings.md +3 -3
- package/skills/gsd-path/templates/plan.md +17 -2
- package/skills/gsd-path/templates/research-handoff.md +14 -3
- package/skills/gsd-path/templates/state.md +2 -1
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +28 -9
- package/skills/gsd-path-build/references/build-native.md +112 -10
- package/skills/gsd-path-build/references/build-recovery.md +13 -0
- package/skills/gsd-path-build/references/coder.md +7 -3
- package/skills/gsd-path-build/references/dispatch.md +13 -0
- package/skills/gsd-path-build/references/operating-rules.md +11 -3
- package/skills/gsd-path-build/references/reviewer-final.md +20 -2
- package/skills/gsd-path-build/references/reviewer-wave.md +56 -12
- package/skills/gsd-path-build/references/reviewer.md +3 -1
- package/skills/gsd-path-build/references/runtime-selection.md +9 -0
- package/skills/gsd-path-build/references/spec-probes.md +150 -0
- package/skills/gsd-path-build/scripts/_common.py +256 -2
- package/skills/gsd-path-build/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-build/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-build/scripts/build_state.py +274 -8
- package/skills/gsd-path-build/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-build/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-build/scripts/detect_project.py +260 -20
- package/skills/gsd-path-build/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-build/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-build/scripts/dispatch_driver.py +549 -53
- package/skills/gsd-path-build/scripts/integration.py +244 -65
- package/skills/gsd-path-build/scripts/isolation.py +539 -70
- package/skills/gsd-path-build/scripts/loop_run.py +16 -4
- package/skills/gsd-path-build/scripts/members.py +77 -32
- package/skills/gsd-path-build/scripts/model_policy.py +5 -1
- package/skills/gsd-path-build/scripts/path_config.py +3 -3
- package/skills/gsd-path-build/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-build/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-build/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-build/scripts/review_findings.py +180 -44
- package/skills/gsd-path-build/scripts/roadmap.py +9 -1
- package/skills/gsd-path-build/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-build/scripts/state_promote.py +15 -4
- package/skills/gsd-path-build/scripts/task_context.py +14 -3
- package/skills/gsd-path-build/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-build/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +28 -9
- package/skills/gsd-path-decide/references/dispatch.md +13 -0
- package/skills/gsd-path-decide/references/operating-rules.md +11 -3
- package/skills/gsd-path-decide/references/runtime-selection.md +9 -0
- package/skills/gsd-path-decide/scripts/_common.py +256 -2
- package/skills/gsd-path-decide/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-decide/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-decide/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-decide/scripts/detect_project.py +260 -20
- package/skills/gsd-path-decide/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-decide/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-decide/scripts/integration.py +244 -65
- package/skills/gsd-path-decide/scripts/isolation.py +539 -70
- package/skills/gsd-path-decide/scripts/loop_run.py +16 -4
- package/skills/gsd-path-decide/scripts/members.py +77 -32
- package/skills/gsd-path-decide/scripts/model_policy.py +5 -1
- package/skills/gsd-path-decide/scripts/path_config.py +3 -3
- package/skills/gsd-path-decide/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-decide/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-decide/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-decide/scripts/roadmap.py +9 -1
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-decide/scripts/state_promote.py +15 -4
- package/skills/gsd-path-decide/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-define/SKILL.md +34 -5
- package/skills/gsd-path-define/references/build-recovery.md +13 -0
- package/skills/gsd-path-define/references/operating-rules.md +11 -3
- package/skills/gsd-path-define/references/runtime-selection.md +9 -0
- package/skills/gsd-path-define/references/spec-probes.md +150 -0
- package/skills/gsd-path-define/scripts/_common.py +256 -2
- package/skills/gsd-path-define/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-define/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-define/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-define/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-define/scripts/detect_project.py +260 -20
- package/skills/gsd-path-define/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-define/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-define/scripts/integration.py +244 -65
- package/skills/gsd-path-define/scripts/isolation.py +539 -70
- package/skills/gsd-path-define/scripts/loop_run.py +16 -4
- package/skills/gsd-path-define/scripts/members.py +77 -32
- package/skills/gsd-path-define/scripts/model_policy.py +5 -1
- package/skills/gsd-path-define/scripts/path_config.py +3 -3
- package/skills/gsd-path-define/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-define/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-define/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-define/scripts/roadmap.py +9 -1
- package/skills/gsd-path-define/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-define/scripts/state_promote.py +15 -4
- package/skills/gsd-path-define/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-define/templates/intent.md +30 -0
- package/skills/gsd-path-define/templates/state.md +2 -1
- package/skills/gsd-path-discuss/references/operating-rules.md +11 -3
- package/skills/gsd-path-discuss/references/runtime-selection.md +9 -0
- package/skills/gsd-path-discuss/scripts/_common.py +256 -2
- package/skills/gsd-path-discuss/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-discuss/scripts/loop_run.py +16 -4
- package/skills/gsd-path-discuss/scripts/model_policy.py +5 -1
- package/skills/gsd-path-discuss/scripts/path_config.py +3 -3
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +5 -0
- package/skills/gsd-path-docs-audit/references/operating-rules.md +11 -3
- package/skills/gsd-path-docs-audit/references/runtime-selection.md +9 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +256 -2
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +260 -20
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-docs-audit/scripts/integration.py +244 -65
- package/skills/gsd-path-docs-audit/scripts/isolation.py +539 -70
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +16 -4
- package/skills/gsd-path-docs-audit/scripts/members.py +77 -32
- package/skills/gsd-path-docs-audit/scripts/model_policy.py +5 -1
- package/skills/gsd-path-docs-audit/scripts/path_config.py +3 -3
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-docs-audit/scripts/roadmap.py +9 -1
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +15 -4
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +5 -1
- package/skills/gsd-path-forensics/references/operating-rules.md +11 -3
- package/skills/gsd-path-forensics/references/runtime-selection.md +9 -0
- package/skills/gsd-path-forensics/scripts/_common.py +256 -2
- package/skills/gsd-path-forensics/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-forensics/scripts/loop_run.py +16 -4
- package/skills/gsd-path-forensics/scripts/model_policy.py +5 -1
- package/skills/gsd-path-forensics/scripts/path_config.py +3 -3
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +17 -2
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +118 -16
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-inspect/references/dispatch.md +13 -0
- package/skills/gsd-path-inspect/references/docs-auditor.md +5 -0
- package/skills/gsd-path-inspect/references/operating-rules.md +11 -3
- package/skills/gsd-path-inspect/references/runtime-selection.md +9 -0
- package/skills/gsd-path-inspect/scripts/_common.py +256 -2
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-inspect/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +77 -4
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-inspect/scripts/detect_project.py +260 -20
- package/skills/gsd-path-inspect/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-inspect/scripts/integration.py +244 -65
- package/skills/gsd-path-inspect/scripts/isolation.py +539 -70
- package/skills/gsd-path-inspect/scripts/loop_run.py +16 -4
- package/skills/gsd-path-inspect/scripts/members.py +77 -32
- package/skills/gsd-path-inspect/scripts/model_policy.py +5 -1
- package/skills/gsd-path-inspect/scripts/path_config.py +3 -3
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-inspect/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-inspect/scripts/roadmap.py +9 -1
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-inspect/scripts/state_promote.py +15 -4
- package/skills/gsd-path-inspect/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-inspect/templates/docs-audit.md +5 -1
- package/skills/gsd-path-inspect/templates/state.md +2 -1
- package/skills/gsd-path-loop/references/operating-rules.md +11 -3
- package/skills/gsd-path-loop/references/runtime-selection.md +9 -0
- package/skills/gsd-path-loop/scripts/_common.py +256 -2
- package/skills/gsd-path-loop/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-loop/scripts/loop_run.py +16 -4
- package/skills/gsd-path-loop/scripts/model_policy.py +5 -1
- package/skills/gsd-path-loop/scripts/path_config.py +3 -3
- package/skills/gsd-path-loop/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-migrate/SKILL.md +8 -0
- package/skills/gsd-path-migrate/references/operating-rules.md +11 -3
- package/skills/gsd-path-migrate/references/runtime-selection.md +9 -0
- package/skills/gsd-path-migrate/scripts/_common.py +256 -2
- package/skills/gsd-path-migrate/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-migrate/scripts/loop_run.py +16 -4
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -0
- package/skills/gsd-path-migrate/scripts/model_policy.py +5 -1
- package/skills/gsd-path-migrate/scripts/path_config.py +3 -3
- package/skills/gsd-path-plan/SKILL.md +14 -3
- package/skills/gsd-path-plan/references/build-recovery.md +13 -0
- package/skills/gsd-path-plan/references/dispatch.md +13 -0
- package/skills/gsd-path-plan/references/operating-rules.md +11 -3
- package/skills/gsd-path-plan/references/planner.md +26 -4
- package/skills/gsd-path-plan/references/runtime-selection.md +9 -0
- package/skills/gsd-path-plan/references/spec-probes.md +150 -0
- package/skills/gsd-path-plan/scripts/_common.py +256 -2
- package/skills/gsd-path-plan/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-plan/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-plan/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-plan/scripts/detect_project.py +260 -20
- package/skills/gsd-path-plan/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-plan/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-plan/scripts/integration.py +244 -65
- package/skills/gsd-path-plan/scripts/isolation.py +539 -70
- package/skills/gsd-path-plan/scripts/loop_run.py +16 -4
- package/skills/gsd-path-plan/scripts/members.py +77 -32
- package/skills/gsd-path-plan/scripts/model_policy.py +5 -1
- package/skills/gsd-path-plan/scripts/path_config.py +3 -3
- package/skills/gsd-path-plan/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-plan/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-plan/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-plan/scripts/roadmap.py +9 -1
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-plan/scripts/state_promote.py +15 -4
- package/skills/gsd-path-plan/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-plan/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-plan/templates/patch-findings.md +3 -3
- package/skills/gsd-path-plan/templates/plan.md +17 -2
- package/skills/gsd-path-plan/templates/task.md +1 -0
- package/skills/gsd-path-research/SKILL.md +11 -0
- package/skills/gsd-path-research/references/dispatch.md +13 -0
- package/skills/gsd-path-research/references/operating-rules.md +11 -3
- package/skills/gsd-path-research/references/runtime-selection.md +9 -0
- package/skills/gsd-path-research/scripts/_common.py +256 -2
- package/skills/gsd-path-research/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-research/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-research/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-research/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-research/scripts/detect_project.py +260 -20
- package/skills/gsd-path-research/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-research/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-research/scripts/integration.py +244 -65
- package/skills/gsd-path-research/scripts/isolation.py +539 -70
- package/skills/gsd-path-research/scripts/loop_run.py +16 -4
- package/skills/gsd-path-research/scripts/members.py +77 -32
- package/skills/gsd-path-research/scripts/model_policy.py +5 -1
- package/skills/gsd-path-research/scripts/path_config.py +3 -3
- package/skills/gsd-path-research/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-research/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-research/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-research/scripts/roadmap.py +9 -1
- package/skills/gsd-path-research/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-research/scripts/state_promote.py +15 -4
- package/skills/gsd-path-research/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-research/templates/research-handoff.md +14 -3
- package/skills/gsd-path-roadmap/SKILL.md +16 -6
- package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
- package/skills/gsd-path-roadmap/references/operating-rules.md +11 -3
- package/skills/gsd-path-roadmap/references/runtime-selection.md +9 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +256 -2
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-roadmap/scripts/detect_project.py +260 -20
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-roadmap/scripts/integration.py +244 -65
- package/skills/gsd-path-roadmap/scripts/isolation.py +539 -70
- package/skills/gsd-path-roadmap/scripts/loop_run.py +16 -4
- package/skills/gsd-path-roadmap/scripts/members.py +77 -32
- package/skills/gsd-path-roadmap/scripts/model_policy.py +5 -1
- package/skills/gsd-path-roadmap/scripts/path_config.py +3 -3
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-roadmap/scripts/roadmap.py +9 -1
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-roadmap/scripts/state_promote.py +15 -4
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-ship/SKILL.md +32 -5
- package/skills/gsd-path-ship/references/dispatch.md +13 -0
- package/skills/gsd-path-ship/references/operating-rules.md +11 -3
- package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
- package/skills/gsd-path-ship/references/reviewer-wave.md +56 -12
- package/skills/gsd-path-ship/references/reviewer.md +3 -1
- package/skills/gsd-path-ship/references/runtime-selection.md +9 -0
- package/skills/gsd-path-ship/references/spec-probes.md +150 -0
- package/skills/gsd-path-ship/scripts/_common.py +256 -2
- package/skills/gsd-path-ship/scripts/archive_milestone.py +14 -13
- package/skills/gsd-path-ship/scripts/build_recovery.py +155 -58
- package/skills/gsd-path-ship/scripts/build_state.py +274 -8
- package/skills/gsd-path-ship/scripts/check_handoffs.py +635 -57
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +293 -32
- package/skills/gsd-path-ship/scripts/detect_project.py +260 -20
- package/skills/gsd-path-ship/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-ship/scripts/discussion_validate.py +93 -35
- package/skills/gsd-path-ship/scripts/integration.py +244 -65
- package/skills/gsd-path-ship/scripts/isolation.py +539 -70
- package/skills/gsd-path-ship/scripts/loop_run.py +16 -4
- package/skills/gsd-path-ship/scripts/members.py +77 -32
- package/skills/gsd-path-ship/scripts/model_policy.py +5 -1
- package/skills/gsd-path-ship/scripts/path_config.py +3 -3
- package/skills/gsd-path-ship/scripts/pipeline_git.py +131 -42
- package/skills/gsd-path-ship/scripts/pipeline_state.py +139 -39
- package/skills/gsd-path-ship/scripts/promote_lookahead.py +3 -3
- package/skills/gsd-path-ship/scripts/roadmap.py +9 -1
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +39 -36
- package/skills/gsd-path-ship/scripts/state_promote.py +15 -4
- package/skills/gsd-path-ship/scripts/workflow_run.py +14 -4
- package/skills/gsd-path-ship/scripts/worktree_paths.py +54 -2
- package/skills/gsd-path-ship/templates/final-review.md +11 -2
- package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
- package/skills/gsd-path-ship/templates/wave-review.md +28 -9
- package/skills/gsd-path-undo/references/operating-rules.md +11 -3
- package/skills/gsd-path-undo/references/runtime-selection.md +9 -0
- package/skills/gsd-path-undo/scripts/_common.py +256 -2
- package/skills/gsd-path-undo/scripts/discussion_records.py +9 -1
- package/skills/gsd-path-undo/scripts/loop_run.py +16 -4
- package/skills/gsd-path-undo/scripts/model_policy.py +5 -1
- package/skills/gsd-path-undo/scripts/path_config.py +3 -3
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +118 -16
- package/skills/gsd-path-undo/scripts/worktree_paths.py +54 -2
- package/skills/path/DEFINE.md +34 -5
- package/skills/path/PLAN.md +14 -3
- package/skills/path/RESEARCH.md +11 -0
- package/skills/path/ROADMAP.md +16 -6
- package/skills/path/SHIP.md +32 -5
- package/skills/path/SKILL.md +52 -24
- package/skills/path/references/build-native.md +112 -10
- package/skills/path/references/build-recovery.md +13 -0
- package/skills/path/references/coder.md +7 -3
- package/skills/path/references/dispatch.md +13 -0
- package/skills/path/references/docs-auditor.md +5 -0
- package/skills/path/references/operating-rules.md +11 -3
- package/skills/path/references/planner.md +26 -4
- package/skills/path/references/reviewer-final.md +20 -2
- package/skills/path/references/reviewer-wave.md +56 -12
- package/skills/path/references/reviewer.md +3 -1
- package/skills/path/references/runtime-selection.md +9 -0
- package/skills/path/references/spec-probes.md +150 -0
- package/skills/path/scripts/_common.py +256 -2
- package/skills/path/scripts/archive_milestone.py +14 -13
- package/skills/path/scripts/build_recovery.py +155 -58
- package/skills/path/scripts/build_state.py +274 -8
- package/skills/path/scripts/check_docs_audit.py +77 -4
- package/skills/path/scripts/check_handoffs.py +635 -57
- package/skills/path/scripts/check_task_briefs.py +293 -32
- package/skills/path/scripts/detect_project.py +260 -20
- package/skills/path/scripts/discussion_records.py +9 -1
- package/skills/path/scripts/discussion_validate.py +93 -35
- package/skills/path/scripts/dispatch_driver.py +549 -53
- package/skills/path/scripts/git_guard.py +27 -8
- package/skills/path/scripts/integration.py +244 -65
- package/skills/path/scripts/isolation.py +539 -70
- package/skills/path/scripts/loop_run.py +16 -4
- package/skills/path/scripts/members.py +77 -32
- package/skills/path/scripts/model_policy.py +5 -1
- package/skills/path/scripts/path_config.py +3 -3
- package/skills/path/scripts/pipeline_git.py +131 -42
- package/skills/path/scripts/pipeline_state.py +139 -39
- package/skills/path/scripts/promote_lookahead.py +3 -3
- package/skills/path/scripts/review_findings.py +180 -44
- package/skills/path/scripts/roadmap.py +9 -1
- package/skills/path/scripts/state_checkpoint.py +39 -36
- package/skills/path/scripts/state_promote.py +15 -4
- package/skills/path/scripts/status_runtime.py +22 -4
- package/skills/path/scripts/task_context.py +14 -3
- package/skills/path/scripts/workflow_run.py +14 -4
- package/skills/path/scripts/worktree_paths.py +54 -2
- package/skills/path/templates/docs-audit.md +5 -1
- package/skills/path/templates/final-review.md +11 -2
- package/skills/path/templates/intent.md +30 -0
- package/skills/path/templates/patch-findings.md +3 -3
- package/skills/path/templates/plan.md +17 -2
- package/skills/path/templates/research-handoff.md +14 -3
- package/skills/path/templates/state.md +2 -1
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +28 -9
- package/skills/gsd-path/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-build/scripts/__pycache__/check_handoffs.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
|
@@ -53,6 +53,9 @@ COMMENT_PATTERN = re.compile(r"<!--.*?-->", re.DOTALL)
|
|
|
53
53
|
BACKTICK_PATTERN = re.compile(r"`([^`\n]+)`")
|
|
54
54
|
PATH_TOKEN_PATTERN = re.compile(r"[A-Za-z0-9._~/-]+")
|
|
55
55
|
VERIFY_BLOCK_PATTERN = re.compile(r"```bash[ \t]*\n(?P<block>.*?)```", re.DOTALL)
|
|
56
|
+
TEXT_TOOL_COMMANDS = frozenset({"awk", "egrep", "fgrep", "gawk", "grep", "gsed", "rg", "sed"})
|
|
57
|
+
REGEX_PATTERN_CHARS = frozenset("|*+?[]()^$.\\")
|
|
58
|
+
PIPELINE_WORKSPACE_DIRS = ("review", "discuss", "build", "plan")
|
|
56
59
|
|
|
57
60
|
|
|
58
61
|
class BriefError(RuntimeError):
|
|
@@ -73,10 +76,20 @@ def _base_exists(repo: Path, base: str, path: str) -> bool:
|
|
|
73
76
|
return _run_git(repo, "cat-file", "-e", f"{base}:{path}").returncode == 0
|
|
74
77
|
|
|
75
78
|
|
|
79
|
+
def _project_track(task: Path, repo: Path) -> Optional[str]:
|
|
80
|
+
try:
|
|
81
|
+
track = task.parent.parent.relative_to(repo).as_posix()
|
|
82
|
+
except ValueError:
|
|
83
|
+
return None
|
|
84
|
+
if track not in {".project", ".project/next"}:
|
|
85
|
+
return None
|
|
86
|
+
return track
|
|
87
|
+
|
|
88
|
+
|
|
76
89
|
def _supplied_contract(repo: Path, task: Path, token: str) -> bool:
|
|
77
90
|
"""Plan approval checkpoints these supplied inputs after the brief gate."""
|
|
78
|
-
track = task
|
|
79
|
-
if track
|
|
91
|
+
track = _project_track(task, repo)
|
|
92
|
+
if track is None:
|
|
80
93
|
return False
|
|
81
94
|
if token not in {
|
|
82
95
|
f"{track}/intent/INTENT.md",
|
|
@@ -87,6 +100,20 @@ def _supplied_contract(repo: Path, task: Path, token: str) -> bool:
|
|
|
87
100
|
return path.is_file() and path.resolve() == repo.resolve() / token
|
|
88
101
|
|
|
89
102
|
|
|
103
|
+
def _pipeline_workspace_path(repo: Path, task: Path, token: str) -> bool:
|
|
104
|
+
track = _project_track(task, repo)
|
|
105
|
+
return track is not None and token.startswith(
|
|
106
|
+
tuple(f"{track}/{name}/" for name in PIPELINE_WORKSPACE_DIRS))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _pipeline_workspace_file(repo: Path, task: Path, token: str) -> bool:
|
|
110
|
+
"""Pipeline-owned paths may exist only in the working tree before checkpoint."""
|
|
111
|
+
if not _pipeline_workspace_path(repo, task, token):
|
|
112
|
+
return False
|
|
113
|
+
path = repo / token
|
|
114
|
+
return path.is_file() and path.resolve() == repo.resolve() / token
|
|
115
|
+
|
|
116
|
+
|
|
90
117
|
_strip_yaml_comment = _common.strip_yaml_comment
|
|
91
118
|
_unquote = _common.unquote
|
|
92
119
|
|
|
@@ -151,7 +178,7 @@ def _clean(body: str) -> str:
|
|
|
151
178
|
return COMMENT_PATTERN.sub("", body).strip()
|
|
152
179
|
|
|
153
180
|
|
|
154
|
-
def
|
|
181
|
+
def _slash_token_shape(token: str) -> bool:
|
|
155
182
|
return (
|
|
156
183
|
"/" in token
|
|
157
184
|
and PATH_TOKEN_PATTERN.fullmatch(token) is not None
|
|
@@ -162,32 +189,97 @@ def _looks_like_path(token: str) -> bool:
|
|
|
162
189
|
)
|
|
163
190
|
|
|
164
191
|
|
|
192
|
+
def _last_segment_has_extension(token: str) -> bool:
|
|
193
|
+
name = PurePosixPath(token).name
|
|
194
|
+
return "." in name and not name.startswith(".")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _looks_like_path(
|
|
198
|
+
token: str,
|
|
199
|
+
*,
|
|
200
|
+
repo: Path,
|
|
201
|
+
git_root: Path,
|
|
202
|
+
base: str,
|
|
203
|
+
task: Path,
|
|
204
|
+
) -> bool:
|
|
205
|
+
if not _slash_token_shape(token):
|
|
206
|
+
return False
|
|
207
|
+
if _last_segment_has_extension(token):
|
|
208
|
+
return True
|
|
209
|
+
if _base_exists(git_root, base, token):
|
|
210
|
+
return True
|
|
211
|
+
if _pipeline_workspace_file(repo, task, token):
|
|
212
|
+
return True
|
|
213
|
+
return False
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _looks_like_regex_pattern(token: str) -> bool:
|
|
217
|
+
return any(character in token for character in REGEX_PATTERN_CHARS)
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def _text_tool_command(command: str) -> bool:
|
|
221
|
+
return Path(command).name.casefold() in TEXT_TOOL_COMMANDS
|
|
222
|
+
|
|
223
|
+
|
|
165
224
|
def _normalize(path: str) -> str:
|
|
166
225
|
return str(PurePosixPath(path))
|
|
167
226
|
|
|
168
227
|
|
|
169
|
-
def _prose_tokens(
|
|
228
|
+
def _prose_tokens(
|
|
229
|
+
body: str,
|
|
230
|
+
*,
|
|
231
|
+
repo: Path,
|
|
232
|
+
git_root: Path,
|
|
233
|
+
base: str,
|
|
234
|
+
task: Path,
|
|
235
|
+
) -> List[str]:
|
|
170
236
|
cleaned = COMMENT_PATTERN.sub("", body)
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if _looks_like_path(
|
|
175
|
-
|
|
237
|
+
tokens: List[str] = []
|
|
238
|
+
for match in BACKTICK_PATTERN.finditer(cleaned):
|
|
239
|
+
candidate = match.group(1).strip()
|
|
240
|
+
if _looks_like_path(
|
|
241
|
+
candidate, repo=repo, git_root=git_root, base=base, task=task
|
|
242
|
+
):
|
|
243
|
+
tokens.append(_normalize(candidate))
|
|
244
|
+
return tokens
|
|
176
245
|
|
|
177
246
|
|
|
178
|
-
def _verify_tokens(
|
|
179
|
-
|
|
247
|
+
def _verify_tokens(
|
|
248
|
+
block: str,
|
|
249
|
+
*,
|
|
250
|
+
repo: Path,
|
|
251
|
+
git_root: Path,
|
|
252
|
+
base: str,
|
|
253
|
+
task: Path,
|
|
254
|
+
) -> List[str]:
|
|
255
|
+
tokens: List[str] = []
|
|
180
256
|
for line in block.splitlines():
|
|
181
257
|
parts = line.split()
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
258
|
+
if len(parts) < 2:
|
|
259
|
+
continue
|
|
260
|
+
command = parts[0]
|
|
261
|
+
extended_grep = False
|
|
262
|
+
index = 1
|
|
263
|
+
while index < len(parts) and parts[index].startswith("-") and "=" not in parts[index]:
|
|
264
|
+
flag = parts[index]
|
|
265
|
+
if flag in {"-E", "-G"} or flag.startswith("-E"):
|
|
266
|
+
extended_grep = True
|
|
267
|
+
index += 1
|
|
268
|
+
text_tool = _text_tool_command(command)
|
|
269
|
+
for raw in parts[index:]:
|
|
270
|
+
quoted = raw.startswith(("'", '"'))
|
|
271
|
+
token = raw.strip("\"'")
|
|
272
|
+
if text_tool and quoted:
|
|
273
|
+
continue
|
|
274
|
+
if text_tool and command.casefold() == "grep" and extended_grep and _looks_like_regex_pattern(token):
|
|
275
|
+
continue
|
|
276
|
+
if _looks_like_path(token, repo=repo, git_root=git_root, base=base, task=task):
|
|
185
277
|
tokens.append(_normalize(token))
|
|
186
278
|
return tokens
|
|
187
279
|
|
|
188
280
|
|
|
189
281
|
def _member_bases(root: Path):
|
|
190
|
-
"""Resolve a member name to (checkout,
|
|
282
|
+
"""Resolve a member name to (checkout, base SHA), reading MEMBERS.md once."""
|
|
191
283
|
cache: Dict[str, Optional[Tuple[Path, str]]] = {}
|
|
192
284
|
|
|
193
285
|
def locate(name: str) -> Optional[Tuple[Path, str]]:
|
|
@@ -200,21 +292,22 @@ def _member_bases(root: Path):
|
|
|
200
292
|
except ImportError: # pragma: no cover - package import used by tests
|
|
201
293
|
from scripts import members
|
|
202
294
|
try:
|
|
203
|
-
listed = {member["name"]:
|
|
204
|
-
|
|
205
|
-
if checkout is None:
|
|
295
|
+
listed = {member["name"]: member for member in members.read_members(root)}
|
|
296
|
+
if name not in listed:
|
|
206
297
|
cache[name] = None
|
|
207
298
|
else:
|
|
299
|
+
checkout = Path(listed[name]["checkout"])
|
|
208
300
|
# A build lock selects the bound tip, including during Plan recovery;
|
|
209
|
-
# without the lock, use
|
|
301
|
+
# without the lock, use the member's recorded default branch on origin
|
|
302
|
+
# before the first build start.
|
|
210
303
|
lock = root / members.LOCK_PATH
|
|
211
304
|
locked = [entry for entry in (json.loads(lock.read_text(encoding="utf-8"))["members"]
|
|
212
305
|
if lock.is_file() else []) if entry["name"] == name]
|
|
213
306
|
if locked:
|
|
214
307
|
cache[name] = (checkout, _resolve_base(checkout, f"refs/heads/{locked[0]['branch']}"))
|
|
215
308
|
else:
|
|
216
|
-
members.
|
|
217
|
-
|
|
309
|
+
cache[name] = (checkout, members.require_origin_branch(
|
|
310
|
+
checkout, members.default_branch(listed[name])))
|
|
218
311
|
except (members.MembersError, BriefError) as error:
|
|
219
312
|
raise BriefError(f"member {name} is unavailable: {error}") from error
|
|
220
313
|
return cache[name]
|
|
@@ -238,8 +331,8 @@ def _lint_task(
|
|
|
238
331
|
checked = 0
|
|
239
332
|
if fields is None:
|
|
240
333
|
return task_id, [error or "invalid frontmatter"], None, checked
|
|
241
|
-
# A member task's paths resolve in the member at its origin
|
|
242
|
-
# member bound branch starts; `repo:` absent means the coordinator.
|
|
334
|
+
# A member task's paths resolve in the member at its default branch on origin,
|
|
335
|
+
# where the member bound branch starts; `repo:` absent means the coordinator.
|
|
243
336
|
git_root = repo
|
|
244
337
|
member = fields.get("repo")
|
|
245
338
|
if member is not None:
|
|
@@ -298,12 +391,17 @@ def _lint_task(
|
|
|
298
391
|
body = sections.get(name)
|
|
299
392
|
if body is None or not _clean(body):
|
|
300
393
|
continue
|
|
301
|
-
for token in _prose_tokens(
|
|
394
|
+
for token in _prose_tokens(
|
|
395
|
+
body, repo=repo, git_root=git_root, base=base, task=path
|
|
396
|
+
):
|
|
302
397
|
checked += 1
|
|
303
398
|
if (
|
|
304
399
|
token not in declared
|
|
305
400
|
and token not in supplied
|
|
306
401
|
and not _supplied_contract(repo, path, token)
|
|
402
|
+
and not _pipeline_workspace_file(repo, path, token)
|
|
403
|
+
# A landed brief is history: the pipeline moves its own files (build recovery, archive) later.
|
|
404
|
+
and not (task_id in (landed_bases or {}) and _pipeline_workspace_path(repo, path, token))
|
|
307
405
|
and not _base_exists(git_root, base, token)
|
|
308
406
|
):
|
|
309
407
|
problems.append(f"## {name} names a path missing at the layer base: {token}")
|
|
@@ -314,9 +412,20 @@ def _lint_task(
|
|
|
314
412
|
if block is None or not block.group("block").strip():
|
|
315
413
|
problems.append("## Verify must contain a non-empty fenced bash block")
|
|
316
414
|
else:
|
|
317
|
-
for token in _verify_tokens(
|
|
415
|
+
for token in _verify_tokens(
|
|
416
|
+
block.group("block"),
|
|
417
|
+
repo=repo,
|
|
418
|
+
git_root=git_root,
|
|
419
|
+
base=base,
|
|
420
|
+
task=path,
|
|
421
|
+
):
|
|
318
422
|
checked += 1
|
|
319
|
-
if
|
|
423
|
+
if (
|
|
424
|
+
token not in declared
|
|
425
|
+
and token not in supplied
|
|
426
|
+
and not _pipeline_workspace_file(repo, path, token)
|
|
427
|
+
and not _base_exists(git_root, base, token)
|
|
428
|
+
):
|
|
320
429
|
problems.append(f"## Verify names a path missing at the layer base: {token}")
|
|
321
430
|
|
|
322
431
|
contract = None
|
|
@@ -337,9 +446,9 @@ def validate_task_briefs(
|
|
|
337
446
|
) -> Dict[str, object]:
|
|
338
447
|
"""Lint task briefs using the caller's validation bases.
|
|
339
448
|
|
|
340
|
-
|
|
341
|
-
transitive dependency files for
|
|
342
|
-
for landed tasks, whose immutable briefs must survive later file changes.
|
|
449
|
+
Plain lint uses the layer base without overrides. Plan approval and dispatch
|
|
450
|
+
supply transitive dependency files for unlanded tasks and resolved historical
|
|
451
|
+
bases for landed tasks, whose immutable briefs must survive later file changes.
|
|
343
452
|
The caller validates the task graph and landed metadata before supplying
|
|
344
453
|
these mappings; landed tasks receive no dependency-file allowance.
|
|
345
454
|
"""
|
|
@@ -381,6 +490,136 @@ def validate_task_briefs(
|
|
|
381
490
|
return {"base": resolved_base, "checked": checked, "tasks": len(task_files)}
|
|
382
491
|
|
|
383
492
|
|
|
493
|
+
def _resolve_landed_task_base(
|
|
494
|
+
task_id: str,
|
|
495
|
+
recorded_base: str,
|
|
496
|
+
recorded_member_base: object,
|
|
497
|
+
coordinator_repo: Path,
|
|
498
|
+
member_repo: Optional[Path],
|
|
499
|
+
) -> str:
|
|
500
|
+
"""Resolve a landed task's historical base in the repository it names."""
|
|
501
|
+
if __package__:
|
|
502
|
+
from .isolation import IsolationError, require_commit, require_full_sha
|
|
503
|
+
else:
|
|
504
|
+
try:
|
|
505
|
+
from isolation import IsolationError, require_commit, require_full_sha
|
|
506
|
+
except ModuleNotFoundError as error:
|
|
507
|
+
if error.name != "isolation":
|
|
508
|
+
raise
|
|
509
|
+
from scripts.isolation import IsolationError, require_commit, require_full_sha
|
|
510
|
+
|
|
511
|
+
recorded_full = require_full_sha(recorded_base)
|
|
512
|
+
if member_repo is None:
|
|
513
|
+
try:
|
|
514
|
+
return require_commit(coordinator_repo, recorded_full)
|
|
515
|
+
except IsolationError as error:
|
|
516
|
+
raise BriefError(
|
|
517
|
+
f"{task_id} landed task has invalid historical base: {error}"
|
|
518
|
+
) from error
|
|
519
|
+
|
|
520
|
+
legacy_member_base = (
|
|
521
|
+
recorded_member_base is None
|
|
522
|
+
or (isinstance(recorded_member_base, str)
|
|
523
|
+
and recorded_member_base.strip().casefold() in {"", "null", "~"})
|
|
524
|
+
or (isinstance(recorded_member_base, list) and not recorded_member_base)
|
|
525
|
+
)
|
|
526
|
+
try:
|
|
527
|
+
if not legacy_member_base:
|
|
528
|
+
if not isinstance(recorded_member_base, str):
|
|
529
|
+
raise IsolationError(
|
|
530
|
+
f"member_base must be a full 40-character SHA: {recorded_member_base}"
|
|
531
|
+
)
|
|
532
|
+
member_full = require_full_sha(recorded_member_base)
|
|
533
|
+
return require_commit(member_repo, member_full)
|
|
534
|
+
try:
|
|
535
|
+
return require_commit(coordinator_repo, recorded_full)
|
|
536
|
+
except IsolationError:
|
|
537
|
+
return require_commit(member_repo, recorded_full)
|
|
538
|
+
except IsolationError as error:
|
|
539
|
+
raise BriefError(
|
|
540
|
+
f"{task_id} landed task has invalid historical base: {error}"
|
|
541
|
+
) from error
|
|
542
|
+
|
|
543
|
+
def plan_validation_bases(
|
|
544
|
+
root: Path, project_dir: str, member_base=None, *, initial: bool = True,
|
|
545
|
+
) -> Tuple[Dict[str, str], Dict[str, Set[str]], Dict[str, str]]:
|
|
546
|
+
"""Share dependency files and landed historical bases across approval and dispatch.
|
|
547
|
+
|
|
548
|
+
Approval requires unlanded tasks to start clean. Dispatch may run beside
|
|
549
|
+
in-flight tasks, while retaining the same graph and path checks.
|
|
550
|
+
"""
|
|
551
|
+
if __package__:
|
|
552
|
+
from . import check_handoffs
|
|
553
|
+
from .isolation import IsolationError
|
|
554
|
+
else:
|
|
555
|
+
try:
|
|
556
|
+
import check_handoffs
|
|
557
|
+
from isolation import IsolationError
|
|
558
|
+
except ModuleNotFoundError as error:
|
|
559
|
+
if error.name not in {"check_handoffs", "isolation"}:
|
|
560
|
+
raise
|
|
561
|
+
from scripts import check_handoffs
|
|
562
|
+
from scripts.isolation import IsolationError
|
|
563
|
+
if member_base is None:
|
|
564
|
+
member_base = _member_bases(root)
|
|
565
|
+
try:
|
|
566
|
+
tasks, dependency_files = check_handoffs.plan_brief_inputs(
|
|
567
|
+
root, project_dir, initial=initial
|
|
568
|
+
)
|
|
569
|
+
landed_bases: Dict[str, str] = {}
|
|
570
|
+
for task_id, text in tasks.items():
|
|
571
|
+
if check_handoffs._task_scalar(text, task_id, "status") != "done":
|
|
572
|
+
continue
|
|
573
|
+
agent = check_handoffs._task_scalar(text, task_id, "agent")
|
|
574
|
+
if agent in {"", "null"}:
|
|
575
|
+
raise BriefError(f"{task_id} landed task has no recorded agent")
|
|
576
|
+
fields = check_handoffs._strict_frontmatter(text, task_id)
|
|
577
|
+
member = fields.get("repo")
|
|
578
|
+
base_repo = root
|
|
579
|
+
if member is not None:
|
|
580
|
+
located = member_base(member) if isinstance(member, str) and member else None
|
|
581
|
+
if located is None:
|
|
582
|
+
raise BriefError(f"repo: names no member in MEMBERS.md: {member}")
|
|
583
|
+
base_repo = located[0]
|
|
584
|
+
recorded_base = check_handoffs._task_scalar(text, task_id, "base")
|
|
585
|
+
try:
|
|
586
|
+
landed_bases[task_id] = _resolve_landed_task_base(
|
|
587
|
+
task_id,
|
|
588
|
+
recorded_base,
|
|
589
|
+
fields.get("member_base") if member is not None else None,
|
|
590
|
+
root,
|
|
591
|
+
base_repo if member is not None else None,
|
|
592
|
+
)
|
|
593
|
+
except IsolationError as error:
|
|
594
|
+
raise BriefError(f"{task_id} landed task has invalid historical base: {error}") from error
|
|
595
|
+
dependency_files[task_id] = set()
|
|
596
|
+
except check_handoffs.HandoffError as error:
|
|
597
|
+
raise BriefError(str(error)) from error
|
|
598
|
+
return tasks, dependency_files, landed_bases
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
def validate_plan_task_briefs(
|
|
602
|
+
root: Path,
|
|
603
|
+
base: str,
|
|
604
|
+
project_dir: str = ".project",
|
|
605
|
+
tasks_dir: Optional[str] = None,
|
|
606
|
+
) -> Dict[str, object]:
|
|
607
|
+
"""Dispatch lint with dependency files and landed historical bases."""
|
|
608
|
+
member_base = _member_bases(root)
|
|
609
|
+
_, dependency_files, landed_bases = plan_validation_bases(
|
|
610
|
+
root, project_dir, member_base, initial=False
|
|
611
|
+
)
|
|
612
|
+
resolved_tasks_dir = tasks_dir or f"{project_dir}/tasks"
|
|
613
|
+
return validate_task_briefs(
|
|
614
|
+
root,
|
|
615
|
+
base,
|
|
616
|
+
resolved_tasks_dir,
|
|
617
|
+
dependency_files=dependency_files,
|
|
618
|
+
landed_bases=landed_bases,
|
|
619
|
+
member_base=member_base,
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
|
|
384
623
|
def _tasks_dir(value: str) -> str:
|
|
385
624
|
"""Argparse type for --tasks-dir: a relative POSIX-style path."""
|
|
386
625
|
|
|
@@ -411,15 +650,37 @@ def parser() -> argparse.ArgumentParser:
|
|
|
411
650
|
help="relative POSIX-style directory under --repo holding the task files "
|
|
412
651
|
"(default: .project/tasks)",
|
|
413
652
|
)
|
|
653
|
+
argument_parser.add_argument(
|
|
654
|
+
"--project-dir",
|
|
655
|
+
default=None,
|
|
656
|
+
help="apply plan dependency files and landed-task bases for this track "
|
|
657
|
+
"(inferred from --tasks-dir when its sibling plan/PLAN.md exists)",
|
|
658
|
+
)
|
|
414
659
|
return argument_parser
|
|
415
660
|
|
|
416
661
|
|
|
417
662
|
def main(argv: Optional[Sequence[str]] = None) -> int:
|
|
418
663
|
arguments = parser().parse_args(argv)
|
|
419
664
|
try:
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
665
|
+
root = arguments.repo.resolve()
|
|
666
|
+
project_dir = arguments.project_dir
|
|
667
|
+
if project_dir is None:
|
|
668
|
+
tasks_path = PurePosixPath(arguments.tasks_dir)
|
|
669
|
+
if tasks_path.name == "tasks" and len(tasks_path.parts) > 1:
|
|
670
|
+
track = tasks_path.parent.as_posix()
|
|
671
|
+
if (root / track / "plan/PLAN.md").is_file():
|
|
672
|
+
project_dir = track
|
|
673
|
+
if project_dir is not None:
|
|
674
|
+
result = validate_plan_task_briefs(
|
|
675
|
+
root,
|
|
676
|
+
arguments.base,
|
|
677
|
+
project_dir,
|
|
678
|
+
None if arguments.tasks_dir == DEFAULT_TASKS_DIR else arguments.tasks_dir,
|
|
679
|
+
)
|
|
680
|
+
else:
|
|
681
|
+
result = validate_task_briefs(
|
|
682
|
+
root, arguments.base, arguments.tasks_dir
|
|
683
|
+
)
|
|
423
684
|
except BriefError as error:
|
|
424
685
|
print(f"task brief validation failed: {error}", file=sys.stderr)
|
|
425
686
|
return 1
|