@opengsd/gsd-path 1.0.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 +397 -0
- package/DOCS.md +341 -0
- package/FULL.md +475 -0
- package/GUIDE.md +23 -0
- package/HOOKS.md +273 -0
- package/LICENSE +21 -0
- package/MIGRATE.md +100 -0
- package/QUICK.md +146 -0
- package/README.md +280 -0
- package/RUNTIME.md +229 -0
- package/UPDATE.md +196 -0
- package/WORKFLOW.md +683 -0
- package/package.json +80 -0
- package/platforms/claude/dispatch.md +63 -0
- package/platforms/copilot/dispatch.md +61 -0
- package/platforms/cursor/agent.md +17 -0
- package/platforms/cursor/dispatch.md +63 -0
- package/platforms/grok/dispatch.md +61 -0
- package/platforms/kimi/dispatch.md +64 -0
- package/platforms/kiro/dispatch.md +58 -0
- package/platforms/opencode/dispatch.md +62 -0
- package/platforms/qwen/dispatch.md +60 -0
- package/platforms/shared-agents/dispatch.md +131 -0
- package/plugin.json +14 -0
- package/scripts/_common.py +180 -0
- package/scripts/archive_milestone.py +2265 -0
- package/scripts/bootstrap_repository.py +710 -0
- package/scripts/build_state.py +854 -0
- package/scripts/check_docs_audit.py +463 -0
- package/scripts/check_handoffs.py +1855 -0
- package/scripts/check_task_briefs.py +376 -0
- package/scripts/check_update.py +93 -0
- package/scripts/core_hook_gate.py +34 -0
- package/scripts/core_hook_settings.py +119 -0
- package/scripts/detect_project.py +1517 -0
- package/scripts/discussion_records.py +619 -0
- package/scripts/discussion_validate.py +1321 -0
- package/scripts/dispatch_driver.py +1812 -0
- package/scripts/git_guard.py +759 -0
- package/scripts/guard_hook.py +2124 -0
- package/scripts/install.mjs +3239 -0
- package/scripts/install.py +3008 -0
- package/scripts/integration.py +1433 -0
- package/scripts/isolation.py +3538 -0
- package/scripts/lean_verification.py +256 -0
- package/scripts/loop_run.py +837 -0
- package/scripts/migrate_core.py +169 -0
- package/scripts/pipeline_diagnose.py +715 -0
- package/scripts/pipeline_git.py +940 -0
- package/scripts/pipeline_state.py +2291 -0
- package/scripts/pipeline_undo.py +1039 -0
- package/scripts/promote_lookahead.py +415 -0
- package/scripts/review_findings.py +714 -0
- package/scripts/review_panel.py +553 -0
- package/scripts/skill-resources.json +340 -0
- package/scripts/state_checkpoint.py +1039 -0
- package/scripts/state_promote.py +743 -0
- package/scripts/status_runtime.py +122 -0
- package/scripts/sync_skill_resources.py +259 -0
- package/scripts/token_budget.py +146 -0
- package/scripts/wizard.mjs +179 -0
- package/scripts/workflow_run.py +117 -0
- package/skills/gsd-path/BUILD.md +700 -0
- package/skills/gsd-path/DECIDE.md +115 -0
- package/skills/gsd-path/DEFINE.md +297 -0
- package/skills/gsd-path/DOCS-AUDIT.md +190 -0
- package/skills/gsd-path/INSPECT.md +167 -0
- package/skills/gsd-path/PLAN.md +411 -0
- package/skills/gsd-path/RESEARCH.md +159 -0
- package/skills/gsd-path/ROADMAP.md +215 -0
- package/skills/gsd-path/SHIP.md +412 -0
- package/skills/gsd-path/SKILL.md +471 -0
- package/skills/gsd-path/agents/openai.yaml +6 -0
- package/skills/gsd-path/references/codebase-mapper.md +52 -0
- package/skills/gsd-path/references/coder.md +90 -0
- package/skills/gsd-path/references/decider.md +36 -0
- package/skills/gsd-path/references/dispatch.md +131 -0
- package/skills/gsd-path/references/docs-auditor.md +60 -0
- package/skills/gsd-path/references/planner.md +104 -0
- package/skills/gsd-path/references/researcher.md +42 -0
- package/skills/gsd-path/references/reviewer.md +188 -0
- package/skills/gsd-path/references/roadmapper.md +48 -0
- package/skills/gsd-path/scripts/_common.py +180 -0
- package/skills/gsd-path/scripts/archive_milestone.py +2265 -0
- package/skills/gsd-path/scripts/bootstrap_repository.py +710 -0
- package/skills/gsd-path/scripts/build_state.py +854 -0
- package/skills/gsd-path/scripts/check_docs_audit.py +463 -0
- package/skills/gsd-path/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path/scripts/check_update.py +93 -0
- package/skills/gsd-path/scripts/detect_project.py +1517 -0
- package/skills/gsd-path/scripts/discussion_records.py +619 -0
- package/skills/gsd-path/scripts/discussion_validate.py +1321 -0
- package/skills/gsd-path/scripts/dispatch_driver.py +1812 -0
- package/skills/gsd-path/scripts/integration.py +1433 -0
- package/skills/gsd-path/scripts/isolation.py +3538 -0
- package/skills/gsd-path/scripts/lean_verification.py +256 -0
- package/skills/gsd-path/scripts/loop_run.py +837 -0
- package/skills/gsd-path/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path/scripts/promote_lookahead.py +415 -0
- package/skills/gsd-path/scripts/review_findings.py +714 -0
- package/skills/gsd-path/scripts/review_panel.py +553 -0
- package/skills/gsd-path/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path/scripts/state_promote.py +743 -0
- package/skills/gsd-path/scripts/token_budget.py +146 -0
- package/skills/gsd-path/scripts/workflow_run.py +117 -0
- package/skills/gsd-path/templates/answers.md +29 -0
- package/skills/gsd-path/templates/archive-manifest.md +37 -0
- package/skills/gsd-path/templates/charter.md +50 -0
- package/skills/gsd-path/templates/codebase.md +46 -0
- package/skills/gsd-path/templates/dialogue.md +21 -0
- package/skills/gsd-path/templates/docs-audit.md +69 -0
- package/skills/gsd-path/templates/evidence.md +24 -0
- package/skills/gsd-path/templates/final-review.md +27 -0
- package/skills/gsd-path/templates/gap-review.md +20 -0
- package/skills/gsd-path/templates/intent.md +98 -0
- package/skills/gsd-path/templates/loop.md +59 -0
- package/skills/gsd-path/templates/patch-findings.md +16 -0
- package/skills/gsd-path/templates/plan-panel.md +25 -0
- package/skills/gsd-path/templates/plan.md +89 -0
- package/skills/gsd-path/templates/repository.md +16 -0
- package/skills/gsd-path/templates/research-handoff.md +25 -0
- package/skills/gsd-path/templates/roadmap.md +38 -0
- package/skills/gsd-path/templates/skeptic.md +36 -0
- package/skills/gsd-path/templates/state.md +27 -0
- package/skills/gsd-path/templates/synthesis.md +36 -0
- package/skills/gsd-path/templates/task.md +74 -0
- package/skills/gsd-path/templates/wave-panel.md +25 -0
- package/skills/gsd-path/templates/wave-review.md +64 -0
- package/skills/gsd-path-build/SKILL.md +700 -0
- package/skills/gsd-path-build/agents/openai.yaml +6 -0
- package/skills/gsd-path-build/references/coder.md +90 -0
- package/skills/gsd-path-build/references/dispatch.md +131 -0
- package/skills/gsd-path-build/references/reviewer.md +188 -0
- package/skills/gsd-path-build/scripts/_common.py +180 -0
- package/skills/gsd-path-build/scripts/archive_milestone.py +2265 -0
- package/skills/gsd-path-build/scripts/build_state.py +854 -0
- package/skills/gsd-path-build/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-build/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-build/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-build/scripts/discussion_validate.py +1321 -0
- package/skills/gsd-path-build/scripts/dispatch_driver.py +1812 -0
- package/skills/gsd-path-build/scripts/integration.py +1433 -0
- package/skills/gsd-path-build/scripts/isolation.py +3538 -0
- package/skills/gsd-path-build/scripts/loop_run.py +837 -0
- package/skills/gsd-path-build/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-build/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-build/scripts/review_findings.py +714 -0
- package/skills/gsd-path-build/scripts/review_panel.py +553 -0
- package/skills/gsd-path-build/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-build/scripts/state_promote.py +743 -0
- package/skills/gsd-path-build/scripts/token_budget.py +146 -0
- package/skills/gsd-path-build/scripts/workflow_run.py +117 -0
- package/skills/gsd-path-build/templates/skeptic.md +36 -0
- package/skills/gsd-path-build/templates/task.md +74 -0
- package/skills/gsd-path-build/templates/wave-panel.md +25 -0
- package/skills/gsd-path-build/templates/wave-review.md +64 -0
- package/skills/gsd-path-decide/SKILL.md +115 -0
- package/skills/gsd-path-decide/agents/openai.yaml +6 -0
- package/skills/gsd-path-decide/references/decider.md +36 -0
- package/skills/gsd-path-decide/references/dispatch.md +131 -0
- package/skills/gsd-path-decide/scripts/_common.py +180 -0
- package/skills/gsd-path-decide/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-decide/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-decide/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-decide/scripts/isolation.py +3538 -0
- package/skills/gsd-path-decide/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-decide/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-decide/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-decide/scripts/state_promote.py +743 -0
- package/skills/gsd-path-decide/templates/synthesis.md +36 -0
- package/skills/gsd-path-define/SKILL.md +297 -0
- package/skills/gsd-path-define/agents/openai.yaml +6 -0
- package/skills/gsd-path-define/scripts/_common.py +180 -0
- package/skills/gsd-path-define/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-define/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-define/scripts/detect_project.py +1517 -0
- package/skills/gsd-path-define/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-define/scripts/isolation.py +3538 -0
- package/skills/gsd-path-define/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-define/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-define/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-define/scripts/state_promote.py +743 -0
- package/skills/gsd-path-define/templates/charter.md +50 -0
- package/skills/gsd-path-define/templates/intent.md +98 -0
- package/skills/gsd-path-define/templates/state.md +27 -0
- package/skills/gsd-path-discuss/SKILL.md +162 -0
- package/skills/gsd-path-discuss/agents/openai.yaml +6 -0
- package/skills/gsd-path-discuss/scripts/_common.py +180 -0
- package/skills/gsd-path-discuss/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-discuss/templates/answers.md +29 -0
- package/skills/gsd-path-discuss/templates/dialogue.md +21 -0
- package/skills/gsd-path-docs-audit/SKILL.md +190 -0
- package/skills/gsd-path-docs-audit/agents/openai.yaml +6 -0
- package/skills/gsd-path-docs-audit/references/dispatch.md +131 -0
- package/skills/gsd-path-docs-audit/references/docs-auditor.md +60 -0
- package/skills/gsd-path-docs-audit/scripts/_common.py +180 -0
- package/skills/gsd-path-docs-audit/scripts/check_docs_audit.py +463 -0
- package/skills/gsd-path-docs-audit/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-docs-audit/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-docs-audit/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-docs-audit/scripts/isolation.py +3538 -0
- package/skills/gsd-path-docs-audit/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-docs-audit/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-docs-audit/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-docs-audit/scripts/state_promote.py +743 -0
- package/skills/gsd-path-docs-audit/templates/docs-audit.md +69 -0
- package/skills/gsd-path-forensics/SKILL.md +39 -0
- package/skills/gsd-path-forensics/agents/openai.yaml +6 -0
- package/skills/gsd-path-forensics/scripts/_common.py +180 -0
- package/skills/gsd-path-forensics/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-forensics/scripts/pipeline_diagnose.py +715 -0
- package/skills/gsd-path-forensics/scripts/pipeline_undo.py +1039 -0
- package/skills/gsd-path-inspect/SKILL.md +167 -0
- package/skills/gsd-path-inspect/agents/openai.yaml +6 -0
- package/skills/gsd-path-inspect/references/codebase-mapper.md +52 -0
- package/skills/gsd-path-inspect/references/dispatch.md +131 -0
- package/skills/gsd-path-inspect/references/docs-auditor.md +60 -0
- package/skills/gsd-path-inspect/scripts/_common.py +180 -0
- package/skills/gsd-path-inspect/scripts/check_docs_audit.py +463 -0
- package/skills/gsd-path-inspect/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-inspect/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-inspect/scripts/detect_project.py +1517 -0
- package/skills/gsd-path-inspect/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-inspect/scripts/isolation.py +3538 -0
- package/skills/gsd-path-inspect/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-inspect/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-inspect/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-inspect/scripts/state_promote.py +743 -0
- package/skills/gsd-path-inspect/templates/codebase.md +46 -0
- package/skills/gsd-path-inspect/templates/docs-audit.md +69 -0
- package/skills/gsd-path-inspect/templates/state.md +27 -0
- package/skills/gsd-path-loop/SKILL.md +98 -0
- package/skills/gsd-path-loop/agents/openai.yaml +6 -0
- package/skills/gsd-path-loop/examples/ci-repair.LOOP.md +61 -0
- package/skills/gsd-path-loop/scripts/_common.py +180 -0
- package/skills/gsd-path-loop/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-loop/scripts/loop_run.py +837 -0
- package/skills/gsd-path-loop/templates/loop.md +59 -0
- package/skills/gsd-path-migrate/SKILL.md +134 -0
- package/skills/gsd-path-migrate/agents/openai.yaml +6 -0
- package/skills/gsd-path-migrate/scripts/core_hook_gate.py +34 -0
- package/skills/gsd-path-migrate/scripts/core_hook_settings.py +119 -0
- package/skills/gsd-path-migrate/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-migrate/scripts/migrate_core.py +169 -0
- package/skills/gsd-path-plan/SKILL.md +411 -0
- package/skills/gsd-path-plan/agents/openai.yaml +6 -0
- package/skills/gsd-path-plan/references/dispatch.md +131 -0
- package/skills/gsd-path-plan/references/planner.md +104 -0
- package/skills/gsd-path-plan/scripts/_common.py +180 -0
- package/skills/gsd-path-plan/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-plan/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-plan/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-plan/scripts/isolation.py +3538 -0
- package/skills/gsd-path-plan/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-plan/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-plan/scripts/review_panel.py +553 -0
- package/skills/gsd-path-plan/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-plan/scripts/state_promote.py +743 -0
- package/skills/gsd-path-plan/scripts/workflow_run.py +117 -0
- package/skills/gsd-path-plan/templates/patch-findings.md +16 -0
- package/skills/gsd-path-plan/templates/plan-panel.md +25 -0
- package/skills/gsd-path-plan/templates/plan.md +89 -0
- package/skills/gsd-path-plan/templates/task.md +74 -0
- package/skills/gsd-path-research/SKILL.md +159 -0
- package/skills/gsd-path-research/agents/openai.yaml +6 -0
- package/skills/gsd-path-research/references/dispatch.md +131 -0
- package/skills/gsd-path-research/references/researcher.md +42 -0
- package/skills/gsd-path-research/scripts/_common.py +180 -0
- package/skills/gsd-path-research/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-research/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-research/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-research/scripts/isolation.py +3538 -0
- package/skills/gsd-path-research/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-research/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-research/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-research/scripts/state_promote.py +743 -0
- package/skills/gsd-path-research/templates/evidence.md +24 -0
- package/skills/gsd-path-research/templates/research-handoff.md +25 -0
- package/skills/gsd-path-roadmap/SKILL.md +215 -0
- package/skills/gsd-path-roadmap/agents/openai.yaml +6 -0
- package/skills/gsd-path-roadmap/references/dispatch.md +131 -0
- package/skills/gsd-path-roadmap/references/roadmapper.md +48 -0
- package/skills/gsd-path-roadmap/scripts/_common.py +180 -0
- package/skills/gsd-path-roadmap/scripts/archive_milestone.py +2265 -0
- package/skills/gsd-path-roadmap/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-roadmap/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-roadmap/scripts/detect_project.py +1517 -0
- package/skills/gsd-path-roadmap/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-roadmap/scripts/discussion_validate.py +1321 -0
- package/skills/gsd-path-roadmap/scripts/integration.py +1433 -0
- package/skills/gsd-path-roadmap/scripts/isolation.py +3538 -0
- package/skills/gsd-path-roadmap/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-roadmap/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-roadmap/scripts/promote_lookahead.py +415 -0
- package/skills/gsd-path-roadmap/scripts/review_panel.py +553 -0
- package/skills/gsd-path-roadmap/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-roadmap/scripts/state_promote.py +743 -0
- package/skills/gsd-path-roadmap/templates/roadmap.md +38 -0
- package/skills/gsd-path-ship/SKILL.md +412 -0
- package/skills/gsd-path-ship/agents/openai.yaml +6 -0
- package/skills/gsd-path-ship/references/dispatch.md +131 -0
- package/skills/gsd-path-ship/references/reviewer.md +188 -0
- package/skills/gsd-path-ship/scripts/_common.py +180 -0
- package/skills/gsd-path-ship/scripts/archive_milestone.py +2265 -0
- package/skills/gsd-path-ship/scripts/build_state.py +854 -0
- package/skills/gsd-path-ship/scripts/check_handoffs.py +1855 -0
- package/skills/gsd-path-ship/scripts/check_task_briefs.py +376 -0
- package/skills/gsd-path-ship/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-ship/scripts/discussion_validate.py +1321 -0
- package/skills/gsd-path-ship/scripts/integration.py +1433 -0
- package/skills/gsd-path-ship/scripts/isolation.py +3538 -0
- package/skills/gsd-path-ship/scripts/lean_verification.py +256 -0
- package/skills/gsd-path-ship/scripts/pipeline_git.py +940 -0
- package/skills/gsd-path-ship/scripts/pipeline_state.py +2291 -0
- package/skills/gsd-path-ship/scripts/review_panel.py +553 -0
- package/skills/gsd-path-ship/scripts/state_checkpoint.py +1039 -0
- package/skills/gsd-path-ship/scripts/state_promote.py +743 -0
- package/skills/gsd-path-ship/scripts/workflow_run.py +117 -0
- package/skills/gsd-path-ship/templates/archive-manifest.md +37 -0
- package/skills/gsd-path-ship/templates/final-review.md +27 -0
- package/skills/gsd-path-ship/templates/gap-review.md +20 -0
- package/skills/gsd-path-ship/templates/patch-findings.md +16 -0
- package/skills/gsd-path-ship/templates/wave-review.md +64 -0
- package/skills/gsd-path-undo/SKILL.md +45 -0
- package/skills/gsd-path-undo/agents/openai.yaml +6 -0
- package/skills/gsd-path-undo/scripts/_common.py +180 -0
- package/skills/gsd-path-undo/scripts/discussion_records.py +619 -0
- package/skills/gsd-path-undo/scripts/pipeline_undo.py +1039 -0
- package/skills/path/BUILD.md +700 -0
- package/skills/path/DECIDE.md +115 -0
- package/skills/path/DEFINE.md +297 -0
- package/skills/path/DOCS-AUDIT.md +190 -0
- package/skills/path/INSPECT.md +167 -0
- package/skills/path/PLAN.md +411 -0
- package/skills/path/RESEARCH.md +159 -0
- package/skills/path/ROADMAP.md +215 -0
- package/skills/path/SHIP.md +412 -0
- package/skills/path/SKILL.md +471 -0
- package/skills/path/agents/openai.yaml +6 -0
- package/skills/path/references/codebase-mapper.md +52 -0
- package/skills/path/references/coder.md +90 -0
- package/skills/path/references/decider.md +36 -0
- package/skills/path/references/dispatch.md +131 -0
- package/skills/path/references/docs-auditor.md +60 -0
- package/skills/path/references/planner.md +104 -0
- package/skills/path/references/researcher.md +42 -0
- package/skills/path/references/reviewer.md +188 -0
- package/skills/path/references/roadmapper.md +48 -0
- package/skills/path/scripts/_common.py +180 -0
- package/skills/path/scripts/archive_milestone.py +2265 -0
- package/skills/path/scripts/bootstrap_repository.py +710 -0
- package/skills/path/scripts/build_state.py +854 -0
- package/skills/path/scripts/check_docs_audit.py +463 -0
- package/skills/path/scripts/check_handoffs.py +1855 -0
- package/skills/path/scripts/check_task_briefs.py +376 -0
- package/skills/path/scripts/check_update.py +93 -0
- package/skills/path/scripts/detect_project.py +1517 -0
- package/skills/path/scripts/discussion_records.py +619 -0
- package/skills/path/scripts/discussion_validate.py +1321 -0
- package/skills/path/scripts/dispatch_driver.py +1812 -0
- package/skills/path/scripts/integration.py +1433 -0
- package/skills/path/scripts/isolation.py +3538 -0
- package/skills/path/scripts/lean_verification.py +256 -0
- package/skills/path/scripts/loop_run.py +837 -0
- package/skills/path/scripts/pipeline_git.py +940 -0
- package/skills/path/scripts/pipeline_state.py +2291 -0
- package/skills/path/scripts/promote_lookahead.py +415 -0
- package/skills/path/scripts/review_findings.py +714 -0
- package/skills/path/scripts/review_panel.py +553 -0
- package/skills/path/scripts/state_checkpoint.py +1039 -0
- package/skills/path/scripts/state_promote.py +743 -0
- package/skills/path/scripts/token_budget.py +146 -0
- package/skills/path/scripts/workflow_run.py +117 -0
- package/skills/path/templates/answers.md +29 -0
- package/skills/path/templates/archive-manifest.md +37 -0
- package/skills/path/templates/charter.md +50 -0
- package/skills/path/templates/codebase.md +46 -0
- package/skills/path/templates/dialogue.md +21 -0
- package/skills/path/templates/docs-audit.md +69 -0
- package/skills/path/templates/evidence.md +24 -0
- package/skills/path/templates/final-review.md +27 -0
- package/skills/path/templates/gap-review.md +20 -0
- package/skills/path/templates/intent.md +98 -0
- package/skills/path/templates/loop.md +59 -0
- package/skills/path/templates/patch-findings.md +16 -0
- package/skills/path/templates/plan-panel.md +25 -0
- package/skills/path/templates/plan.md +89 -0
- package/skills/path/templates/repository.md +16 -0
- package/skills/path/templates/research-handoff.md +25 -0
- package/skills/path/templates/roadmap.md +38 -0
- package/skills/path/templates/skeptic.md +36 -0
- package/skills/path/templates/state.md +27 -0
- package/skills/path/templates/synthesis.md +36 -0
- package/skills/path/templates/task.md +74 -0
- package/skills/path/templates/wave-panel.md +25 -0
- package/skills/path/templates/wave-review.md +64 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Shared Agent Skills dispatch
|
|
2
|
+
|
|
3
|
+
Apply this contract whenever a GSD Path skill delegates work from the shared
|
|
4
|
+
`~/.agents/skills` bundle. Inspect the advertised child-agent tool schema and
|
|
5
|
+
use exactly one matching branch:
|
|
6
|
+
|
|
7
|
+
- A `spawn_agent` tool exposing `task_name`, `agent_type`, and `fork_turns` is
|
|
8
|
+
Codex. Use `fork_turns: "none"`; coders use the built-in `worker` type and
|
|
9
|
+
every other role uses `default`. Reuse a completed logical target with
|
|
10
|
+
`followup_task`. For Codex reasoning effort, use `high` for the portable
|
|
11
|
+
`heavy` tier and `low` for the portable `light` tier; leave reasoning effort
|
|
12
|
+
unset for the session-default tier, and never pass `heavy` or `light` as a
|
|
13
|
+
literal Codex value.
|
|
14
|
+
- A `spawn_agent` tool without those Codex fields is Zed. Spawn one isolated,
|
|
15
|
+
full-capability child per brief. Zed children are not resumable, so retries
|
|
16
|
+
use a fresh child and a complete prompt.
|
|
17
|
+
- An `invoke_subagent` tool advertising `TypeName`, `Workspace`, and `Role` is
|
|
18
|
+
Antigravity. Use `TypeName: self`, the exact supplied root as `Workspace`,
|
|
19
|
+
and the logical task name as `Role`. Keep the returned child ID and use
|
|
20
|
+
`send_message` for follow-up work when available; otherwise start a fresh
|
|
21
|
+
child with the complete prompt.
|
|
22
|
+
- A `spawn_subagent` tool advertising the `general-purpose` type is Grok. Use
|
|
23
|
+
`subagent_type: general-purpose`, `capability_mode: all`, the exact supplied
|
|
24
|
+
root as `cwd`, `isolation: none`, and `background: true`. Supply the logical
|
|
25
|
+
task name as `description`, keep the returned ID, and use `resume_from` with
|
|
26
|
+
the complete new prompt for later work. Wait for a colliding active child and
|
|
27
|
+
collect results with `wait_commands_or_subagents`.
|
|
28
|
+
- A `Task` tool advertising the custom `gsd-path` subagent is Cursor. Use that
|
|
29
|
+
model-inheriting, full-capability child. Resume it by returned agent ID when
|
|
30
|
+
available; otherwise retry with a fresh child and a complete prompt.
|
|
31
|
+
- A `Task` tool advertising the built-in `general` subagent is OpenCode. Use
|
|
32
|
+
that child; if an installed OpenCode v2 host exposes the renamed `subagent`
|
|
33
|
+
tool instead, use its advertised schema with the built-in `general` agent.
|
|
34
|
+
Supply the logical task name as the child description. Reuse a returned
|
|
35
|
+
child-session ID only when the host advertises a resume parameter; otherwise
|
|
36
|
+
use a fresh `general` child and the complete prompt.
|
|
37
|
+
- A `task` tool advertising the `general-purpose` child is GitHub Copilot CLI.
|
|
38
|
+
Use that child. Keep its returned ID for follow-up while the host exposes
|
|
39
|
+
it; otherwise retry with a fresh child and a complete prompt.
|
|
40
|
+
- An `invoke_sub_agent` tool with a `general-purpose` subagent is Kiro. Use
|
|
41
|
+
that child for every role; there is no worker/default type split. Start a
|
|
42
|
+
fresh general-purpose child for every correction, retry, post-patch review,
|
|
43
|
+
repeated audit, or later milestone — Kiro subagents are not resumable and
|
|
44
|
+
disk artifacts are the source of truth. Supply the logical task name as the
|
|
45
|
+
task description. Set the child working directory to the exact repository or
|
|
46
|
+
linked-worktree root supplied by GSD Path; do not ask Kiro or the child to
|
|
47
|
+
create another worktree. Encode task dependencies explicitly; launch
|
|
48
|
+
independent children concurrently up to the host's advertised
|
|
49
|
+
concurrent-subagent capacity.
|
|
50
|
+
|
|
51
|
+
For every branch:
|
|
52
|
+
|
|
53
|
+
- Supply the deterministic logical task name: `inspect_codebase`,
|
|
54
|
+
`inspect_docs`, `docs_audit`, `research_<dimension>`, `decide`, `roadmap`,
|
|
55
|
+
`plan`,
|
|
56
|
+
`plan_patch`, `build_<task_id>`, `review_wave_<wave>_cycle_<cycle>`
|
|
57
|
+
(a `deep` wave review appends the lens suffix `_contract` or
|
|
58
|
+
`_adversarial`; an optional review panel uses
|
|
59
|
+
`review_wave_<wave>_cycle_<cycle>_panel_<family>`; an optional finding
|
|
60
|
+
skeptic uses `review_wave_<wave>_cycle_<cycle>_skeptic_<criterion_locator>`),
|
|
61
|
+
`review_plan_panel_<family>`,
|
|
62
|
+
`review_final`, or `review_gap_<number>`. Normalize variable parts to
|
|
63
|
+
lowercase ASCII and replace non-alphanumeric runs with one underscore.
|
|
64
|
+
Never add a random suffix or collide with a running logical target.
|
|
65
|
+
- Resolve the phase's linked role brief to an absolute path, include it in the
|
|
66
|
+
prompt, and require the child to read it before acting. The role brief
|
|
67
|
+
supplies the read-only boundary for auditors and reviewers.
|
|
68
|
+
- Tier hints: use the portable `heavy` tier for `plan`, `plan_patch`, `decide`,
|
|
69
|
+
and `roadmap`, the portable `light` tier for `inspect_docs` and `docs_audit`,
|
|
70
|
+
and the session-default tier for every other role. Apply the Codex mapping
|
|
71
|
+
above when its schema advertises reasoning-effort selection. On every other
|
|
72
|
+
host, use only an exact native equivalent advertised by that host; otherwise
|
|
73
|
+
do not override the model or reasoning effort. The only exception is a
|
|
74
|
+
review-panel child: when the host advertises model selection, pass the exact
|
|
75
|
+
slug returned by `scripts/review_panel.py resolve` for that family. Never
|
|
76
|
+
override the model on the canonical reviewer, planner, coder, or any other
|
|
77
|
+
role.
|
|
78
|
+
Host isolation: none. The child's working directory is the exact absolute
|
|
79
|
+
root GSD Path supplied; a host SHA checkout or extra worktree is a contract
|
|
80
|
+
failure. Never ask the host to create a worktree. Give the child the exact
|
|
81
|
+
repository or linked-worktree root supplied by GSD Path.
|
|
82
|
+
- Send a self-contained prompt with absolute input, template, and output paths
|
|
83
|
+
plus the child's bounded responsibility. Every brief also names the absolute
|
|
84
|
+
`AGENTS.md` and `WORKFLOW.md` paths (or explicitly says they are absent), the
|
|
85
|
+
next phase that consumes the output, the gate it must satisfy, and the
|
|
86
|
+
terminal result it must return. A coder prompt also names its isolated
|
|
87
|
+
linked-worktree root; no child may infer the primary worktree.
|
|
88
|
+
- The parent is the sole dispatcher and lifecycle owner. If the runtime exposes
|
|
89
|
+
structured Run/Task/Dispatch orchestration, bind one Run, create one Task per
|
|
90
|
+
independent brief with explicit dependencies, inject the brief, and wait for
|
|
91
|
+
every `worker_done`, `escalation`, or question before applying the gate.
|
|
92
|
+
Verify the task and dispatch records before reporting the work as
|
|
93
|
+
orchestrated. On runtimes without that layer, use the host adapter's
|
|
94
|
+
equivalent and preserve the same logical name, completion state,
|
|
95
|
+
timeout/cancellation, and cleanup rules; never silently delegate again from a
|
|
96
|
+
child.
|
|
97
|
+
- When the structured layer exposes a blocking ask/reply channel, route a
|
|
98
|
+
coder's `NEEDS-ORCHESTRATOR` question through it as a live question with
|
|
99
|
+
the worker held alive for the reply, instead of block-and-redispatch. The
|
|
100
|
+
answer is still appended to the task Log as
|
|
101
|
+
`Orchestrator answer:` so the portable on-disk record stays complete, and a
|
|
102
|
+
timed-out or unavailable channel falls back to the portable block path.
|
|
103
|
+
- A child that receives a disposable worktree stages its assigned artifact
|
|
104
|
+
under that root. The parent validates it and atomically transfers it to the
|
|
105
|
+
canonical project path before removing the exact disposable root. A child
|
|
106
|
+
never writes a disposable-review output directly into the primary worktree.
|
|
107
|
+
- Launch independent briefs concurrently up to the advertised child capacity,
|
|
108
|
+
batch any remainder without combining briefs, and collect every result
|
|
109
|
+
before applying the phase gate. Do not leave an active child, logical task, or
|
|
110
|
+
temporary worktree after collection; a timeout or cancellation is a blocked
|
|
111
|
+
result, not a silent success.
|
|
112
|
+
- If the tool schema is ambiguous or the required full-capability child is
|
|
113
|
+
unavailable, stop and report the missing capability. Do not guess the host
|
|
114
|
+
or silently collapse an independence boundary into the main context.
|
|
115
|
+
|
|
116
|
+
## Configured output budgets
|
|
117
|
+
|
|
118
|
+
When the owner supplies token budgets, use the router bundle's
|
|
119
|
+
`scripts/token_budget.py` with the owner's exact task and session values and
|
|
120
|
+
quoted authority. Keep one ledger outside the worktree under the Git common
|
|
121
|
+
directory for the full logical session; resumptions reuse it. Record completed
|
|
122
|
+
parent CLI run events and each native child's session events with stable logical
|
|
123
|
+
task names before the next dispatch. The helper reads host counters and refuses
|
|
124
|
+
incomplete or ambiguous usage; never estimate tokens or reset the ledger.
|
|
125
|
+
Run `admit` for the next task and stop dispatch on a blocked result. Preserve
|
|
126
|
+
its output in the dispatch evidence. This gates observed usage only: concurrent
|
|
127
|
+
or in-flight work can overrun before the host reports usage. Codex CLI has no
|
|
128
|
+
advertised hard output cap; report that limitation once. If the owner requires
|
|
129
|
+
hard generation enforcement, use `admit --require-hard-cap`; unsupported means
|
|
130
|
+
blocked, not budget compliance. Other hosts require a verified native counter
|
|
131
|
+
and cap adapter before any enforcement claim.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Planner role
|
|
2
|
+
|
|
3
|
+
Write a complete GSD Path plan. Spec outcomes and constraints; coders own
|
|
4
|
+
the how.
|
|
5
|
+
|
|
6
|
+
## Input and output
|
|
7
|
+
|
|
8
|
+
- Require absolute paths for INTENT.md, SYNTHESIS.md, and both templates.
|
|
9
|
+
Write the plan to `.project/plan/PLAN.md` and each task file to
|
|
10
|
+
`.project/tasks/T###-slug.md` — these paths are canonical; nothing in the
|
|
11
|
+
pipeline reads `.project/PLAN.md`.
|
|
12
|
+
- Read AGENTS.md, both inputs, both templates, and relevant existing code.
|
|
13
|
+
Read `.project/LESSONS.md` when supplied; do not repeat a recorded planning
|
|
14
|
+
defect. When CHARTER.md and ROADMAP.md are supplied (milestone mode), plan
|
|
15
|
+
only the active milestone entry — the charter and remaining roadmap entries
|
|
16
|
+
are context, never scope.
|
|
17
|
+
- Write only the exact outputs using the supplied templates. Stop on a missing
|
|
18
|
+
path or template.
|
|
19
|
+
|
|
20
|
+
## Authority
|
|
21
|
+
|
|
22
|
+
- Treat intent constraints, corrections, and vetoes as hard limits.
|
|
23
|
+
- Treat synthesis decisions as settled. Surface conflicts; never average.
|
|
24
|
+
- Route low-confidence assumptions to wave 1.
|
|
25
|
+
|
|
26
|
+
## Plan order
|
|
27
|
+
|
|
28
|
+
1. Put every plan-invalidating risk in wave 1.
|
|
29
|
+
2. Make wave 2 the thinnest running end-to-end slice.
|
|
30
|
+
3. Order remaining features by dependency, then polish.
|
|
31
|
+
4. Prefer the fewest waves that respect dependencies — every wave costs a
|
|
32
|
+
full review cycle. Merge a wave into its neighbor unless it adds
|
|
33
|
+
parallelism or isolates a risk.
|
|
34
|
+
5. Assign each wave `Review depth: full`, `deep`, or `verify-only`. Wave 1
|
|
35
|
+
and any wave touching authentication, authorization, payments, data
|
|
36
|
+
migration, or concurrency requires `full` or `deep`. Assign `deep`
|
|
37
|
+
sparingly, only to waves where a wrong merge is irreversible or
|
|
38
|
+
security-critical; `verify-only` suits polish and low-risk feature waves
|
|
39
|
+
whose Verify commands meaningfully cover the criteria.
|
|
40
|
+
|
|
41
|
+
Every dependency must be in an earlier wave or in the same wave with no file
|
|
42
|
+
overlap. Produce an acyclic graph; same-wave chains execute in layers.
|
|
43
|
+
|
|
44
|
+
Declare a dependency only when something real crosses it: data — the dependent
|
|
45
|
+
consumes a symbol, signature, schema, endpoint, file format, or path named in
|
|
46
|
+
that dependency's Interface contract, or the two tasks' `files` overlap — or a
|
|
47
|
+
prerequisite effect the dependent needs already landed, named in Dependency
|
|
48
|
+
notes with the evidence a reviewer would see. Test each edge separately.
|
|
49
|
+
Narrative order is not a dependency: drop that edge and place both tasks by the
|
|
50
|
+
plan order above, which still keeps plan-invalidating risk in wave 1.
|
|
51
|
+
|
|
52
|
+
## Task contract
|
|
53
|
+
|
|
54
|
+
- Size tasks as deliverables, not edits: one task is the largest coherent
|
|
55
|
+
vertical slice — feature plus its tests, wiring, and imports — that one
|
|
56
|
+
agent run can complete. Split only when parallel file scopes, a dependency
|
|
57
|
+
layer, or agent-run capacity forces it; merge tasks that share files or a
|
|
58
|
+
deliverable. A task whose expected diff is smaller than its own task file
|
|
59
|
+
is too small.
|
|
60
|
+
- Inline necessary synthesis context. Map every INTENT.md success criterion
|
|
61
|
+
into PLAN.md `## Intent coverage` (SCn → task id → ACn) and list those SCn
|
|
62
|
+
ids in each task's `## Intent coverage` (`- None` when a task owns none).
|
|
63
|
+
The named task's Verify command is what must fail if that SC is skipped.
|
|
64
|
+
- In Approach, give constraints, applicable pitfalls, and pointers to real
|
|
65
|
+
paths, symbols, endpoints, and schemas — not an ordered edit script. The
|
|
66
|
+
coder owns implementation decisions inside those constraints.
|
|
67
|
+
- When INTENT.md names surfaces, write PLAN.md `## Surface contract`: one
|
|
68
|
+
block per surface with its entry point, what empty, loading, error, and
|
|
69
|
+
success each show, and the walkthrough a reviewer performs. Give each
|
|
70
|
+
surface to the task that delivers it, list in Criteria the success criteria
|
|
71
|
+
that prove that surface, which the task also owns in Intent coverage. A
|
|
72
|
+
criterion may appear in only one surface block. Put the surface in the same
|
|
73
|
+
wave as the capability behind it. A milestone with a surface is not done
|
|
74
|
+
when only its internals run.
|
|
75
|
+
- Make `files` exhaustive, including imports, routes, generated artifacts,
|
|
76
|
+
tests, and wiring. Require disjoint files for same-wave tasks.
|
|
77
|
+
- Write an Interface contract in every task: `None` for independent tasks;
|
|
78
|
+
for any tasks that exchange a symbol, signature, schema, endpoint, file
|
|
79
|
+
format, or path, the exact shapes both sides code against — identical text
|
|
80
|
+
in every involved task. This contract is the only cross-task communication;
|
|
81
|
+
coders may not negotiate or deviate, so settle the seam here. List only
|
|
82
|
+
the shapes this task defines or consumes through its `files`; a task that
|
|
83
|
+
exchanges nothing writes `None`, and one shared block pasted into every
|
|
84
|
+
task is a plan defect.
|
|
85
|
+
- Write observable acceptance criteria and one Verify command that fails when
|
|
86
|
+
this task's work is skipped. That command must name a path from `files`,
|
|
87
|
+
and must not be PLAN.md's project Verify unless an SC this task owns names
|
|
88
|
+
that command. Criteria and Verify are the contract; Approach is guidance.
|
|
89
|
+
- Preserve every template field and its required initial value.
|
|
90
|
+
|
|
91
|
+
Put the full-project build-and-test command in PLAN.md. Copy `Review panel:`
|
|
92
|
+
from INTENT.md into PLAN.md Config as `review_panel:` when INTENT names one;
|
|
93
|
+
otherwise copy CHARTER.md's durable default when that file is supplied;
|
|
94
|
+
otherwise write `review_panel: off`. Never invent `detected` or a named
|
|
95
|
+
family list. Copy `Finding skeptics:` from INTENT.md into PLAN.md Config as
|
|
96
|
+
`finding_skeptics:`; when it is absent, write `finding_skeptics: off`. Never
|
|
97
|
+
invent `on`. Quick-lane plans always write both values as `off`.
|
|
98
|
+
|
|
99
|
+
Before returning, check veto exclusion, decision coverage, Intent coverage,
|
|
100
|
+
the Surface contract, dependencies, file overlap, task size, criteria, and
|
|
101
|
+
Verify commands.
|
|
102
|
+
|
|
103
|
+
Return a brief structured summary: wave count, task count, and the wave-1
|
|
104
|
+
risk list.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# gsd-path project runtime
|
|
3
|
+
"""Helpers shared by the gsd-path scripts.
|
|
4
|
+
|
|
5
|
+
Every consuming script binds the names it used before (for example
|
|
6
|
+
``run_git = _common.run_git``) so callers and tests that patch the name on the
|
|
7
|
+
consuming module keep working.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
import re
|
|
15
|
+
import subprocess
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
from typing import Optional
|
|
18
|
+
|
|
19
|
+
PIPELINE_MARKER = "gsd-path/v2"
|
|
20
|
+
BOUND_BRANCH_RE = re.compile(r"^gsd-path/M(\d{3,})$")
|
|
21
|
+
|
|
22
|
+
FIELD_PATTERN = re.compile(r"^(?P<key>[a-z_]+):\s*(?P<value>.*)$")
|
|
23
|
+
INLINE_LIST_PATTERN = re.compile(r"^\[(?P<body>.*)\]$")
|
|
24
|
+
LIST_ITEM_PATTERN = re.compile(r"^\s*-\s+(?P<value>.*)$")
|
|
25
|
+
VERIFY_LEDGER_PATH = ".project/build/verify-ledger.jsonl"
|
|
26
|
+
VERIFY_RESULTS = ("pass", "fail")
|
|
27
|
+
VERIFY_LEDGER_SCHEMA = "gsd-path/verify-ledger/v2"
|
|
28
|
+
VERIFY_BLOCK_PATTERN = re.compile(r"```bash[ \t]*\n(?P<block>.*?)```", re.DOTALL)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def section_body(text: str, heading: str) -> Optional[str]:
|
|
32
|
+
"""The text under `## <heading>` up to the next `## `, or None when absent."""
|
|
33
|
+
match = re.search(
|
|
34
|
+
rf"(?ms)^## {re.escape(heading)}\s*\n(?P<body>.*?)(?=^## |\Z)", text
|
|
35
|
+
)
|
|
36
|
+
return match.group("body") if match else None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def task_verify_command(task_text: str) -> str:
|
|
40
|
+
"""The Verify shell text, excluding the closing fence's separator newline."""
|
|
41
|
+
body = section_body(task_text, "Verify")
|
|
42
|
+
block = VERIFY_BLOCK_PATTERN.search(body) if body is not None else None
|
|
43
|
+
return block.group("block").removesuffix("\n") if block else ""
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def latest_verify_entry(entries: list, command: str, commit: str) -> Optional[dict]:
|
|
47
|
+
for entry in reversed(entries):
|
|
48
|
+
if (entry.get("schema") == VERIFY_LEDGER_SCHEMA
|
|
49
|
+
and entry["command"] == command and entry["commit"] == commit):
|
|
50
|
+
return entry
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def verify_ledger_entries(path: Path) -> list:
|
|
55
|
+
"""Parsed verify-ledger rows; raises ValueError on a malformed line."""
|
|
56
|
+
if not path.exists():
|
|
57
|
+
return []
|
|
58
|
+
return parse_verify_ledger(path.read_text(encoding="utf-8"))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def parse_verify_ledger(text: str) -> list:
|
|
62
|
+
entries = []
|
|
63
|
+
for number, line in enumerate(text.splitlines(), start=1):
|
|
64
|
+
if not line.strip():
|
|
65
|
+
continue
|
|
66
|
+
try:
|
|
67
|
+
entry = json.loads(line)
|
|
68
|
+
except json.JSONDecodeError as error:
|
|
69
|
+
raise ValueError(f"{VERIFY_LEDGER_PATH} line {number} is not JSON: {error}") from error
|
|
70
|
+
if (
|
|
71
|
+
not isinstance(entry, dict)
|
|
72
|
+
or not isinstance(entry.get("command"), str)
|
|
73
|
+
or not isinstance(entry.get("commit"), str)
|
|
74
|
+
or entry.get("result") not in VERIFY_RESULTS
|
|
75
|
+
or not isinstance(entry.get("recorded_at"), str)
|
|
76
|
+
):
|
|
77
|
+
raise ValueError(f"{VERIFY_LEDGER_PATH} line {number} has invalid fields")
|
|
78
|
+
entries.append(entry)
|
|
79
|
+
return entries
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def run_command(
|
|
83
|
+
*arguments: str, cwd: Optional[Path] = None
|
|
84
|
+
) -> subprocess.CompletedProcess[str]:
|
|
85
|
+
return subprocess.run(
|
|
86
|
+
arguments,
|
|
87
|
+
cwd=cwd,
|
|
88
|
+
text=True,
|
|
89
|
+
capture_output=True,
|
|
90
|
+
check=False,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def run_git(
|
|
95
|
+
repo: Path, *arguments: str, input: Optional[str] = None
|
|
96
|
+
) -> subprocess.CompletedProcess[str]:
|
|
97
|
+
return subprocess.run(
|
|
98
|
+
("git", "-C", str(repo), *arguments),
|
|
99
|
+
input=input,
|
|
100
|
+
text=True,
|
|
101
|
+
capture_output=True,
|
|
102
|
+
check=False,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def atomic_replace(path: Path, temporary_path: Path, content: str) -> None:
|
|
107
|
+
temporary_path.parent.mkdir(parents=True, exist_ok=True)
|
|
108
|
+
descriptor = None
|
|
109
|
+
try:
|
|
110
|
+
if temporary_path.exists() or temporary_path.is_symlink():
|
|
111
|
+
temporary_path.unlink()
|
|
112
|
+
descriptor = os.open(
|
|
113
|
+
temporary_path,
|
|
114
|
+
os.O_WRONLY | os.O_CREAT | os.O_EXCL,
|
|
115
|
+
0o666,
|
|
116
|
+
)
|
|
117
|
+
handle = os.fdopen(descriptor, "w", encoding="utf-8")
|
|
118
|
+
descriptor = None
|
|
119
|
+
with handle:
|
|
120
|
+
handle.write(content)
|
|
121
|
+
os.replace(temporary_path, path)
|
|
122
|
+
finally:
|
|
123
|
+
if descriptor is not None:
|
|
124
|
+
os.close(descriptor)
|
|
125
|
+
if temporary_path.exists() or temporary_path.is_symlink():
|
|
126
|
+
temporary_path.unlink()
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def atomic_write(path: Path, content: str) -> None:
|
|
130
|
+
atomic_replace(path, path.parent / f".{path.name}.gsd-path-tmp", content)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def strip_yaml_comment(value: str) -> str:
|
|
134
|
+
quote = None
|
|
135
|
+
previous_significant = None
|
|
136
|
+
inline_list = value.lstrip().startswith("[")
|
|
137
|
+
index = 0
|
|
138
|
+
while index < len(value):
|
|
139
|
+
character = value[index]
|
|
140
|
+
if quote == '"':
|
|
141
|
+
if character == "\\" and index + 1 < len(value):
|
|
142
|
+
index += 2
|
|
143
|
+
continue
|
|
144
|
+
if character == quote:
|
|
145
|
+
quote = None
|
|
146
|
+
elif quote == "'":
|
|
147
|
+
if (
|
|
148
|
+
character == quote
|
|
149
|
+
and index + 1 < len(value)
|
|
150
|
+
and value[index + 1] == quote
|
|
151
|
+
):
|
|
152
|
+
index += 2
|
|
153
|
+
continue
|
|
154
|
+
if character == quote:
|
|
155
|
+
quote = None
|
|
156
|
+
else:
|
|
157
|
+
if character in {"'", '"'} and (
|
|
158
|
+
previous_significant is None
|
|
159
|
+
or (inline_list and previous_significant in {"[", ","})
|
|
160
|
+
):
|
|
161
|
+
quote = character
|
|
162
|
+
elif character == "#" and (
|
|
163
|
+
index == 0 or value[index - 1].isspace()
|
|
164
|
+
):
|
|
165
|
+
return value[:index].rstrip()
|
|
166
|
+
if quote is None and not character.isspace():
|
|
167
|
+
previous_significant = character
|
|
168
|
+
index += 1
|
|
169
|
+
return value.strip()
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def unquote(value: str) -> str:
|
|
173
|
+
cleaned = strip_yaml_comment(value).strip()
|
|
174
|
+
if (
|
|
175
|
+
len(cleaned) >= 2
|
|
176
|
+
and cleaned[0] == cleaned[-1]
|
|
177
|
+
and cleaned[0] in {"'", '"'}
|
|
178
|
+
):
|
|
179
|
+
return cleaned[1:-1]
|
|
180
|
+
return cleaned
|