@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
package/scripts/pipeline_undo.py
CHANGED
|
@@ -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:
|
|
@@ -205,7 +205,7 @@ def select_fetched_base(
|
|
|
205
205
|
resolved = subprocess.run(
|
|
206
206
|
["git", "-C", str(root), "rev-parse", "--verify", f"{remote_default}^{{commit}}"],
|
|
207
207
|
capture_output=True,
|
|
208
|
-
|
|
208
|
+
encoding="utf-8", errors="replace",
|
|
209
209
|
check=False,
|
|
210
210
|
)
|
|
211
211
|
if resolved.returncode != 0 or resolved.stdout.strip() != base:
|
package/scripts/review_panel.py
CHANGED
|
@@ -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,
|
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,42 @@ 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
|
+
# Optional owner-recorded provenance on .gsd-path/runtime.json declarations,
|
|
31
|
+
# e.g. {"source": "<npm version or package id>", "patch_ref": "<commit sha
|
|
32
|
+
# or patch list>", "note": "<owner label>"}. Provenance is display/audit
|
|
33
|
+
# metadata ONLY: it never joins the hashed manifest input (manifest_digest
|
|
34
|
+
# covers exactly {"version", "files"}), never acts as an alternate accepted
|
|
35
|
+
# digest, and never bypasses or weakens validate_runtime. A declaration
|
|
36
|
+
# without provenance is stock and stays exactly as valid as one with it.
|
|
37
|
+
PROVENANCE_KEYS = ("source", "patch_ref", "note")
|
|
38
|
+
|
|
39
|
+
# Access denied and sharing violation: on Windows a scanner or indexer that
|
|
40
|
+
# briefly opens a freshly written file blocks renaming the directory holding it.
|
|
41
|
+
_WINDOWS_BUSY_ERRORS = (5, 32)
|
|
42
|
+
_RENAME_ATTEMPTS = 20
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _rename_directory(source, destination):
|
|
46
|
+
"""Path.rename, retried while Windows briefly holds a file inside ``source``."""
|
|
47
|
+
if os.name != "nt":
|
|
48
|
+
source.rename(destination)
|
|
49
|
+
return
|
|
50
|
+
for attempt in range(_RENAME_ATTEMPTS):
|
|
51
|
+
try:
|
|
52
|
+
source.rename(destination)
|
|
53
|
+
return
|
|
54
|
+
except PermissionError as error:
|
|
55
|
+
# Never retry onto a directory that appeared meanwhile.
|
|
56
|
+
if (getattr(error, "winerror", None) not in _WINDOWS_BUSY_ERRORS
|
|
57
|
+
or os.path.lexists(destination)
|
|
58
|
+
or attempt == _RENAME_ATTEMPTS - 1):
|
|
59
|
+
raise
|
|
60
|
+
time.sleep(min(0.01 * 2 ** attempt, 0.25))
|
|
61
|
+
|
|
29
62
|
|
|
30
63
|
def guard_launcher(name):
|
|
31
64
|
if name not in GUARDS:
|
|
@@ -41,7 +74,7 @@ def guard_launcher(name):
|
|
|
41
74
|
|
|
42
75
|
|
|
43
76
|
def source_manifest(source):
|
|
44
|
-
version = json.loads((source / "package.json").read_text())["version"]
|
|
77
|
+
version = json.loads((source / "package.json").read_text(encoding="utf-8"))["version"]
|
|
45
78
|
files = {}
|
|
46
79
|
for name in (*RUNTIME_FILES, *GUARDS, "status_runtime.py"):
|
|
47
80
|
path = source / "scripts" / name
|
|
@@ -107,7 +140,7 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
|
|
|
107
140
|
shutil.copyfile(source / "scripts" / name, staging / name)
|
|
108
141
|
if hashlib.sha256((staging / name).read_bytes()).hexdigest() != digest:
|
|
109
142
|
raise ValueError(f"runtime source changed while installing: {name}")
|
|
110
|
-
(staging / "manifest.json").
|
|
143
|
+
(staging / "manifest.json").write_bytes(pin_text(manifest).encode("utf-8"))
|
|
111
144
|
# Serialize publication/repair, including two explicit restorations.
|
|
112
145
|
previous = Path(temporary) / "previous"
|
|
113
146
|
with publication_lock(parent, pin["digest"]):
|
|
@@ -118,13 +151,13 @@ def publish(source, *, expected=None, dry_run=False, repair=False):
|
|
|
118
151
|
except ValueError:
|
|
119
152
|
if not repair:
|
|
120
153
|
raise
|
|
121
|
-
destination
|
|
154
|
+
_rename_directory(destination, previous)
|
|
122
155
|
try:
|
|
123
|
-
staging
|
|
156
|
+
_rename_directory(staging, destination)
|
|
124
157
|
status_runtime.validate_runtime(pin)
|
|
125
158
|
except BaseException:
|
|
126
159
|
if previous.exists() and not destination.exists():
|
|
127
|
-
previous
|
|
160
|
+
_rename_directory(previous, destination)
|
|
128
161
|
raise
|
|
129
162
|
return pin
|
|
130
163
|
|
|
@@ -167,7 +200,7 @@ def recover_migration(project):
|
|
|
167
200
|
return
|
|
168
201
|
if journal.is_symlink():
|
|
169
202
|
raise ValueError(f"unsafe runtime migration journal: {journal}")
|
|
170
|
-
data = json.loads(journal.read_text())
|
|
203
|
+
data = json.loads(journal.read_text(encoding="utf-8"))
|
|
171
204
|
recorded_project = data.get("project")
|
|
172
205
|
if (data.get("schema") != "gsd-path/runtime-migration/v1"
|
|
173
206
|
or not isinstance(recorded_project, str)
|
|
@@ -196,7 +229,7 @@ def recover_migration(project):
|
|
|
196
229
|
journal.unlink()
|
|
197
230
|
|
|
198
231
|
|
|
199
|
-
def operate(source, project, action, *, dry_run=False):
|
|
232
|
+
def operate(source, project, action, *, dry_run=False, provenance=None):
|
|
200
233
|
if project.is_symlink() or (project / ".gsd-path").is_symlink():
|
|
201
234
|
raise ValueError("unsafe project runtime directory")
|
|
202
235
|
if action == "restore":
|
|
@@ -204,12 +237,23 @@ def operate(source, project, action, *, dry_run=False):
|
|
|
204
237
|
publish(source, expected=pin, dry_run=dry_run, repair=True)
|
|
205
238
|
return pin
|
|
206
239
|
if action == "upgrade":
|
|
207
|
-
status_runtime.declaration(project)
|
|
240
|
+
previous = status_runtime.declaration(project)
|
|
208
241
|
pin = publish(source, dry_run=dry_run)
|
|
242
|
+
# Explicit provenance replaces the recorded object. Without new flags,
|
|
243
|
+
# an existing entry carries forward only while the pinned digest is
|
|
244
|
+
# unchanged — a different source drops stale hotfix metadata instead
|
|
245
|
+
# of stamping it onto bytes it no longer describes. Metadata only —
|
|
246
|
+
# it never changes the pinned digest.
|
|
247
|
+
if provenance is None and previous.get("digest") == pin["digest"]:
|
|
248
|
+
provenance = previous.get("provenance")
|
|
249
|
+
if provenance:
|
|
250
|
+
pin = {**pin, "provenance": provenance}
|
|
209
251
|
if not dry_run:
|
|
210
252
|
launcher = project / ".gsd-path/status_runtime.py"
|
|
211
|
-
|
|
212
|
-
|
|
253
|
+
# Exact bytes: read_text() would turn CRLF into LF, leaving the
|
|
254
|
+
# launcher unequal to the runtime's byte-for-byte copy.
|
|
255
|
+
original = launcher.read_bytes().decode("utf-8")
|
|
256
|
+
replacement = (source / "scripts/status_runtime.py").read_bytes().decode("utf-8")
|
|
213
257
|
# Both launchers understand the same declaration schema. Publishing
|
|
214
258
|
# the compatible launcher first leaves the old selection usable.
|
|
215
259
|
if replacement != original:
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"cursor": {"local_root": ".cursor/skills", "guard_tier": "native-fail-closed", "child_apis": ["Task"]},
|
|
11
11
|
"zed": {"local_root": ".agents/skills", "guard_tier": "git-only", "invocation_prefix": "/", "child_apis": ["spawn_agent"]},
|
|
12
12
|
"kiro": {"local_root": ".kiro/skills", "guard_tier": "git-only", "child_apis": ["invoke_sub_agent"]},
|
|
13
|
-
"kimi": {"local_root": ".kimi-code/skills", "guard_tier": "git-only", "child_apis": ["Agent"]}
|
|
13
|
+
"kimi": {"local_root": ".kimi-code/skills", "guard_tier": "git-only", "child_apis": ["Agent"]},
|
|
14
|
+
"muse": {"local_root": ".agents/skills", "guard_tier": "git-only", "invocation_prefix": "/", "child_apis": ["muse.subagent_spawn"]}
|
|
14
15
|
},
|
|
15
16
|
"skills": [
|
|
16
17
|
"gsd-path",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"scripts/integration.py",
|
|
56
57
|
"scripts/archive_milestone.py",
|
|
57
58
|
"scripts/bootstrap_repository.py",
|
|
59
|
+
"scripts/members.py",
|
|
58
60
|
"scripts/detect_project.py",
|
|
59
61
|
"scripts/promote_lookahead.py",
|
|
60
62
|
"scripts/discussion_records.py",
|
|
@@ -95,11 +97,14 @@
|
|
|
95
97
|
"skills/",
|
|
96
98
|
"platforms/",
|
|
97
99
|
"AGENTS.md",
|
|
98
|
-
"WORKFLOW.md"
|
|
100
|
+
"WORKFLOW.md",
|
|
101
|
+
"!**/__pycache__/**",
|
|
102
|
+
"!**/*.pyc"
|
|
99
103
|
],
|
|
100
104
|
"phase_resources": {
|
|
101
105
|
"gsd-path-build": [
|
|
102
106
|
"references/runtime-selection.md",
|
|
107
|
+
"references/operating-rules.md",
|
|
103
108
|
"references/build-recovery.md",
|
|
104
109
|
"references/build-native.md",
|
|
105
110
|
"references/build-abandon.md",
|
|
@@ -112,6 +117,7 @@
|
|
|
112
117
|
"references/reviewer-skeptic.md",
|
|
113
118
|
"references/reviewer-final.md",
|
|
114
119
|
"references/reviewer-panel.md",
|
|
120
|
+
"references/spec-probes.md",
|
|
115
121
|
|
|
116
122
|
"templates/task.md",
|
|
117
123
|
"templates/wave-review.md",
|
|
@@ -120,11 +126,13 @@
|
|
|
120
126
|
],
|
|
121
127
|
"gsd-path-discuss": [
|
|
122
128
|
"references/runtime-selection.md",
|
|
129
|
+
"references/operating-rules.md",
|
|
123
130
|
"templates/answers.md",
|
|
124
131
|
"templates/dialogue.md"
|
|
125
132
|
],
|
|
126
133
|
"gsd-path-docs-audit": [
|
|
127
134
|
"references/runtime-selection.md",
|
|
135
|
+
"references/operating-rules.md",
|
|
128
136
|
"references/dispatch.md",
|
|
129
137
|
"references/model-policy.md",
|
|
130
138
|
"references/docs-auditor.md",
|
|
@@ -132,13 +140,16 @@
|
|
|
132
140
|
],
|
|
133
141
|
"gsd-path-define": [
|
|
134
142
|
"references/runtime-selection.md",
|
|
143
|
+
"references/operating-rules.md",
|
|
135
144
|
"references/build-recovery.md",
|
|
145
|
+
"references/spec-probes.md",
|
|
136
146
|
"templates/charter.md",
|
|
137
147
|
"templates/intent.md",
|
|
138
148
|
"templates/state.md"
|
|
139
149
|
],
|
|
140
150
|
"gsd-path-inspect": [
|
|
141
151
|
"references/runtime-selection.md",
|
|
152
|
+
"references/operating-rules.md",
|
|
142
153
|
"references/codebase-mapper.md",
|
|
143
154
|
"references/dispatch.md",
|
|
144
155
|
"references/model-policy.md",
|
|
@@ -148,21 +159,26 @@
|
|
|
148
159
|
"templates/state.md"
|
|
149
160
|
],
|
|
150
161
|
"gsd-path-forensics": [
|
|
151
|
-
"references/runtime-selection.md"
|
|
162
|
+
"references/runtime-selection.md",
|
|
163
|
+
"references/operating-rules.md"
|
|
152
164
|
],
|
|
153
165
|
"gsd-path-migrate": [
|
|
154
|
-
"references/runtime-selection.md"
|
|
166
|
+
"references/runtime-selection.md",
|
|
167
|
+
"references/operating-rules.md"
|
|
155
168
|
],
|
|
156
169
|
"gsd-path-loop": [
|
|
157
170
|
"references/runtime-selection.md",
|
|
171
|
+
"references/operating-rules.md",
|
|
158
172
|
"templates/loop.md"
|
|
159
173
|
],
|
|
160
174
|
"gsd-path-plan": [
|
|
161
175
|
"references/runtime-selection.md",
|
|
176
|
+
"references/operating-rules.md",
|
|
162
177
|
"references/build-recovery.md",
|
|
163
178
|
"references/dispatch.md",
|
|
164
179
|
"references/model-policy.md",
|
|
165
180
|
"references/planner.md",
|
|
181
|
+
"references/spec-probes.md",
|
|
166
182
|
"templates/patch-findings.md",
|
|
167
183
|
"templates/plan.md",
|
|
168
184
|
"templates/plan-panel.md",
|
|
@@ -170,6 +186,7 @@
|
|
|
170
186
|
],
|
|
171
187
|
"gsd-path-research": [
|
|
172
188
|
"references/runtime-selection.md",
|
|
189
|
+
"references/operating-rules.md",
|
|
173
190
|
"references/dispatch.md",
|
|
174
191
|
"references/model-policy.md",
|
|
175
192
|
"references/researcher.md",
|
|
@@ -178,6 +195,7 @@
|
|
|
178
195
|
],
|
|
179
196
|
"gsd-path-roadmap": [
|
|
180
197
|
"references/runtime-selection.md",
|
|
198
|
+
"references/operating-rules.md",
|
|
181
199
|
"references/dispatch.md",
|
|
182
200
|
"references/model-policy.md",
|
|
183
201
|
"references/roadmapper.md",
|
|
@@ -185,6 +203,7 @@
|
|
|
185
203
|
],
|
|
186
204
|
"gsd-path-ship": [
|
|
187
205
|
"references/runtime-selection.md",
|
|
206
|
+
"references/operating-rules.md",
|
|
188
207
|
"references/dispatch.md",
|
|
189
208
|
"references/model-policy.md",
|
|
190
209
|
"references/reviewer.md",
|
|
@@ -193,6 +212,7 @@
|
|
|
193
212
|
"references/reviewer-skeptic.md",
|
|
194
213
|
"references/reviewer-final.md",
|
|
195
214
|
"references/reviewer-panel.md",
|
|
215
|
+
"references/spec-probes.md",
|
|
196
216
|
|
|
197
217
|
"templates/archive-manifest.md",
|
|
198
218
|
"templates/final-review.md",
|
|
@@ -202,13 +222,15 @@
|
|
|
202
222
|
],
|
|
203
223
|
"gsd-path-decide": [
|
|
204
224
|
"references/runtime-selection.md",
|
|
225
|
+
"references/operating-rules.md",
|
|
205
226
|
"references/dispatch.md",
|
|
206
227
|
"references/model-policy.md",
|
|
207
228
|
"references/decider.md",
|
|
208
229
|
"templates/synthesis.md"
|
|
209
230
|
],
|
|
210
231
|
"gsd-path-undo": [
|
|
211
|
-
"references/runtime-selection.md"
|
|
232
|
+
"references/runtime-selection.md",
|
|
233
|
+
"references/operating-rules.md"
|
|
212
234
|
]
|
|
213
235
|
},
|
|
214
236
|
"script_targets": [
|
|
@@ -259,6 +281,16 @@
|
|
|
259
281
|
["scripts/discussion_validate.py", "skills/gsd-path-ship/scripts/discussion_validate.py"],
|
|
260
282
|
["scripts/integration.py", "skills/gsd-path-ship/scripts/integration.py"],
|
|
261
283
|
["scripts/bootstrap_repository.py", "skills/gsd-path/scripts/bootstrap_repository.py"],
|
|
284
|
+
["scripts/members.py", "skills/gsd-path/scripts/members.py"],
|
|
285
|
+
["scripts/members.py", "skills/gsd-path-build/scripts/members.py"],
|
|
286
|
+
["scripts/members.py", "skills/gsd-path-decide/scripts/members.py"],
|
|
287
|
+
["scripts/members.py", "skills/gsd-path-define/scripts/members.py"],
|
|
288
|
+
["scripts/members.py", "skills/gsd-path-docs-audit/scripts/members.py"],
|
|
289
|
+
["scripts/members.py", "skills/gsd-path-inspect/scripts/members.py"],
|
|
290
|
+
["scripts/members.py", "skills/gsd-path-plan/scripts/members.py"],
|
|
291
|
+
["scripts/members.py", "skills/gsd-path-research/scripts/members.py"],
|
|
292
|
+
["scripts/members.py", "skills/gsd-path-roadmap/scripts/members.py"],
|
|
293
|
+
["scripts/members.py", "skills/gsd-path-ship/scripts/members.py"],
|
|
262
294
|
["scripts/detect_project.py", "skills/gsd-path/scripts/detect_project.py"],
|
|
263
295
|
["scripts/detect_project.py", "skills/gsd-path-define/scripts/detect_project.py"],
|
|
264
296
|
["scripts/detect_project.py", "skills/gsd-path-inspect/scripts/detect_project.py"],
|