@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,46 @@
|
|
|
1
|
+
# Evidence — codebase
|
|
2
|
+
|
|
3
|
+
<!-- Written by the codebase mapper during $gsd-path-inspect. Read by define
|
|
4
|
+
(brownfield mode), researchers (fifth standard dimension), the planner
|
|
5
|
+
(conventions are binding), and reviewers. -->
|
|
6
|
+
|
|
7
|
+
Repo root: <absolute path>
|
|
8
|
+
Scanned: <date>
|
|
9
|
+
Checks run: <exact commands run and their results, e.g. `npm test` → 37/40 pass>
|
|
10
|
+
|
|
11
|
+
## Map
|
|
12
|
+
|
|
13
|
+
- **Stack**: <languages, frameworks, versions actually in use, from manifests>
|
|
14
|
+
- **Entry points**: <binaries, main modules, routes — how this thing starts>
|
|
15
|
+
- **Architecture**: <layers and flow in 3–5 sentences>
|
|
16
|
+
- **Conventions**: <naming, error handling, test style, commit style — binding on the planner>
|
|
17
|
+
- **Maturity**: <what runs, test coverage shape, what is scaffolding>
|
|
18
|
+
- **Recent activity**: <where the last N commits cluster — what was being worked on>
|
|
19
|
+
|
|
20
|
+
## Finding: <short claim as heading>
|
|
21
|
+
|
|
22
|
+
- **Claim**: <one specific, falsifiable statement about this codebase>
|
|
23
|
+
- **Source**: <file:line or command actually run>
|
|
24
|
+
- **Confidence**: <high | medium | low>
|
|
25
|
+
- **Why it matters here**: <what inspection/planning gets wrong without this>
|
|
26
|
+
|
|
27
|
+
<!-- Record every load-bearing surprise or half-built area observed. There is
|
|
28
|
+
no minimum finding quota; explain an empty section if none were found. -->
|
|
29
|
+
|
|
30
|
+
## Apparent intent
|
|
31
|
+
|
|
32
|
+
<!-- Inference, clearly flagged — what the project seems to be becoming. -->
|
|
33
|
+
|
|
34
|
+
- <inference> — based on <evidence>
|
|
35
|
+
|
|
36
|
+
## Open questions for define
|
|
37
|
+
|
|
38
|
+
<!-- What only the user can settle about this codebase. -->
|
|
39
|
+
|
|
40
|
+
- <question>
|
|
41
|
+
|
|
42
|
+
## Blocked areas
|
|
43
|
+
|
|
44
|
+
<!-- What could not be inspected and why. "none" if clean. -->
|
|
45
|
+
|
|
46
|
+
- <area> — <what blocked inspection>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Docs Audit
|
|
2
|
+
|
|
3
|
+
<!-- Written by the docs auditor ($gsd-path-docs-audit or $gsd-path-inspect).
|
|
4
|
+
Every verdict carries evidence; a verdict without evidence is a defect. -->
|
|
5
|
+
|
|
6
|
+
Repo root: <absolute path>
|
|
7
|
+
Audited: <date>
|
|
8
|
+
Audited HEAD: <40-hex commit the claims were checked at, or none>
|
|
9
|
+
Alignment mode: <yes | no — yes when .project/ artifacts were also audited>
|
|
10
|
+
|
|
11
|
+
## Summary
|
|
12
|
+
|
|
13
|
+
| Verdict | Count |
|
|
14
|
+
|---------|-------|
|
|
15
|
+
| verified | <n> |
|
|
16
|
+
| stale | <n> |
|
|
17
|
+
| aspirational | <n> |
|
|
18
|
+
| unverifiable | <n> |
|
|
19
|
+
| descriptive docs (no testable claims) | <n> |
|
|
20
|
+
|
|
21
|
+
Worst drift: <one sentence — the most misleading claim found>
|
|
22
|
+
|
|
23
|
+
## Doc: <path/to/doc.md>
|
|
24
|
+
|
|
25
|
+
| Claim | Type | Verdict | Evidence |
|
|
26
|
+
|-------|------|---------|----------|
|
|
27
|
+
| "<claim, short-quoted>" | command \| feature \| structure \| status \| config \| integration | verified \| stale \| aspirational \| unverifiable | <file:line or command → result> |
|
|
28
|
+
|
|
29
|
+
<!-- One section per doc that has at least one testable claim. Docs without
|
|
30
|
+
testable claims go in the Descriptive docs list below, never in their
|
|
31
|
+
own section. Evidence with exactly one `unchanged: ` prefix marks a row
|
|
32
|
+
carried from the prior audit under the role's delta rule. Copy an
|
|
33
|
+
already-carried row verbatim without adding another prefix. -->
|
|
34
|
+
|
|
35
|
+
## Descriptive docs
|
|
36
|
+
|
|
37
|
+
<!-- Every inventoried doc with no testable claims, one path per line.
|
|
38
|
+
The union of this list and the Doc section paths must equal the frozen
|
|
39
|
+
inventory exactly. -->
|
|
40
|
+
|
|
41
|
+
- <path/to/doc.md>
|
|
42
|
+
|
|
43
|
+
## Alignment (alignment mode only)
|
|
44
|
+
|
|
45
|
+
- **INTENT success criteria**: <each → met so far | not yet | contradicted, with evidence>
|
|
46
|
+
- **Done tasks**: <each status:done task → recover-proven landing SHA? Verify re-run result?>
|
|
47
|
+
- **SYNTHESIS decisions**: <each → code conforms? evidence>
|
|
48
|
+
- **STATE vs frontmatter**: <agree | discrepancies listed>
|
|
49
|
+
|
|
50
|
+
## User rulings
|
|
51
|
+
|
|
52
|
+
<!-- Appended after the ruling walk (standalone runs). Verbatim, append-only.
|
|
53
|
+
accept-drift rulings suppress the item in future audits.
|
|
54
|
+
`planned: no` rows are the alignment queue: $gsd-path and $gsd-path-plan offer
|
|
55
|
+
to absorb them until drained. When a ruling becomes a task, set
|
|
56
|
+
planned to the task id — never delete the row. -->
|
|
57
|
+
|
|
58
|
+
| Queue # | Ruling | User's words | Planned |
|
|
59
|
+
|---------|--------|--------------|---------|
|
|
60
|
+
| 1 | fix-code \| fix-doc \| accept-drift | "<verbatim>" | no \| <task id> \| n/a (accept-drift) |
|
|
61
|
+
|
|
62
|
+
## Remediation queue
|
|
63
|
+
|
|
64
|
+
<!-- Every non-verified claim, classified. The user rules on this queue;
|
|
65
|
+
the auditor never fixes anything. -->
|
|
66
|
+
|
|
67
|
+
| # | Doc | Claim | Verdict | Class | Suggested action |
|
|
68
|
+
|---|-----|-------|---------|-------|------------------|
|
|
69
|
+
| 1 | <doc> | <claim> | stale | fix-doc \| fix-code \| NEEDS-USER | <one line> |
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
pipeline: gsd-path/v2
|
|
3
|
+
project: <slug>
|
|
4
|
+
milestone: null # set by define; names the archive directory at ship
|
|
5
|
+
phase: define # v2 tokens: inspect | define | research | decide | roadmap | plan | build | ship | shipped
|
|
6
|
+
# inspect only for brownfield; greenfield starts at define
|
|
7
|
+
# roadmap only in program flow (CHARTER.md exists)
|
|
8
|
+
status: active # active | done | blocked; shipped is only phase: shipped + status: done
|
|
9
|
+
branch: null # bound per milestone as gsd-path/M00N; after integration
|
|
10
|
+
# the router rebinds before any next-milestone file change
|
|
11
|
+
# the bound branch is never main; ship integrates it there
|
|
12
|
+
archive: null # persisted archive transaction path; never recomputed
|
|
13
|
+
integration_default: direct # direct | pull-request; project setting
|
|
14
|
+
integration: direct # current milestone; may override the default before build
|
|
15
|
+
integration_source: default # default | milestone; preserves override provenance
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Project State
|
|
19
|
+
|
|
20
|
+
One file, always current. The router reads this first; every phase updates
|
|
21
|
+
it on completion. If this file and the artifacts disagree, the artifacts win
|
|
22
|
+
— fix this file.
|
|
23
|
+
|
|
24
|
+
## Log
|
|
25
|
+
|
|
26
|
+
<!-- append one line per transition: date, phase, event -->
|
|
27
|
+
- YYYY-MM-DD — <phase> — project initialized
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsd-path-loop
|
|
3
|
+
description: Use only when the user explicitly invokes $gsd-path-loop. Runs one bounded loop pass from a LOOP.md spec — gate checks, independent verification, one fix worker, telemetry. Autonomy lives in the external scheduler that invokes this skill; the skill never schedules itself.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GSD Path Loop
|
|
7
|
+
|
|
8
|
+
One invocation = one bounded pass. The bundled deterministic helper
|
|
9
|
+
[loop_run.py](scripts/loop_run.py) owns the gates — atomic claim, verify,
|
|
10
|
+
finish, status — and its output is the only gate authority; do not
|
|
11
|
+
reimplement that logic in model reasoning. The model owns what the helper
|
|
12
|
+
cannot: reading the spec's prose, dispatching one fix worker, and feeding
|
|
13
|
+
failures back. Fill new specs from the canonical
|
|
14
|
+
[LOOP.md template](templates/loop.md); a filled dogfood example lives at
|
|
15
|
+
[examples/ci-repair.LOOP.md](examples/ci-repair.LOOP.md).
|
|
16
|
+
|
|
17
|
+
Run every helper command from the repository root — relative paths in the
|
|
18
|
+
spec (`log:`, `skip_when:`, `verify:`) resolve against the working
|
|
19
|
+
directory. Use the bundled copy of the helper next to this file. When the
|
|
20
|
+
repository has a `.project/`, first run the bundled
|
|
21
|
+
`scripts/discussion_records.py pending --repo <absolute-root>`; when
|
|
22
|
+
`.project/discuss/ANSWERS.md` is absent, continue. A pending follow-up owned
|
|
23
|
+
by loop work blocks the pass with links to ANSWERS.md.
|
|
24
|
+
|
|
25
|
+
This skill never advances a gsd-path phase gate: it wraps bounded work, it
|
|
26
|
+
does not route the pipeline.
|
|
27
|
+
|
|
28
|
+
## Process
|
|
29
|
+
|
|
30
|
+
1. **Read the spec.** Read the whole LOOP.md: machine fields and prose
|
|
31
|
+
sections (Goal, Worker scope, Feedback route, Human gates, Stops, Output).
|
|
32
|
+
The prose binds the worker brief below.
|
|
33
|
+
2. **Claim.** Before verify or worker dispatch, run `python3
|
|
34
|
+
scripts/loop_run.py claim --spec <path>`. The atomic result is the only
|
|
35
|
+
admission decision. On `run`, retain the returned `claim` and admitted
|
|
36
|
+
limits for this pass. On `skip` with `recovery.recoverable: false`, another
|
|
37
|
+
pass still owns its admitted lease: report that the loop is already active
|
|
38
|
+
and stop without finishing or dispatching work. On another `skip` without
|
|
39
|
+
an expired claim, report the reason and stop; no outcome exists to finish.
|
|
40
|
+
Only when the helper returns `recovery.recoverable: true` and the expired
|
|
41
|
+
`claim`, close that exact prior claim as recovery before stopping:
|
|
42
|
+
`python3 scripts/loop_run.py recover --spec <path> --claim <returned
|
|
43
|
+
claim>`. The helper derives the elapsed time, completed verify cycles, and
|
|
44
|
+
truthful result from the latest verify (`pass`, `fail`, or `blocked` when
|
|
45
|
+
none completed). Never start work under a prior claim.
|
|
46
|
+
3. **Baseline verify.** Run `python3 scripts/loop_run.py verify --spec
|
|
47
|
+
<path> --claim <retained claim>`. The helper enforces the claim's one
|
|
48
|
+
admitted wall-clock deadline across every verify command and every later
|
|
49
|
+
verify invocation. On `pass`, the goal is already green: record `pass` with
|
|
50
|
+
`finish` for the retained claim and `--iterations 0`, report, and stop. A
|
|
51
|
+
green baseline never dispatches a worker.
|
|
52
|
+
4. **One bounded worker.** On `fail`, dispatch ONE fix worker (v1: single
|
|
53
|
+
worker, no fan-out) with the exact failing commands and output tails from
|
|
54
|
+
the helper, plus the spec's Worker scope. The worker fixes the smallest
|
|
55
|
+
failed unit named by the Feedback route — not the whole goal.
|
|
56
|
+
5. **Independent verify.** The wrapper re-runs `verify` with the same
|
|
57
|
+
`--claim`; worker claims are
|
|
58
|
+
not evidence. On `fail`, feed the new failing output back to the worker.
|
|
59
|
+
The helper appends each verify result and refuses a verify beyond
|
|
60
|
+
`max_iterations` fix → verify cycles. Stop when that limit or the admitted
|
|
61
|
+
`wall_clock` is spent, whichever comes first.
|
|
62
|
+
6. **Blocked.** When the worker cannot proceed, or the only remaining fix
|
|
63
|
+
needs a Human gates action, stop with `BLOCKED: <reason>` naming the
|
|
64
|
+
gate — never perform the gated action to unblock.
|
|
65
|
+
7. **Finish.** Every admitted pass has exactly one terminal outcome. Append it
|
|
66
|
+
with `python3 scripts/loop_run.py finish --spec <path> --claim <retained
|
|
67
|
+
claim> --result pass|fail|blocked|skipped --iterations <n>
|
|
68
|
+
[--notes ...] [--rescue]`. The helper checks `<n>` against its verify events
|
|
69
|
+
and derives elapsed time from the claim. Use the exact same claim for
|
|
70
|
+
baseline pass, successful repair, exhausted verification, human-gate
|
|
71
|
+
block, or another terminal stop. Rerunning the identical `finish` is the
|
|
72
|
+
only completion retry.
|
|
73
|
+
8. **Report.** Close per the AGENTS.md asking conventions: **Outcome** —
|
|
74
|
+
what changed, or why nothing ran; **Review** — a Markdown link to the
|
|
75
|
+
spec's log path (or the spec itself when no record was written), resolved
|
|
76
|
+
absolute path printed if the host cannot render links; **Next** — the one
|
|
77
|
+
question or action now required. `python3 scripts/loop_run.py status
|
|
78
|
+
--spec <path>` gives the aggregate counters when the user asks how the
|
|
79
|
+
loop is trending; `acceptance_rate` divides accepted by accepted plus
|
|
80
|
+
rejected — blocked and skipped runs are not evaluations.
|
|
81
|
+
`wall_clock_per_accept_seconds` divides total all-run wall clock by
|
|
82
|
+
accepts, so blocked and rejected runs raise it.
|
|
83
|
+
|
|
84
|
+
## Rules
|
|
85
|
+
|
|
86
|
+
- Never commit, push, tag, or mutate git state — a loop pass leaves version
|
|
87
|
+
control to the user.
|
|
88
|
+
- Never edit tests to match broken code. If the test is the bug, say so in
|
|
89
|
+
the report and stop; weakening a verifier is a human-gate action.
|
|
90
|
+
- Never touch paths the spec's Worker scope declares read-only.
|
|
91
|
+
- Verify output tails are persisted to the spec's log; a verify command must
|
|
92
|
+
never echo secrets or credentials.
|
|
93
|
+
- Human gates are never-auto: reaching one means `BLOCKED: <reason>`, not a
|
|
94
|
+
judgment call.
|
|
95
|
+
- The helper's atomic `claim` output decides whether a pass runs. `check` is
|
|
96
|
+
preview-only and never authorizes verify, worker dispatch, or mutation.
|
|
97
|
+
- A pass that cannot honestly reach green stops per the spec's Stops and
|
|
98
|
+
records the truth; silent partial success is the worst outcome.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# LOOP — ci-repair
|
|
2
|
+
|
|
3
|
+
<!-- Dogfood spec for the gsd-path distribution repo itself. One pass repairs
|
|
4
|
+
a failing CI trio: pytest, the node installer tests, and the resource
|
|
5
|
+
sync check. Invoke from the repository root. -->
|
|
6
|
+
|
|
7
|
+
loop: ci-repair
|
|
8
|
+
status: active
|
|
9
|
+
trigger: manual
|
|
10
|
+
cooldown: 10m
|
|
11
|
+
verify: python3 -m pytest tests/ -q
|
|
12
|
+
verify: npm test
|
|
13
|
+
verify: python3 scripts/sync_skill_resources.py --check
|
|
14
|
+
max_iterations: 3
|
|
15
|
+
wall_clock: 30m
|
|
16
|
+
period: 24h
|
|
17
|
+
period_budget: 4h
|
|
18
|
+
log: .project/loop/ci-repair.LOG.jsonl
|
|
19
|
+
|
|
20
|
+
## Goal
|
|
21
|
+
|
|
22
|
+
The three verifier commands above all exit 0 — the same trio
|
|
23
|
+
`.github/workflows/ci.yml` runs. Anything less is a failure, not a partial
|
|
24
|
+
success.
|
|
25
|
+
|
|
26
|
+
## Worker scope
|
|
27
|
+
|
|
28
|
+
One fix worker repairs the failing test, installer check, or sync drift at
|
|
29
|
+
its root cause. The worker must never: commit, push, or tag; edit a test to
|
|
30
|
+
match broken product code; edit generated per-skill copies under
|
|
31
|
+
`skills/gsd-path-*/{references,templates,scripts}/` instead of their
|
|
32
|
+
canonical sources (`skills/gsd-path/` and `scripts/`); or touch files outside
|
|
33
|
+
the failing unit's blast radius.
|
|
34
|
+
|
|
35
|
+
## Feedback route
|
|
36
|
+
|
|
37
|
+
On a failed verify, the worker gets the exact failing command and its output
|
|
38
|
+
tail from `loop_run.py verify`, aimed at the smallest failed unit — the one
|
|
39
|
+
failing test file, installer assertion, or sync mismatch — not the whole
|
|
40
|
+
suite.
|
|
41
|
+
|
|
42
|
+
## Human gates
|
|
43
|
+
|
|
44
|
+
- Any commit, push, or tag.
|
|
45
|
+
- Weakening, deleting, or skipping a test or verifier to reach green.
|
|
46
|
+
- Editing a canonical template/reference and its generated copies in
|
|
47
|
+
conflicting directions (sync's wrong-direction-edit warning).
|
|
48
|
+
- Changing CI itself (`.github/workflows/ci.yml`).
|
|
49
|
+
|
|
50
|
+
## Stops
|
|
51
|
+
|
|
52
|
+
- `pass` — all three verify commands exit 0.
|
|
53
|
+
- `fail` — max_iterations or the 30m wall_clock budget is spent.
|
|
54
|
+
- `blocked` — the only remaining fix needs a human-gate action; report
|
|
55
|
+
`BLOCKED: <reason>` and stop.
|
|
56
|
+
|
|
57
|
+
## Output
|
|
58
|
+
|
|
59
|
+
Append-only claim, verify, and finish records in
|
|
60
|
+
`.project/loop/ci-repair.LOG.jsonl`, then the Outcome / Review / Next report
|
|
61
|
+
naming the verify result, helper-counted iterations, and the log path.
|
|
@@ -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
|