@opengsd/gsd-path 1.3.1 → 1.4.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 +2 -207
- package/CHANGELOG.md +281 -0
- package/DOCS.md +13 -7
- package/FULL.md +9 -3
- package/GUIDE.md +1 -1
- package/HOOKS.md +9 -6
- package/QUICK.md +4 -1
- package/README.md +63 -11
- package/RUNTIME.md +1 -1
- package/UPDATE.md +57 -8
- package/WORKFLOW.md +22 -6
- package/package.json +9 -8
- package/scripts/_common.py +472 -19
- package/scripts/archive_milestone.py +146 -73
- package/scripts/bootstrap_repository.py +8 -5
- package/scripts/build_recovery.py +4 -1
- package/scripts/build_state.py +66 -23
- package/scripts/check_docs_audit.py +14 -3
- package/scripts/check_handoffs.py +116 -20
- package/scripts/check_task_briefs.py +60 -8
- package/scripts/check_update.py +2 -2
- package/scripts/core_hook_gate.py +10 -1
- package/scripts/core_hook_settings.py +11 -4
- package/scripts/detect_project.py +345 -15
- package/scripts/discussion_records.py +19 -13
- package/scripts/discussion_validate.py +66 -21
- package/scripts/dispatch_driver.py +111 -26
- package/scripts/git_guard.py +116 -29
- package/scripts/guard_hook.py +151 -29
- package/scripts/install.mjs +54 -38
- package/scripts/install.py +562 -41
- package/scripts/integration.py +434 -24
- package/scripts/isolation.py +1077 -28
- package/scripts/lean_verification.py +99 -19
- package/scripts/loop_run.py +20 -30
- package/scripts/members.py +704 -0
- package/scripts/migrate_core.py +2 -2
- package/scripts/path_config.py +2 -2
- package/scripts/pipeline_diagnose.py +82 -31
- package/scripts/pipeline_git.py +61 -22
- package/scripts/pipeline_state.py +176 -54
- package/scripts/pipeline_undo.py +117 -22
- package/scripts/promote_lookahead.py +1 -1
- package/scripts/review_panel.py +1 -1
- package/scripts/runtime_store.py +35 -9
- package/scripts/skill-resources.json +28 -3
- package/scripts/state_checkpoint.py +140 -31
- package/scripts/state_promote.py +2 -0
- package/scripts/status_runtime.py +36 -6
- package/scripts/sync_skill_resources.py +8 -7
- package/scripts/token_budget.py +12 -8
- package/scripts/workflow_run.py +103 -29
- package/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path/BUILD.md +7 -1
- package/skills/gsd-path/DECIDE.md +11 -4
- package/skills/gsd-path/DEFINE.md +8 -1
- package/skills/gsd-path/DOCS-AUDIT.md +6 -4
- package/skills/gsd-path/INSPECT.md +5 -4
- package/skills/gsd-path/PLAN.md +7 -1
- package/skills/gsd-path/RESEARCH.md +2 -1
- package/skills/gsd-path/ROADMAP.md +2 -1
- package/skills/gsd-path/SHIP.md +27 -10
- package/skills/gsd-path/SKILL.md +45 -1
- package/skills/gsd-path/references/build-native.md +47 -14
- package/skills/gsd-path/references/codebase-mapper.md +2 -1
- package/skills/gsd-path/references/docs-auditor.md +2 -1
- package/skills/gsd-path/references/operating-rules.md +214 -0
- package/skills/gsd-path/references/planner.md +8 -0
- package/skills/gsd-path/references/reviewer-wave.md +3 -1
- 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 +472 -19
- package/skills/gsd-path/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path/scripts/bootstrap_repository.py +8 -5
- package/skills/gsd-path/scripts/build_recovery.py +4 -1
- package/skills/gsd-path/scripts/build_state.py +66 -23
- package/skills/gsd-path/scripts/check_docs_audit.py +14 -3
- package/skills/gsd-path/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path/scripts/check_update.py +2 -2
- package/skills/gsd-path/scripts/detect_project.py +345 -15
- package/skills/gsd-path/scripts/discussion_records.py +19 -13
- package/skills/gsd-path/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path/scripts/dispatch_driver.py +111 -26
- package/skills/gsd-path/scripts/git_guard.py +116 -29
- package/skills/gsd-path/scripts/integration.py +434 -24
- package/skills/gsd-path/scripts/isolation.py +1077 -28
- package/skills/gsd-path/scripts/lean_verification.py +99 -19
- package/skills/gsd-path/scripts/loop_run.py +20 -30
- package/skills/gsd-path/scripts/members.py +704 -0
- package/skills/gsd-path/scripts/path_config.py +2 -2
- package/skills/gsd-path/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path/scripts/review_panel.py +1 -1
- package/skills/gsd-path/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path/scripts/state_promote.py +2 -0
- package/skills/gsd-path/scripts/status_runtime.py +36 -6
- package/skills/gsd-path/scripts/token_budget.py +12 -8
- package/skills/gsd-path/scripts/workflow_run.py +103 -29
- package/skills/gsd-path/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path/templates/codebase.md +1 -1
- package/skills/gsd-path/templates/docs-audit.md +1 -1
- package/skills/gsd-path/templates/final-review.md +5 -2
- package/skills/gsd-path/templates/gap-review.md +2 -1
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +3 -1
- package/skills/gsd-path-build/SKILL.md +7 -1
- package/skills/gsd-path-build/references/build-native.md +47 -14
- package/skills/gsd-path-build/references/operating-rules.md +214 -0
- package/skills/gsd-path-build/references/reviewer-wave.md +3 -1
- 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 +472 -19
- package/skills/gsd-path-build/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-build/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-build/scripts/build_state.py +66 -23
- package/skills/gsd-path-build/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-build/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-build/scripts/detect_project.py +345 -15
- package/skills/gsd-path-build/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-build/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-build/scripts/dispatch_driver.py +111 -26
- package/skills/gsd-path-build/scripts/integration.py +434 -24
- package/skills/gsd-path-build/scripts/isolation.py +1077 -28
- package/skills/gsd-path-build/scripts/loop_run.py +20 -30
- package/skills/gsd-path-build/scripts/members.py +704 -0
- package/skills/gsd-path-build/scripts/path_config.py +2 -2
- package/skills/gsd-path-build/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-build/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-build/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-build/scripts/review_panel.py +1 -1
- package/skills/gsd-path-build/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-build/scripts/state_promote.py +2 -0
- package/skills/gsd-path-build/scripts/token_budget.py +12 -8
- package/skills/gsd-path-build/scripts/workflow_run.py +103 -29
- package/skills/gsd-path-build/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +3 -1
- package/skills/gsd-path-decide/SKILL.md +11 -4
- package/skills/gsd-path-decide/references/operating-rules.md +214 -0
- package/skills/gsd-path-decide/scripts/_common.py +472 -19
- package/skills/gsd-path-decide/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-decide/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-decide/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-decide/scripts/detect_project.py +345 -15
- package/skills/gsd-path-decide/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-decide/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-decide/scripts/integration.py +434 -24
- package/skills/gsd-path-decide/scripts/isolation.py +1077 -28
- package/skills/gsd-path-decide/scripts/loop_run.py +20 -30
- package/skills/gsd-path-decide/scripts/members.py +704 -0
- package/skills/gsd-path-decide/scripts/path_config.py +2 -2
- package/skills/gsd-path-decide/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-decide/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-decide/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-decide/scripts/review_panel.py +1 -1
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-decide/scripts/state_promote.py +2 -0
- package/skills/gsd-path-decide/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-define/SKILL.md +8 -1
- package/skills/gsd-path-define/references/operating-rules.md +214 -0
- package/skills/gsd-path-define/scripts/_common.py +472 -19
- package/skills/gsd-path-define/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-define/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-define/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-define/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-define/scripts/detect_project.py +345 -15
- package/skills/gsd-path-define/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-define/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-define/scripts/integration.py +434 -24
- package/skills/gsd-path-define/scripts/isolation.py +1077 -28
- package/skills/gsd-path-define/scripts/loop_run.py +20 -30
- package/skills/gsd-path-define/scripts/members.py +704 -0
- package/skills/gsd-path-define/scripts/path_config.py +2 -2
- package/skills/gsd-path-define/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-define/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-define/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-define/scripts/review_panel.py +1 -1
- package/skills/gsd-path-define/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-define/scripts/state_promote.py +2 -0
- package/skills/gsd-path-define/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-discuss/SKILL.md +2 -1
- package/skills/gsd-path-discuss/references/operating-rules.md +214 -0
- package/skills/gsd-path-discuss/scripts/_common.py +472 -19
- package/skills/gsd-path-discuss/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-discuss/scripts/loop_run.py +20 -30
- package/skills/gsd-path-discuss/scripts/path_config.py +2 -2
- package/skills/gsd-path-discuss/scripts/review_panel.py +1 -1
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-docs-audit/SKILL.md +6 -4
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +2 -1
- package/skills/gsd-path-docs-audit/references/operating-rules.md +214 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +472 -19
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +14 -3
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +345 -15
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-docs-audit/scripts/integration.py +434 -24
- package/skills/gsd-path-docs-audit/scripts/isolation.py +1077 -28
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +20 -30
- package/skills/gsd-path-docs-audit/scripts/members.py +704 -0
- package/skills/gsd-path-docs-audit/scripts/path_config.py +2 -2
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-docs-audit/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-docs-audit/scripts/review_panel.py +1 -1
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +2 -0
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +1 -1
- package/skills/gsd-path-forensics/SKILL.md +2 -1
- package/skills/gsd-path-forensics/references/operating-rules.md +214 -0
- package/skills/gsd-path-forensics/scripts/_common.py +472 -19
- package/skills/gsd-path-forensics/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-forensics/scripts/loop_run.py +20 -30
- package/skills/gsd-path-forensics/scripts/path_config.py +2 -2
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +82 -31
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +117 -22
- package/skills/gsd-path-forensics/scripts/review_panel.py +1 -1
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-inspect/SKILL.md +5 -4
- package/skills/gsd-path-inspect/references/codebase-mapper.md +2 -1
- package/skills/gsd-path-inspect/references/docs-auditor.md +2 -1
- package/skills/gsd-path-inspect/references/operating-rules.md +214 -0
- package/skills/gsd-path-inspect/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-inspect/scripts/_common.py +472 -19
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-inspect/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +14 -3
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-inspect/scripts/detect_project.py +345 -15
- package/skills/gsd-path-inspect/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-inspect/scripts/integration.py +434 -24
- package/skills/gsd-path-inspect/scripts/isolation.py +1077 -28
- package/skills/gsd-path-inspect/scripts/loop_run.py +20 -30
- package/skills/gsd-path-inspect/scripts/members.py +704 -0
- package/skills/gsd-path-inspect/scripts/path_config.py +2 -2
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-inspect/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-inspect/scripts/review_panel.py +1 -1
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-inspect/scripts/state_promote.py +2 -0
- package/skills/gsd-path-inspect/scripts/workflow_run.py +103 -29
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-inspect/templates/codebase.md +1 -1
- package/skills/gsd-path-inspect/templates/docs-audit.md +1 -1
- package/skills/gsd-path-loop/SKILL.md +2 -1
- package/skills/gsd-path-loop/references/operating-rules.md +214 -0
- package/skills/gsd-path-loop/scripts/_common.py +472 -19
- package/skills/gsd-path-loop/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-loop/scripts/loop_run.py +20 -30
- package/skills/gsd-path-loop/scripts/path_config.py +2 -2
- package/skills/gsd-path-loop/scripts/review_panel.py +1 -1
- package/skills/gsd-path-loop/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-migrate/SKILL.md +2 -1
- package/skills/gsd-path-migrate/references/operating-rules.md +214 -0
- package/skills/gsd-path-migrate/scripts/_common.py +472 -19
- package/skills/gsd-path-migrate/scripts/core_hook_gate.py +10 -1
- package/skills/gsd-path-migrate/scripts/core_hook_settings.py +11 -4
- package/skills/gsd-path-migrate/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-migrate/scripts/loop_run.py +20 -30
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -2
- package/skills/gsd-path-migrate/scripts/path_config.py +2 -2
- package/skills/gsd-path-migrate/scripts/review_panel.py +1 -1
- package/skills/gsd-path-plan/SKILL.md +7 -1
- package/skills/gsd-path-plan/references/operating-rules.md +214 -0
- package/skills/gsd-path-plan/references/planner.md +8 -0
- package/skills/gsd-path-plan/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-plan/scripts/_common.py +472 -19
- package/skills/gsd-path-plan/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-plan/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-plan/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-plan/scripts/detect_project.py +345 -15
- package/skills/gsd-path-plan/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-plan/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-plan/scripts/integration.py +434 -24
- package/skills/gsd-path-plan/scripts/isolation.py +1077 -28
- package/skills/gsd-path-plan/scripts/loop_run.py +20 -30
- package/skills/gsd-path-plan/scripts/members.py +704 -0
- package/skills/gsd-path-plan/scripts/path_config.py +2 -2
- package/skills/gsd-path-plan/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-plan/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-plan/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-plan/scripts/review_panel.py +1 -1
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-plan/scripts/state_promote.py +2 -0
- package/skills/gsd-path-plan/scripts/workflow_run.py +103 -29
- package/skills/gsd-path-plan/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-plan/templates/task.md +1 -0
- package/skills/gsd-path-research/SKILL.md +2 -1
- package/skills/gsd-path-research/references/operating-rules.md +214 -0
- package/skills/gsd-path-research/scripts/_common.py +472 -19
- package/skills/gsd-path-research/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-research/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-research/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-research/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-research/scripts/detect_project.py +345 -15
- package/skills/gsd-path-research/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-research/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-research/scripts/integration.py +434 -24
- package/skills/gsd-path-research/scripts/isolation.py +1077 -28
- package/skills/gsd-path-research/scripts/loop_run.py +20 -30
- package/skills/gsd-path-research/scripts/members.py +704 -0
- package/skills/gsd-path-research/scripts/path_config.py +2 -2
- package/skills/gsd-path-research/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-research/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-research/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-research/scripts/review_panel.py +1 -1
- package/skills/gsd-path-research/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-research/scripts/state_promote.py +2 -0
- package/skills/gsd-path-research/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-roadmap/SKILL.md +2 -1
- package/skills/gsd-path-roadmap/references/operating-rules.md +214 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +472 -19
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-roadmap/scripts/detect_project.py +345 -15
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-roadmap/scripts/integration.py +434 -24
- package/skills/gsd-path-roadmap/scripts/isolation.py +1077 -28
- package/skills/gsd-path-roadmap/scripts/loop_run.py +20 -30
- package/skills/gsd-path-roadmap/scripts/members.py +704 -0
- package/skills/gsd-path-roadmap/scripts/path_config.py +2 -2
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-roadmap/scripts/review_panel.py +1 -1
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-roadmap/scripts/state_promote.py +2 -0
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-ship/SKILL.md +27 -10
- package/skills/gsd-path-ship/references/operating-rules.md +214 -0
- package/skills/gsd-path-ship/references/reviewer-wave.md +3 -1
- package/skills/gsd-path-ship/scripts/__pycache__/_common.cpython-312.pyc +0 -0
- package/skills/gsd-path-ship/scripts/_common.py +472 -19
- package/skills/gsd-path-ship/scripts/archive_milestone.py +146 -73
- package/skills/gsd-path-ship/scripts/build_recovery.py +4 -1
- package/skills/gsd-path-ship/scripts/build_state.py +66 -23
- package/skills/gsd-path-ship/scripts/check_handoffs.py +116 -20
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +60 -8
- package/skills/gsd-path-ship/scripts/detect_project.py +345 -15
- package/skills/gsd-path-ship/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-ship/scripts/discussion_validate.py +66 -21
- package/skills/gsd-path-ship/scripts/integration.py +434 -24
- package/skills/gsd-path-ship/scripts/isolation.py +1077 -28
- package/skills/gsd-path-ship/scripts/lean_verification.py +99 -19
- package/skills/gsd-path-ship/scripts/loop_run.py +20 -30
- package/skills/gsd-path-ship/scripts/members.py +704 -0
- package/skills/gsd-path-ship/scripts/path_config.py +2 -2
- package/skills/gsd-path-ship/scripts/pipeline_git.py +61 -22
- package/skills/gsd-path-ship/scripts/pipeline_state.py +176 -54
- package/skills/gsd-path-ship/scripts/promote_lookahead.py +1 -1
- package/skills/gsd-path-ship/scripts/review_panel.py +1 -1
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +140 -31
- package/skills/gsd-path-ship/scripts/state_promote.py +2 -0
- package/skills/gsd-path-ship/scripts/workflow_run.py +103 -29
- package/skills/gsd-path-ship/scripts/worktree_paths.py +18 -8
- package/skills/gsd-path-ship/templates/final-review.md +5 -2
- package/skills/gsd-path-ship/templates/gap-review.md +2 -1
- package/skills/gsd-path-ship/templates/wave-review.md +3 -1
- package/skills/gsd-path-undo/SKILL.md +2 -1
- package/skills/gsd-path-undo/references/operating-rules.md +214 -0
- package/skills/gsd-path-undo/scripts/_common.py +472 -19
- package/skills/gsd-path-undo/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-undo/scripts/loop_run.py +20 -30
- package/skills/gsd-path-undo/scripts/path_config.py +2 -2
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +117 -22
- package/skills/gsd-path-undo/scripts/review_panel.py +1 -1
- package/skills/gsd-path-undo/scripts/worktree_paths.py +18 -8
- package/skills/path/BUILD.md +7 -1
- package/skills/path/DECIDE.md +11 -4
- package/skills/path/DEFINE.md +8 -1
- package/skills/path/DOCS-AUDIT.md +6 -4
- package/skills/path/INSPECT.md +5 -4
- package/skills/path/PLAN.md +7 -1
- package/skills/path/RESEARCH.md +2 -1
- package/skills/path/ROADMAP.md +2 -1
- package/skills/path/SHIP.md +27 -10
- package/skills/path/SKILL.md +45 -1
- package/skills/path/references/build-native.md +47 -14
- package/skills/path/references/codebase-mapper.md +2 -1
- package/skills/path/references/docs-auditor.md +2 -1
- package/skills/path/references/operating-rules.md +214 -0
- package/skills/path/references/planner.md +8 -0
- package/skills/path/references/reviewer-wave.md +3 -1
- package/skills/path/scripts/_common.py +472 -19
- package/skills/path/scripts/archive_milestone.py +146 -73
- package/skills/path/scripts/bootstrap_repository.py +8 -5
- package/skills/path/scripts/build_recovery.py +4 -1
- package/skills/path/scripts/build_state.py +66 -23
- package/skills/path/scripts/check_docs_audit.py +14 -3
- package/skills/path/scripts/check_handoffs.py +116 -20
- package/skills/path/scripts/check_task_briefs.py +60 -8
- package/skills/path/scripts/check_update.py +2 -2
- package/skills/path/scripts/detect_project.py +345 -15
- package/skills/path/scripts/discussion_records.py +19 -13
- package/skills/path/scripts/discussion_validate.py +66 -21
- package/skills/path/scripts/dispatch_driver.py +111 -26
- package/skills/path/scripts/git_guard.py +116 -29
- package/skills/path/scripts/integration.py +434 -24
- package/skills/path/scripts/isolation.py +1077 -28
- package/skills/path/scripts/lean_verification.py +99 -19
- package/skills/path/scripts/loop_run.py +20 -30
- package/skills/path/scripts/members.py +704 -0
- package/skills/path/scripts/path_config.py +2 -2
- package/skills/path/scripts/pipeline_git.py +61 -22
- package/skills/path/scripts/pipeline_state.py +176 -54
- package/skills/path/scripts/promote_lookahead.py +1 -1
- package/skills/path/scripts/review_panel.py +1 -1
- package/skills/path/scripts/state_checkpoint.py +140 -31
- package/skills/path/scripts/state_promote.py +2 -0
- package/skills/path/scripts/status_runtime.py +36 -6
- package/skills/path/scripts/token_budget.py +12 -8
- package/skills/path/scripts/workflow_run.py +103 -29
- package/skills/path/scripts/worktree_paths.py +18 -8
- package/skills/path/templates/codebase.md +1 -1
- package/skills/path/templates/docs-audit.md +1 -1
- package/skills/path/templates/final-review.md +5 -2
- package/skills/path/templates/gap-review.md +2 -1
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +3 -1
package/scripts/runtime_store.py
CHANGED
|
@@ -8,6 +8,7 @@ from pathlib import Path
|
|
|
8
8
|
import shutil
|
|
9
9
|
import shlex
|
|
10
10
|
import tempfile
|
|
11
|
+
import time
|
|
11
12
|
from contextlib import contextmanager
|
|
12
13
|
|
|
13
14
|
try:
|
|
@@ -22,10 +23,33 @@ RUNTIME_FILES = (
|
|
|
22
23
|
"review_panel.py", "_common.py", "worktree_paths.py", "build_recovery.py",
|
|
23
24
|
"state_checkpoint.py", "state_promote.py", "discussion_validate.py", "integration.py",
|
|
24
25
|
"build_state.py", "lean_verification.py", "check_docs_audit.py",
|
|
25
|
-
"path_config.py", "model_policy.py", "loop_run.py",
|
|
26
|
+
"path_config.py", "model_policy.py", "loop_run.py", "members.py",
|
|
26
27
|
)
|
|
27
28
|
GUARDS = ("guard_hook.py", "git_guard.py")
|
|
28
29
|
|
|
30
|
+
# Access denied and sharing violation: on Windows a scanner or indexer that
|
|
31
|
+
# briefly opens a freshly written file blocks renaming the directory holding it.
|
|
32
|
+
_WINDOWS_BUSY_ERRORS = (5, 32)
|
|
33
|
+
_RENAME_ATTEMPTS = 20
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _rename_directory(source, destination):
|
|
37
|
+
"""Path.rename, retried while Windows briefly holds a file inside ``source``."""
|
|
38
|
+
if os.name != "nt":
|
|
39
|
+
source.rename(destination)
|
|
40
|
+
return
|
|
41
|
+
for attempt in range(_RENAME_ATTEMPTS):
|
|
42
|
+
try:
|
|
43
|
+
source.rename(destination)
|
|
44
|
+
return
|
|
45
|
+
except PermissionError as error:
|
|
46
|
+
# Never retry onto a directory that appeared meanwhile.
|
|
47
|
+
if (getattr(error, "winerror", None) not in _WINDOWS_BUSY_ERRORS
|
|
48
|
+
or os.path.lexists(destination)
|
|
49
|
+
or attempt == _RENAME_ATTEMPTS - 1):
|
|
50
|
+
raise
|
|
51
|
+
time.sleep(min(0.01 * 2 ** attempt, 0.25))
|
|
52
|
+
|
|
29
53
|
|
|
30
54
|
def guard_launcher(name):
|
|
31
55
|
if name not in GUARDS:
|
|
@@ -41,7 +65,7 @@ def guard_launcher(name):
|
|
|
41
65
|
|
|
42
66
|
|
|
43
67
|
def source_manifest(source):
|
|
44
|
-
version = json.loads((source / "package.json").read_text())["version"]
|
|
68
|
+
version = json.loads((source / "package.json").read_text(encoding="utf-8"))["version"]
|
|
45
69
|
files = {}
|
|
46
70
|
for name in (*RUNTIME_FILES, *GUARDS, "status_runtime.py"):
|
|
47
71
|
path = source / "scripts" / name
|
|
@@ -107,7 +131,7 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
|
|
|
107
131
|
shutil.copyfile(source / "scripts" / name, staging / name)
|
|
108
132
|
if hashlib.sha256((staging / name).read_bytes()).hexdigest() != digest:
|
|
109
133
|
raise ValueError(f"runtime source changed while installing: {name}")
|
|
110
|
-
(staging / "manifest.json").
|
|
134
|
+
(staging / "manifest.json").write_bytes(pin_text(manifest).encode("utf-8"))
|
|
111
135
|
# Serialize publication/repair, including two explicit restorations.
|
|
112
136
|
previous = Path(temporary) / "previous"
|
|
113
137
|
with publication_lock(parent, pin["digest"]):
|
|
@@ -118,13 +142,13 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
|
|
|
118
142
|
except ValueError:
|
|
119
143
|
if not repair:
|
|
120
144
|
raise
|
|
121
|
-
destination
|
|
145
|
+
_rename_directory(destination, previous)
|
|
122
146
|
try:
|
|
123
|
-
staging
|
|
147
|
+
_rename_directory(staging, destination)
|
|
124
148
|
status_runtime.validate_runtime(pin)
|
|
125
149
|
except BaseException:
|
|
126
150
|
if previous.exists() and not destination.exists():
|
|
127
|
-
previous
|
|
151
|
+
_rename_directory(previous, destination)
|
|
128
152
|
raise
|
|
129
153
|
return pin
|
|
130
154
|
|
|
@@ -167,7 +191,7 @@ def recover_migration(project):
|
|
|
167
191
|
return
|
|
168
192
|
if journal.is_symlink():
|
|
169
193
|
raise ValueError(f"unsafe runtime migration journal: {journal}")
|
|
170
|
-
data = json.loads(journal.read_text())
|
|
194
|
+
data = json.loads(journal.read_text(encoding="utf-8"))
|
|
171
195
|
recorded_project = data.get("project")
|
|
172
196
|
if (data.get("schema") != "gsd-path/runtime-migration/v1"
|
|
173
197
|
or not isinstance(recorded_project, str)
|
|
@@ -208,8 +232,10 @@ def operate(source, project, action, *, dry_run=False):
|
|
|
208
232
|
pin = publish(source, dry_run=dry_run)
|
|
209
233
|
if not dry_run:
|
|
210
234
|
launcher = project / ".gsd-path/status_runtime.py"
|
|
211
|
-
|
|
212
|
-
|
|
235
|
+
# Exact bytes: read_text() would turn CRLF into LF, leaving the
|
|
236
|
+
# launcher unequal to the runtime's byte-for-byte copy.
|
|
237
|
+
original = launcher.read_bytes().decode("utf-8")
|
|
238
|
+
replacement = (source / "scripts/status_runtime.py").read_bytes().decode("utf-8")
|
|
213
239
|
# Both launchers understand the same declaration schema. Publishing
|
|
214
240
|
# the compatible launcher first leaves the old selection usable.
|
|
215
241
|
if replacement != original:
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"scripts/integration.py",
|
|
56
56
|
"scripts/archive_milestone.py",
|
|
57
57
|
"scripts/bootstrap_repository.py",
|
|
58
|
+
"scripts/members.py",
|
|
58
59
|
"scripts/detect_project.py",
|
|
59
60
|
"scripts/promote_lookahead.py",
|
|
60
61
|
"scripts/discussion_records.py",
|
|
@@ -100,6 +101,7 @@
|
|
|
100
101
|
"phase_resources": {
|
|
101
102
|
"gsd-path-build": [
|
|
102
103
|
"references/runtime-selection.md",
|
|
104
|
+
"references/operating-rules.md",
|
|
103
105
|
"references/build-recovery.md",
|
|
104
106
|
"references/build-native.md",
|
|
105
107
|
"references/build-abandon.md",
|
|
@@ -120,11 +122,13 @@
|
|
|
120
122
|
],
|
|
121
123
|
"gsd-path-discuss": [
|
|
122
124
|
"references/runtime-selection.md",
|
|
125
|
+
"references/operating-rules.md",
|
|
123
126
|
"templates/answers.md",
|
|
124
127
|
"templates/dialogue.md"
|
|
125
128
|
],
|
|
126
129
|
"gsd-path-docs-audit": [
|
|
127
130
|
"references/runtime-selection.md",
|
|
131
|
+
"references/operating-rules.md",
|
|
128
132
|
"references/dispatch.md",
|
|
129
133
|
"references/model-policy.md",
|
|
130
134
|
"references/docs-auditor.md",
|
|
@@ -132,6 +136,7 @@
|
|
|
132
136
|
],
|
|
133
137
|
"gsd-path-define": [
|
|
134
138
|
"references/runtime-selection.md",
|
|
139
|
+
"references/operating-rules.md",
|
|
135
140
|
"references/build-recovery.md",
|
|
136
141
|
"templates/charter.md",
|
|
137
142
|
"templates/intent.md",
|
|
@@ -139,6 +144,7 @@
|
|
|
139
144
|
],
|
|
140
145
|
"gsd-path-inspect": [
|
|
141
146
|
"references/runtime-selection.md",
|
|
147
|
+
"references/operating-rules.md",
|
|
142
148
|
"references/codebase-mapper.md",
|
|
143
149
|
"references/dispatch.md",
|
|
144
150
|
"references/model-policy.md",
|
|
@@ -148,17 +154,21 @@
|
|
|
148
154
|
"templates/state.md"
|
|
149
155
|
],
|
|
150
156
|
"gsd-path-forensics": [
|
|
151
|
-
"references/runtime-selection.md"
|
|
157
|
+
"references/runtime-selection.md",
|
|
158
|
+
"references/operating-rules.md"
|
|
152
159
|
],
|
|
153
160
|
"gsd-path-migrate": [
|
|
154
|
-
"references/runtime-selection.md"
|
|
161
|
+
"references/runtime-selection.md",
|
|
162
|
+
"references/operating-rules.md"
|
|
155
163
|
],
|
|
156
164
|
"gsd-path-loop": [
|
|
157
165
|
"references/runtime-selection.md",
|
|
166
|
+
"references/operating-rules.md",
|
|
158
167
|
"templates/loop.md"
|
|
159
168
|
],
|
|
160
169
|
"gsd-path-plan": [
|
|
161
170
|
"references/runtime-selection.md",
|
|
171
|
+
"references/operating-rules.md",
|
|
162
172
|
"references/build-recovery.md",
|
|
163
173
|
"references/dispatch.md",
|
|
164
174
|
"references/model-policy.md",
|
|
@@ -170,6 +180,7 @@
|
|
|
170
180
|
],
|
|
171
181
|
"gsd-path-research": [
|
|
172
182
|
"references/runtime-selection.md",
|
|
183
|
+
"references/operating-rules.md",
|
|
173
184
|
"references/dispatch.md",
|
|
174
185
|
"references/model-policy.md",
|
|
175
186
|
"references/researcher.md",
|
|
@@ -178,6 +189,7 @@
|
|
|
178
189
|
],
|
|
179
190
|
"gsd-path-roadmap": [
|
|
180
191
|
"references/runtime-selection.md",
|
|
192
|
+
"references/operating-rules.md",
|
|
181
193
|
"references/dispatch.md",
|
|
182
194
|
"references/model-policy.md",
|
|
183
195
|
"references/roadmapper.md",
|
|
@@ -185,6 +197,7 @@
|
|
|
185
197
|
],
|
|
186
198
|
"gsd-path-ship": [
|
|
187
199
|
"references/runtime-selection.md",
|
|
200
|
+
"references/operating-rules.md",
|
|
188
201
|
"references/dispatch.md",
|
|
189
202
|
"references/model-policy.md",
|
|
190
203
|
"references/reviewer.md",
|
|
@@ -202,13 +215,15 @@
|
|
|
202
215
|
],
|
|
203
216
|
"gsd-path-decide": [
|
|
204
217
|
"references/runtime-selection.md",
|
|
218
|
+
"references/operating-rules.md",
|
|
205
219
|
"references/dispatch.md",
|
|
206
220
|
"references/model-policy.md",
|
|
207
221
|
"references/decider.md",
|
|
208
222
|
"templates/synthesis.md"
|
|
209
223
|
],
|
|
210
224
|
"gsd-path-undo": [
|
|
211
|
-
"references/runtime-selection.md"
|
|
225
|
+
"references/runtime-selection.md",
|
|
226
|
+
"references/operating-rules.md"
|
|
212
227
|
]
|
|
213
228
|
},
|
|
214
229
|
"script_targets": [
|
|
@@ -259,6 +274,16 @@
|
|
|
259
274
|
["scripts/discussion_validate.py", "skills/gsd-path-ship/scripts/discussion_validate.py"],
|
|
260
275
|
["scripts/integration.py", "skills/gsd-path-ship/scripts/integration.py"],
|
|
261
276
|
["scripts/bootstrap_repository.py", "skills/gsd-path/scripts/bootstrap_repository.py"],
|
|
277
|
+
["scripts/members.py", "skills/gsd-path/scripts/members.py"],
|
|
278
|
+
["scripts/members.py", "skills/gsd-path-build/scripts/members.py"],
|
|
279
|
+
["scripts/members.py", "skills/gsd-path-decide/scripts/members.py"],
|
|
280
|
+
["scripts/members.py", "skills/gsd-path-define/scripts/members.py"],
|
|
281
|
+
["scripts/members.py", "skills/gsd-path-docs-audit/scripts/members.py"],
|
|
282
|
+
["scripts/members.py", "skills/gsd-path-inspect/scripts/members.py"],
|
|
283
|
+
["scripts/members.py", "skills/gsd-path-plan/scripts/members.py"],
|
|
284
|
+
["scripts/members.py", "skills/gsd-path-research/scripts/members.py"],
|
|
285
|
+
["scripts/members.py", "skills/gsd-path-roadmap/scripts/members.py"],
|
|
286
|
+
["scripts/members.py", "skills/gsd-path-ship/scripts/members.py"],
|
|
262
287
|
["scripts/detect_project.py", "skills/gsd-path/scripts/detect_project.py"],
|
|
263
288
|
["scripts/detect_project.py", "skills/gsd-path-define/scripts/detect_project.py"],
|
|
264
289
|
["scripts/detect_project.py", "skills/gsd-path-inspect/scripts/detect_project.py"],
|
|
@@ -17,12 +17,15 @@ from datetime import date
|
|
|
17
17
|
from pathlib import Path, PurePosixPath
|
|
18
18
|
from typing import Mapping, Optional, Sequence
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
from isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
if __package__:
|
|
21
|
+
from .isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
|
|
22
|
+
else:
|
|
23
|
+
try:
|
|
24
|
+
from isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
|
|
25
|
+
except ModuleNotFoundError as error: # pragma: no cover - package imports used by tests
|
|
26
|
+
if error.name != "isolation":
|
|
27
|
+
raise
|
|
28
|
+
from scripts.isolation import IsolationError, checkpoint as isolation_checkpoint, require_commit, require_full_sha, PROJECT_ENTRIES
|
|
26
29
|
|
|
27
30
|
|
|
28
31
|
if __package__:
|
|
@@ -66,6 +69,11 @@ def _sha256(content: str) -> str:
|
|
|
66
69
|
return hashlib.sha256(content.encode("utf-8")).hexdigest()
|
|
67
70
|
|
|
68
71
|
|
|
72
|
+
def _is_junk_file(path: Path) -> bool:
|
|
73
|
+
# Drift digests skip OS junk by name: Finder rewrites it whatever its ignore status.
|
|
74
|
+
return path.name in pipeline_state._common.OS_JUNK_NAMES and path.is_file() and not path.is_symlink()
|
|
75
|
+
|
|
76
|
+
|
|
69
77
|
def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
70
78
|
if path.is_symlink() or not path.is_dir():
|
|
71
79
|
raise PipelineStateError(f"promotion path must be a real directory: {path}")
|
|
@@ -74,7 +82,7 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
|
74
82
|
if child.is_symlink():
|
|
75
83
|
raise PipelineStateError(f"promotion path contains a symlink: {child}")
|
|
76
84
|
relative = child.relative_to(path).as_posix()
|
|
77
|
-
if PurePosixPath(relative).parts[0] in excluded:
|
|
85
|
+
if PurePosixPath(relative).parts[0] in excluded or _is_junk_file(child):
|
|
78
86
|
continue
|
|
79
87
|
if child.is_dir():
|
|
80
88
|
digest.update(f"d\0{relative}\0".encode())
|
|
@@ -87,15 +95,15 @@ def _tree_digest(path: Path, excluded: Sequence[str] = ()) -> str:
|
|
|
87
95
|
|
|
88
96
|
|
|
89
97
|
def _checkpoint_artifact_digest(project: Path, mutable_paths: set[str]) -> str:
|
|
90
|
-
"""Hash
|
|
98
|
+
"""Hash approval artifacts except helper-owned metadata and OS junk."""
|
|
91
99
|
digest = hashlib.sha256()
|
|
92
100
|
for child in sorted(project.rglob("*")):
|
|
93
101
|
if child.is_symlink():
|
|
94
102
|
raise PipelineStateError(f"checkpoint path contains a symlink: {child}")
|
|
95
103
|
relative = child.relative_to(project).as_posix()
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
104
|
+
# Finder can rewrite OS junk during approval; it must not cause artifact drift.
|
|
105
|
+
if (relative in mutable_paths or relative.split("/", 1)[0] not in PROJECT_ENTRIES
|
|
106
|
+
or _is_junk_file(child)):
|
|
99
107
|
continue
|
|
100
108
|
if child.is_dir():
|
|
101
109
|
digest.update(f"d\0{relative}\0".encode())
|
|
@@ -333,11 +341,7 @@ def _converge_checkpoint_file(path: Path, before: str, after: str, label: str) -
|
|
|
333
341
|
|
|
334
342
|
def _unlink_checkpoint_journal(path: Path) -> None:
|
|
335
343
|
path.unlink()
|
|
336
|
-
|
|
337
|
-
try:
|
|
338
|
-
os.fsync(descriptor)
|
|
339
|
-
finally:
|
|
340
|
-
os.close(descriptor)
|
|
344
|
+
pipeline_state._common.fsync_directory(path.parent)
|
|
341
345
|
|
|
342
346
|
|
|
343
347
|
def _resume_checkpoint_locked(
|
|
@@ -439,41 +443,103 @@ def _validate_plan_briefs(repo: Path, kind: str, project_dir: str) -> None:
|
|
|
439
443
|
if head.returncode != 0:
|
|
440
444
|
# Pre-Git approval defers base-dependent checks to build.
|
|
441
445
|
return
|
|
442
|
-
|
|
443
|
-
from check_task_briefs import BriefError, validate_task_briefs
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
446
|
+
if __package__:
|
|
447
|
+
from .check_task_briefs import BriefError, _member_bases, validate_task_briefs
|
|
448
|
+
else:
|
|
449
|
+
try:
|
|
450
|
+
from check_task_briefs import BriefError, _member_bases, validate_task_briefs
|
|
451
|
+
except ModuleNotFoundError as error: # pragma: no cover - package imports
|
|
452
|
+
if error.name != "check_task_briefs":
|
|
453
|
+
raise
|
|
454
|
+
from scripts.check_task_briefs import BriefError, _member_bases, validate_task_briefs
|
|
455
|
+
if __package__:
|
|
456
|
+
from . import check_handoffs
|
|
457
|
+
else:
|
|
458
|
+
try:
|
|
459
|
+
import check_handoffs
|
|
460
|
+
except ModuleNotFoundError as error:
|
|
461
|
+
if error.name != "check_handoffs":
|
|
462
|
+
raise
|
|
463
|
+
from scripts import check_handoffs
|
|
454
464
|
try:
|
|
455
465
|
tasks, dependency_files = check_handoffs.plan_brief_inputs(repo, project_dir)
|
|
456
466
|
landed_bases = {}
|
|
467
|
+
member_base = _member_bases(repo)
|
|
457
468
|
for task_id, text in tasks.items():
|
|
458
469
|
if check_handoffs._task_scalar(text, task_id, "status") != "done":
|
|
459
470
|
continue
|
|
460
471
|
agent = check_handoffs._task_scalar(text, task_id, "agent")
|
|
461
472
|
if agent in {"", "null"}:
|
|
462
473
|
raise BriefError(f"{task_id} landed task has no recorded agent")
|
|
474
|
+
member = check_handoffs._strict_frontmatter(text, task_id).get("repo")
|
|
475
|
+
base_repo = repo
|
|
476
|
+
if member is not None:
|
|
477
|
+
located = member_base(member) if isinstance(member, str) and member else None
|
|
478
|
+
if located is None:
|
|
479
|
+
raise BriefError(f"repo: names no member in MEMBERS.md: {member}")
|
|
480
|
+
base_repo = located[0]
|
|
463
481
|
recorded_base = check_handoffs._task_scalar(text, task_id, "base")
|
|
464
482
|
try:
|
|
465
|
-
landed_bases[task_id] = require_commit(
|
|
483
|
+
landed_bases[task_id] = require_commit(base_repo, require_full_sha(recorded_base))
|
|
466
484
|
except IsolationError as error:
|
|
467
485
|
raise BriefError(f"{task_id} landed task has invalid historical base: {error}") from error
|
|
468
486
|
dependency_files[task_id] = set()
|
|
469
487
|
validate_task_briefs(
|
|
470
488
|
repo, head.stdout.strip(), f"{project_dir}/tasks",
|
|
471
489
|
dependency_files=dependency_files, landed_bases=landed_bases,
|
|
490
|
+
member_base=member_base,
|
|
472
491
|
)
|
|
492
|
+
if project_dir == ".project/next":
|
|
493
|
+
# Promotion checks lookahead member tasks from the bases their briefs were checked at.
|
|
494
|
+
named = {
|
|
495
|
+
str(check_handoffs._strict_frontmatter(text, task_id).get("repo"))
|
|
496
|
+
for task_id, text in tasks.items()
|
|
497
|
+
if check_handoffs._strict_frontmatter(text, task_id).get("repo")
|
|
498
|
+
and check_handoffs._task_scalar(text, task_id, "status") != "done"
|
|
499
|
+
}
|
|
500
|
+
if named:
|
|
501
|
+
bases = {name: member_base(name)[1] for name in sorted(named)}
|
|
502
|
+
milestone = pipeline_state.load_state(repo, project_dir)[0].milestone
|
|
503
|
+
path = _lookahead_member_bases_path(repo, str(milestone))
|
|
504
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
505
|
+
pipeline_state._common.atomic_write(path, json.dumps(
|
|
506
|
+
{"schema": LOOKAHEAD_MEMBER_BASES_SCHEMA, "milestone": milestone, "bases": bases},
|
|
507
|
+
indent=2, sort_keys=True) + "\n")
|
|
473
508
|
except (BriefError, check_handoffs.HandoffError) as error:
|
|
474
509
|
raise PipelineStateError(f"task brief validation failed: {error}") from error
|
|
475
510
|
|
|
476
511
|
|
|
512
|
+
LOOKAHEAD_MEMBER_BASES_SCHEMA = "gsd-path/lookahead-member-bases/v1"
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
def _lookahead_member_bases_path(repo: Path, milestone: str) -> Path:
|
|
516
|
+
common = pipeline_state._run_git(repo, "rev-parse", "--path-format=absolute", "--git-common-dir").stdout.strip()
|
|
517
|
+
return Path(common) / "gsd-path" / "lookahead-member-bases" / f"{milestone}.json"
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
def _lookahead_member_bases(repo: Path, milestone: str) -> Optional[dict]:
|
|
521
|
+
path = _lookahead_member_bases_path(repo, milestone)
|
|
522
|
+
if not path.is_file():
|
|
523
|
+
return None
|
|
524
|
+
value = json.loads(path.read_text(encoding="utf-8"))
|
|
525
|
+
if value.get("schema") != LOOKAHEAD_MEMBER_BASES_SCHEMA or value.get("milestone") != milestone:
|
|
526
|
+
return None
|
|
527
|
+
return value.get("bases")
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def _shipped_member_merges(repo: Path, landing: str) -> dict:
|
|
531
|
+
"""Member merges named by the ship commit the integration landing merged."""
|
|
532
|
+
if __package__:
|
|
533
|
+
from .pipeline_git import ship_member_rows
|
|
534
|
+
else:
|
|
535
|
+
from pipeline_git import ship_member_rows
|
|
536
|
+
ship = pipeline_state._run_git(repo, "rev-parse", "--verify", "--quiet", f"{landing}^2", check=False)
|
|
537
|
+
if ship.returncode != 0:
|
|
538
|
+
return {}
|
|
539
|
+
message = pipeline_state._run_git(repo, "show", "-s", "--format=%B", ship.stdout.strip()).stdout
|
|
540
|
+
return {row["name"]: row["merge"] for row in ship_member_rows(message)}
|
|
541
|
+
|
|
542
|
+
|
|
477
543
|
def checkpoint_approval(
|
|
478
544
|
repo: Path,
|
|
479
545
|
kind: str,
|
|
@@ -1027,6 +1093,46 @@ def _classify_plan_drift(
|
|
|
1027
1093
|
}
|
|
1028
1094
|
approved = _approved_task_contracts(repo, checkpoint)
|
|
1029
1095
|
current = _task_contracts_at(repo, revision)
|
|
1096
|
+
if __package__:
|
|
1097
|
+
from . import check_handoffs
|
|
1098
|
+
else:
|
|
1099
|
+
import check_handoffs
|
|
1100
|
+
# Member task paths live in member repos: compare each member from the base its brief
|
|
1101
|
+
# was checked at to the member merge the shipped milestone made (both fixed commits).
|
|
1102
|
+
task_repos = {
|
|
1103
|
+
task_id: str(check_handoffs._strict_frontmatter(contract.text, contract.path).get("repo") or "")
|
|
1104
|
+
for task_id, contract in approved.items()
|
|
1105
|
+
}
|
|
1106
|
+
active_member_tasks = {
|
|
1107
|
+
task_id for task_id, name in task_repos.items()
|
|
1108
|
+
if name and check_handoffs._task_scalar(approved[task_id].text, task_id, "status") != "done"
|
|
1109
|
+
}
|
|
1110
|
+
active_members = {task_repos[task_id] for task_id in active_member_tasks}
|
|
1111
|
+
member_changes: dict[str, list] = {}
|
|
1112
|
+
if active_members:
|
|
1113
|
+
bases = _lookahead_member_bases(repo, str(state.milestone)) or {}
|
|
1114
|
+
if any(name not in bases for name in active_members):
|
|
1115
|
+
return {
|
|
1116
|
+
"class": "unverifiable",
|
|
1117
|
+
"checkpoint": checkpoint,
|
|
1118
|
+
"task_ids": [],
|
|
1119
|
+
"changed_paths": [],
|
|
1120
|
+
"contract_paths": [],
|
|
1121
|
+
"member_tasks": True,
|
|
1122
|
+
"reason": "member bases were not recorded at plan approval",
|
|
1123
|
+
}
|
|
1124
|
+
if __package__:
|
|
1125
|
+
from . import members
|
|
1126
|
+
else:
|
|
1127
|
+
import members
|
|
1128
|
+
checkouts = {item["name"]: Path(item["checkout"]) for item in members.read_members(repo)}
|
|
1129
|
+
merges = _shipped_member_merges(repo, landing or revision)
|
|
1130
|
+
for name in active_members:
|
|
1131
|
+
member_changes[name] = [
|
|
1132
|
+
item for item in pipeline_state._run_git(
|
|
1133
|
+
checkouts[name], "diff", "--no-renames", "--name-only", "-z", bases[name], merges[name]
|
|
1134
|
+
).stdout.split("\0") if item
|
|
1135
|
+
] if name in merges else []
|
|
1030
1136
|
|
|
1031
1137
|
contract_paths: set[str] = set()
|
|
1032
1138
|
flagged_ids: set[str] = set()
|
|
@@ -1050,9 +1156,12 @@ def _classify_plan_drift(
|
|
|
1050
1156
|
|
|
1051
1157
|
product_paths: set[str] = set()
|
|
1052
1158
|
for task_id, contract in approved.items():
|
|
1159
|
+
member = task_repos.get(task_id)
|
|
1160
|
+
if member and task_id not in active_member_tasks:
|
|
1161
|
+
continue
|
|
1053
1162
|
matches = sorted(
|
|
1054
|
-
changed_path
|
|
1055
|
-
for changed_path in changed
|
|
1163
|
+
(f"{member}:{changed_path}" if member else changed_path)
|
|
1164
|
+
for changed_path in (member_changes[member] if member else changed)
|
|
1056
1165
|
if any(
|
|
1057
1166
|
changed_path == path
|
|
1058
1167
|
or changed_path.startswith(f"{path.rstrip('/')}/")
|
package/scripts/state_promote.py
CHANGED
|
@@ -82,6 +82,8 @@ def _promotion_event(
|
|
|
82
82
|
if isinstance(task_ids, list) and task_ids:
|
|
83
83
|
return f"{prefix}; plan drift flagged tasks {', '.join(task_ids)}"
|
|
84
84
|
return f"{prefix}; plan contract changed after approval"
|
|
85
|
+
if drift_class == "unverifiable" and drift.get("member_tasks"):
|
|
86
|
+
return f"{prefix}; plan drift unverifiable because member bases were not recorded at plan approval"
|
|
85
87
|
if drift_class == "unverifiable":
|
|
86
88
|
return f"{prefix}; plan drift unverifiable because approval checkpoint is missing"
|
|
87
89
|
return prefix
|
|
@@ -29,7 +29,7 @@ def process_identity(pid: int):
|
|
|
29
29
|
else:
|
|
30
30
|
command = ["ps", "-o", "lstart=", "-p", str(pid)]
|
|
31
31
|
try:
|
|
32
|
-
result = subprocess.run(command, capture_output=True,
|
|
32
|
+
result = subprocess.run(command, capture_output=True, encoding="utf-8", errors="replace", check=False)
|
|
33
33
|
except OSError:
|
|
34
34
|
return None
|
|
35
35
|
value = result.stdout.strip()
|
|
@@ -45,11 +45,39 @@ def runtime_identity(runtime: Path):
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def process_alive(pid: int) -> bool:
|
|
48
|
+
"""Whether pid names a running process, without signalling it.
|
|
49
|
+
|
|
50
|
+
Windows os.kill(pid, 0) sends CTRL_C_EVENT, so Windows asks the kernel.
|
|
51
|
+
status_runtime and install carry verbatim copies (they cannot import this
|
|
52
|
+
module); tests/test_common_platform.py keeps them identical.
|
|
53
|
+
"""
|
|
54
|
+
if pid <= 0:
|
|
55
|
+
return False
|
|
56
|
+
if os.name != "nt":
|
|
57
|
+
try:
|
|
58
|
+
os.kill(pid, 0)
|
|
59
|
+
except OSError as error:
|
|
60
|
+
return error.errno == errno.EPERM
|
|
61
|
+
return True
|
|
62
|
+
import ctypes
|
|
63
|
+
from ctypes import wintypes
|
|
64
|
+
|
|
65
|
+
kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)
|
|
66
|
+
kernel32.OpenProcess.restype = wintypes.HANDLE
|
|
67
|
+
kernel32.OpenProcess.argtypes = (wintypes.DWORD, wintypes.BOOL, wintypes.DWORD)
|
|
68
|
+
kernel32.GetExitCodeProcess.argtypes = (wintypes.HANDLE, ctypes.POINTER(wintypes.DWORD))
|
|
69
|
+
kernel32.CloseHandle.argtypes = (wintypes.HANDLE,)
|
|
70
|
+
handle = kernel32.OpenProcess(0x1000, False, pid) # PROCESS_QUERY_LIMITED_INFORMATION
|
|
71
|
+
if not handle:
|
|
72
|
+
# ERROR_ACCESS_DENIED: a protected process exists but refuses the query.
|
|
73
|
+
return ctypes.get_last_error() == 5
|
|
48
74
|
try:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
75
|
+
code = wintypes.DWORD()
|
|
76
|
+
if not kernel32.GetExitCodeProcess(handle, ctypes.byref(code)):
|
|
77
|
+
return True
|
|
78
|
+
return code.value == 259 # STILL_ACTIVE
|
|
79
|
+
finally:
|
|
80
|
+
kernel32.CloseHandle(handle)
|
|
53
81
|
|
|
54
82
|
|
|
55
83
|
def install_lock_active(lock: Path) -> bool:
|
|
@@ -196,7 +224,9 @@ def main(argv: Sequence[str] = sys.argv[1:]) -> int:
|
|
|
196
224
|
return 2
|
|
197
225
|
if args.runtime_path:
|
|
198
226
|
try:
|
|
199
|
-
|
|
227
|
+
# Forward slashes: agents paste this into Git Bash on Windows, where
|
|
228
|
+
# unquoted backslashes are escapes.
|
|
229
|
+
print(resolve_runtime(args.repo.resolve()).as_posix())
|
|
200
230
|
return 0
|
|
201
231
|
except (OSError, ValueError) as error:
|
|
202
232
|
print(str(error), file=sys.stderr)
|
|
@@ -129,8 +129,8 @@ def divergence_warning(source: Path, destination: Path, root: Path) -> Optional[
|
|
|
129
129
|
if destination.stat().st_mtime > source.stat().st_mtime:
|
|
130
130
|
return (
|
|
131
131
|
f"generated resource diverges from canonical and is newer "
|
|
132
|
-
f"(possible wrong-direction edit; edit {source.relative_to(root)} "
|
|
133
|
-
f"instead): {destination.relative_to(root)}"
|
|
132
|
+
f"(possible wrong-direction edit; edit {source.relative_to(root).as_posix()} "
|
|
133
|
+
f"instead): {destination.relative_to(root).as_posix()}"
|
|
134
134
|
)
|
|
135
135
|
return None
|
|
136
136
|
|
|
@@ -166,9 +166,9 @@ def mismatches(root: Path) -> Sequence[str]:
|
|
|
166
166
|
problems.append("package.json files do not match manifest package_files")
|
|
167
167
|
for source, destination in resource_pairs(root):
|
|
168
168
|
if not source.is_file():
|
|
169
|
-
problems.append(f"missing canonical resource: {source.relative_to(root)}")
|
|
169
|
+
problems.append(f"missing canonical resource: {source.relative_to(root).as_posix()}")
|
|
170
170
|
elif not destination.is_file():
|
|
171
|
-
problems.append(f"missing generated resource: {destination.relative_to(root)}")
|
|
171
|
+
problems.append(f"missing generated resource: {destination.relative_to(root).as_posix()}")
|
|
172
172
|
else:
|
|
173
173
|
try:
|
|
174
174
|
expected = materialized_resource_bytes(source, destination)
|
|
@@ -181,10 +181,10 @@ def mismatches(root: Path) -> Sequence[str]:
|
|
|
181
181
|
problems.append(warning)
|
|
182
182
|
else:
|
|
183
183
|
problems.append(
|
|
184
|
-
f"stale generated resource: {destination.relative_to(root)}"
|
|
184
|
+
f"stale generated resource: {destination.relative_to(root).as_posix()}"
|
|
185
185
|
)
|
|
186
186
|
for path in package_metadata(root):
|
|
187
|
-
problems.append(f"unexpected package metadata: {path.relative_to(root)}")
|
|
187
|
+
problems.append(f"unexpected package metadata: {path.relative_to(root).as_posix()}")
|
|
188
188
|
return problems
|
|
189
189
|
|
|
190
190
|
|
|
@@ -216,7 +216,8 @@ def synchronize(root: Path) -> int:
|
|
|
216
216
|
package_path = root / "package.json"
|
|
217
217
|
package = json.loads(package_path.read_text(encoding="utf-8"))
|
|
218
218
|
package["files"] = list(PACKAGE_FILES)
|
|
219
|
-
|
|
219
|
+
# Bytes, so Windows text mode never writes CRLF.
|
|
220
|
+
package_path.write_bytes((json.dumps(package, indent=2) + "\n").encode("utf-8"))
|
|
220
221
|
print(
|
|
221
222
|
json.dumps(
|
|
222
223
|
{
|
package/scripts/token_budget.py
CHANGED
|
@@ -10,12 +10,16 @@ import json
|
|
|
10
10
|
import sys
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
from _common import atomic_write
|
|
15
|
-
from loop_run import log_lock
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
if __package__:
|
|
14
|
+
from ._common import atomic_write
|
|
15
|
+
from .loop_run import log_lock
|
|
16
|
+
else:
|
|
17
|
+
try:
|
|
18
|
+
from _common import atomic_write
|
|
19
|
+
from loop_run import log_lock
|
|
20
|
+
except ModuleNotFoundError: # pragma: no cover - package imports
|
|
21
|
+
from scripts._common import atomic_write
|
|
22
|
+
from scripts.loop_run import log_lock
|
|
19
23
|
|
|
20
24
|
|
|
21
25
|
SCHEMA = "gsd-path/token-budget/v1"
|
|
@@ -97,14 +101,14 @@ def operate(args):
|
|
|
97
101
|
"task_limit": args.task_limit, "session_limit": args.session_limit,
|
|
98
102
|
"authority": args.authority}
|
|
99
103
|
if ledger.exists():
|
|
100
|
-
data = json.loads(ledger.read_text())
|
|
104
|
+
data = json.loads(ledger.read_text(encoding="utf-8"))
|
|
101
105
|
if any(data.get(key) != value for key, value in policy.items()):
|
|
102
106
|
raise ValueError("existing session policy differs; configuration cannot reset usage")
|
|
103
107
|
else:
|
|
104
108
|
data = {**policy, "observations": {}}
|
|
105
109
|
atomic_write(ledger, json.dumps(data, indent=2) + "\n")
|
|
106
110
|
return {"status": "configured", "hard_cap_supported": False}
|
|
107
|
-
data = json.loads(ledger.read_text())
|
|
111
|
+
data = json.loads(ledger.read_text(encoding="utf-8"))
|
|
108
112
|
if data.get("schema") != SCHEMA or data.get("host") != "codex-cli":
|
|
109
113
|
raise ValueError("unsupported budget ledger")
|
|
110
114
|
if args.action == "record":
|