@opengsd/gsd-path 1.3.1 → 1.5.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 +331 -69
- package/DOCS.md +25 -9
- package/FULL.md +12 -5
- package/GUIDE.md +1 -1
- package/HOOKS.md +104 -14
- package/QUICK.md +5 -2
- package/README.md +131 -111
- package/RUNTIME.md +2 -2
- package/UPDATE.md +61 -11
- package/WORKFLOW.md +44 -7
- package/package.json +13 -9
- package/platforms/shared-agents/dispatch.md +13 -0
- package/scripts/_common.py +619 -18
- package/scripts/archive_milestone.py +160 -86
- package/scripts/bootstrap_repository.py +8 -5
- package/scripts/build_recovery.py +100 -32
- package/scripts/build_state.py +143 -24
- package/scripts/check_docs_audit.py +91 -7
- package/scripts/check_handoffs.py +662 -50
- package/scripts/check_task_briefs.py +338 -30
- 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 +587 -32
- package/scripts/discussion_records.py +19 -13
- package/scripts/discussion_validate.py +152 -50
- package/scripts/dispatch_driver.py +501 -46
- package/scripts/git_guard.py +118 -31
- package/scripts/guard_hook.py +1567 -194
- package/scripts/install.mjs +77 -46
- package/scripts/install.py +611 -50
- package/scripts/integration.py +580 -25
- package/scripts/isolation.py +1438 -57
- package/scripts/lean_verification.py +99 -19
- package/scripts/loop_run.py +31 -29
- package/scripts/members.py +706 -0
- package/scripts/migrate_core.py +2 -2
- package/scripts/path_config.py +5 -5
- package/scripts/pipeline_diagnose.py +82 -31
- package/scripts/pipeline_git.py +124 -34
- package/scripts/pipeline_state.py +287 -87
- package/scripts/pipeline_undo.py +218 -30
- package/scripts/promote_lookahead.py +1 -1
- package/scripts/review_panel.py +1 -1
- package/scripts/runtime_store.py +55 -11
- package/scripts/skill-resources.json +37 -5
- package/scripts/state_checkpoint.py +135 -44
- package/scripts/state_promote.py +2 -0
- package/scripts/status_runtime.py +58 -10
- package/scripts/sync_skill_resources.py +8 -7
- package/scripts/task_context.py +12 -3
- package/scripts/token_budget.py +12 -8
- package/scripts/wizard.mjs +1 -0
- package/scripts/workflow_run.py +107 -30
- package/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path/BUILD.md +7 -1
- package/skills/gsd-path/DECIDE.md +11 -4
- package/skills/gsd-path/DEFINE.md +36 -4
- package/skills/gsd-path/DOCS-AUDIT.md +6 -4
- package/skills/gsd-path/INSPECT.md +5 -4
- package/skills/gsd-path/PLAN.md +18 -4
- package/skills/gsd-path/RESEARCH.md +13 -1
- package/skills/gsd-path/ROADMAP.md +2 -1
- package/skills/gsd-path/SHIP.md +33 -11
- package/skills/gsd-path/SKILL.md +45 -1
- package/skills/gsd-path/references/build-native.md +63 -15
- package/skills/gsd-path/references/codebase-mapper.md +2 -1
- package/skills/gsd-path/references/dispatch.md +13 -0
- package/skills/gsd-path/references/docs-auditor.md +7 -1
- package/skills/gsd-path/references/operating-rules.md +214 -0
- package/skills/gsd-path/references/planner.md +22 -4
- package/skills/gsd-path/references/reviewer-final.md +20 -2
- package/skills/gsd-path/references/reviewer-wave.md +18 -5
- package/skills/gsd-path/references/reviewer.md +3 -1
- package/skills/gsd-path/references/spec-probes.md +150 -0
- package/skills/gsd-path/scripts/_common.py +619 -18
- package/skills/gsd-path/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path/scripts/bootstrap_repository.py +8 -5
- package/skills/gsd-path/scripts/build_recovery.py +100 -32
- package/skills/gsd-path/scripts/build_state.py +143 -24
- package/skills/gsd-path/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path/scripts/check_update.py +2 -2
- package/skills/gsd-path/scripts/detect_project.py +587 -32
- package/skills/gsd-path/scripts/discussion_records.py +19 -13
- package/skills/gsd-path/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path/scripts/dispatch_driver.py +501 -46
- package/skills/gsd-path/scripts/git_guard.py +118 -31
- package/skills/gsd-path/scripts/integration.py +580 -25
- package/skills/gsd-path/scripts/isolation.py +1438 -57
- package/skills/gsd-path/scripts/lean_verification.py +99 -19
- package/skills/gsd-path/scripts/loop_run.py +31 -29
- package/skills/gsd-path/scripts/members.py +706 -0
- package/skills/gsd-path/scripts/path_config.py +5 -5
- package/skills/gsd-path/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path/scripts/state_promote.py +2 -0
- package/skills/gsd-path/scripts/status_runtime.py +58 -10
- package/skills/gsd-path/scripts/task_context.py +12 -3
- package/skills/gsd-path/scripts/token_budget.py +12 -8
- package/skills/gsd-path/scripts/workflow_run.py +107 -30
- package/skills/gsd-path/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path/templates/codebase.md +1 -1
- package/skills/gsd-path/templates/docs-audit.md +6 -2
- package/skills/gsd-path/templates/final-review.md +16 -4
- package/skills/gsd-path/templates/gap-review.md +2 -1
- 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 +1 -1
- package/skills/gsd-path/templates/task.md +1 -0
- package/skills/gsd-path/templates/wave-review.md +16 -4
- package/skills/gsd-path-build/SKILL.md +7 -1
- package/skills/gsd-path-build/references/build-native.md +63 -15
- package/skills/gsd-path-build/references/dispatch.md +13 -0
- package/skills/gsd-path-build/references/operating-rules.md +214 -0
- package/skills/gsd-path-build/references/reviewer-final.md +20 -2
- package/skills/gsd-path-build/references/reviewer-wave.md +18 -5
- package/skills/gsd-path-build/references/reviewer.md +3 -1
- package/skills/gsd-path-build/references/spec-probes.md +150 -0
- package/skills/gsd-path-build/scripts/_common.py +619 -18
- package/skills/gsd-path-build/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-build/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-build/scripts/build_state.py +143 -24
- package/skills/gsd-path-build/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-build/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-build/scripts/detect_project.py +587 -32
- package/skills/gsd-path-build/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-build/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-build/scripts/dispatch_driver.py +501 -46
- package/skills/gsd-path-build/scripts/integration.py +580 -25
- package/skills/gsd-path-build/scripts/isolation.py +1438 -57
- package/skills/gsd-path-build/scripts/loop_run.py +31 -29
- package/skills/gsd-path-build/scripts/members.py +706 -0
- package/skills/gsd-path-build/scripts/path_config.py +5 -5
- package/skills/gsd-path-build/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-build/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-build/scripts/state_promote.py +2 -0
- package/skills/gsd-path-build/scripts/task_context.py +12 -3
- package/skills/gsd-path-build/scripts/token_budget.py +12 -8
- package/skills/gsd-path-build/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-build/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-build/templates/task.md +1 -0
- package/skills/gsd-path-build/templates/wave-review.md +16 -4
- package/skills/gsd-path-decide/SKILL.md +11 -4
- package/skills/gsd-path-decide/references/dispatch.md +13 -0
- package/skills/gsd-path-decide/references/operating-rules.md +214 -0
- package/skills/gsd-path-decide/scripts/_common.py +619 -18
- package/skills/gsd-path-decide/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-decide/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-decide/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-decide/scripts/detect_project.py +587 -32
- package/skills/gsd-path-decide/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-decide/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-decide/scripts/integration.py +580 -25
- package/skills/gsd-path-decide/scripts/isolation.py +1438 -57
- package/skills/gsd-path-decide/scripts/loop_run.py +31 -29
- package/skills/gsd-path-decide/scripts/members.py +706 -0
- package/skills/gsd-path-decide/scripts/path_config.py +5 -5
- package/skills/gsd-path-decide/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-decide/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-decide/scripts/state_promote.py +2 -0
- package/skills/gsd-path-decide/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-define/SKILL.md +36 -4
- package/skills/gsd-path-define/references/operating-rules.md +214 -0
- package/skills/gsd-path-define/references/spec-probes.md +150 -0
- package/skills/gsd-path-define/scripts/_common.py +619 -18
- package/skills/gsd-path-define/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-define/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-define/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-define/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-define/scripts/detect_project.py +587 -32
- package/skills/gsd-path-define/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-define/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-define/scripts/integration.py +580 -25
- package/skills/gsd-path-define/scripts/isolation.py +1438 -57
- package/skills/gsd-path-define/scripts/loop_run.py +31 -29
- package/skills/gsd-path-define/scripts/members.py +706 -0
- package/skills/gsd-path-define/scripts/path_config.py +5 -5
- package/skills/gsd-path-define/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-define/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-define/scripts/state_promote.py +2 -0
- package/skills/gsd-path-define/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-define/templates/intent.md +30 -0
- package/skills/gsd-path-define/templates/state.md +1 -1
- 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 +619 -18
- package/skills/gsd-path-discuss/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-discuss/scripts/loop_run.py +31 -29
- package/skills/gsd-path-discuss/scripts/path_config.py +5 -5
- package/skills/gsd-path-discuss/scripts/review_panel.py +1 -1
- package/skills/gsd-path-discuss/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-docs-audit/SKILL.md +6 -4
- package/skills/gsd-path-docs-audit/references/dispatch.md +13 -0
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +7 -1
- package/skills/gsd-path-docs-audit/references/operating-rules.md +214 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +619 -18
- package/skills/gsd-path-docs-audit/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-docs-audit/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-docs-audit/scripts/detect_project.py +587 -32
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-docs-audit/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-docs-audit/scripts/integration.py +580 -25
- package/skills/gsd-path-docs-audit/scripts/isolation.py +1438 -57
- package/skills/gsd-path-docs-audit/scripts/loop_run.py +31 -29
- package/skills/gsd-path-docs-audit/scripts/members.py +706 -0
- package/skills/gsd-path-docs-audit/scripts/path_config.py +5 -5
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +2 -0
- package/skills/gsd-path-docs-audit/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +6 -2
- 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 +619 -18
- package/skills/gsd-path-forensics/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-forensics/scripts/loop_run.py +31 -29
- package/skills/gsd-path-forensics/scripts/path_config.py +5 -5
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +82 -31
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +218 -30
- package/skills/gsd-path-forensics/scripts/review_panel.py +1 -1
- package/skills/gsd-path-forensics/scripts/worktree_paths.py +72 -10
- 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/dispatch.md +13 -0
- package/skills/gsd-path-inspect/references/docs-auditor.md +7 -1
- package/skills/gsd-path-inspect/references/operating-rules.md +214 -0
- package/skills/gsd-path-inspect/scripts/_common.py +619 -18
- package/skills/gsd-path-inspect/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-inspect/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +91 -7
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-inspect/scripts/detect_project.py +587 -32
- package/skills/gsd-path-inspect/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-inspect/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-inspect/scripts/integration.py +580 -25
- package/skills/gsd-path-inspect/scripts/isolation.py +1438 -57
- package/skills/gsd-path-inspect/scripts/loop_run.py +31 -29
- package/skills/gsd-path-inspect/scripts/members.py +706 -0
- package/skills/gsd-path-inspect/scripts/path_config.py +5 -5
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-inspect/scripts/state_promote.py +2 -0
- package/skills/gsd-path-inspect/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-inspect/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-inspect/templates/codebase.md +1 -1
- package/skills/gsd-path-inspect/templates/docs-audit.md +6 -2
- package/skills/gsd-path-inspect/templates/state.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 +619 -18
- package/skills/gsd-path-loop/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-loop/scripts/loop_run.py +31 -29
- package/skills/gsd-path-loop/scripts/path_config.py +5 -5
- package/skills/gsd-path-loop/scripts/review_panel.py +1 -1
- package/skills/gsd-path-loop/scripts/worktree_paths.py +72 -10
- 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 +619 -18
- 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 +31 -29
- package/skills/gsd-path-migrate/scripts/migrate_core.py +2 -2
- package/skills/gsd-path-migrate/scripts/path_config.py +5 -5
- package/skills/gsd-path-migrate/scripts/review_panel.py +1 -1
- package/skills/gsd-path-plan/SKILL.md +18 -4
- package/skills/gsd-path-plan/references/dispatch.md +13 -0
- package/skills/gsd-path-plan/references/operating-rules.md +214 -0
- package/skills/gsd-path-plan/references/planner.md +22 -4
- package/skills/gsd-path-plan/references/spec-probes.md +150 -0
- package/skills/gsd-path-plan/scripts/_common.py +619 -18
- package/skills/gsd-path-plan/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-plan/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-plan/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-plan/scripts/detect_project.py +587 -32
- package/skills/gsd-path-plan/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-plan/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-plan/scripts/integration.py +580 -25
- package/skills/gsd-path-plan/scripts/isolation.py +1438 -57
- package/skills/gsd-path-plan/scripts/loop_run.py +31 -29
- package/skills/gsd-path-plan/scripts/members.py +706 -0
- package/skills/gsd-path-plan/scripts/path_config.py +5 -5
- package/skills/gsd-path-plan/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-plan/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-plan/scripts/state_promote.py +2 -0
- package/skills/gsd-path-plan/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-plan/scripts/worktree_paths.py +72 -10
- 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 +13 -1
- package/skills/gsd-path-research/references/dispatch.md +13 -0
- package/skills/gsd-path-research/references/operating-rules.md +214 -0
- package/skills/gsd-path-research/scripts/_common.py +619 -18
- package/skills/gsd-path-research/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-research/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-research/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-research/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-research/scripts/detect_project.py +587 -32
- package/skills/gsd-path-research/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-research/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-research/scripts/integration.py +580 -25
- package/skills/gsd-path-research/scripts/isolation.py +1438 -57
- package/skills/gsd-path-research/scripts/loop_run.py +31 -29
- package/skills/gsd-path-research/scripts/members.py +706 -0
- package/skills/gsd-path-research/scripts/path_config.py +5 -5
- package/skills/gsd-path-research/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-research/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-research/scripts/state_promote.py +2 -0
- package/skills/gsd-path-research/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-research/templates/research-handoff.md +14 -3
- package/skills/gsd-path-roadmap/SKILL.md +2 -1
- package/skills/gsd-path-roadmap/references/dispatch.md +13 -0
- package/skills/gsd-path-roadmap/references/operating-rules.md +214 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +619 -18
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-roadmap/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-roadmap/scripts/detect_project.py +587 -32
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-roadmap/scripts/integration.py +580 -25
- package/skills/gsd-path-roadmap/scripts/isolation.py +1438 -57
- package/skills/gsd-path-roadmap/scripts/loop_run.py +31 -29
- package/skills/gsd-path-roadmap/scripts/members.py +706 -0
- package/skills/gsd-path-roadmap/scripts/path_config.py +5 -5
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-roadmap/scripts/state_promote.py +2 -0
- package/skills/gsd-path-roadmap/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-ship/SKILL.md +33 -11
- package/skills/gsd-path-ship/references/dispatch.md +13 -0
- package/skills/gsd-path-ship/references/operating-rules.md +214 -0
- package/skills/gsd-path-ship/references/reviewer-final.md +20 -2
- package/skills/gsd-path-ship/references/reviewer-wave.md +18 -5
- package/skills/gsd-path-ship/references/reviewer.md +3 -1
- package/skills/gsd-path-ship/references/spec-probes.md +150 -0
- package/skills/gsd-path-ship/scripts/_common.py +619 -18
- package/skills/gsd-path-ship/scripts/archive_milestone.py +160 -86
- package/skills/gsd-path-ship/scripts/build_recovery.py +100 -32
- package/skills/gsd-path-ship/scripts/build_state.py +143 -24
- package/skills/gsd-path-ship/scripts/check_handoffs.py +662 -50
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +338 -30
- package/skills/gsd-path-ship/scripts/detect_project.py +587 -32
- package/skills/gsd-path-ship/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-ship/scripts/discussion_validate.py +152 -50
- package/skills/gsd-path-ship/scripts/integration.py +580 -25
- package/skills/gsd-path-ship/scripts/isolation.py +1438 -57
- package/skills/gsd-path-ship/scripts/lean_verification.py +99 -19
- package/skills/gsd-path-ship/scripts/loop_run.py +31 -29
- package/skills/gsd-path-ship/scripts/members.py +706 -0
- package/skills/gsd-path-ship/scripts/path_config.py +5 -5
- package/skills/gsd-path-ship/scripts/pipeline_git.py +124 -34
- package/skills/gsd-path-ship/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/gsd-path-ship/scripts/state_promote.py +2 -0
- package/skills/gsd-path-ship/scripts/workflow_run.py +107 -30
- package/skills/gsd-path-ship/scripts/worktree_paths.py +72 -10
- package/skills/gsd-path-ship/templates/final-review.md +16 -4
- package/skills/gsd-path-ship/templates/gap-review.md +2 -1
- package/skills/gsd-path-ship/templates/patch-findings.md +3 -3
- package/skills/gsd-path-ship/templates/wave-review.md +16 -4
- 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 +619 -18
- package/skills/gsd-path-undo/scripts/discussion_records.py +19 -13
- package/skills/gsd-path-undo/scripts/loop_run.py +31 -29
- package/skills/gsd-path-undo/scripts/path_config.py +5 -5
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +218 -30
- package/skills/gsd-path-undo/scripts/review_panel.py +1 -1
- package/skills/gsd-path-undo/scripts/worktree_paths.py +72 -10
- package/skills/path/BUILD.md +7 -1
- package/skills/path/DECIDE.md +11 -4
- package/skills/path/DEFINE.md +36 -4
- package/skills/path/DOCS-AUDIT.md +6 -4
- package/skills/path/INSPECT.md +5 -4
- package/skills/path/PLAN.md +18 -4
- package/skills/path/RESEARCH.md +13 -1
- package/skills/path/ROADMAP.md +2 -1
- package/skills/path/SHIP.md +33 -11
- package/skills/path/SKILL.md +45 -1
- package/skills/path/references/build-native.md +63 -15
- package/skills/path/references/codebase-mapper.md +2 -1
- package/skills/path/references/dispatch.md +13 -0
- package/skills/path/references/docs-auditor.md +7 -1
- package/skills/path/references/operating-rules.md +214 -0
- package/skills/path/references/planner.md +22 -4
- package/skills/path/references/reviewer-final.md +20 -2
- package/skills/path/references/reviewer-wave.md +18 -5
- package/skills/path/references/reviewer.md +3 -1
- package/skills/path/references/spec-probes.md +150 -0
- package/skills/path/scripts/_common.py +619 -18
- package/skills/path/scripts/archive_milestone.py +160 -86
- package/skills/path/scripts/bootstrap_repository.py +8 -5
- package/skills/path/scripts/build_recovery.py +100 -32
- package/skills/path/scripts/build_state.py +143 -24
- package/skills/path/scripts/check_docs_audit.py +91 -7
- package/skills/path/scripts/check_handoffs.py +662 -50
- package/skills/path/scripts/check_task_briefs.py +338 -30
- package/skills/path/scripts/check_update.py +2 -2
- package/skills/path/scripts/detect_project.py +587 -32
- package/skills/path/scripts/discussion_records.py +19 -13
- package/skills/path/scripts/discussion_validate.py +152 -50
- package/skills/path/scripts/dispatch_driver.py +501 -46
- package/skills/path/scripts/git_guard.py +118 -31
- package/skills/path/scripts/integration.py +580 -25
- package/skills/path/scripts/isolation.py +1438 -57
- package/skills/path/scripts/lean_verification.py +99 -19
- package/skills/path/scripts/loop_run.py +31 -29
- package/skills/path/scripts/members.py +706 -0
- package/skills/path/scripts/path_config.py +5 -5
- package/skills/path/scripts/pipeline_git.py +124 -34
- package/skills/path/scripts/pipeline_state.py +287 -87
- 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 +135 -44
- package/skills/path/scripts/state_promote.py +2 -0
- package/skills/path/scripts/status_runtime.py +58 -10
- package/skills/path/scripts/task_context.py +12 -3
- package/skills/path/scripts/token_budget.py +12 -8
- package/skills/path/scripts/workflow_run.py +107 -30
- package/skills/path/scripts/worktree_paths.py +72 -10
- package/skills/path/templates/codebase.md +1 -1
- package/skills/path/templates/docs-audit.md +6 -2
- package/skills/path/templates/final-review.md +16 -4
- package/skills/path/templates/gap-review.md +2 -1
- 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 +1 -1
- package/skills/path/templates/task.md +1 -0
- package/skills/path/templates/wave-review.md +16 -4
- 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
|
@@ -17,6 +17,7 @@ import os
|
|
|
17
17
|
import re
|
|
18
18
|
import shutil
|
|
19
19
|
import sys
|
|
20
|
+
from datetime import date
|
|
20
21
|
|
|
21
22
|
# Runtime helpers must not modify their immutable installation.
|
|
22
23
|
sys.dont_write_bytecode = True
|
|
@@ -25,22 +26,30 @@ from pathlib import Path, PurePosixPath
|
|
|
25
26
|
from typing import Optional, Sequence
|
|
26
27
|
|
|
27
28
|
def _load_pipeline_modules():
|
|
28
|
-
|
|
29
|
-
import archive_milestone
|
|
30
|
-
import isolation
|
|
31
|
-
import pipeline_git
|
|
32
|
-
import pipeline_state
|
|
33
|
-
import state_checkpoint
|
|
29
|
+
if __package__:
|
|
30
|
+
from . import archive_milestone
|
|
31
|
+
from . import isolation
|
|
32
|
+
from . import pipeline_git
|
|
33
|
+
from . import pipeline_state
|
|
34
|
+
from . import state_checkpoint
|
|
34
35
|
return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
else:
|
|
37
|
+
try:
|
|
38
|
+
import archive_milestone
|
|
39
|
+
import isolation
|
|
40
|
+
import pipeline_git
|
|
41
|
+
import pipeline_state
|
|
42
|
+
import state_checkpoint
|
|
43
|
+
return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
|
|
44
|
+
except ModuleNotFoundError as error:
|
|
45
|
+
if error.name not in {
|
|
46
|
+
"archive_milestone",
|
|
47
|
+
"isolation",
|
|
48
|
+
"pipeline_git",
|
|
49
|
+
"pipeline_state",
|
|
50
|
+
"state_checkpoint",
|
|
51
|
+
}:
|
|
52
|
+
raise
|
|
44
53
|
try:
|
|
45
54
|
from scripts import archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
|
|
46
55
|
return archive_milestone, isolation, pipeline_git, pipeline_state, state_checkpoint
|
|
@@ -94,10 +103,20 @@ UNDO_TRANSACTION_SCHEMA = pipeline_state.UNDO_TRANSACTION_SCHEMA
|
|
|
94
103
|
UNDO_TRANSACTION_NAME = pipeline_state.UNDO_TRANSACTION_NAME
|
|
95
104
|
ROADMAP_APPROVAL_SUBJECT = "roadmap: program roadmap approved"
|
|
96
105
|
TASK_SUBJECT_RE = re.compile(r"^(T\d{3,}): .+")
|
|
97
|
-
KINDS = ("checkpoint", "task", "uncommitted-archive", "lookahead")
|
|
106
|
+
KINDS = ("checkpoint", "task", "member-task", "uncommitted-archive", "lookahead")
|
|
98
107
|
PROMOTION_PREFIX = "router: promote lookahead milestone "
|
|
99
108
|
ABANDON_PREFIX = "build: abandon milestone "
|
|
100
109
|
INTEGRATE_PREFIX = "integrate: "
|
|
110
|
+
SHIP_LOG_ONLY_LINE = re.compile(
|
|
111
|
+
r"- (?P<date>\d{4}-\d{2}-\d{2}) — ship — (?P<event>[^\r\n]+)\n\Z"
|
|
112
|
+
)
|
|
113
|
+
SHIPMENT_RECORD_LINE = re.compile(
|
|
114
|
+
r"- (?P<date>\d{4}-\d{2}-\d{2}) — shipped — (?P<event>[^\r\n]+)\n\Z"
|
|
115
|
+
)
|
|
116
|
+
SHIPMENT_EVENTS = {
|
|
117
|
+
"archive preflight passed; shipment recorded",
|
|
118
|
+
"archive preflight passed; shipment recorded; program complete",
|
|
119
|
+
}
|
|
101
120
|
|
|
102
121
|
|
|
103
122
|
class UndoError(RuntimeError):
|
|
@@ -367,6 +386,80 @@ def pending_transaction(repo: Path) -> Optional[dict[str, object]]:
|
|
|
367
386
|
raise UndoError(str(error)) from error
|
|
368
387
|
|
|
369
388
|
|
|
389
|
+
def _valid_state_event_line(line: str, phase: str) -> bool:
|
|
390
|
+
pattern = SHIP_LOG_ONLY_LINE if phase == "ship" else SHIPMENT_RECORD_LINE
|
|
391
|
+
match = pattern.fullmatch(line)
|
|
392
|
+
if match is None:
|
|
393
|
+
return False
|
|
394
|
+
try:
|
|
395
|
+
event_date = date.fromisoformat(match.group("date"))
|
|
396
|
+
except ValueError:
|
|
397
|
+
return False
|
|
398
|
+
event = match.group("event")
|
|
399
|
+
return event_date.isoformat() == match.group("date") and event == " ".join(event.split())
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
def _owned_ship_log_events(
|
|
403
|
+
prepared_state: str,
|
|
404
|
+
current_state: str,
|
|
405
|
+
phase: object,
|
|
406
|
+
status: object,
|
|
407
|
+
) -> Optional[str]:
|
|
408
|
+
"""Return only ship log lines appended around a helper-owned archive event.
|
|
409
|
+
|
|
410
|
+
The prepared text must remain byte-for-byte unchanged. For shipped/done,
|
|
411
|
+
record-shipment changes only phase and status before appending its one
|
|
412
|
+
generated shipment event, so validate that exact prefix and event shape.
|
|
413
|
+
"""
|
|
414
|
+
if (phase, status) == ("ship", "active"):
|
|
415
|
+
if current_state == prepared_state:
|
|
416
|
+
return ""
|
|
417
|
+
if not current_state.startswith(prepared_state):
|
|
418
|
+
return None
|
|
419
|
+
suffix = current_state[len(prepared_state):]
|
|
420
|
+
separator = "" if prepared_state.endswith("\n") else "\n"
|
|
421
|
+
if separator:
|
|
422
|
+
if not suffix.startswith(separator):
|
|
423
|
+
return None
|
|
424
|
+
suffix = suffix[len(separator):]
|
|
425
|
+
lines = suffix.splitlines(keepends=True)
|
|
426
|
+
if not lines or "".join(lines) != suffix:
|
|
427
|
+
return None
|
|
428
|
+
if not all(_valid_state_event_line(line, "ship") for line in lines):
|
|
429
|
+
return None
|
|
430
|
+
return separator + suffix
|
|
431
|
+
|
|
432
|
+
if (phase, status) != ("shipped", "done"):
|
|
433
|
+
return None
|
|
434
|
+
try:
|
|
435
|
+
shipped_prefix = pipeline_state._set_frontmatter(
|
|
436
|
+
prepared_state,
|
|
437
|
+
{"phase": "shipped", "status": "done"},
|
|
438
|
+
)
|
|
439
|
+
except PipelineStateError:
|
|
440
|
+
return None
|
|
441
|
+
if not current_state.startswith(shipped_prefix):
|
|
442
|
+
return None
|
|
443
|
+
suffix = current_state[len(shipped_prefix):]
|
|
444
|
+
separator = "" if shipped_prefix.endswith("\n") else "\n"
|
|
445
|
+
if separator:
|
|
446
|
+
if not suffix.startswith(separator):
|
|
447
|
+
return None
|
|
448
|
+
suffix = suffix[len(separator):]
|
|
449
|
+
lines = suffix.splitlines(keepends=True)
|
|
450
|
+
if not lines or "".join(lines) != suffix:
|
|
451
|
+
return None
|
|
452
|
+
shipment_event = lines[-1]
|
|
453
|
+
if not _valid_state_event_line(shipment_event, "shipped"):
|
|
454
|
+
return None
|
|
455
|
+
if SHIPMENT_RECORD_LINE.fullmatch(shipment_event).group("event") not in SHIPMENT_EVENTS:
|
|
456
|
+
return None
|
|
457
|
+
ship_events = lines[:-1]
|
|
458
|
+
if not all(_valid_state_event_line(line, "ship") for line in ship_events):
|
|
459
|
+
return None
|
|
460
|
+
return separator + "".join(ship_events) if ship_events else ""
|
|
461
|
+
|
|
462
|
+
|
|
370
463
|
def _archive_metadata_error(
|
|
371
464
|
repo: Path,
|
|
372
465
|
state_fields: dict[str, object],
|
|
@@ -412,8 +505,13 @@ def _archive_metadata_error(
|
|
|
412
505
|
if final_review.exists() or gap_reviews:
|
|
413
506
|
reviewed_head, _ = archive_milestone.parse_final_review(archive_path)
|
|
414
507
|
archive_milestone.validate_gap_reviews(archive_path, reviewed_head)
|
|
415
|
-
if
|
|
416
|
-
|
|
508
|
+
if not archive_milestone.reviewed_head_covers(
|
|
509
|
+
repo, reviewed_head, _optional_rev(repo, "HEAD")
|
|
510
|
+
):
|
|
511
|
+
return (
|
|
512
|
+
"archive undo final review does not match current HEAD; "
|
|
513
|
+
f"{archive_milestone._common.RUNTIME_PIN_ALLOWANCE}"
|
|
514
|
+
)
|
|
417
515
|
expected_inventory.add("review/FINAL.md")
|
|
418
516
|
expected_inventory.update(
|
|
419
517
|
path.relative_to(archive_path).as_posix() for path in gap_reviews
|
|
@@ -468,10 +566,14 @@ def _archive_metadata_error(
|
|
|
468
566
|
"archive",
|
|
469
567
|
configured,
|
|
470
568
|
)
|
|
471
|
-
current_state = (repo / ".project" / "STATE.md").
|
|
569
|
+
current_state = (repo / ".project" / "STATE.md").read_bytes().decode("utf-8")
|
|
472
570
|
phase = state_fields.get("phase")
|
|
473
571
|
status = state_fields.get("status")
|
|
572
|
+
ship_events = _owned_ship_log_events(prepared_state, current_state, phase, status)
|
|
474
573
|
if (phase, status) == ("ship", "active"):
|
|
574
|
+
if ship_events is None:
|
|
575
|
+
return "archive undo found unowned STATE.md changes"
|
|
576
|
+
prepared_state += ship_events
|
|
475
577
|
if current_state != prepared_state:
|
|
476
578
|
return "archive undo found unowned STATE.md changes"
|
|
477
579
|
if ".project/ROADMAP.md" in dirty:
|
|
@@ -479,14 +581,13 @@ def _archive_metadata_error(
|
|
|
479
581
|
return None
|
|
480
582
|
if (phase, status) != ("shipped", "done"):
|
|
481
583
|
return "archive undo requires ship/active or shipped/done"
|
|
584
|
+
if ship_events is None:
|
|
585
|
+
return "archive undo found unowned shipment STATE.md changes"
|
|
586
|
+
prepared_state += ship_events
|
|
482
587
|
|
|
483
588
|
prepared = _state_from_text(prepared_state, "prepared archive STATE.md")
|
|
484
|
-
events = (
|
|
485
|
-
"archive preflight passed; shipment recorded",
|
|
486
|
-
"archive preflight passed; shipment recorded; program complete",
|
|
487
|
-
)
|
|
488
589
|
rendered_states = []
|
|
489
|
-
for event in
|
|
590
|
+
for event in SHIPMENT_EVENTS:
|
|
490
591
|
try:
|
|
491
592
|
_, _, rendered = _render_transition(
|
|
492
593
|
prepared,
|
|
@@ -528,6 +629,7 @@ def _prepare_transaction(
|
|
|
528
629
|
branch: str,
|
|
529
630
|
archive: Optional[str],
|
|
530
631
|
discussion: Optional[dict[str, bytes]],
|
|
632
|
+
member_fields: Optional[dict[str, str]] = None,
|
|
531
633
|
) -> dict[str, object]:
|
|
532
634
|
transaction = {
|
|
533
635
|
"schema": UNDO_TRANSACTION_SCHEMA,
|
|
@@ -545,6 +647,8 @@ def _prepare_transaction(
|
|
|
545
647
|
),
|
|
546
648
|
"discussion": _encode_discussion(discussion),
|
|
547
649
|
}
|
|
650
|
+
if member_fields is not None:
|
|
651
|
+
transaction.update(member_fields)
|
|
548
652
|
_write_json(_git_path(repo, UNDO_TRANSACTION_NAME), transaction)
|
|
549
653
|
return transaction
|
|
550
654
|
|
|
@@ -641,7 +745,7 @@ def _transaction_recovery_stage(
|
|
|
641
745
|
expected_head = str(transaction["expected_head"])
|
|
642
746
|
parent = str(transaction["parent"])
|
|
643
747
|
current = _optional_rev(repo, "HEAD")
|
|
644
|
-
if transaction["kind"]
|
|
748
|
+
if transaction["kind"] in {"checkpoint", "member-task"}:
|
|
645
749
|
allowed = {expected_head, parent}
|
|
646
750
|
else:
|
|
647
751
|
allowed = {expected_head}
|
|
@@ -662,8 +766,60 @@ def _transaction_recovery_stage(
|
|
|
662
766
|
return "reset"
|
|
663
767
|
|
|
664
768
|
|
|
769
|
+
def _member_undo_parent(repo: Path, member: str, landing: str) -> str:
|
|
770
|
+
"""The member landing's parent, while that landing is the unpublished bound tip."""
|
|
771
|
+
checkout, _, entry = isolation._member_context(repo, member)
|
|
772
|
+
bound = entry["branch"]
|
|
773
|
+
if _run_git(checkout, "rev-parse", f"refs/heads/{bound}").stdout.strip() != landing:
|
|
774
|
+
raise UndoError(f"member {member} {bound} moved past this landing")
|
|
775
|
+
_require_member_unpublished(checkout, member, landing, bound)
|
|
776
|
+
return _run_git(checkout, "rev-parse", f"{landing}^").stdout.strip()
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
def _require_member_unpublished(checkout: Path, member: str, landing: str, bound: str) -> None:
|
|
780
|
+
for ref, where in (("refs/remotes/origin/main", "origin/main"), (f"refs/remotes/origin/{bound}", f"origin/{bound}")):
|
|
781
|
+
if _run_git(checkout, "merge-base", "--is-ancestor", landing, ref, check=False).returncode == 0:
|
|
782
|
+
raise UndoError(f"member {member} landing is already on {where}")
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def _require_no_member_landing_journal(repo: Path) -> None:
|
|
786
|
+
directory = isolation.common_git_dir(repo).joinpath(*isolation.MEMBER_LANDING_DIR)
|
|
787
|
+
if any(directory.glob("*.json")):
|
|
788
|
+
raise UndoError("member landing journal is pending; recover member landing first")
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
def _undo_member_landing(repo: Path, transaction: dict[str, object]) -> None:
|
|
792
|
+
"""Reset the member bound branch first; a resumed undo finds it already reset."""
|
|
793
|
+
member = str(transaction["member"])
|
|
794
|
+
checkout, _, entry = isolation._member_context(repo, member)
|
|
795
|
+
tip = _run_git(checkout, "rev-parse", f"refs/heads/{entry['branch']}").stdout.strip()
|
|
796
|
+
if tip == transaction["member_parent"]:
|
|
797
|
+
_require_member_unpublished(checkout, member, str(transaction["landing"]), entry["branch"])
|
|
798
|
+
return
|
|
799
|
+
if tip != transaction["landing"]:
|
|
800
|
+
raise UndoError(f"member {member} bound branch moved during undo")
|
|
801
|
+
if _member_undo_parent(repo, member, str(transaction["landing"])) != transaction["member_parent"]:
|
|
802
|
+
raise UndoError(f"member {member} landing parent changed during undo")
|
|
803
|
+
bound = Path(isolation.member_bound_checkout(repo, member)["checkout"])
|
|
804
|
+
if _run_git(bound, "status", "--porcelain", "--untracked-files=all").stdout:
|
|
805
|
+
raise UndoError(f"member {member} bound checkout is dirty")
|
|
806
|
+
_run_git(bound, "reset", "--hard", str(transaction["member_parent"]))
|
|
807
|
+
|
|
808
|
+
|
|
665
809
|
def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
|
|
810
|
+
if transaction["kind"] == "member-task":
|
|
811
|
+
with isolation._member_landing_lock(repo):
|
|
812
|
+
_finish_transaction_locked(repo, transaction)
|
|
813
|
+
return
|
|
814
|
+
_finish_transaction_locked(repo, transaction)
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
def _finish_transaction_locked(repo: Path, transaction: dict[str, object]) -> None:
|
|
818
|
+
if transaction["kind"] == "member-task":
|
|
819
|
+
_require_no_member_landing_journal(repo)
|
|
666
820
|
stage = _transaction_recovery_stage(repo, transaction)
|
|
821
|
+
if transaction["kind"] == "member-task":
|
|
822
|
+
_undo_member_landing(repo, transaction)
|
|
667
823
|
if stage == "prepared":
|
|
668
824
|
_require_unpublished_reset(repo, str(transaction["branch"]))
|
|
669
825
|
_reset_to(repo, str(transaction["parent"]))
|
|
@@ -675,11 +831,7 @@ def _finish_transaction(repo: Path, transaction: dict[str, object]) -> None:
|
|
|
675
831
|
_remove_untracked_tree(repo, archive)
|
|
676
832
|
path = _git_path(repo, UNDO_TRANSACTION_NAME)
|
|
677
833
|
path.unlink()
|
|
678
|
-
|
|
679
|
-
try:
|
|
680
|
-
os.fsync(descriptor)
|
|
681
|
-
finally:
|
|
682
|
-
os.close(descriptor)
|
|
834
|
+
pipeline_state._common.fsync_directory(path.parent)
|
|
683
835
|
|
|
684
836
|
|
|
685
837
|
def classify_undo(repo: Path) -> dict[str, object]:
|
|
@@ -821,6 +973,28 @@ def classify_undo(repo: Path) -> dict[str, object]:
|
|
|
821
973
|
proof_error = _task_proof_error(resolved, head)
|
|
822
974
|
if proof_error:
|
|
823
975
|
return _blocked([f"task landing ownership is unproven: {proof_error}"])
|
|
976
|
+
record = isolation.MEMBER_RECORD_RE.search(body)
|
|
977
|
+
if record is not None:
|
|
978
|
+
try:
|
|
979
|
+
_require_no_member_landing_journal(resolved)
|
|
980
|
+
member_parent = _member_undo_parent(resolved, record["member"], record["landing"])
|
|
981
|
+
except (IsolationError, UndoError, PipelineStateError) as error:
|
|
982
|
+
return _blocked([f"member landing undo is unsafe: {error}"])
|
|
983
|
+
return {
|
|
984
|
+
"kind": "member-task",
|
|
985
|
+
"branch": recorded_branch,
|
|
986
|
+
"head": head,
|
|
987
|
+
"parent": parent,
|
|
988
|
+
"subject": subject,
|
|
989
|
+
"member": record["member"],
|
|
990
|
+
"landing": record["landing"],
|
|
991
|
+
"member_parent": member_parent,
|
|
992
|
+
"effects": [
|
|
993
|
+
f"reset member {record['member']} bound branch to {member_parent}",
|
|
994
|
+
f"reset {recorded_branch} to {parent}",
|
|
995
|
+
],
|
|
996
|
+
"blocked": [],
|
|
997
|
+
}
|
|
824
998
|
return {
|
|
825
999
|
"kind": "task",
|
|
826
1000
|
"branch": recorded_branch,
|
|
@@ -978,6 +1152,20 @@ def apply_undo(repo: Path, kind: str, expected_head: str) -> dict[str, object]:
|
|
|
978
1152
|
discussion,
|
|
979
1153
|
)
|
|
980
1154
|
_finish_transaction(resolved, transaction)
|
|
1155
|
+
elif kind == "member-task":
|
|
1156
|
+
with isolation._member_landing_lock(resolved):
|
|
1157
|
+
_require_no_member_landing_journal(resolved)
|
|
1158
|
+
if preview(resolved)["target"] != target:
|
|
1159
|
+
raise UndoError("member task undo target changed after preview")
|
|
1160
|
+
if _worktree_changes(resolved):
|
|
1161
|
+
raise UndoError("worktree changed after member task undo preview")
|
|
1162
|
+
_require_unpublished_reset(resolved, str(target["branch"]))
|
|
1163
|
+
transaction = _prepare_transaction(
|
|
1164
|
+
resolved, kind, expected_head, str(target["parent"]), str(target["branch"]), None, None,
|
|
1165
|
+
{"member": str(target["member"]), "landing": str(target["landing"]),
|
|
1166
|
+
"member_parent": str(target["member_parent"])},
|
|
1167
|
+
)
|
|
1168
|
+
_finish_transaction_locked(resolved, transaction)
|
|
981
1169
|
elif kind == "task":
|
|
982
1170
|
parent = target["parent"]
|
|
983
1171
|
if not parent:
|
|
@@ -470,7 +470,7 @@ def merge_artifacts(
|
|
|
470
470
|
lines.append(artifact["text"].rstrip())
|
|
471
471
|
lines.append("")
|
|
472
472
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
473
|
-
output.
|
|
473
|
+
output.write_bytes(("\n".join(lines).rstrip() + "\n").encode("utf-8"))
|
|
474
474
|
return {
|
|
475
475
|
"output": str(output.resolve()),
|
|
476
476
|
"families": families,
|
|
@@ -13,10 +13,34 @@ import os
|
|
|
13
13
|
import tempfile
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
import _common
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
if __package__:
|
|
17
|
+
from . import _common
|
|
18
|
+
else:
|
|
19
|
+
try:
|
|
20
|
+
import _common
|
|
21
|
+
except ImportError:
|
|
22
|
+
from scripts import _common
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _worktree_list_porcelain(primary: Path) -> tuple[str, bool]:
|
|
26
|
+
try:
|
|
27
|
+
if __package__:
|
|
28
|
+
from . import pipeline_git as pg
|
|
29
|
+
else:
|
|
30
|
+
from scripts import pipeline_git as pg
|
|
31
|
+
except ImportError:
|
|
32
|
+
try:
|
|
33
|
+
import pipeline_git as pg
|
|
34
|
+
except ImportError:
|
|
35
|
+
pg = None
|
|
36
|
+
if pg is not None:
|
|
37
|
+
return pg.worktree_list_porcelain(primary)
|
|
38
|
+
try:
|
|
39
|
+
output = _git(primary, "worktree", "list", "--porcelain", "-z")
|
|
40
|
+
return output, True
|
|
41
|
+
except ValueError:
|
|
42
|
+
output = _git(primary, "worktree", "list", "--porcelain")
|
|
43
|
+
return output, False
|
|
20
44
|
|
|
21
45
|
|
|
22
46
|
def _git(primary: Path, *args: str) -> str:
|
|
@@ -27,7 +51,10 @@ def _git(primary: Path, *args: str) -> str:
|
|
|
27
51
|
|
|
28
52
|
|
|
29
53
|
def _identity(path: Path) -> str:
|
|
30
|
-
|
|
54
|
+
digest = hashlib.sha256(os.fsencode(path)).hexdigest()
|
|
55
|
+
# Two identities nest in every managed path; full digests would use about
|
|
56
|
+
# 130 of Windows' 260-character MAX_PATH before any repository content.
|
|
57
|
+
return digest[:16] if os.name == "nt" else digest
|
|
31
58
|
|
|
32
59
|
|
|
33
60
|
def _workspace(primary: Path, pin: bool) -> Path:
|
|
@@ -65,7 +92,7 @@ def _workspace(primary: Path, pin: bool) -> Path:
|
|
|
65
92
|
receipt.parent.mkdir(parents=True, exist_ok=True)
|
|
66
93
|
fd, temporary = tempfile.mkstemp(dir=receipt.parent)
|
|
67
94
|
try:
|
|
68
|
-
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
95
|
+
with os.fdopen(fd, "w", encoding="utf-8", newline="\n") as handle:
|
|
69
96
|
json.dump({"primary": str(primary), "root": str(workspace)}, handle)
|
|
70
97
|
try:
|
|
71
98
|
os.link(temporary, receipt)
|
|
@@ -76,17 +103,52 @@ def _workspace(primary: Path, pin: bool) -> Path:
|
|
|
76
103
|
return workspace
|
|
77
104
|
|
|
78
105
|
|
|
106
|
+
def release_workspace(primary: Path) -> bool:
|
|
107
|
+
"""Forget the pinned placement receipt once no linked worktrees remain.
|
|
108
|
+
|
|
109
|
+
Lets GSD_PATH_WORKTREE_ROOT (or a new default) apply again at the next
|
|
110
|
+
milestone's first allocation. Returns True when a receipt was removed;
|
|
111
|
+
any remaining linked worktree (including one only still registered) keeps
|
|
112
|
+
the pin.
|
|
113
|
+
"""
|
|
114
|
+
primary = primary.resolve()
|
|
115
|
+
common = Path(_git(primary, "rev-parse", "--git-common-dir"))
|
|
116
|
+
common = (primary / common).resolve()
|
|
117
|
+
receipt = common / "gsd-path" / "workspaces" / f"{_identity(primary)}.json"
|
|
118
|
+
if not receipt.is_file():
|
|
119
|
+
return False
|
|
120
|
+
output, nul_separated = _worktree_list_porcelain(primary)
|
|
121
|
+
records = output.split("\0\0") if nul_separated else [
|
|
122
|
+
block for block in output.strip().split("\n\n") if block.strip()
|
|
123
|
+
]
|
|
124
|
+
for record in records:
|
|
125
|
+
fields = record.split("\0") if nul_separated else record.splitlines()
|
|
126
|
+
for field in fields:
|
|
127
|
+
if field.startswith("worktree ") and Path(field[len("worktree "):]).resolve() != primary:
|
|
128
|
+
return False
|
|
129
|
+
receipt.unlink()
|
|
130
|
+
return True
|
|
131
|
+
|
|
132
|
+
|
|
79
133
|
def worktree_path(primary: Path, kind: str, name: str, *, pin: bool = False) -> Path:
|
|
80
134
|
primary = primary.resolve()
|
|
81
|
-
if kind not in {"task", "verify", "integrate"} or not name or Path(name).name != name or name in {".", ".."}:
|
|
135
|
+
if kind not in {"task", "verify", "integrate", "bound"} or not name or Path(name).name != name or name in {".", ".."}:
|
|
82
136
|
raise ValueError("invalid managed worktree kind or name")
|
|
137
|
+
if kind == "bound":
|
|
138
|
+
return _workspace(primary, pin) / kind / name
|
|
83
139
|
legacy = (primary.parent / f".{primary.name}-gsd-path-integrate-{name}"
|
|
84
140
|
if kind == "integrate" else primary.parent / f"{primary.name}.gsd-path" / kind / name)
|
|
85
141
|
branch = f"refs/heads/gsd-path-{kind}/{name}"
|
|
86
|
-
|
|
142
|
+
output, nul_separated = _worktree_list_porcelain(primary)
|
|
143
|
+
if nul_separated:
|
|
144
|
+
records = output.split("\0\0")
|
|
145
|
+
else:
|
|
146
|
+
records = [block for block in output.strip().split("\n\n") if block.strip()]
|
|
87
147
|
for record in records:
|
|
88
|
-
fields = record.split("\0")
|
|
89
|
-
|
|
148
|
+
fields = record.split("\0") if nul_separated else record.splitlines()
|
|
149
|
+
# Compare as paths: git prints forward slashes on Windows.
|
|
150
|
+
worktrees = [Path(field[len("worktree "):]) for field in fields if field.startswith("worktree ")]
|
|
151
|
+
if legacy in worktrees and f"branch {branch}" in fields:
|
|
90
152
|
return legacy
|
|
91
153
|
# Keep collision checks and missing-directory recovery at the old location.
|
|
92
154
|
if os.path.lexists(legacy):
|
|
@@ -3,7 +3,8 @@ name: gsd-path-inspect
|
|
|
3
3
|
description: Inspect an existing codebase and its documentation to establish brownfield ground truth before intent is defined. Use only when the user explicitly invokes $gsd-path-inspect or an active $gsd-path router explicitly routes to this phase.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Before executing project helpers, read [runtime selection](references/runtime-selection.md)
|
|
6
|
+
Before executing project helpers, read [runtime selection](references/runtime-selection.md)
|
|
7
|
+
and [operating rules](references/operating-rules.md).
|
|
7
8
|
|
|
8
9
|
# GSD Path Inspect Phase
|
|
9
10
|
|
|
@@ -112,15 +113,15 @@ Preparation never changes phase state; neither command dispatches agents.
|
|
|
112
113
|
includes its path and revision for project commands; expected new pipeline
|
|
113
114
|
artifacts do not make product code dirty. Each agent writes only its
|
|
114
115
|
assigned output under that sidecar and keeps it there for the gates in step
|
|
115
|
-
3. Otherwise no
|
|
116
|
+
3; its `Repo root` header still names the absolute primary. Otherwise no
|
|
116
117
|
project command may run. The docs-auditor brief carries current HEAD as the
|
|
117
118
|
audit baseline only when its verify sidecar was created at HEAD; otherwise
|
|
118
119
|
it carries `none`. The auditor writes that baseline as `Audited HEAD`.
|
|
119
120
|
3. Gate both artifacts against their templates: the codebase evidence needs
|
|
120
121
|
a filled `## Map` plus findings as observed — no quota, but an empty
|
|
121
122
|
findings section must say why; the docs audit must pass the bundled
|
|
122
|
-
`python3 <absolute check_docs_audit.py> --repo <docs sidecar> --
|
|
123
|
-
<track-relative DOCS-AUDIT.md> --inventory <frozen inventory file>`, where
|
|
123
|
+
`python3 <absolute check_docs_audit.py> --repo <docs sidecar> --primary
|
|
124
|
+
<absolute primary> --audit <track-relative DOCS-AUDIT.md> --inventory <frozen inventory file>`, where
|
|
124
125
|
the audit path is `.project/research/DOCS-AUDIT.md` normally and
|
|
125
126
|
`.project/next/research/DOCS-AUDIT.md` in Lookahead mode; add
|
|
126
127
|
`--prior-audit <temporary prior-audit file>` when one was preserved and
|
|
@@ -10,7 +10,8 @@ change nothing outside your single output file.
|
|
|
10
10
|
- Read AGENTS.md and the template before scanning. Stop on a missing path.
|
|
11
11
|
- Write only the assigned output using the template. When the brief supplies a
|
|
12
12
|
disposable root, write the output under that root at the relative handoff
|
|
13
|
-
path; the orchestrator transfers it after validation.
|
|
13
|
+
path; the orchestrator transfers it after validation. `Repo root` still names
|
|
14
|
+
the primary repo root, never the disposable root. Do not ask the user
|
|
14
15
|
questions.
|
|
15
16
|
|
|
16
17
|
## What to establish
|
|
@@ -44,6 +44,19 @@ use exactly one matching branch:
|
|
|
44
44
|
create another worktree. Encode task dependencies explicitly; launch
|
|
45
45
|
independent children concurrently up to the host's advertised
|
|
46
46
|
concurrent-subagent capacity.
|
|
47
|
+
- A `muse.subagent_spawn` tool (with `muse.subagent_wait`,
|
|
48
|
+
`muse.subagent_read_result`, and `muse.subagent_send_message` siblings) is
|
|
49
|
+
Muse Code. Omit `subagent_type` (general-purpose, full capability), pass the
|
|
50
|
+
logical task name as `task_name` and `role`, and the complete brief as
|
|
51
|
+
`objective`. Never set `worktree_isolation`. Keep the returned
|
|
52
|
+
`subagent_id`; send a correction to a still-live child with
|
|
53
|
+
`muse.subagent_send_message` mode `followup` and the complete new prompt,
|
|
54
|
+
otherwise start a fresh child. Collect with `muse.subagent_wait`
|
|
55
|
+
(`wait_for: task_terminal`) then `muse.subagent_read_result`; on
|
|
56
|
+
`root_capacity_exhausted`, wait for a child to finish and retry. Spawn has no
|
|
57
|
+
model or effort argument, so record no such capability. If only
|
|
58
|
+
`muse.workflow` is exposed (untrusted workspace), do not script or inline
|
|
59
|
+
the work; stop and report that the workspace must be trusted.
|
|
47
60
|
|
|
48
61
|
For every branch:
|
|
49
62
|
|
|
@@ -11,7 +11,8 @@ actually does. Read-only: change nothing outside your single output file.
|
|
|
11
11
|
- Read AGENTS.md and the template before auditing. Stop on a missing path.
|
|
12
12
|
- Write only the assigned output using the template. When the brief supplies a
|
|
13
13
|
disposable root, write the output under that root at the relative handoff
|
|
14
|
-
path; the orchestrator transfers it after validation.
|
|
14
|
+
path; the orchestrator transfers it after validation. `Repo root` still names
|
|
15
|
+
the primary repo root, never the disposable root. Do not ask the user
|
|
15
16
|
questions.
|
|
16
17
|
|
|
17
18
|
## Method
|
|
@@ -58,6 +59,11 @@ actually does. Read-only: change nothing outside your single output file.
|
|
|
58
59
|
5. **Classify remediation** for every non-verified claim: `fix-doc`,
|
|
59
60
|
`fix-code`, or `NEEDS-USER` when the right side of the conflict is not
|
|
60
61
|
yours to decide.
|
|
62
|
+
Number queue rows with unique, strictly increasing positive integers; they
|
|
63
|
+
need not be contiguous. A row that persists from the prior audit keeps its
|
|
64
|
+
number. A new row takes a number greater than every prior queue number and
|
|
65
|
+
every `## User rulings` Queue #. Never reuse a retired number: a ruling
|
|
66
|
+
stays bound to the item it was made for.
|
|
61
67
|
|
|
62
68
|
## Rules
|
|
63
69
|
|