@ai-is-gonna/get-tasks-done 0.2.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/LICENSE +21 -0
- package/README.md +249 -0
- package/agents/gtd-advisor-researcher.md +127 -0
- package/agents/gtd-ai-researcher.md +133 -0
- package/agents/gtd-assumptions-analyzer.md +105 -0
- package/agents/gtd-code-fixer.md +668 -0
- package/agents/gtd-code-reviewer.md +387 -0
- package/agents/gtd-codebase-mapper.md +853 -0
- package/agents/gtd-debug-session-manager.md +314 -0
- package/agents/gtd-debugger.md +1452 -0
- package/agents/gtd-doc-classifier.md +168 -0
- package/agents/gtd-doc-synthesizer.md +204 -0
- package/agents/gtd-doc-verifier.md +217 -0
- package/agents/gtd-doc-writer.md +615 -0
- package/agents/gtd-domain-researcher.md +153 -0
- package/agents/gtd-eval-auditor.md +191 -0
- package/agents/gtd-eval-planner.md +154 -0
- package/agents/gtd-framework-selector.md +160 -0
- package/agents/gtd-integration-checker.md +470 -0
- package/agents/gtd-intel-updater.md +342 -0
- package/agents/gtd-nyquist-auditor.md +203 -0
- package/agents/gtd-pattern-mapper.md +335 -0
- package/agents/gtd-phase-researcher.md +928 -0
- package/agents/gtd-plan-checker.md +1000 -0
- package/agents/gtd-planner.md +926 -0
- package/agents/gtd-project-researcher.md +677 -0
- package/agents/gtd-research-synthesizer.md +247 -0
- package/agents/gtd-roadmapper.md +688 -0
- package/agents/gtd-security-auditor.md +155 -0
- package/agents/gtd-task-executor.md +166 -0
- package/agents/gtd-ui-auditor.md +495 -0
- package/agents/gtd-ui-checker.md +309 -0
- package/agents/gtd-ui-researcher.md +380 -0
- package/agents/gtd-user-profiler.md +171 -0
- package/agents/gtd-verifier.md +917 -0
- package/bin/gtd-sdk.js +37 -0
- package/bin/install.js +11358 -0
- package/commands/gtd/add-tests.md +42 -0
- package/commands/gtd/ai-integration-phase.md +37 -0
- package/commands/gtd/audit-fix.md +34 -0
- package/commands/gtd/audit-milestone.md +37 -0
- package/commands/gtd/audit-uat.md +24 -0
- package/commands/gtd/autonomous.md +46 -0
- package/commands/gtd/capture.md +62 -0
- package/commands/gtd/cleanup.md +24 -0
- package/commands/gtd/code-review.md +59 -0
- package/commands/gtd/complete-milestone.md +143 -0
- package/commands/gtd/config.md +58 -0
- package/commands/gtd/debug.md +52 -0
- package/commands/gtd/discuss-phase.md +76 -0
- package/commands/gtd/docs-update.md +49 -0
- package/commands/gtd/eval-review.md +33 -0
- package/commands/gtd/explore.md +27 -0
- package/commands/gtd/export-phase-issues.md +43 -0
- package/commands/gtd/extract-learnings.md +23 -0
- package/commands/gtd/fast.md +31 -0
- package/commands/gtd/forensics.md +57 -0
- package/commands/gtd/graphify.md +199 -0
- package/commands/gtd/health.md +31 -0
- package/commands/gtd/help.md +28 -0
- package/commands/gtd/import.md +35 -0
- package/commands/gtd/inbox.md +39 -0
- package/commands/gtd/ingest-docs.md +42 -0
- package/commands/gtd/manager.md +45 -0
- package/commands/gtd/map-codebase.md +83 -0
- package/commands/gtd/milestone-summary.md +51 -0
- package/commands/gtd/mvp-phase.md +45 -0
- package/commands/gtd/new-milestone.md +45 -0
- package/commands/gtd/new-project.md +47 -0
- package/commands/gtd/ns-context.md +23 -0
- package/commands/gtd/ns-ideate.md +24 -0
- package/commands/gtd/ns-manage.md +28 -0
- package/commands/gtd/ns-project.md +22 -0
- package/commands/gtd/ns-review.md +26 -0
- package/commands/gtd/ns-workflow.md +30 -0
- package/commands/gtd/orchestrate-tasks.md +83 -0
- package/commands/gtd/pause-work.md +43 -0
- package/commands/gtd/phase.md +56 -0
- package/commands/gtd/plan-phase.md +62 -0
- package/commands/gtd/plan-review-convergence.md +59 -0
- package/commands/gtd/pr-branch.md +26 -0
- package/commands/gtd/profile-user.md +46 -0
- package/commands/gtd/progress.md +46 -0
- package/commands/gtd/quick.md +174 -0
- package/commands/gtd/resume-work.md +30 -0
- package/commands/gtd/review-backlog.md +63 -0
- package/commands/gtd/review.md +41 -0
- package/commands/gtd/secure-phase.md +36 -0
- package/commands/gtd/settings.md +29 -0
- package/commands/gtd/sketch.md +60 -0
- package/commands/gtd/spec-phase.md +63 -0
- package/commands/gtd/spike.md +57 -0
- package/commands/gtd/stats.md +19 -0
- package/commands/gtd/surface.md +130 -0
- package/commands/gtd/thread.md +24 -0
- package/commands/gtd/ui-phase.md +35 -0
- package/commands/gtd/ui-review.md +33 -0
- package/commands/gtd/ultraplan-phase.md +34 -0
- package/commands/gtd/undo.md +35 -0
- package/commands/gtd/update.md +48 -0
- package/commands/gtd/validate-phase.md +36 -0
- package/commands/gtd/verify-work.md +39 -0
- package/commands/gtd/work-task-issue.md +45 -0
- package/commands/gtd/workspace.md +52 -0
- package/commands/gtd/workstreams.md +70 -0
- package/get-tasks-done/bin/check-latest-version.cjs +104 -0
- package/get-tasks-done/bin/gtd-tools.cjs +1264 -0
- package/get-tasks-done/bin/lib/active-workstream-store.cjs +85 -0
- package/get-tasks-done/bin/lib/adr-parser.cjs +394 -0
- package/get-tasks-done/bin/lib/artifacts.cjs +53 -0
- package/get-tasks-done/bin/lib/audit.cjs +755 -0
- package/get-tasks-done/bin/lib/cjs-command-router-adapter.cjs +39 -0
- package/get-tasks-done/bin/lib/clusters.cjs +147 -0
- package/get-tasks-done/bin/lib/command-aliases.generated.cjs +830 -0
- package/get-tasks-done/bin/lib/commands.cjs +1031 -0
- package/get-tasks-done/bin/lib/config-schema.cjs +31 -0
- package/get-tasks-done/bin/lib/config.cjs +621 -0
- package/get-tasks-done/bin/lib/configuration.generated.cjs +253 -0
- package/get-tasks-done/bin/lib/context-utilization.cjs +47 -0
- package/get-tasks-done/bin/lib/core.cjs +1921 -0
- package/get-tasks-done/bin/lib/decisions.cjs +48 -0
- package/get-tasks-done/bin/lib/docs.cjs +270 -0
- package/get-tasks-done/bin/lib/drift.cjs +388 -0
- package/get-tasks-done/bin/lib/export-phase-issues.cjs +1862 -0
- package/get-tasks-done/bin/lib/fallow-runner.cjs +109 -0
- package/get-tasks-done/bin/lib/frontmatter.cjs +389 -0
- package/get-tasks-done/bin/lib/gap-checker.cjs +197 -0
- package/get-tasks-done/bin/lib/github-api-client.cjs +97 -0
- package/get-tasks-done/bin/lib/github-repo.cjs +154 -0
- package/get-tasks-done/bin/lib/graphify.cjs +592 -0
- package/get-tasks-done/bin/lib/gtd2-import.cjs +514 -0
- package/get-tasks-done/bin/lib/init-command-router.cjs +65 -0
- package/get-tasks-done/bin/lib/init.cjs +1898 -0
- package/get-tasks-done/bin/lib/install-profiles.cjs +589 -0
- package/get-tasks-done/bin/lib/installer-migration-authoring.cjs +117 -0
- package/get-tasks-done/bin/lib/installer-migration-report.cjs +354 -0
- package/get-tasks-done/bin/lib/installer-migrations/000-first-time-baseline.cjs +220 -0
- package/get-tasks-done/bin/lib/installer-migrations/001-legacy-orphan-files.cjs +41 -0
- package/get-tasks-done/bin/lib/installer-migrations/002-codex-legacy-hooks-json.cjs +80 -0
- package/get-tasks-done/bin/lib/installer-migrations/003-legacy-acronym-install-cleanup.cjs +135 -0
- package/get-tasks-done/bin/lib/installer-migrations.cjs +703 -0
- package/get-tasks-done/bin/lib/intel.cjs +643 -0
- package/get-tasks-done/bin/lib/learnings.cjs +379 -0
- package/get-tasks-done/bin/lib/milestone.cjs +314 -0
- package/get-tasks-done/bin/lib/model-catalog.cjs +143 -0
- package/get-tasks-done/bin/lib/model-profiles.cjs +27 -0
- package/get-tasks-done/bin/lib/orchestrate-tasks.cjs +2166 -0
- package/get-tasks-done/bin/lib/phase-command-router.cjs +96 -0
- package/get-tasks-done/bin/lib/phase.cjs +1422 -0
- package/get-tasks-done/bin/lib/phases-command-router.cjs +39 -0
- package/get-tasks-done/bin/lib/plan-scan.cjs +138 -0
- package/get-tasks-done/bin/lib/planning-workspace.cjs +361 -0
- package/get-tasks-done/bin/lib/profile-output.cjs +1132 -0
- package/get-tasks-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-tasks-done/bin/lib/project-root.generated.cjs +117 -0
- package/get-tasks-done/bin/lib/review-reviewer-selection.cjs +125 -0
- package/get-tasks-done/bin/lib/roadmap-command-router.cjs +23 -0
- package/get-tasks-done/bin/lib/roadmap.cjs +621 -0
- package/get-tasks-done/bin/lib/runtime-homes.cjs +178 -0
- package/get-tasks-done/bin/lib/runtime-slash.cjs +109 -0
- package/get-tasks-done/bin/lib/schema-detect.cjs +238 -0
- package/get-tasks-done/bin/lib/secrets.cjs +33 -0
- package/get-tasks-done/bin/lib/security.cjs +504 -0
- package/get-tasks-done/bin/lib/shell-command-projection.cjs +548 -0
- package/get-tasks-done/bin/lib/state-command-router.cjs +318 -0
- package/get-tasks-done/bin/lib/state-document.cjs +12 -0
- package/get-tasks-done/bin/lib/state-document.generated.cjs +127 -0
- package/get-tasks-done/bin/lib/state.cjs +1917 -0
- package/get-tasks-done/bin/lib/surface.cjs +398 -0
- package/get-tasks-done/bin/lib/task-issue-shared.cjs +64 -0
- package/get-tasks-done/bin/lib/template.cjs +228 -0
- package/get-tasks-done/bin/lib/uat.cjs +289 -0
- package/get-tasks-done/bin/lib/validate-command-router.cjs +57 -0
- package/get-tasks-done/bin/lib/verify-command-router.cjs +34 -0
- package/get-tasks-done/bin/lib/verify.cjs +1557 -0
- package/get-tasks-done/bin/lib/work-task-issue.cjs +3429 -0
- package/get-tasks-done/bin/lib/workstream-inventory-builder.generated.cjs +79 -0
- package/get-tasks-done/bin/lib/workstream-inventory.cjs +132 -0
- package/get-tasks-done/bin/lib/workstream-name-policy.cjs +33 -0
- package/get-tasks-done/bin/lib/workstream.cjs +374 -0
- package/get-tasks-done/bin/lib/worktree-safety.cjs +563 -0
- package/get-tasks-done/bin/verify-reapply-patches.cjs +247 -0
- package/get-tasks-done/contexts/dev.md +21 -0
- package/get-tasks-done/contexts/research.md +22 -0
- package/get-tasks-done/contexts/review.md +23 -0
- package/get-tasks-done/references/agent-contracts.md +79 -0
- package/get-tasks-done/references/ai-evals.md +156 -0
- package/get-tasks-done/references/ai-frameworks.md +186 -0
- package/get-tasks-done/references/artifact-types.md +131 -0
- package/get-tasks-done/references/autonomous-smart-discuss.md +277 -0
- package/get-tasks-done/references/checkpoints.md +814 -0
- package/get-tasks-done/references/common-bug-patterns.md +114 -0
- package/get-tasks-done/references/context-budget.md +85 -0
- package/get-tasks-done/references/continuation-format.md +253 -0
- package/get-tasks-done/references/debugger-philosophy.md +76 -0
- package/get-tasks-done/references/decimal-phase-calculation.md +64 -0
- package/get-tasks-done/references/doc-conflict-engine.md +91 -0
- package/get-tasks-done/references/domain-probes.md +125 -0
- package/get-tasks-done/references/execute-mvp-tdd.md +81 -0
- package/get-tasks-done/references/executor-examples.md +110 -0
- package/get-tasks-done/references/few-shot-examples/plan-checker.md +73 -0
- package/get-tasks-done/references/few-shot-examples/verifier.md +109 -0
- package/get-tasks-done/references/gate-prompts.md +100 -0
- package/get-tasks-done/references/gates.md +70 -0
- package/get-tasks-done/references/git-integration.md +298 -0
- package/get-tasks-done/references/git-planning-commit.md +40 -0
- package/get-tasks-done/references/ios-scaffold.md +123 -0
- package/get-tasks-done/references/mandatory-initial-read.md +2 -0
- package/get-tasks-done/references/model-profile-resolution.md +38 -0
- package/get-tasks-done/references/model-profiles.md +245 -0
- package/get-tasks-done/references/mvp-concepts.md +49 -0
- package/get-tasks-done/references/phase-argument-parsing.md +61 -0
- package/get-tasks-done/references/plan-checker-task-atomicity.md +73 -0
- package/get-tasks-done/references/planner-antipatterns.md +89 -0
- package/get-tasks-done/references/planner-chunked.md +49 -0
- package/get-tasks-done/references/planner-execution-flow.md +85 -0
- package/get-tasks-done/references/planner-gap-closure.md +71 -0
- package/get-tasks-done/references/planner-graphify-auto-update.md +67 -0
- package/get-tasks-done/references/planner-human-verify-mode.md +57 -0
- package/get-tasks-done/references/planner-mvp-mode.md +53 -0
- package/get-tasks-done/references/planner-reviews.md +39 -0
- package/get-tasks-done/references/planner-revision.md +87 -0
- package/get-tasks-done/references/planner-source-audit.md +73 -0
- package/get-tasks-done/references/planning-config.md +463 -0
- package/get-tasks-done/references/project-skills-discovery.md +19 -0
- package/get-tasks-done/references/questioning.md +162 -0
- package/get-tasks-done/references/revision-loop.md +97 -0
- package/get-tasks-done/references/scout-codebase.md +51 -0
- package/get-tasks-done/references/skeleton-template.md +48 -0
- package/get-tasks-done/references/sketch-interactivity.md +41 -0
- package/get-tasks-done/references/sketch-theme-system.md +94 -0
- package/get-tasks-done/references/sketch-tooling.md +45 -0
- package/get-tasks-done/references/sketch-variant-patterns.md +81 -0
- package/get-tasks-done/references/spidr-splitting.md +69 -0
- package/get-tasks-done/references/tdd.md +330 -0
- package/get-tasks-done/references/thinking-models-debug.md +44 -0
- package/get-tasks-done/references/thinking-models-execution.md +50 -0
- package/get-tasks-done/references/thinking-models-planning.md +62 -0
- package/get-tasks-done/references/thinking-models-research.md +50 -0
- package/get-tasks-done/references/thinking-models-verification.md +55 -0
- package/get-tasks-done/references/thinking-partner.md +96 -0
- package/get-tasks-done/references/ui-brand.md +160 -0
- package/get-tasks-done/references/universal-anti-patterns.md +63 -0
- package/get-tasks-done/references/user-profiling.md +681 -0
- package/get-tasks-done/references/user-story-template.md +58 -0
- package/get-tasks-done/references/verification-overrides.md +227 -0
- package/get-tasks-done/references/verification-patterns.md +612 -0
- package/get-tasks-done/references/verify-mvp-mode.md +85 -0
- package/get-tasks-done/references/workstream-flag.md +111 -0
- package/get-tasks-done/references/worktree-path-safety.md +89 -0
- package/get-tasks-done/templates/AI-SPEC.md +246 -0
- package/get-tasks-done/templates/DEBUG.md +169 -0
- package/get-tasks-done/templates/README.md +77 -0
- package/get-tasks-done/templates/SECURITY.md +61 -0
- package/get-tasks-done/templates/UAT.md +265 -0
- package/get-tasks-done/templates/UI-SPEC.md +100 -0
- package/get-tasks-done/templates/VALIDATION.md +76 -0
- package/get-tasks-done/templates/claude-md.md +147 -0
- package/get-tasks-done/templates/codebase/architecture.md +255 -0
- package/get-tasks-done/templates/codebase/concerns.md +310 -0
- package/get-tasks-done/templates/codebase/conventions.md +307 -0
- package/get-tasks-done/templates/codebase/integrations.md +280 -0
- package/get-tasks-done/templates/codebase/stack.md +186 -0
- package/get-tasks-done/templates/codebase/structure.md +285 -0
- package/get-tasks-done/templates/codebase/testing.md +480 -0
- package/get-tasks-done/templates/config.json +55 -0
- package/get-tasks-done/templates/context.md +352 -0
- package/get-tasks-done/templates/continue-here.md +78 -0
- package/get-tasks-done/templates/copilot-instructions.md +8 -0
- package/get-tasks-done/templates/debug-subagent-prompt.md +91 -0
- package/get-tasks-done/templates/dev-preferences.md +21 -0
- package/get-tasks-done/templates/discovery.md +146 -0
- package/get-tasks-done/templates/discussion-log.md +63 -0
- package/get-tasks-done/templates/milestone-archive.md +123 -0
- package/get-tasks-done/templates/milestone.md +115 -0
- package/get-tasks-done/templates/phase-prompt.md +616 -0
- package/get-tasks-done/templates/planner-subagent-prompt.md +118 -0
- package/get-tasks-done/templates/project.md +186 -0
- package/get-tasks-done/templates/requirements.md +231 -0
- package/get-tasks-done/templates/research-project/ARCHITECTURE.md +204 -0
- package/get-tasks-done/templates/research-project/FEATURES.md +147 -0
- package/get-tasks-done/templates/research-project/PITFALLS.md +200 -0
- package/get-tasks-done/templates/research-project/STACK.md +120 -0
- package/get-tasks-done/templates/research-project/SUMMARY.md +170 -0
- package/get-tasks-done/templates/research.md +592 -0
- package/get-tasks-done/templates/retrospective.md +54 -0
- package/get-tasks-done/templates/roadmap.md +202 -0
- package/get-tasks-done/templates/spec.md +307 -0
- package/get-tasks-done/templates/state.md +184 -0
- package/get-tasks-done/templates/summary-complex.md +59 -0
- package/get-tasks-done/templates/summary-minimal.md +41 -0
- package/get-tasks-done/templates/summary-standard.md +48 -0
- package/get-tasks-done/templates/summary.md +248 -0
- package/get-tasks-done/templates/user-profile.md +146 -0
- package/get-tasks-done/templates/user-setup.md +311 -0
- package/get-tasks-done/templates/verification-report.md +322 -0
- package/get-tasks-done/workflows/add-backlog.md +90 -0
- package/get-tasks-done/workflows/add-phase.md +112 -0
- package/get-tasks-done/workflows/add-tests.md +354 -0
- package/get-tasks-done/workflows/add-todo.md +160 -0
- package/get-tasks-done/workflows/ai-integration-phase.md +294 -0
- package/get-tasks-done/workflows/analyze-dependencies.md +96 -0
- package/get-tasks-done/workflows/audit-fix.md +177 -0
- package/get-tasks-done/workflows/audit-milestone.md +357 -0
- package/get-tasks-done/workflows/audit-uat.md +109 -0
- package/get-tasks-done/workflows/autonomous.md +790 -0
- package/get-tasks-done/workflows/check-todos.md +179 -0
- package/get-tasks-done/workflows/cleanup.md +154 -0
- package/get-tasks-done/workflows/code-review-fix.md +501 -0
- package/get-tasks-done/workflows/code-review.md +613 -0
- package/get-tasks-done/workflows/complete-milestone.md +854 -0
- package/get-tasks-done/workflows/debug.md +231 -0
- package/get-tasks-done/workflows/diagnose-issues.md +240 -0
- package/get-tasks-done/workflows/discovery-phase.md +291 -0
- package/get-tasks-done/workflows/discuss-phase/modes/advisor.md +175 -0
- package/get-tasks-done/workflows/discuss-phase/modes/all.md +28 -0
- package/get-tasks-done/workflows/discuss-phase/modes/analyze.md +44 -0
- package/get-tasks-done/workflows/discuss-phase/modes/auto.md +56 -0
- package/get-tasks-done/workflows/discuss-phase/modes/batch.md +52 -0
- package/get-tasks-done/workflows/discuss-phase/modes/chain.md +97 -0
- package/get-tasks-done/workflows/discuss-phase/modes/default.md +141 -0
- package/get-tasks-done/workflows/discuss-phase/modes/power.md +44 -0
- package/get-tasks-done/workflows/discuss-phase/modes/text.md +55 -0
- package/get-tasks-done/workflows/discuss-phase/templates/checkpoint.json +18 -0
- package/get-tasks-done/workflows/discuss-phase/templates/context.md +136 -0
- package/get-tasks-done/workflows/discuss-phase/templates/discussion-log.md +50 -0
- package/get-tasks-done/workflows/discuss-phase-assumptions.md +674 -0
- package/get-tasks-done/workflows/discuss-phase-power.md +291 -0
- package/get-tasks-done/workflows/discuss-phase.md +499 -0
- package/get-tasks-done/workflows/do.md +110 -0
- package/get-tasks-done/workflows/docs-update.md +1161 -0
- package/get-tasks-done/workflows/edit-phase.md +294 -0
- package/get-tasks-done/workflows/eval-review.md +155 -0
- package/get-tasks-done/workflows/explore.md +143 -0
- package/get-tasks-done/workflows/export-phase-issues.md +74 -0
- package/get-tasks-done/workflows/extract-learnings.md +242 -0
- package/get-tasks-done/workflows/fast.md +105 -0
- package/get-tasks-done/workflows/forensics.md +278 -0
- package/get-tasks-done/workflows/graduation.md +195 -0
- package/get-tasks-done/workflows/health.md +223 -0
- package/get-tasks-done/workflows/help/modes/brief.md +24 -0
- package/get-tasks-done/workflows/help/modes/default.md +52 -0
- package/get-tasks-done/workflows/help/modes/full.md +813 -0
- package/get-tasks-done/workflows/help/modes/topic.md +74 -0
- package/get-tasks-done/workflows/help.md +24 -0
- package/get-tasks-done/workflows/import.md +253 -0
- package/get-tasks-done/workflows/inbox.md +87 -0
- package/get-tasks-done/workflows/ingest-docs.md +339 -0
- package/get-tasks-done/workflows/insert-phase.md +151 -0
- package/get-tasks-done/workflows/list-phase-assumptions.md +178 -0
- package/get-tasks-done/workflows/list-workspaces.md +56 -0
- package/get-tasks-done/workflows/manager.md +393 -0
- package/get-tasks-done/workflows/map-codebase.md +443 -0
- package/get-tasks-done/workflows/milestone-summary.md +223 -0
- package/get-tasks-done/workflows/mvp-phase.md +221 -0
- package/get-tasks-done/workflows/new-milestone.md +634 -0
- package/get-tasks-done/workflows/new-project.md +1443 -0
- package/get-tasks-done/workflows/new-workspace.md +239 -0
- package/get-tasks-done/workflows/next.md +220 -0
- package/get-tasks-done/workflows/node-repair.md +92 -0
- package/get-tasks-done/workflows/note.md +158 -0
- package/get-tasks-done/workflows/orchestrate-tasks.md +209 -0
- package/get-tasks-done/workflows/pause-work.md +243 -0
- package/get-tasks-done/workflows/plan-milestone-gaps.md +280 -0
- package/get-tasks-done/workflows/plan-phase.md +1756 -0
- package/get-tasks-done/workflows/plan-review-convergence.md +329 -0
- package/get-tasks-done/workflows/plant-seed.md +229 -0
- package/get-tasks-done/workflows/pr-branch.md +156 -0
- package/get-tasks-done/workflows/profile-user.md +452 -0
- package/get-tasks-done/workflows/progress.md +668 -0
- package/get-tasks-done/workflows/quick.md +1169 -0
- package/get-tasks-done/workflows/reapply-patches.md +390 -0
- package/get-tasks-done/workflows/remove-phase.md +155 -0
- package/get-tasks-done/workflows/remove-workspace.md +107 -0
- package/get-tasks-done/workflows/resume-project.md +329 -0
- package/get-tasks-done/workflows/review.md +459 -0
- package/get-tasks-done/workflows/scan.md +104 -0
- package/get-tasks-done/workflows/secure-phase.md +179 -0
- package/get-tasks-done/workflows/session-report.md +146 -0
- package/get-tasks-done/workflows/settings-advanced.md +532 -0
- package/get-tasks-done/workflows/settings-integrations.md +281 -0
- package/get-tasks-done/workflows/settings.md +502 -0
- package/get-tasks-done/workflows/sketch-wrap-up.md +285 -0
- package/get-tasks-done/workflows/sketch.md +360 -0
- package/get-tasks-done/workflows/spec-phase.md +262 -0
- package/get-tasks-done/workflows/spike-wrap-up.md +306 -0
- package/get-tasks-done/workflows/spike.md +452 -0
- package/get-tasks-done/workflows/stats.md +79 -0
- package/get-tasks-done/workflows/sync-skills.md +182 -0
- package/get-tasks-done/workflows/thread.md +221 -0
- package/get-tasks-done/workflows/transition.md +693 -0
- package/get-tasks-done/workflows/ui-phase.md +327 -0
- package/get-tasks-done/workflows/ui-review.md +192 -0
- package/get-tasks-done/workflows/ultraplan-phase.md +198 -0
- package/get-tasks-done/workflows/undo.md +314 -0
- package/get-tasks-done/workflows/update.md +644 -0
- package/get-tasks-done/workflows/validate-phase.md +178 -0
- package/get-tasks-done/workflows/verify-phase.md +543 -0
- package/get-tasks-done/workflows/verify-work.md +797 -0
- package/get-tasks-done/workflows/work-task-issue.md +249 -0
- package/hooks/dist/gtd-check-update-worker.js +117 -0
- package/hooks/dist/gtd-check-update.js +64 -0
- package/hooks/dist/gtd-context-monitor.js +192 -0
- package/hooks/dist/gtd-phase-boundary.sh +47 -0
- package/hooks/dist/gtd-prompt-guard.js +97 -0
- package/hooks/dist/gtd-read-guard.js +101 -0
- package/hooks/dist/gtd-read-injection-scanner.js +152 -0
- package/hooks/dist/gtd-session-state.sh +59 -0
- package/hooks/dist/gtd-statusline.js +537 -0
- package/hooks/dist/gtd-update-banner.js +134 -0
- package/hooks/dist/gtd-validate-commit.sh +57 -0
- package/hooks/dist/gtd-workflow-guard.js +94 -0
- package/hooks/gtd-check-update-worker.js +117 -0
- package/hooks/gtd-check-update.js +64 -0
- package/hooks/gtd-context-monitor.js +192 -0
- package/hooks/gtd-graphify-update.sh +152 -0
- package/hooks/gtd-phase-boundary.sh +47 -0
- package/hooks/gtd-prompt-guard.js +97 -0
- package/hooks/gtd-read-guard.js +101 -0
- package/hooks/gtd-read-injection-scanner.js +152 -0
- package/hooks/gtd-session-state.sh +59 -0
- package/hooks/gtd-statusline.js +537 -0
- package/hooks/gtd-update-banner.js +134 -0
- package/hooks/gtd-validate-commit.sh +57 -0
- package/hooks/gtd-workflow-guard.js +94 -0
- package/hooks/lib/git-cmd.js +150 -0
- package/hooks/lib/gtd-graphify-rebuild.sh +65 -0
- package/package.json +85 -0
- package/scripts/audit-workflow-script-paths.cjs +73 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +187 -0
- package/scripts/command-contract-helpers.cjs +61 -0
- package/scripts/fix-slash-commands.cjs +106 -0
- package/scripts/lint-command-contract.cjs +108 -0
- package/scripts/lint-descriptions.cjs +83 -0
- package/scripts/lint-no-source-grep-extras.cjs +81 -0
- package/scripts/lint-no-source-grep.cjs +174 -0
- package/scripts/lint-pr-check-project-dir.cjs +94 -0
- package/scripts/lint-shell-command-projection-drift.cjs +57 -0
- package/scripts/lint-skill-deps.cjs +180 -0
- package/scripts/prompt-injection-scan.sh +201 -0
- package/scripts/run-tests.cjs +33 -0
- package/scripts/secret-scan.sh +227 -0
- package/scripts/strip-prose-atrefs.cjs +106 -0
- package/scripts/verify-tarball-sdk-dist.sh +69 -0
- package/sdk/dist/cli-transport.d.ts +19 -0
- package/sdk/dist/cli-transport.d.ts.map +1 -0
- package/sdk/dist/cli-transport.js +104 -0
- package/sdk/dist/cli-transport.js.map +1 -0
- package/sdk/dist/cli.d.ts +46 -0
- package/sdk/dist/cli.d.ts.map +1 -0
- package/sdk/dist/cli.js +511 -0
- package/sdk/dist/cli.js.map +1 -0
- package/sdk/dist/config.d.ts +107 -0
- package/sdk/dist/config.d.ts.map +1 -0
- package/sdk/dist/config.js +115 -0
- package/sdk/dist/config.js.map +1 -0
- package/sdk/dist/configuration/index.d.ts +85 -0
- package/sdk/dist/configuration/index.d.ts.map +1 -0
- package/sdk/dist/configuration/index.js +257 -0
- package/sdk/dist/configuration/index.js.map +1 -0
- package/sdk/dist/context-engine.d.ts +49 -0
- package/sdk/dist/context-engine.d.ts.map +1 -0
- package/sdk/dist/context-engine.js +142 -0
- package/sdk/dist/context-engine.js.map +1 -0
- package/sdk/dist/context-truncation.d.ts +33 -0
- package/sdk/dist/context-truncation.d.ts.map +1 -0
- package/sdk/dist/context-truncation.js +197 -0
- package/sdk/dist/context-truncation.js.map +1 -0
- package/sdk/dist/errors.d.ts +46 -0
- package/sdk/dist/errors.d.ts.map +1 -0
- package/sdk/dist/errors.js +64 -0
- package/sdk/dist/errors.js.map +1 -0
- package/sdk/dist/event-stream.d.ts +53 -0
- package/sdk/dist/event-stream.d.ts.map +1 -0
- package/sdk/dist/event-stream.js +321 -0
- package/sdk/dist/event-stream.js.map +1 -0
- package/sdk/dist/golden/capture.d.ts +15 -0
- package/sdk/dist/golden/capture.d.ts.map +1 -0
- package/sdk/dist/golden/capture.js +67 -0
- package/sdk/dist/golden/capture.js.map +1 -0
- package/sdk/dist/golden/golden-integration-covered.d.ts +6 -0
- package/sdk/dist/golden/golden-integration-covered.d.ts.map +1 -0
- package/sdk/dist/golden/golden-integration-covered.js +30 -0
- package/sdk/dist/golden/golden-integration-covered.js.map +1 -0
- package/sdk/dist/golden/golden-mutation-covered.d.ts +7 -0
- package/sdk/dist/golden/golden-mutation-covered.d.ts.map +1 -0
- package/sdk/dist/golden/golden-mutation-covered.js +17 -0
- package/sdk/dist/golden/golden-mutation-covered.js.map +1 -0
- package/sdk/dist/golden/golden-policy.d.ts +10 -0
- package/sdk/dist/golden/golden-policy.d.ts.map +1 -0
- package/sdk/dist/golden/golden-policy.js +97 -0
- package/sdk/dist/golden/golden-policy.js.map +1 -0
- package/sdk/dist/golden/init-golden-normalize.d.ts +8 -0
- package/sdk/dist/golden/init-golden-normalize.d.ts.map +1 -0
- package/sdk/dist/golden/init-golden-normalize.js +14 -0
- package/sdk/dist/golden/init-golden-normalize.js.map +1 -0
- package/sdk/dist/golden/read-only-golden-rows.d.ts +20 -0
- package/sdk/dist/golden/read-only-golden-rows.d.ts.map +1 -0
- package/sdk/dist/golden/read-only-golden-rows.js +67 -0
- package/sdk/dist/golden/read-only-golden-rows.js.map +1 -0
- package/sdk/dist/golden/registry-canonical-commands.d.ts +6 -0
- package/sdk/dist/golden/registry-canonical-commands.d.ts.map +1 -0
- package/sdk/dist/golden/registry-canonical-commands.js +30 -0
- package/sdk/dist/golden/registry-canonical-commands.js.map +1 -0
- package/sdk/dist/gtd-tools-error.d.ts +23 -0
- package/sdk/dist/gtd-tools-error.d.ts.map +1 -0
- package/sdk/dist/gtd-tools-error.js +29 -0
- package/sdk/dist/gtd-tools-error.js.map +1 -0
- package/sdk/dist/gtd-tools.d.ts +102 -0
- package/sdk/dist/gtd-tools.d.ts.map +1 -0
- package/sdk/dist/gtd-tools.js +222 -0
- package/sdk/dist/gtd-tools.js.map +1 -0
- package/sdk/dist/gtd-transport-policy.d.ts +10 -0
- package/sdk/dist/gtd-transport-policy.d.ts.map +1 -0
- package/sdk/dist/gtd-transport-policy.js +32 -0
- package/sdk/dist/gtd-transport-policy.js.map +1 -0
- package/sdk/dist/gtd-transport.d.ts +39 -0
- package/sdk/dist/gtd-transport.d.ts.map +1 -0
- package/sdk/dist/gtd-transport.js +78 -0
- package/sdk/dist/gtd-transport.js.map +1 -0
- package/sdk/dist/index.d.ts +127 -0
- package/sdk/dist/index.d.ts.map +1 -0
- package/sdk/dist/index.js +298 -0
- package/sdk/dist/index.js.map +1 -0
- package/sdk/dist/init-runner.d.ts +90 -0
- package/sdk/dist/init-runner.d.ts.map +1 -0
- package/sdk/dist/init-runner.js +613 -0
- package/sdk/dist/init-runner.js.map +1 -0
- package/sdk/dist/logger.d.ts +50 -0
- package/sdk/dist/logger.d.ts.map +1 -0
- package/sdk/dist/logger.js +70 -0
- package/sdk/dist/logger.js.map +1 -0
- package/sdk/dist/model-catalog.d.ts +33 -0
- package/sdk/dist/model-catalog.d.ts.map +1 -0
- package/sdk/dist/model-catalog.js +34 -0
- package/sdk/dist/model-catalog.js.map +1 -0
- package/sdk/dist/phase-prompt.d.ts +71 -0
- package/sdk/dist/phase-prompt.d.ts.map +1 -0
- package/sdk/dist/phase-prompt.js +208 -0
- package/sdk/dist/phase-prompt.js.map +1 -0
- package/sdk/dist/phase-runner.d.ts +145 -0
- package/sdk/dist/phase-runner.d.ts.map +1 -0
- package/sdk/dist/phase-runner.js +1206 -0
- package/sdk/dist/phase-runner.js.map +1 -0
- package/sdk/dist/plan-atomicity.d.ts +26 -0
- package/sdk/dist/plan-atomicity.d.ts.map +1 -0
- package/sdk/dist/plan-atomicity.js +116 -0
- package/sdk/dist/plan-atomicity.js.map +1 -0
- package/sdk/dist/plan-parser.d.ts +55 -0
- package/sdk/dist/plan-parser.d.ts.map +1 -0
- package/sdk/dist/plan-parser.js +391 -0
- package/sdk/dist/plan-parser.js.map +1 -0
- package/sdk/dist/planning-journal.d.ts +64 -0
- package/sdk/dist/planning-journal.d.ts.map +1 -0
- package/sdk/dist/planning-journal.js +88 -0
- package/sdk/dist/planning-journal.js.map +1 -0
- package/sdk/dist/planning-runtime.d.ts +67 -0
- package/sdk/dist/planning-runtime.d.ts.map +1 -0
- package/sdk/dist/planning-runtime.js +58 -0
- package/sdk/dist/planning-runtime.js.map +1 -0
- package/sdk/dist/project-root/index.d.ts +46 -0
- package/sdk/dist/project-root/index.d.ts.map +1 -0
- package/sdk/dist/project-root/index.js +138 -0
- package/sdk/dist/project-root/index.js.map +1 -0
- package/sdk/dist/prompt-builder.d.ts +44 -0
- package/sdk/dist/prompt-builder.d.ts.map +1 -0
- package/sdk/dist/prompt-builder.js +180 -0
- package/sdk/dist/prompt-builder.js.map +1 -0
- package/sdk/dist/prompt-sanitizer.d.ts +35 -0
- package/sdk/dist/prompt-sanitizer.d.ts.map +1 -0
- package/sdk/dist/prompt-sanitizer.js +101 -0
- package/sdk/dist/prompt-sanitizer.js.map +1 -0
- package/sdk/dist/query/active-workstream-store.d.ts +7 -0
- package/sdk/dist/query/active-workstream-store.d.ts.map +1 -0
- package/sdk/dist/query/active-workstream-store.js +56 -0
- package/sdk/dist/query/active-workstream-store.js.map +1 -0
- package/sdk/dist/query/agent-failure-classifier.d.ts +37 -0
- package/sdk/dist/query/agent-failure-classifier.d.ts.map +1 -0
- package/sdk/dist/query/agent-failure-classifier.js +82 -0
- package/sdk/dist/query/agent-failure-classifier.js.map +1 -0
- package/sdk/dist/query/audit-open.d.ts +46 -0
- package/sdk/dist/query/audit-open.d.ts.map +1 -0
- package/sdk/dist/query/audit-open.js +662 -0
- package/sdk/dist/query/audit-open.js.map +1 -0
- package/sdk/dist/query/check-auto-mode.d.ts +13 -0
- package/sdk/dist/query/check-auto-mode.d.ts.map +1 -0
- package/sdk/dist/query/check-auto-mode.js +40 -0
- package/sdk/dist/query/check-auto-mode.js.map +1 -0
- package/sdk/dist/query/check-completion.d.ts +10 -0
- package/sdk/dist/query/check-completion.d.ts.map +1 -0
- package/sdk/dist/query/check-completion.js +157 -0
- package/sdk/dist/query/check-completion.js.map +1 -0
- package/sdk/dist/query/check-decision-coverage.d.ts +33 -0
- package/sdk/dist/query/check-decision-coverage.d.ts.map +1 -0
- package/sdk/dist/query/check-decision-coverage.js +472 -0
- package/sdk/dist/query/check-decision-coverage.js.map +1 -0
- package/sdk/dist/query/check-gates.d.ts +10 -0
- package/sdk/dist/query/check-gates.d.ts.map +1 -0
- package/sdk/dist/query/check-gates.js +89 -0
- package/sdk/dist/query/check-gates.js.map +1 -0
- package/sdk/dist/query/check-verification-status.d.ts +10 -0
- package/sdk/dist/query/check-verification-status.d.ts.map +1 -0
- package/sdk/dist/query/check-verification-status.js +142 -0
- package/sdk/dist/query/check-verification-status.js.map +1 -0
- package/sdk/dist/query/command-aliases.generated.d.ts +31 -0
- package/sdk/dist/query/command-aliases.generated.d.ts.map +1 -0
- package/sdk/dist/query/command-aliases.generated.js +134 -0
- package/sdk/dist/query/command-aliases.generated.js.map +1 -0
- package/sdk/dist/query/command-catalog.d.ts +9 -0
- package/sdk/dist/query/command-catalog.d.ts.map +1 -0
- package/sdk/dist/query/command-catalog.js +17 -0
- package/sdk/dist/query/command-catalog.js.map +1 -0
- package/sdk/dist/query/command-definition.d.ts +19 -0
- package/sdk/dist/query/command-definition.d.ts.map +1 -0
- package/sdk/dist/query/command-definition.js +44 -0
- package/sdk/dist/query/command-definition.js.map +1 -0
- package/sdk/dist/query/command-family-handlers.d.ts +3 -0
- package/sdk/dist/query/command-family-handlers.d.ts.map +1 -0
- package/sdk/dist/query/command-family-handlers.js +93 -0
- package/sdk/dist/query/command-family-handlers.js.map +1 -0
- package/sdk/dist/query/command-manifest.d.ts +2 -0
- package/sdk/dist/query/command-manifest.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.init.d.ts +6 -0
- package/sdk/dist/query/command-manifest.init.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.init.js +22 -0
- package/sdk/dist/query/command-manifest.init.js.map +1 -0
- package/sdk/dist/query/command-manifest.js +17 -0
- package/sdk/dist/query/command-manifest.js.map +1 -0
- package/sdk/dist/query/command-manifest.non-family.d.ts +9 -0
- package/sdk/dist/query/command-manifest.non-family.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.non-family.js +62 -0
- package/sdk/dist/query/command-manifest.non-family.js.map +1 -0
- package/sdk/dist/query/command-manifest.phase.d.ts +6 -0
- package/sdk/dist/query/command-manifest.phase.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.phase.js +15 -0
- package/sdk/dist/query/command-manifest.phase.js.map +1 -0
- package/sdk/dist/query/command-manifest.phases.d.ts +7 -0
- package/sdk/dist/query/command-manifest.phases.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.phases.js +10 -0
- package/sdk/dist/query/command-manifest.phases.js.map +1 -0
- package/sdk/dist/query/command-manifest.roadmap.d.ts +6 -0
- package/sdk/dist/query/command-manifest.roadmap.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.roadmap.js +10 -0
- package/sdk/dist/query/command-manifest.roadmap.js.map +1 -0
- package/sdk/dist/query/command-manifest.state.d.ts +9 -0
- package/sdk/dist/query/command-manifest.state.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.state.js +30 -0
- package/sdk/dist/query/command-manifest.state.js.map +1 -0
- package/sdk/dist/query/command-manifest.types.d.ts +12 -0
- package/sdk/dist/query/command-manifest.types.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.types.js +2 -0
- package/sdk/dist/query/command-manifest.types.js.map +1 -0
- package/sdk/dist/query/command-manifest.validate.d.ts +6 -0
- package/sdk/dist/query/command-manifest.validate.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.validate.js +10 -0
- package/sdk/dist/query/command-manifest.validate.js.map +1 -0
- package/sdk/dist/query/command-manifest.verify.d.ts +6 -0
- package/sdk/dist/query/command-manifest.verify.d.ts.map +1 -0
- package/sdk/dist/query/command-manifest.verify.js +14 -0
- package/sdk/dist/query/command-manifest.verify.js.map +1 -0
- package/sdk/dist/query/command-static-catalog-domain.d.ts +3 -0
- package/sdk/dist/query/command-static-catalog-domain.d.ts.map +1 -0
- package/sdk/dist/query/command-static-catalog-domain.js +120 -0
- package/sdk/dist/query/command-static-catalog-domain.js.map +1 -0
- package/sdk/dist/query/command-static-catalog-foundation.d.ts +7 -0
- package/sdk/dist/query/command-static-catalog-foundation.d.ts.map +1 -0
- package/sdk/dist/query/command-static-catalog-foundation.js +95 -0
- package/sdk/dist/query/command-static-catalog-foundation.js.map +1 -0
- package/sdk/dist/query/command-topology.d.ts +32 -0
- package/sdk/dist/query/command-topology.d.ts.map +1 -0
- package/sdk/dist/query/command-topology.js +66 -0
- package/sdk/dist/query/command-topology.js.map +1 -0
- package/sdk/dist/query/commands-list.d.ts +14 -0
- package/sdk/dist/query/commands-list.d.ts.map +1 -0
- package/sdk/dist/query/commands-list.js +18 -0
- package/sdk/dist/query/commands-list.js.map +1 -0
- package/sdk/dist/query/commit.d.ts +79 -0
- package/sdk/dist/query/commit.d.ts.map +1 -0
- package/sdk/dist/query/commit.js +340 -0
- package/sdk/dist/query/commit.js.map +1 -0
- package/sdk/dist/query/config-gates.d.ts +12 -0
- package/sdk/dist/query/config-gates.d.ts.map +1 -0
- package/sdk/dist/query/config-gates.js +66 -0
- package/sdk/dist/query/config-gates.js.map +1 -0
- package/sdk/dist/query/config-mutation.d.ts +86 -0
- package/sdk/dist/query/config-mutation.d.ts.map +1 -0
- package/sdk/dist/query/config-mutation.js +445 -0
- package/sdk/dist/query/config-mutation.js.map +1 -0
- package/sdk/dist/query/config-query.d.ts +57 -0
- package/sdk/dist/query/config-query.d.ts.map +1 -0
- package/sdk/dist/query/config-query.js +208 -0
- package/sdk/dist/query/config-query.js.map +1 -0
- package/sdk/dist/query/config-schema.d.ts +19 -0
- package/sdk/dist/query/config-schema.d.ts.map +1 -0
- package/sdk/dist/query/config-schema.js +26 -0
- package/sdk/dist/query/config-schema.js.map +1 -0
- package/sdk/dist/query/decisions.d.ts +58 -0
- package/sdk/dist/query/decisions.d.ts.map +1 -0
- package/sdk/dist/query/decisions.js +161 -0
- package/sdk/dist/query/decisions.js.map +1 -0
- package/sdk/dist/query/detect-custom-files.d.ts +11 -0
- package/sdk/dist/query/detect-custom-files.d.ts.map +1 -0
- package/sdk/dist/query/detect-custom-files.js +89 -0
- package/sdk/dist/query/detect-custom-files.js.map +1 -0
- package/sdk/dist/query/detect-phase-type.d.ts +9 -0
- package/sdk/dist/query/detect-phase-type.d.ts.map +1 -0
- package/sdk/dist/query/detect-phase-type.js +124 -0
- package/sdk/dist/query/detect-phase-type.js.map +1 -0
- package/sdk/dist/query/docs-init.d.ts +26 -0
- package/sdk/dist/query/docs-init.d.ts.map +1 -0
- package/sdk/dist/query/docs-init.js +231 -0
- package/sdk/dist/query/docs-init.js.map +1 -0
- package/sdk/dist/query/fallow-audit.d.ts +44 -0
- package/sdk/dist/query/fallow-audit.d.ts.map +1 -0
- package/sdk/dist/query/fallow-audit.js +44 -0
- package/sdk/dist/query/fallow-audit.js.map +1 -0
- package/sdk/dist/query/frontmatter-mutation.d.ts +77 -0
- package/sdk/dist/query/frontmatter-mutation.d.ts.map +1 -0
- package/sdk/dist/query/frontmatter-mutation.js +317 -0
- package/sdk/dist/query/frontmatter-mutation.js.map +1 -0
- package/sdk/dist/query/frontmatter.d.ts +93 -0
- package/sdk/dist/query/frontmatter.d.ts.map +1 -0
- package/sdk/dist/query/frontmatter.js +365 -0
- package/sdk/dist/query/frontmatter.js.map +1 -0
- package/sdk/dist/query/helpers.d.ts +167 -0
- package/sdk/dist/query/helpers.d.ts.map +1 -0
- package/sdk/dist/query/helpers.js +495 -0
- package/sdk/dist/query/helpers.js.map +1 -0
- package/sdk/dist/query/index.d.ts +8 -0
- package/sdk/dist/query/index.d.ts.map +1 -0
- package/sdk/dist/query/index.js +6 -0
- package/sdk/dist/query/index.js.map +1 -0
- package/sdk/dist/query/init-complex.d.ts +47 -0
- package/sdk/dist/query/init-complex.d.ts.map +1 -0
- package/sdk/dist/query/init-complex.js +723 -0
- package/sdk/dist/query/init-complex.js.map +1 -0
- package/sdk/dist/query/init.d.ts +98 -0
- package/sdk/dist/query/init.d.ts.map +1 -0
- package/sdk/dist/query/init.js +1074 -0
- package/sdk/dist/query/init.js.map +1 -0
- package/sdk/dist/query/intel.d.ts +43 -0
- package/sdk/dist/query/intel.d.ts.map +1 -0
- package/sdk/dist/query/intel.js +416 -0
- package/sdk/dist/query/intel.js.map +1 -0
- package/sdk/dist/query/mutation-event-decorator.d.ts +5 -0
- package/sdk/dist/query/mutation-event-decorator.d.ts.map +1 -0
- package/sdk/dist/query/mutation-event-decorator.js +28 -0
- package/sdk/dist/query/mutation-event-decorator.js.map +1 -0
- package/sdk/dist/query/mutation-event-mapper.d.ts +4 -0
- package/sdk/dist/query/mutation-event-mapper.d.ts.map +1 -0
- package/sdk/dist/query/mutation-event-mapper.js +70 -0
- package/sdk/dist/query/mutation-event-mapper.js.map +1 -0
- package/sdk/dist/query/mvp.d.ts +113 -0
- package/sdk/dist/query/mvp.d.ts.map +1 -0
- package/sdk/dist/query/mvp.js +225 -0
- package/sdk/dist/query/mvp.js.map +1 -0
- package/sdk/dist/query/phase-filesystem-adapter.d.ts +4 -0
- package/sdk/dist/query/phase-filesystem-adapter.d.ts.map +1 -0
- package/sdk/dist/query/phase-filesystem-adapter.js +33 -0
- package/sdk/dist/query/phase-filesystem-adapter.js.map +1 -0
- package/sdk/dist/query/phase-lifecycle-policy.d.ts +34 -0
- package/sdk/dist/query/phase-lifecycle-policy.d.ts.map +1 -0
- package/sdk/dist/query/phase-lifecycle-policy.js +138 -0
- package/sdk/dist/query/phase-lifecycle-policy.js.map +1 -0
- package/sdk/dist/query/phase-lifecycle.d.ts +116 -0
- package/sdk/dist/query/phase-lifecycle.d.ts.map +1 -0
- package/sdk/dist/query/phase-lifecycle.js +1486 -0
- package/sdk/dist/query/phase-lifecycle.js.map +1 -0
- package/sdk/dist/query/phase-list-queries.d.ts +18 -0
- package/sdk/dist/query/phase-list-queries.d.ts.map +1 -0
- package/sdk/dist/query/phase-list-queries.js +129 -0
- package/sdk/dist/query/phase-list-queries.js.map +1 -0
- package/sdk/dist/query/phase-ready.d.ts +9 -0
- package/sdk/dist/query/phase-ready.d.ts.map +1 -0
- package/sdk/dist/query/phase-ready.js +132 -0
- package/sdk/dist/query/phase-ready.js.map +1 -0
- package/sdk/dist/query/phase-roadmap-mutation.d.ts +13 -0
- package/sdk/dist/query/phase-roadmap-mutation.d.ts.map +1 -0
- package/sdk/dist/query/phase-roadmap-mutation.js +65 -0
- package/sdk/dist/query/phase-roadmap-mutation.js.map +1 -0
- package/sdk/dist/query/phase.d.ts +48 -0
- package/sdk/dist/query/phase.d.ts.map +1 -0
- package/sdk/dist/query/phase.js +451 -0
- package/sdk/dist/query/phase.js.map +1 -0
- package/sdk/dist/query/pipeline.d.ts +53 -0
- package/sdk/dist/query/pipeline.d.ts.map +1 -0
- package/sdk/dist/query/pipeline.js +198 -0
- package/sdk/dist/query/pipeline.js.map +1 -0
- package/sdk/dist/query/plan-scan.d.ts +14 -0
- package/sdk/dist/query/plan-scan.d.ts.map +1 -0
- package/sdk/dist/query/plan-scan.js +70 -0
- package/sdk/dist/query/plan-scan.js.map +1 -0
- package/sdk/dist/query/plan-task-structure.d.ts +9 -0
- package/sdk/dist/query/plan-task-structure.d.ts.map +1 -0
- package/sdk/dist/query/plan-task-structure.js +59 -0
- package/sdk/dist/query/plan-task-structure.js.map +1 -0
- package/sdk/dist/query/profile-extract-messages.d.ts +40 -0
- package/sdk/dist/query/profile-extract-messages.d.ts.map +1 -0
- package/sdk/dist/query/profile-extract-messages.js +195 -0
- package/sdk/dist/query/profile-extract-messages.js.map +1 -0
- package/sdk/dist/query/profile-output.d.ts +11 -0
- package/sdk/dist/query/profile-output.d.ts.map +1 -0
- package/sdk/dist/query/profile-output.js +873 -0
- package/sdk/dist/query/profile-output.js.map +1 -0
- package/sdk/dist/query/profile-questionnaire-data.d.ts +21 -0
- package/sdk/dist/query/profile-questionnaire-data.d.ts.map +1 -0
- package/sdk/dist/query/profile-questionnaire-data.js +171 -0
- package/sdk/dist/query/profile-questionnaire-data.js.map +1 -0
- package/sdk/dist/query/profile-sample.d.ts +22 -0
- package/sdk/dist/query/profile-sample.d.ts.map +1 -0
- package/sdk/dist/query/profile-sample.js +136 -0
- package/sdk/dist/query/profile-sample.js.map +1 -0
- package/sdk/dist/query/profile-scan-sessions.d.ts +49 -0
- package/sdk/dist/query/profile-scan-sessions.d.ts.map +1 -0
- package/sdk/dist/query/profile-scan-sessions.js +137 -0
- package/sdk/dist/query/profile-scan-sessions.js.map +1 -0
- package/sdk/dist/query/profile.d.ts +61 -0
- package/sdk/dist/query/profile.d.ts.map +1 -0
- package/sdk/dist/query/profile.js +307 -0
- package/sdk/dist/query/profile.js.map +1 -0
- package/sdk/dist/query/progress.d.ts +77 -0
- package/sdk/dist/query/progress.d.ts.map +1 -0
- package/sdk/dist/query/progress.js +481 -0
- package/sdk/dist/query/progress.js.map +1 -0
- package/sdk/dist/query/query-cli-adapter.d.ts +8 -0
- package/sdk/dist/query/query-cli-adapter.d.ts.map +1 -0
- package/sdk/dist/query/query-cli-adapter.js +32 -0
- package/sdk/dist/query/query-cli-adapter.js.map +1 -0
- package/sdk/dist/query/query-cli-output.d.ts +9 -0
- package/sdk/dist/query/query-cli-output.d.ts.map +1 -0
- package/sdk/dist/query/query-cli-output.js +54 -0
- package/sdk/dist/query/query-cli-output.js.map +1 -0
- package/sdk/dist/query/query-command-diagnosis.d.ts +6 -0
- package/sdk/dist/query/query-command-diagnosis.d.ts.map +1 -0
- package/sdk/dist/query/query-command-diagnosis.js +6 -0
- package/sdk/dist/query/query-command-diagnosis.js.map +1 -0
- package/sdk/dist/query/query-command-resolution-strategy.d.ts +29 -0
- package/sdk/dist/query/query-command-resolution-strategy.d.ts.map +1 -0
- package/sdk/dist/query/query-command-resolution-strategy.js +103 -0
- package/sdk/dist/query/query-command-resolution-strategy.js.map +1 -0
- package/sdk/dist/query/query-command-semantics.d.ts +7 -0
- package/sdk/dist/query/query-command-semantics.d.ts.map +1 -0
- package/sdk/dist/query/query-command-semantics.js +7 -0
- package/sdk/dist/query/query-command-semantics.js.map +1 -0
- package/sdk/dist/query/query-dispatch-contract.d.ts +21 -0
- package/sdk/dist/query/query-dispatch-contract.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-contract.js +2 -0
- package/sdk/dist/query/query-dispatch-contract.js.map +1 -0
- package/sdk/dist/query/query-dispatch-error-mapper.d.ts +6 -0
- package/sdk/dist/query/query-dispatch-error-mapper.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-error-mapper.js +6 -0
- package/sdk/dist/query/query-dispatch-error-mapper.js.map +1 -0
- package/sdk/dist/query/query-dispatch-formatting.d.ts +6 -0
- package/sdk/dist/query/query-dispatch-formatting.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-formatting.js +6 -0
- package/sdk/dist/query/query-dispatch-formatting.js.map +1 -0
- package/sdk/dist/query/query-dispatch-input-validation.d.ts +6 -0
- package/sdk/dist/query/query-dispatch-input-validation.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-input-validation.js +6 -0
- package/sdk/dist/query/query-dispatch-input-validation.js.map +1 -0
- package/sdk/dist/query/query-dispatch-observability.d.ts +2 -0
- package/sdk/dist/query/query-dispatch-observability.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-observability.js +7 -0
- package/sdk/dist/query/query-dispatch-observability.js.map +1 -0
- package/sdk/dist/query/query-dispatch-plan.d.ts +6 -0
- package/sdk/dist/query/query-dispatch-plan.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-plan.js +6 -0
- package/sdk/dist/query/query-dispatch-plan.js.map +1 -0
- package/sdk/dist/query/query-dispatch-result-builder.d.ts +6 -0
- package/sdk/dist/query/query-dispatch-result-builder.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch-result-builder.js +6 -0
- package/sdk/dist/query/query-dispatch-result-builder.js.map +1 -0
- package/sdk/dist/query/query-dispatch.d.ts +48 -0
- package/sdk/dist/query/query-dispatch.d.ts.map +1 -0
- package/sdk/dist/query/query-dispatch.js +205 -0
- package/sdk/dist/query/query-dispatch.js.map +1 -0
- package/sdk/dist/query/query-error-details-schema.d.ts +19 -0
- package/sdk/dist/query/query-error-details-schema.d.ts.map +1 -0
- package/sdk/dist/query/query-error-details-schema.js +10 -0
- package/sdk/dist/query/query-error-details-schema.js.map +1 -0
- package/sdk/dist/query/query-error-taxonomy.d.ts +38 -0
- package/sdk/dist/query/query-error-taxonomy.d.ts.map +1 -0
- package/sdk/dist/query/query-error-taxonomy.js +74 -0
- package/sdk/dist/query/query-error-taxonomy.js.map +1 -0
- package/sdk/dist/query/query-fallback-bridge-adapter.d.ts +14 -0
- package/sdk/dist/query/query-fallback-bridge-adapter.d.ts.map +1 -0
- package/sdk/dist/query/query-fallback-bridge-adapter.js +33 -0
- package/sdk/dist/query/query-fallback-bridge-adapter.js.map +1 -0
- package/sdk/dist/query/query-fallback-executor.d.ts +11 -0
- package/sdk/dist/query/query-fallback-executor.d.ts.map +1 -0
- package/sdk/dist/query/query-fallback-executor.js +31 -0
- package/sdk/dist/query/query-fallback-executor.js.map +1 -0
- package/sdk/dist/query/query-fallback-output-classifier.d.ts +6 -0
- package/sdk/dist/query/query-fallback-output-classifier.d.ts.map +1 -0
- package/sdk/dist/query/query-fallback-output-classifier.js +27 -0
- package/sdk/dist/query/query-fallback-output-classifier.js.map +1 -0
- package/sdk/dist/query/query-fallback-policy.d.ts +6 -0
- package/sdk/dist/query/query-fallback-policy.d.ts.map +1 -0
- package/sdk/dist/query/query-fallback-policy.js +7 -0
- package/sdk/dist/query/query-fallback-policy.js.map +1 -0
- package/sdk/dist/query/query-native-dispatch-adapter.d.ts +7 -0
- package/sdk/dist/query/query-native-dispatch-adapter.d.ts.map +1 -0
- package/sdk/dist/query/query-native-dispatch-adapter.js +6 -0
- package/sdk/dist/query/query-native-dispatch-adapter.js.map +1 -0
- package/sdk/dist/query/query-policy-capability.d.ts +10 -0
- package/sdk/dist/query/query-policy-capability.d.ts.map +1 -0
- package/sdk/dist/query/query-policy-capability.js +17 -0
- package/sdk/dist/query/query-policy-capability.js.map +1 -0
- package/sdk/dist/query/query-runtime-context.d.ts +19 -0
- package/sdk/dist/query/query-runtime-context.d.ts.map +1 -0
- package/sdk/dist/query/query-runtime-context.js +31 -0
- package/sdk/dist/query/query-runtime-context.js.map +1 -0
- package/sdk/dist/query/query-unknown-command-hints.d.ts +2 -0
- package/sdk/dist/query/query-unknown-command-hints.d.ts.map +1 -0
- package/sdk/dist/query/query-unknown-command-hints.js +6 -0
- package/sdk/dist/query/query-unknown-command-hints.js.map +1 -0
- package/sdk/dist/query/registry-assembly-descriptor.d.ts +12 -0
- package/sdk/dist/query/registry-assembly-descriptor.d.ts.map +1 -0
- package/sdk/dist/query/registry-assembly-descriptor.js +61 -0
- package/sdk/dist/query/registry-assembly-descriptor.js.map +1 -0
- package/sdk/dist/query/registry-assembly-invariants.d.ts +30 -0
- package/sdk/dist/query/registry-assembly-invariants.d.ts.map +1 -0
- package/sdk/dist/query/registry-assembly-invariants.js +77 -0
- package/sdk/dist/query/registry-assembly-invariants.js.map +1 -0
- package/sdk/dist/query/registry-assembly.d.ts +10 -0
- package/sdk/dist/query/registry-assembly.d.ts.map +1 -0
- package/sdk/dist/query/registry-assembly.js +53 -0
- package/sdk/dist/query/registry-assembly.js.map +1 -0
- package/sdk/dist/query/registry.d.ts +90 -0
- package/sdk/dist/query/registry.d.ts.map +1 -0
- package/sdk/dist/query/registry.js +129 -0
- package/sdk/dist/query/registry.js.map +1 -0
- package/sdk/dist/query/requirements-extract-from-plans.d.ts +9 -0
- package/sdk/dist/query/requirements-extract-from-plans.d.ts.map +1 -0
- package/sdk/dist/query/requirements-extract-from-plans.js +76 -0
- package/sdk/dist/query/requirements-extract-from-plans.js.map +1 -0
- package/sdk/dist/query/roadmap-update-plan-progress.d.ts +11 -0
- package/sdk/dist/query/roadmap-update-plan-progress.d.ts.map +1 -0
- package/sdk/dist/query/roadmap-update-plan-progress.js +124 -0
- package/sdk/dist/query/roadmap-update-plan-progress.js.map +1 -0
- package/sdk/dist/query/roadmap.d.ts +137 -0
- package/sdk/dist/query/roadmap.d.ts.map +1 -0
- package/sdk/dist/query/roadmap.js +753 -0
- package/sdk/dist/query/roadmap.js.map +1 -0
- package/sdk/dist/query/route-next-action.d.ts +9 -0
- package/sdk/dist/query/route-next-action.d.ts.map +1 -0
- package/sdk/dist/query/route-next-action.js +342 -0
- package/sdk/dist/query/route-next-action.js.map +1 -0
- package/sdk/dist/query/schema-detect.d.ts +21 -0
- package/sdk/dist/query/schema-detect.d.ts.map +1 -0
- package/sdk/dist/query/schema-detect.js +146 -0
- package/sdk/dist/query/schema-detect.js.map +1 -0
- package/sdk/dist/query/secrets.d.ts +27 -0
- package/sdk/dist/query/secrets.d.ts.map +1 -0
- package/sdk/dist/query/secrets.js +42 -0
- package/sdk/dist/query/secrets.js.map +1 -0
- package/sdk/dist/query/skill-manifest.d.ts +50 -0
- package/sdk/dist/query/skill-manifest.d.ts.map +1 -0
- package/sdk/dist/query/skill-manifest.js +171 -0
- package/sdk/dist/query/skill-manifest.js.map +1 -0
- package/sdk/dist/query/skills.d.ts +27 -0
- package/sdk/dist/query/skills.d.ts.map +1 -0
- package/sdk/dist/query/skills.js +137 -0
- package/sdk/dist/query/skills.js.map +1 -0
- package/sdk/dist/query/state-document.d.ts +14 -0
- package/sdk/dist/query/state-document.d.ts.map +1 -0
- package/sdk/dist/query/state-document.js +110 -0
- package/sdk/dist/query/state-document.js.map +1 -0
- package/sdk/dist/query/state-mutation.d.ts +224 -0
- package/sdk/dist/query/state-mutation.d.ts.map +1 -0
- package/sdk/dist/query/state-mutation.js +1539 -0
- package/sdk/dist/query/state-mutation.js.map +1 -0
- package/sdk/dist/query/state-project-load.d.ts +23 -0
- package/sdk/dist/query/state-project-load.d.ts.map +1 -0
- package/sdk/dist/query/state-project-load.js +75 -0
- package/sdk/dist/query/state-project-load.js.map +1 -0
- package/sdk/dist/query/state.d.ts +78 -0
- package/sdk/dist/query/state.d.ts.map +1 -0
- package/sdk/dist/query/state.js +430 -0
- package/sdk/dist/query/state.js.map +1 -0
- package/sdk/dist/query/summary.d.ts +18 -0
- package/sdk/dist/query/summary.d.ts.map +1 -0
- package/sdk/dist/query/summary.js +249 -0
- package/sdk/dist/query/summary.js.map +1 -0
- package/sdk/dist/query/task-issues.d.ts +5 -0
- package/sdk/dist/query/task-issues.d.ts.map +1 -0
- package/sdk/dist/query/task-issues.js +72 -0
- package/sdk/dist/query/task-issues.js.map +1 -0
- package/sdk/dist/query/template.d.ts +46 -0
- package/sdk/dist/query/template.d.ts.map +1 -0
- package/sdk/dist/query/template.js +210 -0
- package/sdk/dist/query/template.js.map +1 -0
- package/sdk/dist/query/uat.d.ts +34 -0
- package/sdk/dist/query/uat.d.ts.map +1 -0
- package/sdk/dist/query/uat.js +339 -0
- package/sdk/dist/query/uat.js.map +1 -0
- package/sdk/dist/query/utils.d.ts +59 -0
- package/sdk/dist/query/utils.d.ts.map +1 -0
- package/sdk/dist/query/utils.js +74 -0
- package/sdk/dist/query/utils.js.map +1 -0
- package/sdk/dist/query/validate.d.ts +67 -0
- package/sdk/dist/query/validate.d.ts.map +1 -0
- package/sdk/dist/query/validate.js +908 -0
- package/sdk/dist/query/validate.js.map +1 -0
- package/sdk/dist/query/verify.d.ts +110 -0
- package/sdk/dist/query/verify.d.ts.map +1 -0
- package/sdk/dist/query/verify.js +647 -0
- package/sdk/dist/query/verify.js.map +1 -0
- package/sdk/dist/query/websearch.d.ts +24 -0
- package/sdk/dist/query/websearch.d.ts.map +1 -0
- package/sdk/dist/query/websearch.js +68 -0
- package/sdk/dist/query/websearch.js.map +1 -0
- package/sdk/dist/query/workspace.d.ts +62 -0
- package/sdk/dist/query/workspace.d.ts.map +1 -0
- package/sdk/dist/query/workspace.js +104 -0
- package/sdk/dist/query/workspace.js.map +1 -0
- package/sdk/dist/query/workstream-inventory.d.ts +24 -0
- package/sdk/dist/query/workstream-inventory.d.ts.map +1 -0
- package/sdk/dist/query/workstream-inventory.js +120 -0
- package/sdk/dist/query/workstream-inventory.js.map +1 -0
- package/sdk/dist/query/workstream.d.ts +35 -0
- package/sdk/dist/query/workstream.d.ts.map +1 -0
- package/sdk/dist/query/workstream.js +298 -0
- package/sdk/dist/query/workstream.js.map +1 -0
- package/sdk/dist/query/worktree.d.ts +3 -0
- package/sdk/dist/query/worktree.d.ts.map +1 -0
- package/sdk/dist/query/worktree.js +36 -0
- package/sdk/dist/query/worktree.js.map +1 -0
- package/sdk/dist/query-command-executor.d.ts +22 -0
- package/sdk/dist/query-command-executor.d.ts.map +1 -0
- package/sdk/dist/query-command-executor.js +22 -0
- package/sdk/dist/query-command-executor.js.map +1 -0
- package/sdk/dist/query-execution-policy.d.ts +24 -0
- package/sdk/dist/query-execution-policy.d.ts.map +1 -0
- package/sdk/dist/query-execution-policy.js +27 -0
- package/sdk/dist/query-execution-policy.js.map +1 -0
- package/sdk/dist/query-failure-classification.d.ts +9 -0
- package/sdk/dist/query-failure-classification.d.ts.map +1 -0
- package/sdk/dist/query-failure-classification.js +32 -0
- package/sdk/dist/query-failure-classification.js.map +1 -0
- package/sdk/dist/query-gtd-tools-path.d.ts +2 -0
- package/sdk/dist/query-gtd-tools-path.d.ts.map +1 -0
- package/sdk/dist/query-gtd-tools-path.js +2 -0
- package/sdk/dist/query-gtd-tools-path.js.map +1 -0
- package/sdk/dist/query-gtd-tools-runtime.d.ts +20 -0
- package/sdk/dist/query-gtd-tools-runtime.d.ts.map +1 -0
- package/sdk/dist/query-gtd-tools-runtime.js +47 -0
- package/sdk/dist/query-gtd-tools-runtime.js.map +1 -0
- package/sdk/dist/query-hotpath-methods.d.ts +19 -0
- package/sdk/dist/query-hotpath-methods.d.ts.map +1 -0
- package/sdk/dist/query-hotpath-methods.js +34 -0
- package/sdk/dist/query-hotpath-methods.js.map +1 -0
- package/sdk/dist/query-native-direct-adapter.d.ts +20 -0
- package/sdk/dist/query-native-direct-adapter.d.ts.map +1 -0
- package/sdk/dist/query-native-direct-adapter.js +52 -0
- package/sdk/dist/query-native-direct-adapter.js.map +1 -0
- package/sdk/dist/query-native-hotpath-adapter.d.ts +15 -0
- package/sdk/dist/query-native-hotpath-adapter.d.ts.map +1 -0
- package/sdk/dist/query-native-hotpath-adapter.js +32 -0
- package/sdk/dist/query-native-hotpath-adapter.js.map +1 -0
- package/sdk/dist/query-raw-output-projection.d.ts +6 -0
- package/sdk/dist/query-raw-output-projection.d.ts.map +1 -0
- package/sdk/dist/query-raw-output-projection.js +67 -0
- package/sdk/dist/query-raw-output-projection.js.map +1 -0
- package/sdk/dist/query-runtime-bridge.d.ts +61 -0
- package/sdk/dist/query-runtime-bridge.d.ts.map +1 -0
- package/sdk/dist/query-runtime-bridge.js +144 -0
- package/sdk/dist/query-runtime-bridge.js.map +1 -0
- package/sdk/dist/query-subprocess-adapter.d.ts +18 -0
- package/sdk/dist/query-subprocess-adapter.d.ts.map +1 -0
- package/sdk/dist/query-subprocess-adapter.js +92 -0
- package/sdk/dist/query-subprocess-adapter.js.map +1 -0
- package/sdk/dist/query-tools-error-factory.d.ts +16 -0
- package/sdk/dist/query-tools-error-factory.d.ts.map +1 -0
- package/sdk/dist/query-tools-error-factory.js +33 -0
- package/sdk/dist/query-tools-error-factory.js.map +1 -0
- package/sdk/dist/research-gate.d.ts +24 -0
- package/sdk/dist/research-gate.d.ts.map +1 -0
- package/sdk/dist/research-gate.js +70 -0
- package/sdk/dist/research-gate.js.map +1 -0
- package/sdk/dist/runtime-bridge-sync/index.d.ts +96 -0
- package/sdk/dist/runtime-bridge-sync/index.d.ts.map +1 -0
- package/sdk/dist/runtime-bridge-sync/index.js +109 -0
- package/sdk/dist/runtime-bridge-sync/index.js.map +1 -0
- package/sdk/dist/runtime-bridge-sync/worker.d.ts +2 -0
- package/sdk/dist/runtime-bridge-sync/worker.d.ts.map +1 -0
- package/sdk/dist/runtime-bridge-sync/worker.js +138 -0
- package/sdk/dist/runtime-bridge-sync/worker.js.map +1 -0
- package/sdk/dist/runtime-gate.d.ts +14 -0
- package/sdk/dist/runtime-gate.d.ts.map +1 -0
- package/sdk/dist/runtime-gate.js +48 -0
- package/sdk/dist/runtime-gate.js.map +1 -0
- package/sdk/dist/sdk-package-compatibility.d.ts +40 -0
- package/sdk/dist/sdk-package-compatibility.d.ts.map +1 -0
- package/sdk/dist/sdk-package-compatibility.js +94 -0
- package/sdk/dist/sdk-package-compatibility.js.map +1 -0
- package/sdk/dist/session-runner.d.ts +40 -0
- package/sdk/dist/session-runner.d.ts.map +1 -0
- package/sdk/dist/session-runner.js +274 -0
- package/sdk/dist/session-runner.js.map +1 -0
- package/sdk/dist/task-issues/adapters.d.ts +94 -0
- package/sdk/dist/task-issues/adapters.d.ts.map +1 -0
- package/sdk/dist/task-issues/adapters.js +2 -0
- package/sdk/dist/task-issues/adapters.js.map +1 -0
- package/sdk/dist/task-issues/core.d.ts +16 -0
- package/sdk/dist/task-issues/core.d.ts.map +1 -0
- package/sdk/dist/task-issues/core.js +283 -0
- package/sdk/dist/task-issues/core.js.map +1 -0
- package/sdk/dist/task-issues/export-phase-issues.d.ts +326 -0
- package/sdk/dist/task-issues/export-phase-issues.d.ts.map +1 -0
- package/sdk/dist/task-issues/export-phase-issues.js +1675 -0
- package/sdk/dist/task-issues/export-phase-issues.js.map +1 -0
- package/sdk/dist/task-issues/github-api-client.d.ts +23 -0
- package/sdk/dist/task-issues/github-api-client.d.ts.map +1 -0
- package/sdk/dist/task-issues/github-api-client.js +66 -0
- package/sdk/dist/task-issues/github-api-client.js.map +1 -0
- package/sdk/dist/task-issues/github-repo.d.ts +4 -0
- package/sdk/dist/task-issues/github-repo.d.ts.map +1 -0
- package/sdk/dist/task-issues/github-repo.js +108 -0
- package/sdk/dist/task-issues/github-repo.js.map +1 -0
- package/sdk/dist/task-issues/orchestrate-tasks.d.ts +319 -0
- package/sdk/dist/task-issues/orchestrate-tasks.d.ts.map +1 -0
- package/sdk/dist/task-issues/orchestrate-tasks.js +2040 -0
- package/sdk/dist/task-issues/orchestrate-tasks.js.map +1 -0
- package/sdk/dist/task-issues/plan-scan.d.ts +13 -0
- package/sdk/dist/task-issues/plan-scan.d.ts.map +1 -0
- package/sdk/dist/task-issues/plan-scan.js +70 -0
- package/sdk/dist/task-issues/plan-scan.js.map +1 -0
- package/sdk/dist/task-issues/runtime-slash.d.ts +4 -0
- package/sdk/dist/task-issues/runtime-slash.d.ts.map +1 -0
- package/sdk/dist/task-issues/runtime-slash.js +40 -0
- package/sdk/dist/task-issues/runtime-slash.js.map +1 -0
- package/sdk/dist/task-issues/task-issue-shared.d.ts +18 -0
- package/sdk/dist/task-issues/task-issue-shared.d.ts.map +1 -0
- package/sdk/dist/task-issues/task-issue-shared.js +44 -0
- package/sdk/dist/task-issues/task-issue-shared.js.map +1 -0
- package/sdk/dist/task-issues/types.d.ts +30 -0
- package/sdk/dist/task-issues/types.d.ts.map +1 -0
- package/sdk/dist/task-issues/types.js +2 -0
- package/sdk/dist/task-issues/types.js.map +1 -0
- package/sdk/dist/task-issues/work-task-issue.d.ts +1199 -0
- package/sdk/dist/task-issues/work-task-issue.d.ts.map +1 -0
- package/sdk/dist/task-issues/work-task-issue.js +3255 -0
- package/sdk/dist/task-issues/work-task-issue.js.map +1 -0
- package/sdk/dist/task-issues/worktree-safety.d.ts +5 -0
- package/sdk/dist/task-issues/worktree-safety.d.ts.map +1 -0
- package/sdk/dist/task-issues/worktree-safety.js +18 -0
- package/sdk/dist/task-issues/worktree-safety.js.map +1 -0
- package/sdk/dist/tool-scoping.d.ts +31 -0
- package/sdk/dist/tool-scoping.d.ts.map +1 -0
- package/sdk/dist/tool-scoping.js +54 -0
- package/sdk/dist/tool-scoping.js.map +1 -0
- package/sdk/dist/types.d.ts +795 -0
- package/sdk/dist/types.d.ts.map +1 -0
- package/sdk/dist/types.js +77 -0
- package/sdk/dist/types.js.map +1 -0
- package/sdk/dist/workstream-inventory/builder.d.ts +88 -0
- package/sdk/dist/workstream-inventory/builder.d.ts.map +1 -0
- package/sdk/dist/workstream-inventory/builder.js +84 -0
- package/sdk/dist/workstream-inventory/builder.js.map +1 -0
- package/sdk/dist/workstream-name-policy.d.ts +13 -0
- package/sdk/dist/workstream-name-policy.d.ts.map +1 -0
- package/sdk/dist/workstream-name-policy.js +24 -0
- package/sdk/dist/workstream-name-policy.js.map +1 -0
- package/sdk/dist/workstream-utils.d.ts +23 -0
- package/sdk/dist/workstream-utils.d.ts.map +1 -0
- package/sdk/dist/workstream-utils.js +34 -0
- package/sdk/dist/workstream-utils.js.map +1 -0
- package/sdk/dist/ws-transport.d.ts +32 -0
- package/sdk/dist/ws-transport.d.ts.map +1 -0
- package/sdk/dist/ws-transport.js +84 -0
- package/sdk/dist/ws-transport.js.map +1 -0
- package/sdk/package-lock.json +2530 -0
- package/sdk/package.json +67 -0
- package/sdk/prompts/templates/project.md +186 -0
- package/sdk/prompts/templates/requirements.md +231 -0
- package/sdk/prompts/templates/research-project/ARCHITECTURE.md +204 -0
- package/sdk/prompts/templates/research-project/FEATURES.md +147 -0
- package/sdk/prompts/templates/research-project/PITFALLS.md +200 -0
- package/sdk/prompts/templates/research-project/STACK.md +120 -0
- package/sdk/prompts/templates/research-project/SUMMARY.md +170 -0
- package/sdk/prompts/templates/roadmap.md +202 -0
- package/sdk/prompts/templates/state.md +175 -0
- package/sdk/shared/config-defaults.manifest.json +71 -0
- package/sdk/shared/config-schema.manifest.json +139 -0
- package/sdk/shared/model-catalog.json +122 -0
- package/sdk/src/assembled-prompts.test.ts +349 -0
- package/sdk/src/bug-3589-planning-paths-validation.test.ts +89 -0
- package/sdk/src/bug-3591-gtdtools-runtime-workstream.test.ts +179 -0
- package/sdk/src/cli-transport.test.ts +388 -0
- package/sdk/src/cli-transport.ts +130 -0
- package/sdk/src/cli.test.ts +426 -0
- package/sdk/src/cli.ts +589 -0
- package/sdk/src/config.test.ts +277 -0
- package/sdk/src/config.ts +201 -0
- package/sdk/src/configuration/index.test.ts +318 -0
- package/sdk/src/configuration/index.ts +325 -0
- package/sdk/src/context-engine.test.ts +295 -0
- package/sdk/src/context-engine.ts +170 -0
- package/sdk/src/context-truncation.test.ts +163 -0
- package/sdk/src/context-truncation.ts +233 -0
- package/sdk/src/e2e.integration.test.ts +181 -0
- package/sdk/src/errors.ts +72 -0
- package/sdk/src/event-stream.test.ts +661 -0
- package/sdk/src/event-stream.ts +441 -0
- package/sdk/src/golden/capture.ts +95 -0
- package/sdk/src/golden/fixtures/generate-slug.golden.json +1 -0
- package/sdk/src/golden/fixtures/profile-sample-sessions/demo-project/sample.jsonl +3 -0
- package/sdk/src/golden/fixtures/summary-extract-sample.md +26 -0
- package/sdk/src/golden/fixtures/uat-render-checkpoint-sample.md +15 -0
- package/sdk/src/golden/golden-integration-covered.ts +30 -0
- package/sdk/src/golden/golden-mutation-covered.ts +17 -0
- package/sdk/src/golden/golden-policy.test.ts +8 -0
- package/sdk/src/golden/golden-policy.ts +118 -0
- package/sdk/src/golden/golden.integration.test.ts +897 -0
- package/sdk/src/golden/init-golden-normalize.ts +15 -0
- package/sdk/src/golden/read-only-golden-rows.ts +77 -0
- package/sdk/src/golden/read-only-parity.integration.test.ts +133 -0
- package/sdk/src/golden/registry-canonical-commands.ts +31 -0
- package/sdk/src/gtd-tools-error.test.ts +21 -0
- package/sdk/src/gtd-tools-error.ts +65 -0
- package/sdk/src/gtd-tools.test.ts +472 -0
- package/sdk/src/gtd-tools.ts +285 -0
- package/sdk/src/gtd-transport-policy.test.ts +34 -0
- package/sdk/src/gtd-transport-policy.ts +48 -0
- package/sdk/src/gtd-transport.test.ts +292 -0
- package/sdk/src/gtd-transport.ts +117 -0
- package/sdk/src/index.ts +371 -0
- package/sdk/src/init-e2e.integration.test.ts +138 -0
- package/sdk/src/init-runner.test.ts +740 -0
- package/sdk/src/init-runner.ts +734 -0
- package/sdk/src/lifecycle-e2e.integration.test.ts +258 -0
- package/sdk/src/logger.test.ts +149 -0
- package/sdk/src/logger.ts +113 -0
- package/sdk/src/milestone-runner.test.ts +421 -0
- package/sdk/src/model-catalog.ts +77 -0
- package/sdk/src/phase-prompt.test.ts +536 -0
- package/sdk/src/phase-prompt.ts +257 -0
- package/sdk/src/phase-runner-types.test.ts +421 -0
- package/sdk/src/phase-runner.integration.test.ts +377 -0
- package/sdk/src/phase-runner.test.ts +2720 -0
- package/sdk/src/phase-runner.ts +1442 -0
- package/sdk/src/plan-atomicity.test.ts +220 -0
- package/sdk/src/plan-atomicity.ts +162 -0
- package/sdk/src/plan-parser.test.ts +579 -0
- package/sdk/src/plan-parser.ts +433 -0
- package/sdk/src/planning-journal.test.ts +70 -0
- package/sdk/src/planning-journal.ts +153 -0
- package/sdk/src/planning-runtime.test.ts +29 -0
- package/sdk/src/planning-runtime.ts +100 -0
- package/sdk/src/project-root/index.test.ts +186 -0
- package/sdk/src/project-root/index.ts +144 -0
- package/sdk/src/prompt-builder.test.ts +318 -0
- package/sdk/src/prompt-builder.ts +218 -0
- package/sdk/src/prompt-sanitizer.test.ts +260 -0
- package/sdk/src/prompt-sanitizer.ts +116 -0
- package/sdk/src/query/QUERY-HANDLERS.md +346 -0
- package/sdk/src/query/active-workstream-store.ts +50 -0
- package/sdk/src/query/agent-failure-classifier.test.ts +157 -0
- package/sdk/src/query/agent-failure-classifier.ts +104 -0
- package/sdk/src/query/audit-open.ts +722 -0
- package/sdk/src/query/check-auto-mode.test.ts +77 -0
- package/sdk/src/query/check-auto-mode.ts +49 -0
- package/sdk/src/query/check-completion.test.ts +113 -0
- package/sdk/src/query/check-completion.ts +182 -0
- package/sdk/src/query/check-decision-coverage.test.ts +519 -0
- package/sdk/src/query/check-decision-coverage.ts +554 -0
- package/sdk/src/query/check-gates.test.ts +103 -0
- package/sdk/src/query/check-gates.ts +112 -0
- package/sdk/src/query/check-verification-status.test.ts +143 -0
- package/sdk/src/query/check-verification-status.ts +160 -0
- package/sdk/src/query/command-aliases.generated.ts +155 -0
- package/sdk/src/query/command-catalog.ts +31 -0
- package/sdk/src/query/command-definition.test.ts +47 -0
- package/sdk/src/query/command-definition.ts +70 -0
- package/sdk/src/query/command-family-handlers.ts +116 -0
- package/sdk/src/query/command-manifest.init.ts +23 -0
- package/sdk/src/query/command-manifest.non-family.ts +89 -0
- package/sdk/src/query/command-manifest.phase.ts +16 -0
- package/sdk/src/query/command-manifest.phases.ts +11 -0
- package/sdk/src/query/command-manifest.roadmap.ts +11 -0
- package/sdk/src/query/command-manifest.state.ts +31 -0
- package/sdk/src/query/command-manifest.ts +17 -0
- package/sdk/src/query/command-manifest.types.ts +13 -0
- package/sdk/src/query/command-manifest.validate.ts +11 -0
- package/sdk/src/query/command-manifest.verify.ts +15 -0
- package/sdk/src/query/command-resolution.test.ts +70 -0
- package/sdk/src/query/command-seam-coverage.test.ts +118 -0
- package/sdk/src/query/command-static-catalog-domain.ts +121 -0
- package/sdk/src/query/command-static-catalog-foundation.ts +100 -0
- package/sdk/src/query/command-topology.test.ts +28 -0
- package/sdk/src/query/command-topology.ts +114 -0
- package/sdk/src/query/commands-list.test.ts +36 -0
- package/sdk/src/query/commands-list.ts +19 -0
- package/sdk/src/query/commit.test.ts +485 -0
- package/sdk/src/query/commit.ts +383 -0
- package/sdk/src/query/config-gates.test.ts +89 -0
- package/sdk/src/query/config-gates.ts +69 -0
- package/sdk/src/query/config-mutation.test.ts +572 -0
- package/sdk/src/query/config-mutation.ts +484 -0
- package/sdk/src/query/config-query.test.ts +367 -0
- package/sdk/src/query/config-query.ts +244 -0
- package/sdk/src/query/config-schema.ts +35 -0
- package/sdk/src/query/decisions.test.ts +215 -0
- package/sdk/src/query/decisions.ts +192 -0
- package/sdk/src/query/decomposed-handlers.test.ts +431 -0
- package/sdk/src/query/detect-custom-files.test.ts +115 -0
- package/sdk/src/query/detect-custom-files.ts +96 -0
- package/sdk/src/query/detect-phase-type.test.ts +105 -0
- package/sdk/src/query/detect-phase-type.ts +141 -0
- package/sdk/src/query/docs-init.ts +258 -0
- package/sdk/src/query/fallow-audit.ts +88 -0
- package/sdk/src/query/frontmatter-array.test.ts +14 -0
- package/sdk/src/query/frontmatter-mutation.test.ts +259 -0
- package/sdk/src/query/frontmatter-mutation.ts +343 -0
- package/sdk/src/query/frontmatter.test.ts +326 -0
- package/sdk/src/query/frontmatter.ts +395 -0
- package/sdk/src/query/helpers.test.ts +615 -0
- package/sdk/src/query/helpers.ts +523 -0
- package/sdk/src/query/index-thin-seam.test.ts +16 -0
- package/sdk/src/query/index.ts +9 -0
- package/sdk/src/query/init-complex.test.ts +616 -0
- package/sdk/src/query/init-complex.ts +805 -0
- package/sdk/src/query/init-progress-precedence.test.ts +177 -0
- package/sdk/src/query/init-workstream-milestone-op.test.ts +321 -0
- package/sdk/src/query/init.test.ts +645 -0
- package/sdk/src/query/init.ts +1167 -0
- package/sdk/src/query/intel.test.ts +90 -0
- package/sdk/src/query/intel.ts +404 -0
- package/sdk/src/query/mutation-event-decorator.test.ts +45 -0
- package/sdk/src/query/mutation-event-decorator.ts +37 -0
- package/sdk/src/query/mutation-event-mapper.test.ts +33 -0
- package/sdk/src/query/mutation-event-mapper.ts +102 -0
- package/sdk/src/query/mvp.test.ts +335 -0
- package/sdk/src/query/mvp.ts +292 -0
- package/sdk/src/query/normalize-query-command.test.ts +102 -0
- package/sdk/src/query/phase-filesystem-adapter.ts +35 -0
- package/sdk/src/query/phase-lifecycle-policy.ts +171 -0
- package/sdk/src/query/phase-lifecycle.test.ts +1750 -0
- package/sdk/src/query/phase-lifecycle.ts +1833 -0
- package/sdk/src/query/phase-list-queries.test.ts +88 -0
- package/sdk/src/query/phase-list-queries.ts +152 -0
- package/sdk/src/query/phase-ready.test.ts +65 -0
- package/sdk/src/query/phase-ready.ts +159 -0
- package/sdk/src/query/phase-roadmap-mutation.ts +77 -0
- package/sdk/src/query/phase.test.ts +651 -0
- package/sdk/src/query/phase.ts +550 -0
- package/sdk/src/query/pipeline.test.ts +169 -0
- package/sdk/src/query/pipeline.ts +243 -0
- package/sdk/src/query/plan-scan.test.ts +35 -0
- package/sdk/src/query/plan-scan.ts +82 -0
- package/sdk/src/query/plan-task-structure.test.ts +65 -0
- package/sdk/src/query/plan-task-structure.ts +63 -0
- package/sdk/src/query/policy-convergence.test.ts +28 -0
- package/sdk/src/query/profile-extract-messages.ts +247 -0
- package/sdk/src/query/profile-output.ts +929 -0
- package/sdk/src/query/profile-questionnaire-data.ts +181 -0
- package/sdk/src/query/profile-sample.ts +184 -0
- package/sdk/src/query/profile-scan-sessions.ts +174 -0
- package/sdk/src/query/profile.test.ts +136 -0
- package/sdk/src/query/profile.ts +337 -0
- package/sdk/src/query/progress.test.ts +156 -0
- package/sdk/src/query/progress.ts +566 -0
- package/sdk/src/query/query-cli-adapter.test.ts +79 -0
- package/sdk/src/query/query-cli-adapter.ts +39 -0
- package/sdk/src/query/query-cli-output.test.ts +33 -0
- package/sdk/src/query/query-cli-output.ts +63 -0
- package/sdk/src/query/query-command-diagnosis.test.ts +22 -0
- package/sdk/src/query/query-command-diagnosis.ts +5 -0
- package/sdk/src/query/query-command-resolution-strategy.test.ts +34 -0
- package/sdk/src/query/query-command-resolution-strategy.ts +121 -0
- package/sdk/src/query/query-command-semantics.test.ts +22 -0
- package/sdk/src/query/query-command-semantics.ts +22 -0
- package/sdk/src/query/query-dispatch-contract.ts +30 -0
- package/sdk/src/query/query-dispatch-error-mapper.test.ts +62 -0
- package/sdk/src/query/query-dispatch-error-mapper.ts +5 -0
- package/sdk/src/query/query-dispatch-formatting.test.ts +28 -0
- package/sdk/src/query/query-dispatch-formatting.ts +5 -0
- package/sdk/src/query/query-dispatch-input-validation.test.ts +23 -0
- package/sdk/src/query/query-dispatch-input-validation.ts +5 -0
- package/sdk/src/query/query-dispatch-observability.test.ts +10 -0
- package/sdk/src/query/query-dispatch-observability.ts +6 -0
- package/sdk/src/query/query-dispatch-plan.test.ts +25 -0
- package/sdk/src/query/query-dispatch-plan.ts +5 -0
- package/sdk/src/query/query-dispatch-result-builder.test.ts +16 -0
- package/sdk/src/query/query-dispatch-result-builder.ts +5 -0
- package/sdk/src/query/query-dispatch.test.ts +399 -0
- package/sdk/src/query/query-dispatch.ts +275 -0
- package/sdk/src/query/query-error-details-schema.ts +29 -0
- package/sdk/src/query/query-error-taxonomy.test.ts +39 -0
- package/sdk/src/query/query-error-taxonomy.ts +117 -0
- package/sdk/src/query/query-fallback-bridge-adapter.test.ts +32 -0
- package/sdk/src/query/query-fallback-bridge-adapter.ts +54 -0
- package/sdk/src/query/query-fallback-executor.test.ts +82 -0
- package/sdk/src/query/query-fallback-executor.ts +44 -0
- package/sdk/src/query/query-fallback-output-classifier.test.ts +36 -0
- package/sdk/src/query/query-fallback-output-classifier.ts +31 -0
- package/sdk/src/query/query-fallback-policy.test.ts +13 -0
- package/sdk/src/query/query-fallback-policy.ts +11 -0
- package/sdk/src/query/query-native-dispatch-adapter.ts +16 -0
- package/sdk/src/query/query-policy-capability.test.ts +10 -0
- package/sdk/src/query/query-policy-capability.ts +26 -0
- package/sdk/src/query/query-policy-snapshot.test.ts +9 -0
- package/sdk/src/query/query-registry-capability.test.ts +14 -0
- package/sdk/src/query/query-runtime-context.ts +44 -0
- package/sdk/src/query/query-unknown-command-hints.test.ts +9 -0
- package/sdk/src/query/query-unknown-command-hints.ts +5 -0
- package/sdk/src/query/registry-assembly-descriptor.ts +87 -0
- package/sdk/src/query/registry-assembly-invariants.ts +127 -0
- package/sdk/src/query/registry-assembly.test.ts +138 -0
- package/sdk/src/query/registry-assembly.ts +78 -0
- package/sdk/src/query/registry.test.ts +208 -0
- package/sdk/src/query/registry.ts +142 -0
- package/sdk/src/query/requirements-extract-from-plans.test.ts +58 -0
- package/sdk/src/query/requirements-extract-from-plans.ts +86 -0
- package/sdk/src/query/roadmap-update-plan-progress.test.ts +233 -0
- package/sdk/src/query/roadmap-update-plan-progress.ts +159 -0
- package/sdk/src/query/roadmap.test.ts +1181 -0
- package/sdk/src/query/roadmap.ts +894 -0
- package/sdk/src/query/route-next-action.test.ts +142 -0
- package/sdk/src/query/route-next-action.ts +370 -0
- package/sdk/src/query/schema-detect.ts +189 -0
- package/sdk/src/query/secrets.test.ts +66 -0
- package/sdk/src/query/secrets.ts +43 -0
- package/sdk/src/query/skill-manifest.test.ts +62 -0
- package/sdk/src/query/skill-manifest.ts +216 -0
- package/sdk/src/query/skills.test.ts +234 -0
- package/sdk/src/query/skills.ts +143 -0
- package/sdk/src/query/state-document.test.ts +197 -0
- package/sdk/src/query/state-document.ts +129 -0
- package/sdk/src/query/state-mutation.test.ts +1198 -0
- package/sdk/src/query/state-mutation.ts +1718 -0
- package/sdk/src/query/state-project-load.ts +80 -0
- package/sdk/src/query/state.test.ts +616 -0
- package/sdk/src/query/state.ts +463 -0
- package/sdk/src/query/sub-repos-root.integration.test.ts +79 -0
- package/sdk/src/query/summary.test.ts +95 -0
- package/sdk/src/query/summary.ts +296 -0
- package/sdk/src/query/task-issues.ts +86 -0
- package/sdk/src/query/template.test.ts +180 -0
- package/sdk/src/query/template.ts +242 -0
- package/sdk/src/query/uat.test.ts +77 -0
- package/sdk/src/query/uat.ts +365 -0
- package/sdk/src/query/utils.test.ts +82 -0
- package/sdk/src/query/utils.ts +106 -0
- package/sdk/src/query/validate.test.ts +831 -0
- package/sdk/src/query/validate.ts +952 -0
- package/sdk/src/query/verify.test.ts +416 -0
- package/sdk/src/query/verify.ts +711 -0
- package/sdk/src/query/websearch.test.ts +31 -0
- package/sdk/src/query/websearch.ts +82 -0
- package/sdk/src/query/workspace.test.ts +120 -0
- package/sdk/src/query/workspace.ts +145 -0
- package/sdk/src/query/workstream-inventory.ts +143 -0
- package/sdk/src/query/workstream.test.ts +153 -0
- package/sdk/src/query/workstream.ts +324 -0
- package/sdk/src/query/worktree.ts +39 -0
- package/sdk/src/query-command-executor.ts +31 -0
- package/sdk/src/query-execution-policy.test.ts +52 -0
- package/sdk/src/query-execution-policy.ts +46 -0
- package/sdk/src/query-failure-classification.test.ts +23 -0
- package/sdk/src/query-failure-classification.ts +42 -0
- package/sdk/src/query-gtd-tools-path.ts +1 -0
- package/sdk/src/query-gtd-tools-runtime.ts +89 -0
- package/sdk/src/query-hotpath-methods.ts +48 -0
- package/sdk/src/query-native-direct-adapter.test.ts +35 -0
- package/sdk/src/query-native-direct-adapter.ts +70 -0
- package/sdk/src/query-native-hotpath-adapter.test.ts +43 -0
- package/sdk/src/query-native-hotpath-adapter.ts +45 -0
- package/sdk/src/query-raw-output-projection.test.ts +39 -0
- package/sdk/src/query-raw-output-projection.ts +74 -0
- package/sdk/src/query-runtime-bridge.test.ts +150 -0
- package/sdk/src/query-runtime-bridge.ts +215 -0
- package/sdk/src/query-runtime-seam-coverage.test.ts +20 -0
- package/sdk/src/query-subprocess-adapter.test.ts +84 -0
- package/sdk/src/query-subprocess-adapter.ts +146 -0
- package/sdk/src/query-tools-error-factory.test.ts +35 -0
- package/sdk/src/query-tools-error-factory.ts +76 -0
- package/sdk/src/research-gate.test.ts +190 -0
- package/sdk/src/research-gate.ts +94 -0
- package/sdk/src/runtime-bridge-options.test.ts +33 -0
- package/sdk/src/runtime-bridge-sync/index.test.ts +164 -0
- package/sdk/src/runtime-bridge-sync/index.ts +154 -0
- package/sdk/src/runtime-bridge-sync/projectdir-regression.test.ts +151 -0
- package/sdk/src/runtime-bridge-sync/worker.ts +181 -0
- package/sdk/src/runtime-gate.test.ts +84 -0
- package/sdk/src/runtime-gate.ts +52 -0
- package/sdk/src/sdk-package-compatibility.test.ts +100 -0
- package/sdk/src/sdk-package-compatibility.ts +149 -0
- package/sdk/src/session-runner.test.ts +164 -0
- package/sdk/src/session-runner.ts +327 -0
- package/sdk/src/task-issues/adapters.ts +86 -0
- package/sdk/src/task-issues/core.ts +287 -0
- package/sdk/src/task-issues/export-phase-issues.ts +1862 -0
- package/sdk/src/task-issues/github-api-client.ts +107 -0
- package/sdk/src/task-issues/github-repo.ts +111 -0
- package/sdk/src/task-issues/orchestrate-tasks.ts +2167 -0
- package/sdk/src/task-issues/plan-scan.ts +78 -0
- package/sdk/src/task-issues/runtime-slash.ts +37 -0
- package/sdk/src/task-issues/task-issue-shared.ts +48 -0
- package/sdk/src/task-issues/types.ts +34 -0
- package/sdk/src/task-issues/work-task-issue.ts +3429 -0
- package/sdk/src/task-issues/worktree-safety.ts +15 -0
- package/sdk/src/task-issues-sdk.test.ts +182 -0
- package/sdk/src/tool-scoping.test.ts +160 -0
- package/sdk/src/tool-scoping.ts +61 -0
- package/sdk/src/types.ts +928 -0
- package/sdk/src/workflow-agent-skills-consistency.test.ts +98 -0
- package/sdk/src/workstream-inventory/builder.test.ts +241 -0
- package/sdk/src/workstream-inventory/builder.ts +170 -0
- package/sdk/src/workstream-name-policy.ts +24 -0
- package/sdk/src/workstream-utils.ts +36 -0
- package/sdk/src/ws-flag.test.ts +285 -0
- package/sdk/src/ws-transport.test.ts +161 -0
- package/sdk/src/ws-transport.ts +93 -0
- package/sdk/tsconfig.json +20 -0
|
@@ -0,0 +1,3429 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Task issue workflow selector and executor.
|
|
5
|
+
*
|
|
6
|
+
* Read-only mode reports the state-sync labels and next action without
|
|
7
|
+
* mutating GitHub or git. Execution mode applies the same preflight, claims one
|
|
8
|
+
* workable task, runs it in an isolated task worktree through the standalone
|
|
9
|
+
* gtd-task-executor contract, validates the result, and opens or updates the
|
|
10
|
+
* task PR.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import * as fs from 'node:fs';
|
|
14
|
+
import * as os from 'node:os';
|
|
15
|
+
import * as path from 'node:path';
|
|
16
|
+
import * as childProcess from 'node:child_process';
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
ERROR_REASON,
|
|
20
|
+
error,
|
|
21
|
+
output,
|
|
22
|
+
planningDir,
|
|
23
|
+
toPosixPath,
|
|
24
|
+
} from './core.js';
|
|
25
|
+
import { loadExportSource } from './export-phase-issues.js';
|
|
26
|
+
import { parseWorktreePorcelain } from './worktree-safety.js';
|
|
27
|
+
import { formatGtdSlashFor } from './runtime-slash.js';
|
|
28
|
+
import {
|
|
29
|
+
normalizeGitHubRepo,
|
|
30
|
+
resolveGitHubRepoFromGit,
|
|
31
|
+
} from './github-repo.js';
|
|
32
|
+
import {
|
|
33
|
+
CHECKPOINT_RESOLVED_STATUS,
|
|
34
|
+
PLAN_ID_RE,
|
|
35
|
+
TASK_EXPORT_STATUSES,
|
|
36
|
+
TASK_ID_RE,
|
|
37
|
+
isCheckpointTaskType,
|
|
38
|
+
isIssueOpen,
|
|
39
|
+
issueLabels,
|
|
40
|
+
mergeLabelSet,
|
|
41
|
+
normalizeRepoPath,
|
|
42
|
+
normalizeTaskType,
|
|
43
|
+
} from './task-issue-shared.js';
|
|
44
|
+
import {
|
|
45
|
+
api as ghApi,
|
|
46
|
+
repoEndpoint as ghRepoEndpoint,
|
|
47
|
+
runGhCommand,
|
|
48
|
+
} from './github-api-client.js';
|
|
49
|
+
|
|
50
|
+
const ISSUE_URL_RE = /^https?:\/\/github\.com\/([^/\s]+)\/([^/\s]+)\/issues\/(\d+)(?:[/?#].*)?$/i;
|
|
51
|
+
|
|
52
|
+
const TASK_STATE_LABELS = Object.freeze([
|
|
53
|
+
'gtd:ready',
|
|
54
|
+
'gtd:blocked',
|
|
55
|
+
'gtd:in-progress',
|
|
56
|
+
'gtd:pr-open',
|
|
57
|
+
'gtd:needs-rework',
|
|
58
|
+
'gtd:validation-failed',
|
|
59
|
+
'gtd:merged',
|
|
60
|
+
'gtd:rejected',
|
|
61
|
+
'gtd:blocked-human',
|
|
62
|
+
'gtd:checkpoint-resolved',
|
|
63
|
+
'gtd:source-drift',
|
|
64
|
+
]);
|
|
65
|
+
|
|
66
|
+
const PARENT_STATE_LABELS = Object.freeze([
|
|
67
|
+
'gtd:ready',
|
|
68
|
+
'gtd:blocked',
|
|
69
|
+
'gtd:ready-for-reconcile',
|
|
70
|
+
'gtd:reconcile-pr-open',
|
|
71
|
+
'gtd:reconcile-failed',
|
|
72
|
+
'gtd:source-drift',
|
|
73
|
+
'gtd:complete',
|
|
74
|
+
]);
|
|
75
|
+
|
|
76
|
+
const BLOCKING_TASK_LABELS = Object.freeze([
|
|
77
|
+
'gtd:blocked-human',
|
|
78
|
+
'gtd:source-drift',
|
|
79
|
+
'gtd:merged',
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
const REWORK_LABELS = Object.freeze([
|
|
83
|
+
'gtd:needs-rework',
|
|
84
|
+
'gtd:rejected',
|
|
85
|
+
'gtd:validation-failed',
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const DEFAULT_EXECUTOR_RETRY_BUDGET = 1;
|
|
89
|
+
const TASK_EXECUTOR_COMMAND = 'gtd-task-executor';
|
|
90
|
+
const GTD_COMPLETION_ARTIFACTS = Object.freeze([
|
|
91
|
+
'.planning/STATE.md',
|
|
92
|
+
'.planning/ROADMAP.md',
|
|
93
|
+
'.planning/REQUIREMENTS.md',
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
const SUMMARY_ARTIFACT_RE = /^\.planning\/phases\/.+\/.+-SUMMARY\.md$/;
|
|
97
|
+
|
|
98
|
+
class GitHubTaskIssueError extends Error {
|
|
99
|
+
constructor(message, operation = null) {
|
|
100
|
+
super(message);
|
|
101
|
+
this.name = 'GitHubTaskIssueError';
|
|
102
|
+
this.operation = operation;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class TaskExecutionError extends Error {
|
|
107
|
+
constructor(message, code = 'task_execution_failed', details = null) {
|
|
108
|
+
super(message);
|
|
109
|
+
this.name = 'TaskExecutionError';
|
|
110
|
+
this.code = code;
|
|
111
|
+
this.details = details;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function usage() {
|
|
116
|
+
return 'Usage: gtd-tools work-task-issue [issue-number|issue-url|task-id|plan-id] [--phase <phase>] [--repo owner/name] [--read-only|--execute] [--reconcile] [--complete-phase <phase> --execute]';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function parseArgs(args) {
|
|
120
|
+
const opts = {
|
|
121
|
+
selector: null,
|
|
122
|
+
phase: null,
|
|
123
|
+
repo: null,
|
|
124
|
+
mode: 'read-only',
|
|
125
|
+
explicitMode: false,
|
|
126
|
+
reconcile: false,
|
|
127
|
+
completePhase: null,
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
for (let i = 1; i < args.length; i += 1) {
|
|
131
|
+
const arg = args[i];
|
|
132
|
+
if (arg === '--phase') {
|
|
133
|
+
const value = args[i + 1];
|
|
134
|
+
if (!value || value.startsWith('--')) error(usage(), ERROR_REASON.USAGE);
|
|
135
|
+
opts.phase = value;
|
|
136
|
+
i += 1;
|
|
137
|
+
} else if (arg === '--repo') {
|
|
138
|
+
const value = args[i + 1];
|
|
139
|
+
if (!value || value.startsWith('--')) error(usage(), ERROR_REASON.USAGE);
|
|
140
|
+
opts.repo = normalizeRepo(value);
|
|
141
|
+
i += 1;
|
|
142
|
+
} else if (arg === '--read-only') {
|
|
143
|
+
if (opts.explicitMode && opts.mode !== 'read-only') error('Use either --read-only or --execute, not both.', ERROR_REASON.USAGE);
|
|
144
|
+
opts.mode = 'read-only';
|
|
145
|
+
opts.explicitMode = true;
|
|
146
|
+
} else if (arg === '--execute') {
|
|
147
|
+
if (opts.explicitMode && opts.mode !== 'execute') error('Use either --read-only or --execute, not both.', ERROR_REASON.USAGE);
|
|
148
|
+
opts.mode = 'execute';
|
|
149
|
+
opts.explicitMode = true;
|
|
150
|
+
} else if (arg === '--reconcile') {
|
|
151
|
+
opts.reconcile = true;
|
|
152
|
+
} else if (arg === '--complete-phase') {
|
|
153
|
+
const value = args[i + 1];
|
|
154
|
+
if (!value || value.startsWith('--')) error(usage(), ERROR_REASON.USAGE);
|
|
155
|
+
opts.completePhase = value;
|
|
156
|
+
i += 1;
|
|
157
|
+
} else if (arg.startsWith('--')) {
|
|
158
|
+
error(`Unknown work-task-issue flag: ${arg}`, ERROR_REASON.USAGE);
|
|
159
|
+
} else if (!opts.selector) {
|
|
160
|
+
opts.selector = arg;
|
|
161
|
+
} else {
|
|
162
|
+
error(usage(), ERROR_REASON.USAGE);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
delete opts.explicitMode;
|
|
167
|
+
return opts;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function normalizeRepo(repo) {
|
|
171
|
+
const value = normalizeGitHubRepo(repo);
|
|
172
|
+
if (!value) {
|
|
173
|
+
error(`Invalid GitHub repository "${repo}". Expected owner/name.`, ERROR_REASON.USAGE);
|
|
174
|
+
}
|
|
175
|
+
return value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function parseSelector(raw) {
|
|
179
|
+
if (!raw) return { mode: 'automatic', raw: null };
|
|
180
|
+
const text = String(raw).trim();
|
|
181
|
+
const url = text.match(ISSUE_URL_RE);
|
|
182
|
+
if (url) {
|
|
183
|
+
return {
|
|
184
|
+
mode: 'explicit',
|
|
185
|
+
type: 'issue',
|
|
186
|
+
raw: text,
|
|
187
|
+
issue: Number(url[3]),
|
|
188
|
+
repo: normalizeRepo(`${url[1]}/${url[2]}`),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (/^#?\d+$/.test(text)) {
|
|
192
|
+
return {
|
|
193
|
+
mode: 'explicit',
|
|
194
|
+
type: 'issue',
|
|
195
|
+
raw: text,
|
|
196
|
+
issue: Number(text.replace(/^#/, '')),
|
|
197
|
+
repo: null,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (TASK_ID_RE.test(text)) {
|
|
201
|
+
return {
|
|
202
|
+
mode: 'explicit',
|
|
203
|
+
type: 'task_id',
|
|
204
|
+
raw: text,
|
|
205
|
+
task_id: text.toUpperCase(),
|
|
206
|
+
repo: null,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
if (PLAN_ID_RE.test(text)) {
|
|
210
|
+
return {
|
|
211
|
+
mode: 'explicit',
|
|
212
|
+
type: 'plan_id',
|
|
213
|
+
raw: text,
|
|
214
|
+
plan_id: text.toUpperCase(),
|
|
215
|
+
repo: null,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
error(`Invalid task selector "${raw}". Expected issue number, issue URL, task id like 01-04-T02, or plan id like 01-04.`, ERROR_REASON.USAGE);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function parseExportMarker(body) {
|
|
222
|
+
const match = String(body || '').match(
|
|
223
|
+
/<!--\s*gtd-export:v1\s+phase=([^\s]+)\s+plan=([^\s]+)(?:\s+task=([^\s]+))?\s+source_hash=([a-f0-9]+)\s*-->/i,
|
|
224
|
+
);
|
|
225
|
+
if (!match) return null;
|
|
226
|
+
return {
|
|
227
|
+
phase: match[1],
|
|
228
|
+
plan: match[2],
|
|
229
|
+
task: match[3] || null,
|
|
230
|
+
source_hash: match[4],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function readManifestFile(cwd, absPath) {
|
|
235
|
+
try {
|
|
236
|
+
return {
|
|
237
|
+
absPath,
|
|
238
|
+
path: toPosixPath(path.relative(cwd, absPath)),
|
|
239
|
+
exists: true,
|
|
240
|
+
data: JSON.parse(fs.readFileSync(absPath, 'utf8')),
|
|
241
|
+
};
|
|
242
|
+
} catch (err) {
|
|
243
|
+
error(`Could not parse export manifest ${toPosixPath(path.relative(cwd, absPath))}: ${err.message}`, ERROR_REASON.USAGE);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function discoverManifestFiles(cwd) {
|
|
248
|
+
const githubDir = path.join(planningDir(cwd), 'github');
|
|
249
|
+
if (!fs.existsSync(githubDir)) return [];
|
|
250
|
+
return fs
|
|
251
|
+
.readdirSync(githubDir)
|
|
252
|
+
.filter((name) => /^phase-.+-issues\.json$/.test(name))
|
|
253
|
+
.map((name) => path.join(githubDir, name))
|
|
254
|
+
.sort();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function phaseArgFromManifestData(data) {
|
|
258
|
+
return data?.directory || data?.phase_number || data?.phase || null;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function makeScope(cwd, source, manifest, opts, selectorRepo) {
|
|
262
|
+
const manifestRepo = manifest.data?.repo || null;
|
|
263
|
+
if (opts.repo && manifestRepo && opts.repo !== manifestRepo) {
|
|
264
|
+
error(`Export manifest ${manifest.path} targets ${manifestRepo}; refusing to read ${opts.repo}.`, ERROR_REASON.USAGE);
|
|
265
|
+
}
|
|
266
|
+
if (selectorRepo && manifestRepo && selectorRepo !== manifestRepo) {
|
|
267
|
+
error(`Selector targets ${selectorRepo}; export manifest ${manifest.path} targets ${manifestRepo}.`, ERROR_REASON.USAGE);
|
|
268
|
+
}
|
|
269
|
+
if (selectorRepo && opts.repo && selectorRepo !== opts.repo) {
|
|
270
|
+
error(`Selector targets ${selectorRepo}; --repo targets ${opts.repo}.`, ERROR_REASON.USAGE);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
let repo = opts.repo || selectorRepo || manifestRepo;
|
|
274
|
+
if (!repo) {
|
|
275
|
+
const inferred = resolveGitHubRepoFromGit(cwd);
|
|
276
|
+
if (!inferred.ok) {
|
|
277
|
+
error(`Export manifest ${manifest.path} has no repo and no GitHub repository could be inferred from current git config (${inferred.message}). Re-run export-phase-issues with --repo owner/name.`, ERROR_REASON.USAGE);
|
|
278
|
+
}
|
|
279
|
+
repo = inferred.repo;
|
|
280
|
+
}
|
|
281
|
+
repo = normalizeRepo(repo);
|
|
282
|
+
|
|
283
|
+
if (manifest.data?.status !== 'complete') {
|
|
284
|
+
error(`Export manifest ${manifest.path} is ${manifest.data?.status || 'missing status'}; rerun export-phase-issues before selecting task work.`, ERROR_REASON.USAGE);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
repo,
|
|
289
|
+
manifest,
|
|
290
|
+
phase: source.phase,
|
|
291
|
+
plans: source.plans,
|
|
292
|
+
planMap: new Map(source.plans.map((plan) => [plan.id, plan])),
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function loadScopes(cwd, opts, selector) {
|
|
297
|
+
if (opts.phase) {
|
|
298
|
+
const source = loadExportSource(cwd, { phase: opts.phase });
|
|
299
|
+
if (!source.manifest.exists) {
|
|
300
|
+
error(`No export manifest found for phase ${opts.phase}. Run export-phase-issues write mode first.`, ERROR_REASON.USAGE);
|
|
301
|
+
}
|
|
302
|
+
return [makeScope(cwd, source, source.manifest, opts, selector.repo)];
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const manifestFiles = discoverManifestFiles(cwd);
|
|
306
|
+
if (manifestFiles.length === 0) {
|
|
307
|
+
error('No GitHub issue export manifests found. Run export-phase-issues write mode first.', ERROR_REASON.USAGE);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const scopes = [];
|
|
311
|
+
const requestedRepo = selector.repo || opts.repo || null;
|
|
312
|
+
for (const file of manifestFiles) {
|
|
313
|
+
const manifest = readManifestFile(cwd, file);
|
|
314
|
+
if (requestedRepo && manifest.data?.repo && manifest.data.repo !== requestedRepo) continue;
|
|
315
|
+
const phaseArg = phaseArgFromManifestData(manifest.data);
|
|
316
|
+
if (!phaseArg) {
|
|
317
|
+
error(`Export manifest ${manifest.path} has no phase directory or phase id.`, ERROR_REASON.USAGE);
|
|
318
|
+
}
|
|
319
|
+
const source = loadExportSource(cwd, { phase: phaseArg });
|
|
320
|
+
scopes.push(makeScope(cwd, source, source.manifest, opts, selector.repo));
|
|
321
|
+
}
|
|
322
|
+
if (scopes.length === 0) {
|
|
323
|
+
error(`No GitHub issue export manifests matched ${requestedRepo}.`, ERROR_REASON.USAGE);
|
|
324
|
+
}
|
|
325
|
+
return scopes;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function manifestPlanEntry(scope, planId) {
|
|
329
|
+
return scope.manifest.data?.plans?.[planId] || null;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function manifestTaskEntry(scope, planId, taskId) {
|
|
333
|
+
return scope.manifest.data?.plans?.[planId]?.tasks?.[taskId] || null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function manifestTaskExportStatus(entry) {
|
|
337
|
+
if (!entry) return null;
|
|
338
|
+
if (entry.exportStatus) return entry.exportStatus;
|
|
339
|
+
return TASK_EXPORT_STATUSES.has(entry.status) ? entry.status : null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function manifestTaskCheckpointStatus(entry) {
|
|
343
|
+
if (!entry) return null;
|
|
344
|
+
if (entry.checkpointStatus) return entry.checkpointStatus;
|
|
345
|
+
return entry.status === CHECKPOINT_RESOLVED_STATUS ? CHECKPOINT_RESOLVED_STATUS : null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function normalizeTaskManifestEntryForWrite(entry) {
|
|
349
|
+
if (!entry) return;
|
|
350
|
+
const exportStatus = manifestTaskExportStatus(entry);
|
|
351
|
+
if (exportStatus && !entry.exportStatus) entry.exportStatus = exportStatus;
|
|
352
|
+
const checkpointStatus = manifestTaskCheckpointStatus(entry);
|
|
353
|
+
if (checkpointStatus && !entry.checkpointStatus) entry.checkpointStatus = checkpointStatus;
|
|
354
|
+
delete entry.status;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function taskBranchName(taskId, issueNumber) {
|
|
358
|
+
return `gtd/task-${taskId}-${issueNumber}`;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function reconciliationBranchName(planId, issueNumber) {
|
|
362
|
+
return `gtd/reconcile-${planId}-${issueNumber}`;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function callRead(operation, fallback, fn, errors) {
|
|
366
|
+
try {
|
|
367
|
+
const value = fn();
|
|
368
|
+
return value === undefined || value === null ? fallback : value;
|
|
369
|
+
} catch (err) {
|
|
370
|
+
errors.push({
|
|
371
|
+
operation,
|
|
372
|
+
message: err.message || String(err),
|
|
373
|
+
});
|
|
374
|
+
return fallback;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function listBlockedBy(adapter, issueNumber, errors, operation) {
|
|
379
|
+
if (!adapter || typeof adapter.listBlockedBy !== 'function') {
|
|
380
|
+
errors.push({
|
|
381
|
+
operation,
|
|
382
|
+
message: 'GitHub issue dependency reads are unavailable.',
|
|
383
|
+
});
|
|
384
|
+
return [];
|
|
385
|
+
}
|
|
386
|
+
const blockers = callRead(operation, [], () => adapter.listBlockedBy(issueNumber), errors);
|
|
387
|
+
return Array.isArray(blockers) ? blockers : [];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function listPullRequestsForIssue(adapter, issueNumber, branchName, errors) {
|
|
391
|
+
if (!adapter || typeof adapter.listPullRequestsForIssue !== 'function') return [];
|
|
392
|
+
const prs = callRead(
|
|
393
|
+
`list_pull_requests_for_issue:${issueNumber}`,
|
|
394
|
+
[],
|
|
395
|
+
() => adapter.listPullRequestsForIssue(issueNumber, branchName),
|
|
396
|
+
errors,
|
|
397
|
+
);
|
|
398
|
+
return Array.isArray(prs) ? dedupePrs(prs) : [];
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function dedupePrs(prs) {
|
|
402
|
+
const seen = new Set();
|
|
403
|
+
const result = [];
|
|
404
|
+
for (const pr of prs || []) {
|
|
405
|
+
const key = pr.url || pr.number;
|
|
406
|
+
if (!key || seen.has(key)) continue;
|
|
407
|
+
seen.add(key);
|
|
408
|
+
result.push(pr);
|
|
409
|
+
}
|
|
410
|
+
return result.sort((a, b) => Number(a.number || 0) - Number(b.number || 0));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function normalizePr(pr) {
|
|
414
|
+
const state = String(pr.state || '').toUpperCase();
|
|
415
|
+
const merged = Boolean(pr.mergedAt || pr.merged || state === 'MERGED');
|
|
416
|
+
const open = state === 'OPEN' || state === 'open';
|
|
417
|
+
const closed = state === 'CLOSED' || state === 'closed';
|
|
418
|
+
const changesRequested =
|
|
419
|
+
pr.changesRequested === true ||
|
|
420
|
+
String(pr.reviewDecision || '').toUpperCase() === 'CHANGES_REQUESTED' ||
|
|
421
|
+
Number(pr.unresolvedComments || 0) > 0 ||
|
|
422
|
+
Number(pr.actionableComments || 0) > 0;
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
number: pr.number,
|
|
426
|
+
title: pr.title || '',
|
|
427
|
+
state: state || (merged ? 'MERGED' : ''),
|
|
428
|
+
url: pr.url || null,
|
|
429
|
+
headRefName: pr.headRefName || pr.head || null,
|
|
430
|
+
baseRefName: pr.baseRefName || pr.base || null,
|
|
431
|
+
isDraft: Boolean(pr.isDraft),
|
|
432
|
+
mergedAt: pr.mergedAt || null,
|
|
433
|
+
reviewDecision: pr.reviewDecision || null,
|
|
434
|
+
open,
|
|
435
|
+
merged,
|
|
436
|
+
closedUnmerged: closed && !merged,
|
|
437
|
+
changesRequested,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function prState(prs) {
|
|
442
|
+
const normalized = prs.map(normalizePr);
|
|
443
|
+
const open = normalized.filter((pr) => pr.open);
|
|
444
|
+
const merged = normalized.filter((pr) => pr.merged);
|
|
445
|
+
const closedUnmerged = normalized.filter((pr) => pr.closedUnmerged);
|
|
446
|
+
const openNeedsRework = open.filter((pr) => pr.changesRequested);
|
|
447
|
+
return {
|
|
448
|
+
all: normalized,
|
|
449
|
+
open,
|
|
450
|
+
merged,
|
|
451
|
+
closedUnmerged,
|
|
452
|
+
openNeedsRework,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function latestPr(prs) {
|
|
457
|
+
return [...(prs || [])].sort((a, b) => Number(b.number || 0) - Number(a.number || 0))[0] || null;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function callWrite(operation, fn) {
|
|
461
|
+
try {
|
|
462
|
+
return fn();
|
|
463
|
+
} catch (err) {
|
|
464
|
+
throw new TaskExecutionError(`${operation}: ${err.message || String(err)}`, 'github_write_failed', { operation });
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function setIssueLabels(adapter, issueNumber, labels) {
|
|
469
|
+
if (!adapter || typeof adapter.setIssueLabels !== 'function') {
|
|
470
|
+
throw new TaskExecutionError('GitHub issue label writes are unavailable.', 'github_write_unavailable');
|
|
471
|
+
}
|
|
472
|
+
return callWrite(`set_issue_labels:${issueNumber}`, () => adapter.setIssueLabels(issueNumber, labels));
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function commentIssue(adapter, issueNumber, body) {
|
|
476
|
+
if (!adapter || typeof adapter.commentIssue !== 'function') {
|
|
477
|
+
throw new TaskExecutionError('GitHub issue comments are unavailable.', 'github_write_unavailable');
|
|
478
|
+
}
|
|
479
|
+
return callWrite(`comment_issue:${issueNumber}`, () => adapter.commentIssue(issueNumber, body));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function updateIssueState(adapter, issueNumber, state) {
|
|
483
|
+
if (!adapter || typeof adapter.updateIssueState !== 'function') return null;
|
|
484
|
+
return callWrite(`update_issue_state:${issueNumber}:${state}`, () => adapter.updateIssueState(issueNumber, state));
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function applyLabelActions(adapter, record) {
|
|
488
|
+
const actions = record.labels.actions;
|
|
489
|
+
if (!actions || (actions.add.length === 0 && actions.remove.length === 0)) return null;
|
|
490
|
+
const labels = mergeLabelSet(record.labels.current, actions.add, actions.remove);
|
|
491
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
492
|
+
record.labels.current = labels;
|
|
493
|
+
record.labels.virtual = labels;
|
|
494
|
+
record.labels.actions = { add: [], remove: [] };
|
|
495
|
+
return {
|
|
496
|
+
issue: record.issue_number,
|
|
497
|
+
kind: record.kind,
|
|
498
|
+
plan_id: record.plan_id,
|
|
499
|
+
task_id: record.task_id || null,
|
|
500
|
+
labels,
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function writeManifestData(manifest) {
|
|
505
|
+
manifest.data.updated_at = new Date().toISOString();
|
|
506
|
+
fs.writeFileSync(manifest.absPath, `${JSON.stringify(manifest.data, null, 2)}\n`, 'utf8');
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function syncCheckpointManifestStatus(record) {
|
|
510
|
+
if (!isResolvedCheckpointTask(record)) return null;
|
|
511
|
+
const entry = manifestTaskEntry(record.scope, record.plan_id, record.task_id);
|
|
512
|
+
if (!entry) return null;
|
|
513
|
+
const alreadyResolved = manifestTaskCheckpointStatus(entry) === CHECKPOINT_RESOLVED_STATUS;
|
|
514
|
+
const needsSchemaWrite = Object.prototype.hasOwnProperty.call(entry, 'status') ||
|
|
515
|
+
(alreadyResolved && entry.checkpointStatus !== CHECKPOINT_RESOLVED_STATUS);
|
|
516
|
+
if (alreadyResolved && !needsSchemaWrite) return null;
|
|
517
|
+
normalizeTaskManifestEntryForWrite(entry);
|
|
518
|
+
entry.checkpointStatus = CHECKPOINT_RESOLVED_STATUS;
|
|
519
|
+
writeManifestData(record.scope.manifest);
|
|
520
|
+
return {
|
|
521
|
+
op: 'sync_checkpoint_manifest_status',
|
|
522
|
+
issue: record.issue_number,
|
|
523
|
+
task_id: record.task_id,
|
|
524
|
+
checkpointStatus: CHECKPOINT_RESOLVED_STATUS,
|
|
525
|
+
manifest: record.scope.manifest.path,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function summaryPathForPlan(plan) {
|
|
530
|
+
const sourcePath = sourcePathForPlan(plan);
|
|
531
|
+
const dir = sourcePath ? path.dirname(sourcePath) : null;
|
|
532
|
+
return dir ? toPosixPath(path.join(dir, `${plan.id}-SUMMARY.md`)) : `${plan.id}-SUMMARY.md`;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function reconciliationArtifactsLanded(cwd, parent) {
|
|
536
|
+
if (!cwd) return { ok: false, missing: ['project cwd unavailable'] };
|
|
537
|
+
const required = [
|
|
538
|
+
summaryPathForPlan(parent.plan),
|
|
539
|
+
'.planning/STATE.md',
|
|
540
|
+
'.planning/ROADMAP.md',
|
|
541
|
+
];
|
|
542
|
+
const missing = required.filter((relPath) => !fs.existsSync(path.join(cwd, relPath)));
|
|
543
|
+
return {
|
|
544
|
+
ok: missing.length === 0,
|
|
545
|
+
missing,
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function applyStateSync(records, adapterForRepo, cwd = null) {
|
|
550
|
+
const operations = [];
|
|
551
|
+
for (const task of records.tasks) {
|
|
552
|
+
const adapter = adapterForRepo(task.scope.repo);
|
|
553
|
+
if (task.linked_prs.merged.length > 0 && task.issue && isIssueOpen(task.issue)) {
|
|
554
|
+
updateIssueState(adapter, task.issue_number, 'closed');
|
|
555
|
+
operations.push({
|
|
556
|
+
op: 'close_merged_task_issue',
|
|
557
|
+
issue: task.issue_number,
|
|
558
|
+
task_id: task.task_id,
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
if (task.linked_prs.closedUnmerged.length > 0 && task.issue && !isIssueOpen(task.issue)) {
|
|
562
|
+
updateIssueState(adapter, task.issue_number, 'open');
|
|
563
|
+
operations.push({
|
|
564
|
+
op: 'reopen_rejected_task_issue',
|
|
565
|
+
issue: task.issue_number,
|
|
566
|
+
task_id: task.task_id,
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
for (const parent of records.parents) {
|
|
572
|
+
const adapter = adapterForRepo(parent.scope.repo);
|
|
573
|
+
if (parent.linked_prs?.merged?.length > 0) {
|
|
574
|
+
const artifacts = reconciliationArtifactsLanded(adapter?.cwd || cwd, parent);
|
|
575
|
+
if (!artifacts.ok) {
|
|
576
|
+
operations.push({
|
|
577
|
+
op: 'merged_reconciliation_pending_pull',
|
|
578
|
+
issue: parent.issue_number,
|
|
579
|
+
plan_id: parent.plan_id,
|
|
580
|
+
missing: artifacts.missing,
|
|
581
|
+
});
|
|
582
|
+
} else {
|
|
583
|
+
if (parent.issue && isIssueOpen(parent.issue)) {
|
|
584
|
+
updateIssueState(adapter, parent.issue_number, 'closed');
|
|
585
|
+
operations.push({
|
|
586
|
+
op: 'close_reconciled_parent_issue',
|
|
587
|
+
issue: parent.issue_number,
|
|
588
|
+
plan_id: parent.plan_id,
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
const labels = mergeLabelSet(parent.labels.virtual, ['gtd:complete'], [
|
|
592
|
+
'gtd:ready',
|
|
593
|
+
'gtd:blocked',
|
|
594
|
+
'gtd:ready-for-reconcile',
|
|
595
|
+
'gtd:reconcile-pr-open',
|
|
596
|
+
'gtd:reconcile-failed',
|
|
597
|
+
'gtd:source-drift',
|
|
598
|
+
]);
|
|
599
|
+
parent.labels.virtual = labels;
|
|
600
|
+
parent.labels.actions = labelActions(parent.labels.current, labels, PARENT_STATE_LABELS);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
for (const record of [...records.parents, ...records.tasks]) {
|
|
606
|
+
const adapter = adapterForRepo(record.scope.repo);
|
|
607
|
+
const applied = applyLabelActions(adapter, record);
|
|
608
|
+
if (applied) operations.push({ op: 'sync_labels', ...applied });
|
|
609
|
+
if (record.kind === 'task') {
|
|
610
|
+
const manifestSync = syncCheckpointManifestStatus(record);
|
|
611
|
+
if (manifestSync) operations.push(manifestSync);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return operations;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function isoTimestamp(deps = {}) {
|
|
618
|
+
const now = deps.now ? deps.now() : new Date();
|
|
619
|
+
return now.toISOString();
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function claimTaskIssue(adapter, record, deps = {}) {
|
|
623
|
+
const timestamp = isoTimestamp(deps);
|
|
624
|
+
const labels = mergeLabelSet(record.labels.virtual, ['gtd:in-progress'], ['gtd:ready', 'gtd:blocked']);
|
|
625
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
626
|
+
const body = [
|
|
627
|
+
`GTD task execution claim at ${timestamp}.`,
|
|
628
|
+
'',
|
|
629
|
+
`Branch: \`${record.branch_name}\``,
|
|
630
|
+
`Task: \`${record.task_id}\``,
|
|
631
|
+
].join('\n');
|
|
632
|
+
commentIssue(adapter, record.issue_number, body);
|
|
633
|
+
return {
|
|
634
|
+
issue: record.issue_number,
|
|
635
|
+
branch: record.branch_name,
|
|
636
|
+
claimed_at: timestamp,
|
|
637
|
+
labels,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function pathMatchesScope(filePath, scopePath) {
|
|
642
|
+
const file = normalizeRepoPath(filePath);
|
|
643
|
+
const scope = normalizeRepoPath(scopePath);
|
|
644
|
+
if (!scope) return false;
|
|
645
|
+
if (scope === '.') return true;
|
|
646
|
+
if (file === scope) return true;
|
|
647
|
+
return file.startsWith(`${scope}/`);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function forbiddenCompletionArtifact(filePath) {
|
|
651
|
+
const file = normalizeRepoPath(filePath);
|
|
652
|
+
return GTD_COMPLETION_ARTIFACTS.includes(file) || SUMMARY_ARTIFACT_RE.test(file);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function validateDiffScope(changedFiles, check) {
|
|
656
|
+
const allowed = (check.paths?.allowed || []).map(normalizeRepoPath).filter(Boolean);
|
|
657
|
+
const forbidden = (check.paths?.forbidden || []).map(normalizeRepoPath).filter(Boolean);
|
|
658
|
+
const files = [...new Set((changedFiles || []).map(normalizeRepoPath).filter(Boolean))].sort();
|
|
659
|
+
const outOfScope = files.filter((file) => allowed.length > 0 && !allowed.some((scope) => pathMatchesScope(file, scope)));
|
|
660
|
+
const forbiddenHits = files.filter((file) =>
|
|
661
|
+
forbidden.some((scope) => pathMatchesScope(file, scope)) ||
|
|
662
|
+
forbiddenCompletionArtifact(file),
|
|
663
|
+
);
|
|
664
|
+
|
|
665
|
+
return {
|
|
666
|
+
id: check.id,
|
|
667
|
+
type: check.type,
|
|
668
|
+
passed: outOfScope.length === 0 && forbiddenHits.length === 0,
|
|
669
|
+
changed_files: files,
|
|
670
|
+
allowed,
|
|
671
|
+
forbidden,
|
|
672
|
+
out_of_scope: outOfScope,
|
|
673
|
+
forbidden_hits: forbiddenHits,
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function runShellCommand(command, cwd, deps = {}) {
|
|
678
|
+
if (deps.runCommand) return deps.runCommand(command, cwd);
|
|
679
|
+
const result = childProcess.spawnSync(command, [], {
|
|
680
|
+
cwd,
|
|
681
|
+
encoding: 'utf8',
|
|
682
|
+
shell: true,
|
|
683
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
684
|
+
env: process.env,
|
|
685
|
+
});
|
|
686
|
+
return {
|
|
687
|
+
status: result.status,
|
|
688
|
+
stdout: String(result.stdout || ''),
|
|
689
|
+
stderr: String(result.stderr || ''),
|
|
690
|
+
error: result.error ? result.error.message : null,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function validateCommandCheck(worktreePath, check, deps = {}) {
|
|
695
|
+
const result = runShellCommand(check.run || check.command || '', worktreePath, deps);
|
|
696
|
+
return {
|
|
697
|
+
id: check.id,
|
|
698
|
+
type: check.type,
|
|
699
|
+
run: check.run || check.command || '',
|
|
700
|
+
passed: result.status === 0,
|
|
701
|
+
status: result.status,
|
|
702
|
+
stdout: String(result.stdout || '').trim(),
|
|
703
|
+
stderr: String(result.stderr || result.error || '').trim(),
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
function validateFileExistsCheck(worktreePath, check) {
|
|
708
|
+
const relPath = normalizeRepoPath(check.path || check.file || '');
|
|
709
|
+
return {
|
|
710
|
+
id: check.id,
|
|
711
|
+
type: check.type,
|
|
712
|
+
path: relPath,
|
|
713
|
+
passed: Boolean(relPath) && fs.existsSync(path.join(worktreePath, relPath)),
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
function validateContentMatchCheck(worktreePath, check) {
|
|
718
|
+
const relPath = normalizeRepoPath(check.path || check.file || '');
|
|
719
|
+
const file = relPath ? path.join(worktreePath, relPath) : null;
|
|
720
|
+
const expected = check.text || check.pattern || check.match || '';
|
|
721
|
+
let content = '';
|
|
722
|
+
if (file && fs.existsSync(file) && fs.statSync(file).isFile()) {
|
|
723
|
+
content = fs.readFileSync(file, 'utf8');
|
|
724
|
+
}
|
|
725
|
+
return {
|
|
726
|
+
id: check.id,
|
|
727
|
+
type: check.type,
|
|
728
|
+
path: relPath,
|
|
729
|
+
expected,
|
|
730
|
+
passed: Boolean(file && expected) && content.includes(expected),
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
function validateTask(worktreePath, record, changedFiles, deps = {}) {
|
|
735
|
+
const checks = record.task.validation_contract?.checks || [];
|
|
736
|
+
const results = [];
|
|
737
|
+
for (const check of checks) {
|
|
738
|
+
if (check.type === 'diff-scope') {
|
|
739
|
+
results.push(validateDiffScope(changedFiles, check));
|
|
740
|
+
} else if (check.type === 'command' || check.type === 'test-selector') {
|
|
741
|
+
results.push(validateCommandCheck(worktreePath, check, deps));
|
|
742
|
+
} else if (check.type === 'file-exists') {
|
|
743
|
+
results.push(validateFileExistsCheck(worktreePath, check));
|
|
744
|
+
} else if (check.type === 'content-match') {
|
|
745
|
+
results.push(validateContentMatchCheck(worktreePath, check));
|
|
746
|
+
} else if (check.type === 'manual') {
|
|
747
|
+
results.push({
|
|
748
|
+
id: check.id,
|
|
749
|
+
type: check.type,
|
|
750
|
+
passed: null,
|
|
751
|
+
description: check.description || '',
|
|
752
|
+
});
|
|
753
|
+
} else {
|
|
754
|
+
results.push({
|
|
755
|
+
id: check.id,
|
|
756
|
+
type: check.type || 'unknown',
|
|
757
|
+
passed: false,
|
|
758
|
+
error: `Unsupported validation check type: ${check.type || 'unknown'}`,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const automated = results.filter((result) => result.passed !== null);
|
|
764
|
+
const manual = results.filter((result) => result.passed === null);
|
|
765
|
+
const failed = automated.filter((result) => result.passed === false);
|
|
766
|
+
return {
|
|
767
|
+
ok: failed.length === 0,
|
|
768
|
+
automated_ok: failed.length === 0,
|
|
769
|
+
checks: results,
|
|
770
|
+
failed,
|
|
771
|
+
manual,
|
|
772
|
+
acceptance_criteria: record.task.acceptance_criteria.map((criterion) => ({
|
|
773
|
+
criterion,
|
|
774
|
+
mechanical: false,
|
|
775
|
+
passed: null,
|
|
776
|
+
})),
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function validationMarkdown(validation) {
|
|
781
|
+
const lines = [
|
|
782
|
+
'## GTD Task Validation',
|
|
783
|
+
'',
|
|
784
|
+
validation.ok ? 'Automated validation passed.' : 'Automated validation failed.',
|
|
785
|
+
'',
|
|
786
|
+
'### Checks',
|
|
787
|
+
];
|
|
788
|
+
for (const check of validation.checks) {
|
|
789
|
+
const status = check.passed === null ? 'manual' : (check.passed ? 'pass' : 'fail');
|
|
790
|
+
lines.push(`- ${check.id || check.type}: ${status}`);
|
|
791
|
+
if (check.run) lines.push(` - run: \`${check.run}\``);
|
|
792
|
+
if (check.out_of_scope?.length) lines.push(` - out of scope: ${check.out_of_scope.map((file) => `\`${file}\``).join(', ')}`);
|
|
793
|
+
if (check.forbidden_hits?.length) lines.push(` - forbidden: ${check.forbidden_hits.map((file) => `\`${file}\``).join(', ')}`);
|
|
794
|
+
}
|
|
795
|
+
if (validation.manual.length > 0 || validation.acceptance_criteria.length > 0) {
|
|
796
|
+
lines.push('', '### Reviewer Validation');
|
|
797
|
+
for (const item of validation.acceptance_criteria) lines.push(`- [ ] ${item.criterion}`);
|
|
798
|
+
for (const check of validation.manual) {
|
|
799
|
+
if (check.description && validation.acceptance_criteria.length === 0) lines.push(`- [ ] ${check.description}`);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
return lines.join('\n');
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
function executorPrompt(record, reviewFeedback = []) {
|
|
806
|
+
if (isCheckpointTask(record)) {
|
|
807
|
+
return [
|
|
808
|
+
`You are gtd-task-executor for ${record.task_id}.`,
|
|
809
|
+
'',
|
|
810
|
+
'This issue is a human-in-the-loop checkpoint, not executable implementation work.',
|
|
811
|
+
'Stop without editing files. Report that the checkpoint requires human resolution in GitHub and must be closed before dependent tasks can run.',
|
|
812
|
+
].join('\n');
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const readFirst = (record.task.read_first || []).map((entry) => `- ${entry}`).join('\n') || '- None declared';
|
|
816
|
+
const allowed = (record.task.files || []).map((entry) => `- ${entry}`).join('\n') || '- No explicit files declared';
|
|
817
|
+
const acceptance = (record.task.acceptance_criteria || []).map((entry) => `- ${entry}`).join('\n') || '- No acceptance criteria declared';
|
|
818
|
+
const feedback = reviewFeedback.length
|
|
819
|
+
? reviewFeedback.map((item) => `- ${item.kind || 'feedback'}${item.author ? ` by ${item.author}` : ''}: ${item.body || item.state || ''}`).join('\n')
|
|
820
|
+
: '- No PR review feedback supplied';
|
|
821
|
+
|
|
822
|
+
return [
|
|
823
|
+
`You are gtd-task-executor for ${record.task_id}.`,
|
|
824
|
+
'',
|
|
825
|
+
'Implement exactly one exported child task issue. Stay inside the declared write scope and commit the task changes before returning.',
|
|
826
|
+
'',
|
|
827
|
+
'## Issue',
|
|
828
|
+
`#${record.issue_number}: ${record.issue?.title || record.task.name}`,
|
|
829
|
+
'',
|
|
830
|
+
'## Source Plan',
|
|
831
|
+
sourcePathForPlan(record.plan) || '',
|
|
832
|
+
'',
|
|
833
|
+
'## Required Read First',
|
|
834
|
+
readFirst,
|
|
835
|
+
'',
|
|
836
|
+
'## Write Scope',
|
|
837
|
+
'Allowed:',
|
|
838
|
+
allowed,
|
|
839
|
+
'',
|
|
840
|
+
'Boundaries:',
|
|
841
|
+
record.task.boundaries || 'No boundaries declared',
|
|
842
|
+
'',
|
|
843
|
+
'## Action',
|
|
844
|
+
record.task.action || 'No action block declared',
|
|
845
|
+
'',
|
|
846
|
+
'## Acceptance Criteria',
|
|
847
|
+
acceptance,
|
|
848
|
+
'',
|
|
849
|
+
'## Verification',
|
|
850
|
+
record.task.verify || 'No task verification command declared',
|
|
851
|
+
'',
|
|
852
|
+
'## Review Feedback',
|
|
853
|
+
feedback,
|
|
854
|
+
'',
|
|
855
|
+
'## Non-Responsibilities',
|
|
856
|
+
'- Do not open or update PRs.',
|
|
857
|
+
'- Do not update parent plan issues.',
|
|
858
|
+
'- Do not create SUMMARY, STATE, ROADMAP, or requirements completion artifacts.',
|
|
859
|
+
].join('\n');
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
function executorContext(record, worktree, reviewFeedback = [], previousFindings = null) {
|
|
863
|
+
return {
|
|
864
|
+
version: 1,
|
|
865
|
+
task_id: record.task_id,
|
|
866
|
+
task_type: record.task.type || record.manifest_entry?.type || null,
|
|
867
|
+
is_checkpoint: isCheckpointTask(record),
|
|
868
|
+
issue: {
|
|
869
|
+
number: record.issue_number,
|
|
870
|
+
title: record.issue?.title || null,
|
|
871
|
+
body: record.issue?.body || null,
|
|
872
|
+
},
|
|
873
|
+
parent: {
|
|
874
|
+
issue: record.parent?.issue_number || null,
|
|
875
|
+
title: record.parent?.issue?.title || null,
|
|
876
|
+
plan_id: record.plan_id,
|
|
877
|
+
},
|
|
878
|
+
source_plan: sourcePathForPlan(record.plan),
|
|
879
|
+
worktree,
|
|
880
|
+
branch: record.branch_name,
|
|
881
|
+
read_first: record.task.read_first,
|
|
882
|
+
write_scope: {
|
|
883
|
+
allowed: record.task.files,
|
|
884
|
+
boundaries: record.task.boundaries || '',
|
|
885
|
+
},
|
|
886
|
+
action: record.task.action || '',
|
|
887
|
+
acceptance_criteria: record.task.acceptance_criteria,
|
|
888
|
+
validation_contract: record.task.validation_contract,
|
|
889
|
+
verification: record.task.verify || '',
|
|
890
|
+
review_feedback: reviewFeedback,
|
|
891
|
+
previous_findings: previousFindings,
|
|
892
|
+
prompt: executorPrompt(record, reviewFeedback),
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
function runTaskExecutor(context, deps = {}) {
|
|
897
|
+
if (deps.runTaskExecutor) return deps.runTaskExecutor(context);
|
|
898
|
+
const result = childProcess.spawnSync(TASK_EXECUTOR_COMMAND, [], {
|
|
899
|
+
cwd: context.worktree.path,
|
|
900
|
+
encoding: 'utf8',
|
|
901
|
+
input: `${JSON.stringify(context)}\n`,
|
|
902
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
903
|
+
env: process.env,
|
|
904
|
+
});
|
|
905
|
+
if (result.error) {
|
|
906
|
+
const message = result.error.code === 'ENOENT'
|
|
907
|
+
? `Standalone ${TASK_EXECUTOR_COMMAND} was not found on PATH.`
|
|
908
|
+
: result.error.message;
|
|
909
|
+
throw new TaskExecutionError(message, 'executor_unavailable');
|
|
910
|
+
}
|
|
911
|
+
const stdout = String(result.stdout || '').trim();
|
|
912
|
+
if (result.status !== 0) {
|
|
913
|
+
throw new TaskExecutionError(String(result.stderr || stdout || `${TASK_EXECUTOR_COMMAND} exited with status ${result.status}`).trim(), 'executor_failed');
|
|
914
|
+
}
|
|
915
|
+
if (!stdout) return { ok: true, notes: '', raw: '' };
|
|
916
|
+
try {
|
|
917
|
+
return JSON.parse(stdout);
|
|
918
|
+
} catch {
|
|
919
|
+
return { ok: true, notes: stdout, raw: stdout };
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function runGit(cwd, args, opts = {}) {
|
|
924
|
+
const result = childProcess.spawnSync('git', args, {
|
|
925
|
+
cwd,
|
|
926
|
+
encoding: 'utf8',
|
|
927
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
928
|
+
env: process.env,
|
|
929
|
+
});
|
|
930
|
+
const stdout = String(result.stdout || '').trim();
|
|
931
|
+
const stderr = String(result.stderr || '').trim();
|
|
932
|
+
if (result.error) {
|
|
933
|
+
throw new TaskExecutionError(result.error.message, 'git_failed', { args });
|
|
934
|
+
}
|
|
935
|
+
if (result.status !== 0 && !opts.allowFailure) {
|
|
936
|
+
throw new TaskExecutionError(stderr || `git ${args.join(' ')} exited with status ${result.status}`, 'git_failed', { args });
|
|
937
|
+
}
|
|
938
|
+
return {
|
|
939
|
+
ok: result.status === 0,
|
|
940
|
+
status: result.status,
|
|
941
|
+
stdout,
|
|
942
|
+
stderr,
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function executorBlockers(executorResult) {
|
|
947
|
+
const raw = executorResult?.blockers ?? executorResult?.blocker ?? executorResult?.blocked_by ?? [];
|
|
948
|
+
if (Array.isArray(raw)) {
|
|
949
|
+
return raw.map((item) => {
|
|
950
|
+
if (typeof item === 'string') return item.trim();
|
|
951
|
+
if (item && typeof item === 'object') return String(item.message || item.reason || item.code || JSON.stringify(item)).trim();
|
|
952
|
+
return String(item || '').trim();
|
|
953
|
+
}).filter(Boolean);
|
|
954
|
+
}
|
|
955
|
+
if (typeof raw === 'string') return raw.trim() ? [raw.trim()] : [];
|
|
956
|
+
if (raw && typeof raw === 'object') return [String(raw.message || raw.reason || raw.code || JSON.stringify(raw)).trim()].filter(Boolean);
|
|
957
|
+
return raw ? [String(raw).trim()].filter(Boolean) : [];
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function executorCommitHash(executorResult) {
|
|
961
|
+
const raw = executorResult?.commit
|
|
962
|
+
?? executorResult?.commit_hash
|
|
963
|
+
?? executorResult?.commitHash
|
|
964
|
+
?? executorResult?.sha
|
|
965
|
+
?? executorResult?.commit_sha
|
|
966
|
+
?? null;
|
|
967
|
+
const value = String(raw || '').trim();
|
|
968
|
+
return value || null;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
function normalizeExecutorEvidence(evidence) {
|
|
972
|
+
const reasons = Array.isArray(evidence?.reasons) ? evidence.reasons : [];
|
|
973
|
+
return {
|
|
974
|
+
ok: Boolean(evidence?.ok) && reasons.length === 0,
|
|
975
|
+
executor_success: Boolean(evidence?.executor_success),
|
|
976
|
+
blockers: Array.isArray(evidence?.blockers) ? evidence.blockers : [],
|
|
977
|
+
commit: evidence?.commit || null,
|
|
978
|
+
reachable_commit: Boolean(evidence?.reachable_commit),
|
|
979
|
+
branch_contains_commit: Boolean(evidence?.branch_contains_commit),
|
|
980
|
+
committed_diff: Boolean(evidence?.committed_diff),
|
|
981
|
+
clean_worktree: Boolean(evidence?.clean_worktree),
|
|
982
|
+
reasons,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
function validateExecutorEvidence(worktree, executorResult, deps = {}) {
|
|
987
|
+
if (deps.validateExecutorEvidence) {
|
|
988
|
+
return normalizeExecutorEvidence(deps.validateExecutorEvidence({ worktree, executorResult }));
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const reasons = [];
|
|
992
|
+
const blockers = executorBlockers(executorResult);
|
|
993
|
+
const executorSuccess = executorResult?.ok === true;
|
|
994
|
+
if (!executorSuccess) {
|
|
995
|
+
reasons.push({
|
|
996
|
+
code: 'executor_not_successful',
|
|
997
|
+
message: 'Executor did not report ok: true.',
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
if (blockers.length > 0) {
|
|
1001
|
+
reasons.push({
|
|
1002
|
+
code: 'executor_blockers',
|
|
1003
|
+
message: `Executor reported blocker(s): ${blockers.join('; ')}`,
|
|
1004
|
+
blockers,
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
let commit = executorCommitHash(executorResult);
|
|
1009
|
+
let reachableCommit = false;
|
|
1010
|
+
let branchContainsCommit = false;
|
|
1011
|
+
let committedDiff = false;
|
|
1012
|
+
let cleanWorktree = false;
|
|
1013
|
+
|
|
1014
|
+
if (!commit) {
|
|
1015
|
+
reasons.push({
|
|
1016
|
+
code: 'missing_executor_commit',
|
|
1017
|
+
message: 'Executor did not return a commit hash.',
|
|
1018
|
+
});
|
|
1019
|
+
} else if (!/^[0-9a-f]{7,40}$/i.test(commit)) {
|
|
1020
|
+
reasons.push({
|
|
1021
|
+
code: 'invalid_executor_commit_hash',
|
|
1022
|
+
message: `Executor commit is not a hash: ${commit}`,
|
|
1023
|
+
});
|
|
1024
|
+
} else {
|
|
1025
|
+
const verified = runGit(worktree.path, ['rev-parse', '--verify', `${commit}^{commit}`], { allowFailure: true });
|
|
1026
|
+
if (verified.ok && verified.stdout) {
|
|
1027
|
+
commit = verified.stdout;
|
|
1028
|
+
reachableCommit = true;
|
|
1029
|
+
} else {
|
|
1030
|
+
reasons.push({
|
|
1031
|
+
code: 'unreachable_executor_commit',
|
|
1032
|
+
message: `Executor commit ${commit} is not reachable as a commit in the task worktree.`,
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
if (reachableCommit) {
|
|
1037
|
+
const contained = runGit(worktree.path, ['merge-base', '--is-ancestor', commit, 'HEAD'], { allowFailure: true });
|
|
1038
|
+
branchContainsCommit = contained.ok;
|
|
1039
|
+
if (!branchContainsCommit) {
|
|
1040
|
+
reasons.push({
|
|
1041
|
+
code: 'executor_commit_not_on_head',
|
|
1042
|
+
message: `Executor commit ${commit} is not reachable from HEAD.`,
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
const parents = runGit(worktree.path, ['rev-list', '--parents', '-n', '1', commit], { allowFailure: true });
|
|
1047
|
+
if (!parents.ok || !parents.stdout) {
|
|
1048
|
+
reasons.push({
|
|
1049
|
+
code: 'executor_commit_parent_unavailable',
|
|
1050
|
+
message: `Could not inspect parent(s) for executor commit ${commit}.`,
|
|
1051
|
+
});
|
|
1052
|
+
} else {
|
|
1053
|
+
const parts = parents.stdout.split(/\s+/).filter(Boolean);
|
|
1054
|
+
const diffArgs = parts.length > 1
|
|
1055
|
+
? ['diff-tree', '--quiet', '--no-ext-diff', parts[1], commit, '--']
|
|
1056
|
+
: ['diff-tree', '--quiet', '--root', '--no-ext-diff', commit, '--'];
|
|
1057
|
+
const diff = runGit(worktree.path, diffArgs, { allowFailure: true });
|
|
1058
|
+
if (diff.status === 1) {
|
|
1059
|
+
committedDiff = true;
|
|
1060
|
+
} else if (diff.status === 0) {
|
|
1061
|
+
reasons.push({
|
|
1062
|
+
code: 'empty_executor_commit_diff',
|
|
1063
|
+
message: `Executor commit ${commit} has no committed diff.`,
|
|
1064
|
+
});
|
|
1065
|
+
} else {
|
|
1066
|
+
reasons.push({
|
|
1067
|
+
code: 'executor_commit_diff_unavailable',
|
|
1068
|
+
message: diff.stderr || `Could not inspect committed diff for executor commit ${commit}.`,
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
const status = runGit(worktree.path, ['status', '--porcelain', '--untracked-files=normal'], { allowFailure: true });
|
|
1076
|
+
if (!status.ok) {
|
|
1077
|
+
reasons.push({
|
|
1078
|
+
code: 'worktree_status_unavailable',
|
|
1079
|
+
message: status.stderr || 'Could not inspect task worktree status.',
|
|
1080
|
+
});
|
|
1081
|
+
} else if (status.stdout) {
|
|
1082
|
+
reasons.push({
|
|
1083
|
+
code: 'dirty_task_worktree_after_executor',
|
|
1084
|
+
message: 'Task worktree is not clean after executor commit.',
|
|
1085
|
+
status: status.stdout,
|
|
1086
|
+
});
|
|
1087
|
+
} else {
|
|
1088
|
+
cleanWorktree = true;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
return normalizeExecutorEvidence({
|
|
1092
|
+
ok: reasons.length === 0,
|
|
1093
|
+
executor_success: executorSuccess,
|
|
1094
|
+
blockers,
|
|
1095
|
+
commit,
|
|
1096
|
+
reachable_commit: reachableCommit,
|
|
1097
|
+
branch_contains_commit: branchContainsCommit,
|
|
1098
|
+
committed_diff: committedDiff,
|
|
1099
|
+
clean_worktree: cleanWorktree,
|
|
1100
|
+
reasons,
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
function defaultBranchRef(cwd) {
|
|
1105
|
+
runGit(cwd, ['fetch', 'origin']);
|
|
1106
|
+
const symbolic = runGit(cwd, ['symbolic-ref', '--quiet', 'refs/remotes/origin/HEAD'], { allowFailure: true });
|
|
1107
|
+
if (symbolic.ok && symbolic.stdout) return symbolic.stdout.replace(/^refs\/remotes\//, '');
|
|
1108
|
+
for (const candidate of ['origin/main', 'origin/master', 'origin/trunk']) {
|
|
1109
|
+
const exists = runGit(cwd, ['rev-parse', '--verify', candidate], { allowFailure: true });
|
|
1110
|
+
if (exists.ok) return candidate;
|
|
1111
|
+
}
|
|
1112
|
+
throw new TaskExecutionError('Could not resolve the default remote branch from origin/HEAD.', 'default_branch_unresolved');
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
function branchExists(cwd, branch) {
|
|
1116
|
+
return runGit(cwd, ['show-ref', '--verify', '--quiet', `refs/heads/${branch}`], { allowFailure: true }).ok;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
function worktreeForBranch(cwd, branch) {
|
|
1120
|
+
const listed = runGit(cwd, ['worktree', 'list', '--porcelain']);
|
|
1121
|
+
return parseWorktreePorcelain(listed.stdout).find((entry) => entry.branch === branch) || null;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
function defaultWorktreeRoot(cwd) {
|
|
1125
|
+
return path.join(path.dirname(cwd), `${path.basename(cwd)}.task-worktrees`);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
function safeWorktreeLeaf(branch) {
|
|
1129
|
+
return String(branch).replace(/[\\/]/g, '__').replace(/[^A-Za-z0-9._-]/g, '-');
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
function ensureTaskWorktree(cwd, record, deps = {}) {
|
|
1133
|
+
if (deps.ensureTaskWorktree) return deps.ensureTaskWorktree({ cwd, record });
|
|
1134
|
+
|
|
1135
|
+
const branch = record.branch_name;
|
|
1136
|
+
const root = deps.worktreeRoot || defaultWorktreeRoot(cwd);
|
|
1137
|
+
const worktreePath = path.join(root, safeWorktreeLeaf(branch));
|
|
1138
|
+
fs.mkdirSync(root, { recursive: true });
|
|
1139
|
+
|
|
1140
|
+
const baseRef = defaultBranchRef(cwd);
|
|
1141
|
+
const existing = worktreeForBranch(cwd, branch);
|
|
1142
|
+
if (existing) {
|
|
1143
|
+
const status = runGit(existing.path, ['status', '--porcelain']).stdout;
|
|
1144
|
+
if (status) {
|
|
1145
|
+
throw new TaskExecutionError(`Task worktree ${existing.path} has uncommitted changes.`, 'dirty_task_worktree', { path: existing.path });
|
|
1146
|
+
}
|
|
1147
|
+
const rebase = runGit(existing.path, ['rebase', baseRef], { allowFailure: true });
|
|
1148
|
+
if (!rebase.ok) {
|
|
1149
|
+
runGit(existing.path, ['rebase', '--abort'], { allowFailure: true });
|
|
1150
|
+
throw new TaskExecutionError(`Could not rebase ${branch} onto ${baseRef}: ${rebase.stderr}`, 'task_branch_rebase_conflict');
|
|
1151
|
+
}
|
|
1152
|
+
return {
|
|
1153
|
+
path: existing.path,
|
|
1154
|
+
branch,
|
|
1155
|
+
base_ref: baseRef,
|
|
1156
|
+
reused: true,
|
|
1157
|
+
};
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
if (fs.existsSync(worktreePath)) {
|
|
1161
|
+
throw new TaskExecutionError(`Task worktree path already exists without matching branch: ${worktreePath}`, 'worktree_path_collision', { path: worktreePath });
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
if (branchExists(cwd, branch)) {
|
|
1165
|
+
runGit(cwd, ['worktree', 'add', worktreePath, branch]);
|
|
1166
|
+
const rebase = runGit(worktreePath, ['rebase', baseRef], { allowFailure: true });
|
|
1167
|
+
if (!rebase.ok) {
|
|
1168
|
+
runGit(worktreePath, ['rebase', '--abort'], { allowFailure: true });
|
|
1169
|
+
throw new TaskExecutionError(`Could not rebase ${branch} onto ${baseRef}: ${rebase.stderr}`, 'task_branch_rebase_conflict');
|
|
1170
|
+
}
|
|
1171
|
+
} else {
|
|
1172
|
+
runGit(cwd, ['worktree', 'add', '-b', branch, worktreePath, baseRef]);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
return {
|
|
1176
|
+
path: worktreePath,
|
|
1177
|
+
branch,
|
|
1178
|
+
base_ref: baseRef,
|
|
1179
|
+
reused: false,
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
function listChangedFiles(worktree, deps = {}) {
|
|
1184
|
+
if (deps.listChangedFiles) return deps.listChangedFiles(worktree);
|
|
1185
|
+
const committed = runGit(worktree.path, ['diff', '--name-only', `${worktree.base_ref}...HEAD`]).stdout;
|
|
1186
|
+
const unstaged = runGit(worktree.path, ['diff', '--name-only']).stdout;
|
|
1187
|
+
const staged = runGit(worktree.path, ['diff', '--cached', '--name-only']).stdout;
|
|
1188
|
+
const untracked = runGit(worktree.path, ['ls-files', '--others', '--exclude-standard']).stdout;
|
|
1189
|
+
return [...new Set([committed, unstaged, staged, untracked]
|
|
1190
|
+
.flatMap((text) => String(text || '').split(/\r?\n/))
|
|
1191
|
+
.map(normalizeRepoPath)
|
|
1192
|
+
.filter(Boolean))]
|
|
1193
|
+
.sort();
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
function pushTaskBranch(worktree, deps = {}) {
|
|
1197
|
+
if (deps.pushBranch) return deps.pushBranch(worktree);
|
|
1198
|
+
runGit(worktree.path, ['push', '--set-upstream', 'origin', worktree.branch]);
|
|
1199
|
+
return {
|
|
1200
|
+
pushed: true,
|
|
1201
|
+
branch: worktree.branch,
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
function reviewFeedback(adapter, record) {
|
|
1206
|
+
const pr = latestPr([...record.linked_prs.open, ...record.linked_prs.closedUnmerged]);
|
|
1207
|
+
if (!pr || !adapter || typeof adapter.listPullRequestFeedback !== 'function') return [];
|
|
1208
|
+
return callWrite(`list_pull_request_feedback:${pr.number}`, () => adapter.listPullRequestFeedback(pr.number));
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
function prBody(record, validation, executorResult, ready) {
|
|
1212
|
+
const lines = [
|
|
1213
|
+
`## Task`,
|
|
1214
|
+
'',
|
|
1215
|
+
`- Issue: #${record.issue_number}`,
|
|
1216
|
+
`- Task ID: \`${record.task_id}\``,
|
|
1217
|
+
`- Source plan: \`${sourcePathForPlan(record.plan)}\``,
|
|
1218
|
+
'',
|
|
1219
|
+
'## Implementation Notes',
|
|
1220
|
+
String(executorResult?.notes || executorResult?.summary || 'No implementation notes returned.').trim(),
|
|
1221
|
+
'',
|
|
1222
|
+
validationMarkdown(validation),
|
|
1223
|
+
];
|
|
1224
|
+
if (ready) {
|
|
1225
|
+
lines.push('', `Closes #${record.issue_number}`);
|
|
1226
|
+
} else {
|
|
1227
|
+
lines.push('', 'This draft intentionally does not close the task issue because automated validation has not passed.');
|
|
1228
|
+
}
|
|
1229
|
+
return lines.join('\n');
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
function withTemporaryPrBodyFile(body, fn) {
|
|
1233
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'gtd-task-pr-body-'));
|
|
1234
|
+
const file = path.join(dir, 'body.md');
|
|
1235
|
+
try {
|
|
1236
|
+
fs.writeFileSync(file, String(body || ''), 'utf8');
|
|
1237
|
+
return fn(file);
|
|
1238
|
+
} finally {
|
|
1239
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
function openOrUpdatePullRequest(adapter, record, worktree, validation, executorResult, ready) {
|
|
1244
|
+
const existingOpen = latestPr(record.linked_prs.open);
|
|
1245
|
+
const existingClosed = latestPr(record.linked_prs.closedUnmerged);
|
|
1246
|
+
const body = prBody(record, validation, executorResult, ready);
|
|
1247
|
+
const title = `[GTD ${record.task_id}] ${record.task.name}`;
|
|
1248
|
+
|
|
1249
|
+
if (existingOpen) {
|
|
1250
|
+
if (!adapter || typeof adapter.updatePullRequest !== 'function') {
|
|
1251
|
+
throw new TaskExecutionError('GitHub PR update is unavailable.', 'github_pr_unavailable');
|
|
1252
|
+
}
|
|
1253
|
+
return callWrite(`update_pull_request:${existingOpen.number}`, () => adapter.updatePullRequest(existingOpen.number, {
|
|
1254
|
+
title,
|
|
1255
|
+
body,
|
|
1256
|
+
draft: !ready,
|
|
1257
|
+
labels: ready ? [] : ['gtd:validation-failed'],
|
|
1258
|
+
}));
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
if (existingClosed && adapter && typeof adapter.reopenPullRequest === 'function') {
|
|
1262
|
+
callWrite(`reopen_pull_request:${existingClosed.number}`, () => adapter.reopenPullRequest(existingClosed.number));
|
|
1263
|
+
return callWrite(`update_pull_request:${existingClosed.number}`, () => adapter.updatePullRequest(existingClosed.number, {
|
|
1264
|
+
title,
|
|
1265
|
+
body,
|
|
1266
|
+
draft: !ready,
|
|
1267
|
+
labels: ready ? [] : ['gtd:validation-failed'],
|
|
1268
|
+
}));
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
if (!adapter || typeof adapter.createPullRequest !== 'function') {
|
|
1272
|
+
throw new TaskExecutionError('GitHub PR creation is unavailable.', 'github_pr_unavailable');
|
|
1273
|
+
}
|
|
1274
|
+
return callWrite(`create_pull_request:${worktree.branch}`, () => adapter.createPullRequest({
|
|
1275
|
+
title,
|
|
1276
|
+
body,
|
|
1277
|
+
head: worktree.branch,
|
|
1278
|
+
base: worktree.base_ref.replace(/^origin\//, ''),
|
|
1279
|
+
draft: !ready,
|
|
1280
|
+
labels: ready ? [] : ['gtd:validation-failed'],
|
|
1281
|
+
}));
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
function finalizeIssueAfterPr(adapter, record, pr, validation, ready) {
|
|
1285
|
+
const labels = ready
|
|
1286
|
+
? mergeLabelSet(record.labels.virtual, ['gtd:pr-open'], ['gtd:in-progress', 'gtd:ready', 'gtd:blocked', 'gtd:needs-rework', 'gtd:validation-failed', 'gtd:rejected'])
|
|
1287
|
+
: mergeLabelSet(record.labels.virtual, ['gtd:pr-open', 'gtd:validation-failed'], ['gtd:in-progress', 'gtd:ready', 'gtd:blocked']);
|
|
1288
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
1289
|
+
const body = [
|
|
1290
|
+
ready ? 'Task PR is ready for review.' : 'Draft task PR opened with validation failures.',
|
|
1291
|
+
'',
|
|
1292
|
+
`PR: ${pr.url || `#${pr.number}`}`,
|
|
1293
|
+
'',
|
|
1294
|
+
validationMarkdown(validation),
|
|
1295
|
+
].join('\n');
|
|
1296
|
+
commentIssue(adapter, record.issue_number, body);
|
|
1297
|
+
return {
|
|
1298
|
+
labels,
|
|
1299
|
+
comment_posted: true,
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
function executorEvidenceMarkdown(executorEvidence) {
|
|
1304
|
+
const lines = [
|
|
1305
|
+
'## Executor Evidence',
|
|
1306
|
+
'',
|
|
1307
|
+
executorEvidence?.ok ? 'Executor commit evidence passed.' : 'Executor commit evidence failed.',
|
|
1308
|
+
];
|
|
1309
|
+
for (const reason of executorEvidence?.reasons || []) {
|
|
1310
|
+
lines.push(`- ${reason.code || 'executor_evidence'}: ${reason.message || 'Evidence check failed.'}`);
|
|
1311
|
+
}
|
|
1312
|
+
return lines.join('\n');
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
function markExecutorEvidenceFailedWithoutPr(adapter, record, validation, executorEvidence) {
|
|
1316
|
+
const labels = mergeLabelSet(record.labels.virtual, ['gtd:validation-failed'], ['gtd:in-progress', 'gtd:ready', 'gtd:blocked']);
|
|
1317
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
1318
|
+
commentIssue(adapter, record.issue_number, [
|
|
1319
|
+
'Task execution did not produce valid executor commit evidence. No PR was opened.',
|
|
1320
|
+
'',
|
|
1321
|
+
validationMarkdown(validation),
|
|
1322
|
+
'',
|
|
1323
|
+
executorEvidenceMarkdown(executorEvidence),
|
|
1324
|
+
].join('\n'));
|
|
1325
|
+
return {
|
|
1326
|
+
labels,
|
|
1327
|
+
comment_posted: true,
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
function sameMarker(marker, expected) {
|
|
1332
|
+
if (!marker || marker.phase !== expected.phase || marker.plan !== expected.plan) return false;
|
|
1333
|
+
if (Object.prototype.hasOwnProperty.call(expected, 'task')) return marker.task === expected.task;
|
|
1334
|
+
return marker.task === null;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
function setAddMany(set, labels) {
|
|
1338
|
+
for (const label of labels) set.add(label);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
function setDeleteMany(set, labels) {
|
|
1342
|
+
for (const label of labels) set.delete(label);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
function labelActions(currentLabels, virtualLabels, managedLabels) {
|
|
1346
|
+
const current = new Set(currentLabels);
|
|
1347
|
+
const virtual = new Set(virtualLabels);
|
|
1348
|
+
const managed = new Set(managedLabels);
|
|
1349
|
+
return {
|
|
1350
|
+
add: [...virtual].filter((label) => managed.has(label) && !current.has(label)).sort(),
|
|
1351
|
+
remove: [...current].filter((label) => managed.has(label) && !virtual.has(label)).sort(),
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
function openIssueNumbers(issues) {
|
|
1356
|
+
return (issues || []).filter(isIssueOpen).map((issue) => Number(issue.number)).filter(Boolean).sort((a, b) => a - b);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
function sourcePathForPlan(plan) {
|
|
1360
|
+
return plan?.source_path || null;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
function isCheckpointTask(record) {
|
|
1364
|
+
if (!record) return false;
|
|
1365
|
+
const labels = new Set(record.labels?.virtual || record.labels?.current || []);
|
|
1366
|
+
return isCheckpointTaskType(record.task?.type || record.manifest_entry?.type) ||
|
|
1367
|
+
labels.has('gtd:checkpoint') ||
|
|
1368
|
+
labels.has('type:checkpoint');
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
function isResolvedCheckpointTask(record) {
|
|
1372
|
+
return isCheckpointTask(record) && record.issue && !isIssueOpen(record.issue);
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
function applyCheckpointVirtualState(record, virtualLabels) {
|
|
1376
|
+
if (!isCheckpointTask(record) || !record.issue) return;
|
|
1377
|
+
setAddMany(virtualLabels, ['gtd:checkpoint', 'gtd:human-in-the-loop']);
|
|
1378
|
+
virtualLabels.delete('type:task');
|
|
1379
|
+
virtualLabels.add('type:checkpoint');
|
|
1380
|
+
|
|
1381
|
+
if (isIssueOpen(record.issue)) {
|
|
1382
|
+
setAddMany(virtualLabels, ['gtd:blocked', 'gtd:blocked-human']);
|
|
1383
|
+
setDeleteMany(virtualLabels, [
|
|
1384
|
+
'gtd:ready',
|
|
1385
|
+
'gtd:in-progress',
|
|
1386
|
+
'gtd:pr-open',
|
|
1387
|
+
'gtd:needs-rework',
|
|
1388
|
+
'gtd:validation-failed',
|
|
1389
|
+
'gtd:rejected',
|
|
1390
|
+
'gtd:merged',
|
|
1391
|
+
'gtd:checkpoint-resolved',
|
|
1392
|
+
]);
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
virtualLabels.add('gtd:checkpoint-resolved');
|
|
1397
|
+
setDeleteMany(virtualLabels, [
|
|
1398
|
+
'gtd:ready',
|
|
1399
|
+
'gtd:blocked',
|
|
1400
|
+
'gtd:in-progress',
|
|
1401
|
+
'gtd:pr-open',
|
|
1402
|
+
'gtd:needs-rework',
|
|
1403
|
+
'gtd:validation-failed',
|
|
1404
|
+
'gtd:rejected',
|
|
1405
|
+
'gtd:merged',
|
|
1406
|
+
'gtd:blocked-human',
|
|
1407
|
+
]);
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
function makeTaskRecord(scope, plan, task, parentRecord, adapter) {
|
|
1411
|
+
const errors = [];
|
|
1412
|
+
const taskEntry = manifestTaskEntry(scope, plan.id, task.id);
|
|
1413
|
+
const issueNumber = taskEntry?.issue || null;
|
|
1414
|
+
const issue = issueNumber
|
|
1415
|
+
? callRead(`get_issue:${issueNumber}`, null, () => adapter.getIssue(issueNumber), errors)
|
|
1416
|
+
: null;
|
|
1417
|
+
const blockers = issueNumber
|
|
1418
|
+
? listBlockedBy(adapter, issueNumber, errors, `list_blocked_by:${issueNumber}`)
|
|
1419
|
+
: [];
|
|
1420
|
+
const branchName = issueNumber ? taskBranchName(task.id, issueNumber) : null;
|
|
1421
|
+
const prs = issueNumber ? listPullRequestsForIssue(adapter, issueNumber, branchName, errors) : [];
|
|
1422
|
+
const pr = prState(prs);
|
|
1423
|
+
const currentLabels = issueLabels(issue);
|
|
1424
|
+
const virtualLabels = new Set(currentLabels);
|
|
1425
|
+
setAddMany(virtualLabels, ['gtd:task']);
|
|
1426
|
+
|
|
1427
|
+
const marker = parseExportMarker(issue?.body || '');
|
|
1428
|
+
const expectedMarker = {
|
|
1429
|
+
phase: scope.phase.phaseSlug,
|
|
1430
|
+
plan: plan.id,
|
|
1431
|
+
task: task.id,
|
|
1432
|
+
};
|
|
1433
|
+
const markerValid = sameMarker(marker, expectedMarker);
|
|
1434
|
+
const sourceDrift =
|
|
1435
|
+
!markerValid ||
|
|
1436
|
+
marker.source_hash !== task.source_hash ||
|
|
1437
|
+
taskEntry?.source_hash !== task.source_hash;
|
|
1438
|
+
|
|
1439
|
+
const openBlockers = blockers.filter(isIssueOpen);
|
|
1440
|
+
if (sourceDrift) virtualLabels.add('gtd:source-drift');
|
|
1441
|
+
const checkpointTask = isCheckpointTask({
|
|
1442
|
+
task,
|
|
1443
|
+
manifest_entry: taskEntry,
|
|
1444
|
+
labels: {
|
|
1445
|
+
current: currentLabels,
|
|
1446
|
+
virtual: [...virtualLabels],
|
|
1447
|
+
},
|
|
1448
|
+
});
|
|
1449
|
+
|
|
1450
|
+
if (checkpointTask) {
|
|
1451
|
+
applyCheckpointVirtualState({
|
|
1452
|
+
task,
|
|
1453
|
+
manifest_entry: taskEntry,
|
|
1454
|
+
issue,
|
|
1455
|
+
labels: {
|
|
1456
|
+
current: currentLabels,
|
|
1457
|
+
virtual: [...virtualLabels],
|
|
1458
|
+
},
|
|
1459
|
+
}, virtualLabels);
|
|
1460
|
+
} else if (pr.merged.length > 0) {
|
|
1461
|
+
virtualLabels.add('gtd:merged');
|
|
1462
|
+
setDeleteMany(virtualLabels, [
|
|
1463
|
+
'gtd:ready',
|
|
1464
|
+
'gtd:blocked',
|
|
1465
|
+
'gtd:in-progress',
|
|
1466
|
+
'gtd:pr-open',
|
|
1467
|
+
'gtd:needs-rework',
|
|
1468
|
+
'gtd:validation-failed',
|
|
1469
|
+
'gtd:rejected',
|
|
1470
|
+
]);
|
|
1471
|
+
} else if (pr.open.length > 0) {
|
|
1472
|
+
virtualLabels.add('gtd:pr-open');
|
|
1473
|
+
virtualLabels.delete('gtd:merged');
|
|
1474
|
+
virtualLabels.delete('gtd:ready');
|
|
1475
|
+
virtualLabels.delete('gtd:blocked');
|
|
1476
|
+
if (pr.openNeedsRework.length > 0) virtualLabels.add('gtd:needs-rework');
|
|
1477
|
+
} else if (pr.closedUnmerged.length > 0) {
|
|
1478
|
+
virtualLabels.add('gtd:rejected');
|
|
1479
|
+
virtualLabels.add('gtd:needs-rework');
|
|
1480
|
+
virtualLabels.delete('gtd:pr-open');
|
|
1481
|
+
} else if (issue && isIssueOpen(issue)) {
|
|
1482
|
+
const hasBlockingLabel = ['gtd:blocked-human', 'gtd:source-drift'].some((label) => virtualLabels.has(label));
|
|
1483
|
+
if (openBlockers.length > 0 || hasBlockingLabel) {
|
|
1484
|
+
virtualLabels.add('gtd:blocked');
|
|
1485
|
+
virtualLabels.delete('gtd:ready');
|
|
1486
|
+
} else {
|
|
1487
|
+
virtualLabels.add('gtd:ready');
|
|
1488
|
+
virtualLabels.delete('gtd:blocked');
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
const record = {
|
|
1493
|
+
kind: 'task',
|
|
1494
|
+
scope,
|
|
1495
|
+
plan,
|
|
1496
|
+
task,
|
|
1497
|
+
task_id: task.id,
|
|
1498
|
+
plan_id: plan.id,
|
|
1499
|
+
issue_number: issueNumber,
|
|
1500
|
+
issue,
|
|
1501
|
+
parent: parentRecord,
|
|
1502
|
+
manifest_entry: taskEntry,
|
|
1503
|
+
marker,
|
|
1504
|
+
marker_valid: markerValid,
|
|
1505
|
+
source_drift: sourceDrift,
|
|
1506
|
+
labels: {
|
|
1507
|
+
current: currentLabels.sort(),
|
|
1508
|
+
virtual: [...virtualLabels].sort(),
|
|
1509
|
+
actions: labelActions(currentLabels, virtualLabels, TASK_STATE_LABELS),
|
|
1510
|
+
},
|
|
1511
|
+
blockers,
|
|
1512
|
+
open_blockers: openBlockers,
|
|
1513
|
+
linked_prs: pr,
|
|
1514
|
+
branch_name: branchName,
|
|
1515
|
+
errors,
|
|
1516
|
+
};
|
|
1517
|
+
record.workability = evaluateWorkability(record);
|
|
1518
|
+
record.selection_bucket = selectionBucket(record);
|
|
1519
|
+
return record;
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
function makeParentRecord(scope, plan, adapter) {
|
|
1523
|
+
const errors = [];
|
|
1524
|
+
const planEntry = manifestPlanEntry(scope, plan.id);
|
|
1525
|
+
const issueNumber = planEntry?.issue || null;
|
|
1526
|
+
const issue = issueNumber
|
|
1527
|
+
? callRead(`get_issue:${issueNumber}`, null, () => adapter.getIssue(issueNumber), errors)
|
|
1528
|
+
: null;
|
|
1529
|
+
const blockers = issueNumber
|
|
1530
|
+
? listBlockedBy(adapter, issueNumber, errors, `list_blocked_by:${issueNumber}`)
|
|
1531
|
+
: [];
|
|
1532
|
+
const branchName = issueNumber ? reconciliationBranchName(plan.id, issueNumber) : null;
|
|
1533
|
+
const prs = issueNumber ? listPullRequestsForIssue(adapter, issueNumber, branchName, errors) : [];
|
|
1534
|
+
const pr = prState(prs);
|
|
1535
|
+
const currentLabels = issueLabels(issue);
|
|
1536
|
+
const virtualLabels = new Set(currentLabels);
|
|
1537
|
+
setAddMany(virtualLabels, ['gtd:plan']);
|
|
1538
|
+
|
|
1539
|
+
const marker = parseExportMarker(issue?.body || '');
|
|
1540
|
+
const expectedMarker = {
|
|
1541
|
+
phase: scope.phase.phaseSlug,
|
|
1542
|
+
plan: plan.id,
|
|
1543
|
+
};
|
|
1544
|
+
const markerValid = sameMarker(marker, expectedMarker);
|
|
1545
|
+
const sourceDrift =
|
|
1546
|
+
!markerValid ||
|
|
1547
|
+
marker.source_hash !== plan.source_hash ||
|
|
1548
|
+
planEntry?.source_hash !== plan.source_hash;
|
|
1549
|
+
if (sourceDrift) virtualLabels.add('gtd:source-drift');
|
|
1550
|
+
|
|
1551
|
+
const parentRecord = {
|
|
1552
|
+
kind: 'parent_plan',
|
|
1553
|
+
scope,
|
|
1554
|
+
plan,
|
|
1555
|
+
plan_id: plan.id,
|
|
1556
|
+
issue_number: issueNumber,
|
|
1557
|
+
issue,
|
|
1558
|
+
manifest_entry: planEntry,
|
|
1559
|
+
marker,
|
|
1560
|
+
marker_valid: markerValid,
|
|
1561
|
+
source_drift: sourceDrift,
|
|
1562
|
+
labels: {
|
|
1563
|
+
current: currentLabels.sort(),
|
|
1564
|
+
virtual: null,
|
|
1565
|
+
actions: null,
|
|
1566
|
+
},
|
|
1567
|
+
blockers,
|
|
1568
|
+
open_blockers: blockers.filter(isIssueOpen),
|
|
1569
|
+
linked_prs: pr,
|
|
1570
|
+
branch_name: branchName,
|
|
1571
|
+
tasks: [],
|
|
1572
|
+
errors,
|
|
1573
|
+
reconciliation: null,
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
parentRecord.labels.virtual = [...virtualLabels].sort();
|
|
1577
|
+
parentRecord.labels.actions = labelActions(currentLabels, virtualLabels, PARENT_STATE_LABELS);
|
|
1578
|
+
return parentRecord;
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
function evaluateWorkability(record) {
|
|
1582
|
+
const reasons = [];
|
|
1583
|
+
const virtualLabels = new Set(record.labels.virtual);
|
|
1584
|
+
const issueNumber = record.issue_number ? `#${record.issue_number}` : 'unknown issue';
|
|
1585
|
+
const checkpointTask = isCheckpointTask(record);
|
|
1586
|
+
|
|
1587
|
+
if (!record.manifest_entry?.issue) {
|
|
1588
|
+
reasons.push({ code: 'missing_manifest_task_issue', message: `${record.task_id} has no task issue in the export manifest.` });
|
|
1589
|
+
}
|
|
1590
|
+
if (checkpointTask) {
|
|
1591
|
+
reasons.push({
|
|
1592
|
+
code: 'checkpoint_human_resolution',
|
|
1593
|
+
message: record.issue && !isIssueOpen(record.issue)
|
|
1594
|
+
? `${issueNumber} is a resolved human-in-the-loop checkpoint. Checkpoint tasks are not executable implementation work.`
|
|
1595
|
+
: `${issueNumber} is a human-in-the-loop checkpoint. Resolve it by recording the human decision/result in GitHub and closing the checkpoint issue; dependent implementation tasks remain blocked while it is open.`,
|
|
1596
|
+
status: record.issue && !isIssueOpen(record.issue) ? CHECKPOINT_RESOLVED_STATUS : 'checkpoint_open',
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
if (!record.issue) {
|
|
1600
|
+
reasons.push({ code: 'issue_not_found', message: `${issueNumber} could not be read from GitHub.` });
|
|
1601
|
+
} else if (!isIssueOpen(record.issue)) {
|
|
1602
|
+
reasons.push({ code: 'issue_closed', message: `${issueNumber} is closed.` });
|
|
1603
|
+
}
|
|
1604
|
+
if (!virtualLabels.has('gtd:task')) {
|
|
1605
|
+
reasons.push({ code: 'missing_task_label', message: `${issueNumber} is not labeled gtd:task.` });
|
|
1606
|
+
}
|
|
1607
|
+
if (!record.marker_valid) {
|
|
1608
|
+
reasons.push({ code: 'invalid_marker', message: `${issueNumber} does not contain the expected gtd-export marker for ${record.task_id}.` });
|
|
1609
|
+
}
|
|
1610
|
+
if (record.source_drift) {
|
|
1611
|
+
reasons.push({
|
|
1612
|
+
code: 'source_drift',
|
|
1613
|
+
message: `${record.task_id} source hash differs from the manifest or issue marker.`,
|
|
1614
|
+
details: {
|
|
1615
|
+
issue_hash: record.marker?.source_hash || null,
|
|
1616
|
+
manifest_hash: record.manifest_entry?.source_hash || null,
|
|
1617
|
+
current_hash: record.task.source_hash,
|
|
1618
|
+
},
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
for (const err of record.errors) {
|
|
1622
|
+
reasons.push({ code: 'preflight_read_failed', message: `${err.operation}: ${err.message}` });
|
|
1623
|
+
}
|
|
1624
|
+
const openBlockerNumbers = openIssueNumbers(record.open_blockers);
|
|
1625
|
+
if (openBlockerNumbers.length > 0) {
|
|
1626
|
+
reasons.push({
|
|
1627
|
+
code: 'open_task_blockers',
|
|
1628
|
+
message: `${issueNumber} is blocked by open issue(s): ${openBlockerNumbers.map((n) => `#${n}`).join(', ')}.`,
|
|
1629
|
+
blockers: openBlockerNumbers,
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
const blockingLabels = BLOCKING_TASK_LABELS.filter((label) => virtualLabels.has(label));
|
|
1633
|
+
if (blockingLabels.length > 0) {
|
|
1634
|
+
reasons.push({
|
|
1635
|
+
code: 'blocking_task_labels',
|
|
1636
|
+
message: `${issueNumber} has blocking label(s): ${blockingLabels.join(', ')}.`,
|
|
1637
|
+
labels: blockingLabels,
|
|
1638
|
+
});
|
|
1639
|
+
}
|
|
1640
|
+
const parentBlockers = openIssueNumbers(record.parent?.open_blockers || []);
|
|
1641
|
+
if (parentBlockers.length > 0) {
|
|
1642
|
+
reasons.push({
|
|
1643
|
+
code: 'open_parent_blockers',
|
|
1644
|
+
message: `Parent plan #${record.parent.issue_number} is blocked by open issue(s): ${parentBlockers.map((n) => `#${n}`).join(', ')}.`,
|
|
1645
|
+
blockers: parentBlockers,
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
if (virtualLabels.has('gtd:in-progress') && !isResumable(record)) {
|
|
1649
|
+
reasons.push({
|
|
1650
|
+
code: 'active_claim',
|
|
1651
|
+
message: `${issueNumber} is already labeled gtd:in-progress; read-only mode does not clear or take over claims.`,
|
|
1652
|
+
});
|
|
1653
|
+
}
|
|
1654
|
+
if (!isActionableState(record)) {
|
|
1655
|
+
reasons.push({
|
|
1656
|
+
code: 'not_actionable',
|
|
1657
|
+
message: `${issueNumber} is not ready, not a rework task, and has no resumable rejected or validation-failed state.`,
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
return {
|
|
1662
|
+
workable: reasons.length === 0,
|
|
1663
|
+
reasons,
|
|
1664
|
+
skipped_checks: [
|
|
1665
|
+
'task worktree creation/reuse is checked in task execution mode',
|
|
1666
|
+
],
|
|
1667
|
+
};
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
function isResumable(record) {
|
|
1671
|
+
const labels = new Set(record.labels.virtual);
|
|
1672
|
+
return record.linked_prs.openNeedsRework.length > 0 ||
|
|
1673
|
+
record.linked_prs.closedUnmerged.length > 0 ||
|
|
1674
|
+
REWORK_LABELS.some((label) => labels.has(label));
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
function isReadyNewWork(record) {
|
|
1678
|
+
const labels = new Set(record.labels.virtual);
|
|
1679
|
+
return labels.has('gtd:ready') &&
|
|
1680
|
+
record.open_blockers.length === 0 &&
|
|
1681
|
+
record.linked_prs.open.length === 0 &&
|
|
1682
|
+
record.linked_prs.closedUnmerged.length === 0 &&
|
|
1683
|
+
record.linked_prs.merged.length === 0;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
function isActionableState(record) {
|
|
1687
|
+
const labels = new Set(record.labels.virtual);
|
|
1688
|
+
return isReadyNewWork(record) ||
|
|
1689
|
+
record.linked_prs.openNeedsRework.length > 0 ||
|
|
1690
|
+
record.linked_prs.closedUnmerged.length > 0 ||
|
|
1691
|
+
REWORK_LABELS.some((label) => labels.has(label));
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
function selectionBucket(record) {
|
|
1695
|
+
const labels = new Set(record.labels.virtual);
|
|
1696
|
+
if (!record.workability?.workable) return null;
|
|
1697
|
+
if (record.linked_prs.openNeedsRework.length > 0) return 1;
|
|
1698
|
+
if (REWORK_LABELS.some((label) => labels.has(label))) return 2;
|
|
1699
|
+
if (isReadyNewWork(record)) return 3;
|
|
1700
|
+
return null;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
function evaluateReconciliation(parent) {
|
|
1704
|
+
const reasons = [];
|
|
1705
|
+
const issueNumber = parent.issue_number ? `#${parent.issue_number}` : 'unknown issue';
|
|
1706
|
+
const hasMergedReconciliation = parent.linked_prs?.merged?.length > 0;
|
|
1707
|
+
const hasOpenReconciliation = parent.linked_prs?.open?.length > 0;
|
|
1708
|
+
|
|
1709
|
+
if (hasMergedReconciliation) {
|
|
1710
|
+
const virtualLabels = new Set(parent.labels.virtual);
|
|
1711
|
+
virtualLabels.add('gtd:complete');
|
|
1712
|
+
setDeleteMany(virtualLabels, [
|
|
1713
|
+
'gtd:ready',
|
|
1714
|
+
'gtd:blocked',
|
|
1715
|
+
'gtd:ready-for-reconcile',
|
|
1716
|
+
'gtd:reconcile-pr-open',
|
|
1717
|
+
'gtd:reconcile-failed',
|
|
1718
|
+
'gtd:source-drift',
|
|
1719
|
+
]);
|
|
1720
|
+
parent.labels.virtual = [...virtualLabels].sort();
|
|
1721
|
+
parent.labels.actions = labelActions(parent.labels.current, virtualLabels, PARENT_STATE_LABELS);
|
|
1722
|
+
parent.reconciliation = {
|
|
1723
|
+
ready: false,
|
|
1724
|
+
permission_required: false,
|
|
1725
|
+
reasons: [],
|
|
1726
|
+
proposed_branch: parent.branch_name,
|
|
1727
|
+
plan_verification: parent.plan.verification || '',
|
|
1728
|
+
artifacts: [
|
|
1729
|
+
summaryPathForPlan(parent.plan),
|
|
1730
|
+
'.planning/STATE.md',
|
|
1731
|
+
'.planning/ROADMAP.md',
|
|
1732
|
+
'requirements completion metadata',
|
|
1733
|
+
],
|
|
1734
|
+
status: 'complete',
|
|
1735
|
+
};
|
|
1736
|
+
return;
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
if (!parent.issue) {
|
|
1740
|
+
reasons.push({ code: 'parent_issue_not_found', message: `${issueNumber} could not be read from GitHub.` });
|
|
1741
|
+
} else if (!isIssueOpen(parent.issue)) {
|
|
1742
|
+
reasons.push({ code: 'parent_closed', message: `${issueNumber} is closed.` });
|
|
1743
|
+
}
|
|
1744
|
+
if (hasOpenReconciliation) {
|
|
1745
|
+
reasons.push({
|
|
1746
|
+
code: 'reconciliation_pr_open',
|
|
1747
|
+
message: `${issueNumber} already has an open reconciliation PR.`,
|
|
1748
|
+
prs: parent.linked_prs.open.map((pr) => pr.number).filter(Boolean),
|
|
1749
|
+
});
|
|
1750
|
+
}
|
|
1751
|
+
if (!parent.marker_valid) {
|
|
1752
|
+
reasons.push({ code: 'invalid_parent_marker', message: `${issueNumber} does not contain the expected parent plan marker.` });
|
|
1753
|
+
}
|
|
1754
|
+
if (parent.source_drift) {
|
|
1755
|
+
reasons.push({
|
|
1756
|
+
code: 'parent_source_drift',
|
|
1757
|
+
message: `${parent.plan_id} source hash differs from the manifest or parent issue marker.`,
|
|
1758
|
+
details: {
|
|
1759
|
+
issue_hash: parent.marker?.source_hash || null,
|
|
1760
|
+
manifest_hash: parent.manifest_entry?.source_hash || null,
|
|
1761
|
+
current_hash: parent.plan.source_hash,
|
|
1762
|
+
source_path: sourcePathForPlan(parent.plan),
|
|
1763
|
+
},
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
const parentBlockers = openIssueNumbers(parent.open_blockers);
|
|
1767
|
+
if (parentBlockers.length > 0) {
|
|
1768
|
+
reasons.push({
|
|
1769
|
+
code: 'open_parent_blockers',
|
|
1770
|
+
message: `${issueNumber} is blocked by open issue(s): ${parentBlockers.map((n) => `#${n}`).join(', ')}.`,
|
|
1771
|
+
blockers: parentBlockers,
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
for (const err of parent.errors) {
|
|
1775
|
+
reasons.push({ code: 'preflight_read_failed', message: `${err.operation}: ${err.message}` });
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
for (const task of parent.tasks) {
|
|
1779
|
+
const labels = new Set(task.labels.virtual);
|
|
1780
|
+
const resolvedCheckpoint = isResolvedCheckpointTask(task);
|
|
1781
|
+
if (task.issue && isIssueOpen(task.issue)) {
|
|
1782
|
+
reasons.push({
|
|
1783
|
+
code: 'child_task_open',
|
|
1784
|
+
message: `Child task #${task.issue_number} (${task.task_id}) is still open.`,
|
|
1785
|
+
issue: task.issue_number,
|
|
1786
|
+
});
|
|
1787
|
+
}
|
|
1788
|
+
if (task.linked_prs.merged.length === 0 && !resolvedCheckpoint) {
|
|
1789
|
+
reasons.push({
|
|
1790
|
+
code: 'child_pr_not_merged',
|
|
1791
|
+
message: `Child task #${task.issue_number} (${task.task_id}) has no merged linked PR.`,
|
|
1792
|
+
issue: task.issue_number,
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
const blockingLabels = ['gtd:needs-rework', 'gtd:blocked-human', 'gtd:source-drift'].filter((label) => labels.has(label));
|
|
1796
|
+
if (blockingLabels.length > 0) {
|
|
1797
|
+
reasons.push({
|
|
1798
|
+
code: 'child_blocking_labels',
|
|
1799
|
+
message: `Child task #${task.issue_number} (${task.task_id}) has blocking label(s): ${blockingLabels.join(', ')}.`,
|
|
1800
|
+
issue: task.issue_number,
|
|
1801
|
+
labels: blockingLabels,
|
|
1802
|
+
});
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
const virtualLabels = new Set(parent.labels.virtual);
|
|
1807
|
+
if (reasons.length === 0) {
|
|
1808
|
+
virtualLabels.add('gtd:ready-for-reconcile');
|
|
1809
|
+
virtualLabels.delete('gtd:blocked');
|
|
1810
|
+
virtualLabels.delete('gtd:reconcile-pr-open');
|
|
1811
|
+
} else if (parent.source_drift) {
|
|
1812
|
+
virtualLabels.delete('gtd:ready-for-reconcile');
|
|
1813
|
+
virtualLabels.add('gtd:source-drift');
|
|
1814
|
+
} else if (hasOpenReconciliation) {
|
|
1815
|
+
virtualLabels.delete('gtd:ready-for-reconcile');
|
|
1816
|
+
virtualLabels.add('gtd:reconcile-pr-open');
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
parent.labels.virtual = [...virtualLabels].sort();
|
|
1820
|
+
parent.labels.actions = labelActions(parent.labels.current, virtualLabels, PARENT_STATE_LABELS);
|
|
1821
|
+
parent.reconciliation = {
|
|
1822
|
+
ready: reasons.length === 0,
|
|
1823
|
+
permission_required: reasons.length === 0,
|
|
1824
|
+
reasons,
|
|
1825
|
+
proposed_branch: parent.issue_number ? reconciliationBranchName(parent.plan_id, parent.issue_number) : null,
|
|
1826
|
+
plan_verification: parent.plan.verification || '',
|
|
1827
|
+
artifacts: [
|
|
1828
|
+
summaryPathForPlan(parent.plan),
|
|
1829
|
+
'.planning/STATE.md',
|
|
1830
|
+
'.planning/ROADMAP.md',
|
|
1831
|
+
'requirements completion metadata',
|
|
1832
|
+
],
|
|
1833
|
+
status: hasOpenReconciliation ? 'pr_open' : (reasons.length === 0 ? 'ready' : 'blocked'),
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
function phaseSortText(record) {
|
|
1838
|
+
return String(record.scope.phase.phaseNumber || record.scope.phase.phaseSlug || '');
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
function taskIndex(record) {
|
|
1842
|
+
const match = String(record.task_id || '').match(/-T(\d+)$/i);
|
|
1843
|
+
return match ? Number(match[1]) : 0;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
function waveNumber(record) {
|
|
1847
|
+
const raw = record.plan?.wave;
|
|
1848
|
+
const parsed = Number(raw);
|
|
1849
|
+
return Number.isFinite(parsed) ? parsed : Number.MAX_SAFE_INTEGER;
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
function compareRecords(a, b) {
|
|
1853
|
+
const phase = phaseSortText(a).localeCompare(phaseSortText(b), undefined, { numeric: true, sensitivity: 'base' });
|
|
1854
|
+
if (phase !== 0) return phase;
|
|
1855
|
+
const wave = waveNumber(a) - waveNumber(b);
|
|
1856
|
+
if (wave !== 0) return wave;
|
|
1857
|
+
const plan = String(a.plan_id).localeCompare(String(b.plan_id), undefined, { numeric: true, sensitivity: 'base' });
|
|
1858
|
+
if (plan !== 0) return plan;
|
|
1859
|
+
const task = taskIndex(a) - taskIndex(b);
|
|
1860
|
+
if (task !== 0) return task;
|
|
1861
|
+
return Number(a.issue_number || 0) - Number(b.issue_number || 0);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
function compareParents(a, b) {
|
|
1865
|
+
const phase = phaseSortText(a).localeCompare(phaseSortText(b), undefined, { numeric: true, sensitivity: 'base' });
|
|
1866
|
+
if (phase !== 0) return phase;
|
|
1867
|
+
const wave = waveNumber(a) - waveNumber(b);
|
|
1868
|
+
if (wave !== 0) return wave;
|
|
1869
|
+
const plan = String(a.plan_id).localeCompare(String(b.plan_id), undefined, { numeric: true, sensitivity: 'base' });
|
|
1870
|
+
if (plan !== 0) return plan;
|
|
1871
|
+
return Number(a.issue_number || 0) - Number(b.issue_number || 0);
|
|
1872
|
+
}
|
|
1873
|
+
|
|
1874
|
+
function collectRecords(scopes, adapterForRepo) {
|
|
1875
|
+
const parents = [];
|
|
1876
|
+
const tasks = [];
|
|
1877
|
+
for (const scope of scopes) {
|
|
1878
|
+
const adapter = adapterForRepo(scope.repo);
|
|
1879
|
+
for (const plan of scope.plans) {
|
|
1880
|
+
const parent = makeParentRecord(scope, plan, adapter);
|
|
1881
|
+
parents.push(parent);
|
|
1882
|
+
for (const task of plan.tasks) {
|
|
1883
|
+
const record = makeTaskRecord(scope, plan, task, parent, adapter);
|
|
1884
|
+
parent.tasks.push(record);
|
|
1885
|
+
tasks.push(record);
|
|
1886
|
+
}
|
|
1887
|
+
evaluateReconciliation(parent);
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
return {
|
|
1891
|
+
parents: parents.sort(compareParents),
|
|
1892
|
+
tasks: tasks.sort(compareRecords),
|
|
1893
|
+
};
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
function resolveExplicitTask(selector, tasks, parents) {
|
|
1897
|
+
if (selector.type === 'task_id') {
|
|
1898
|
+
return tasks.filter((task) => task.task_id.toUpperCase() === selector.task_id);
|
|
1899
|
+
}
|
|
1900
|
+
if (selector.type === 'plan_id') {
|
|
1901
|
+
const parentMatch = parents.find((parent) => parent.plan_id.toUpperCase() === selector.plan_id);
|
|
1902
|
+
if (parentMatch) {
|
|
1903
|
+
return [{
|
|
1904
|
+
kind: 'resolution_error',
|
|
1905
|
+
workability: {
|
|
1906
|
+
workable: false,
|
|
1907
|
+
reasons: [{
|
|
1908
|
+
code: 'selector_resolved_parent_plan',
|
|
1909
|
+
message: `${selector.raw} is a parent plan selector; use --reconcile to reconcile parent plans.`,
|
|
1910
|
+
}],
|
|
1911
|
+
skipped_checks: [],
|
|
1912
|
+
},
|
|
1913
|
+
}];
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
if (selector.type === 'issue') {
|
|
1917
|
+
const matches = tasks.filter((task) => Number(task.issue_number) === selector.issue);
|
|
1918
|
+
if (matches.length > 0) return matches;
|
|
1919
|
+
const parentMatch = parents.find((parent) => Number(parent.issue_number) === selector.issue);
|
|
1920
|
+
if (parentMatch) {
|
|
1921
|
+
return [{
|
|
1922
|
+
kind: 'resolution_error',
|
|
1923
|
+
workability: {
|
|
1924
|
+
workable: false,
|
|
1925
|
+
reasons: [{
|
|
1926
|
+
code: 'selector_resolved_parent_plan',
|
|
1927
|
+
message: `#${selector.issue} is a parent plan issue; step 3 explicit mode only resolves child task issues.`,
|
|
1928
|
+
}],
|
|
1929
|
+
skipped_checks: [],
|
|
1930
|
+
},
|
|
1931
|
+
}];
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
return [];
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
function resolveExplicitParent(selector, parents, tasks) {
|
|
1938
|
+
if (selector.type === 'plan_id') {
|
|
1939
|
+
return parents.filter((parent) => parent.plan_id.toUpperCase() === selector.plan_id);
|
|
1940
|
+
}
|
|
1941
|
+
if (selector.type === 'issue') {
|
|
1942
|
+
const matches = parents.filter((parent) => Number(parent.issue_number) === selector.issue);
|
|
1943
|
+
if (matches.length > 0) return matches;
|
|
1944
|
+
const taskMatch = tasks.find((task) => Number(task.issue_number) === selector.issue);
|
|
1945
|
+
if (taskMatch) {
|
|
1946
|
+
return [{
|
|
1947
|
+
kind: 'resolution_error',
|
|
1948
|
+
reconciliation: {
|
|
1949
|
+
ready: false,
|
|
1950
|
+
permission_required: false,
|
|
1951
|
+
reasons: [{
|
|
1952
|
+
code: 'selector_resolved_child_task',
|
|
1953
|
+
message: `#${selector.issue} is a child task issue; omit --reconcile to work task issues.`,
|
|
1954
|
+
}],
|
|
1955
|
+
},
|
|
1956
|
+
}];
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
if (selector.type === 'task_id') {
|
|
1960
|
+
const taskMatch = tasks.find((task) => task.task_id.toUpperCase() === selector.task_id);
|
|
1961
|
+
if (taskMatch) {
|
|
1962
|
+
return [{
|
|
1963
|
+
kind: 'resolution_error',
|
|
1964
|
+
reconciliation: {
|
|
1965
|
+
ready: false,
|
|
1966
|
+
permission_required: false,
|
|
1967
|
+
reasons: [{
|
|
1968
|
+
code: 'selector_resolved_child_task',
|
|
1969
|
+
message: `${selector.raw} is a child task selector; omit --reconcile to work task issues.`,
|
|
1970
|
+
}],
|
|
1971
|
+
},
|
|
1972
|
+
}];
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return [];
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
function selectAutomatic(tasks, parents) {
|
|
1979
|
+
const workable = tasks.filter((task) => task.workability.workable && task.selection_bucket !== null);
|
|
1980
|
+
for (const bucket of [1, 2, 3]) {
|
|
1981
|
+
const match = workable.filter((task) => task.selection_bucket === bucket).sort(compareRecords)[0];
|
|
1982
|
+
if (match) return { kind: 'task', record: match };
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
const reconcile = parents.filter((parent) => parent.reconciliation.ready).sort(compareParents)[0];
|
|
1986
|
+
if (reconcile) return { kind: 'reconciliation_permission', record: reconcile };
|
|
1987
|
+
|
|
1988
|
+
return { kind: 'none', record: null };
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function prOutput(pr) {
|
|
1992
|
+
return {
|
|
1993
|
+
number: pr.number || null,
|
|
1994
|
+
title: pr.title || '',
|
|
1995
|
+
state: pr.state || '',
|
|
1996
|
+
url: pr.url || null,
|
|
1997
|
+
headRefName: pr.headRefName || null,
|
|
1998
|
+
isDraft: pr.isDraft,
|
|
1999
|
+
mergedAt: pr.mergedAt || null,
|
|
2000
|
+
reviewDecision: pr.reviewDecision || null,
|
|
2001
|
+
changesRequested: pr.changesRequested,
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
function taskOutput(record) {
|
|
2006
|
+
if (record.kind === 'resolution_error') {
|
|
2007
|
+
return {
|
|
2008
|
+
kind: 'task',
|
|
2009
|
+
resolved: false,
|
|
2010
|
+
workability: record.workability,
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
return {
|
|
2014
|
+
kind: 'task',
|
|
2015
|
+
resolved: true,
|
|
2016
|
+
issue: record.issue_number,
|
|
2017
|
+
title: record.issue?.title || null,
|
|
2018
|
+
state: record.issue?.state || null,
|
|
2019
|
+
repo: record.scope.repo,
|
|
2020
|
+
phase: record.scope.phase.phaseSlug,
|
|
2021
|
+
plan_id: record.plan_id,
|
|
2022
|
+
task_id: record.task_id,
|
|
2023
|
+
task_type: record.task.type || record.manifest_entry?.type || null,
|
|
2024
|
+
manifest_export_status: manifestTaskExportStatus(record.manifest_entry),
|
|
2025
|
+
checkpoint_status: manifestTaskCheckpointStatus(record.manifest_entry),
|
|
2026
|
+
checkpoint_resolved: isResolvedCheckpointTask(record),
|
|
2027
|
+
source_path: sourcePathForPlan(record.plan),
|
|
2028
|
+
branch: record.branch_name,
|
|
2029
|
+
labels: record.labels,
|
|
2030
|
+
blockers: {
|
|
2031
|
+
task: openIssueNumbers(record.open_blockers),
|
|
2032
|
+
parent: openIssueNumbers(record.parent?.open_blockers || []),
|
|
2033
|
+
},
|
|
2034
|
+
linked_prs: {
|
|
2035
|
+
open: record.linked_prs.open.map(prOutput),
|
|
2036
|
+
open_needs_rework: record.linked_prs.openNeedsRework.map(prOutput),
|
|
2037
|
+
closed_unmerged: record.linked_prs.closedUnmerged.map(prOutput),
|
|
2038
|
+
merged: record.linked_prs.merged.map(prOutput),
|
|
2039
|
+
},
|
|
2040
|
+
marker: {
|
|
2041
|
+
valid: record.marker_valid,
|
|
2042
|
+
issue_hash: record.marker?.source_hash || null,
|
|
2043
|
+
manifest_hash: record.manifest_entry?.source_hash || null,
|
|
2044
|
+
current_hash: record.task.source_hash,
|
|
2045
|
+
},
|
|
2046
|
+
source_drift: record.source_drift,
|
|
2047
|
+
selection_bucket: record.selection_bucket,
|
|
2048
|
+
workability: record.workability,
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
function parentOutput(parent) {
|
|
2053
|
+
if (parent.kind === 'resolution_error') {
|
|
2054
|
+
return {
|
|
2055
|
+
kind: 'parent_plan',
|
|
2056
|
+
resolved: false,
|
|
2057
|
+
reconciliation: parent.reconciliation,
|
|
2058
|
+
};
|
|
2059
|
+
}
|
|
2060
|
+
return {
|
|
2061
|
+
kind: 'parent_plan',
|
|
2062
|
+
resolved: true,
|
|
2063
|
+
issue: parent.issue_number,
|
|
2064
|
+
title: parent.issue?.title || null,
|
|
2065
|
+
state: parent.issue?.state || null,
|
|
2066
|
+
repo: parent.scope.repo,
|
|
2067
|
+
phase: parent.scope.phase.phaseSlug,
|
|
2068
|
+
plan_id: parent.plan_id,
|
|
2069
|
+
source_path: sourcePathForPlan(parent.plan),
|
|
2070
|
+
labels: parent.labels,
|
|
2071
|
+
blockers: {
|
|
2072
|
+
parent: openIssueNumbers(parent.open_blockers),
|
|
2073
|
+
},
|
|
2074
|
+
linked_prs: {
|
|
2075
|
+
open: parent.linked_prs.open.map(prOutput),
|
|
2076
|
+
merged: parent.linked_prs.merged.map(prOutput),
|
|
2077
|
+
closed_unmerged: parent.linked_prs.closedUnmerged.map(prOutput),
|
|
2078
|
+
},
|
|
2079
|
+
marker: {
|
|
2080
|
+
valid: parent.marker_valid,
|
|
2081
|
+
issue_hash: parent.marker?.source_hash || null,
|
|
2082
|
+
manifest_hash: parent.manifest_entry?.source_hash || null,
|
|
2083
|
+
current_hash: parent.plan.source_hash,
|
|
2084
|
+
},
|
|
2085
|
+
source_drift: parent.source_drift,
|
|
2086
|
+
reconciliation: {
|
|
2087
|
+
ready: parent.reconciliation.ready,
|
|
2088
|
+
permission_required: parent.reconciliation.permission_required,
|
|
2089
|
+
reasons: parent.reconciliation.reasons,
|
|
2090
|
+
proposed_branch: parent.reconciliation.proposed_branch,
|
|
2091
|
+
plan_verification: parent.reconciliation.plan_verification,
|
|
2092
|
+
artifacts: parent.reconciliation.artifacts,
|
|
2093
|
+
status: parent.reconciliation.status,
|
|
2094
|
+
child_tasks: parent.tasks.map((task) => ({
|
|
2095
|
+
issue: task.issue_number,
|
|
2096
|
+
task_id: task.task_id,
|
|
2097
|
+
task_type: task.task.type || task.manifest_entry?.type || null,
|
|
2098
|
+
checkpoint_resolved: isResolvedCheckpointTask(task),
|
|
2099
|
+
merged_prs: task.linked_prs.merged.map(prOutput),
|
|
2100
|
+
})),
|
|
2101
|
+
},
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
function labelActionSummaries(records) {
|
|
2106
|
+
const actions = [];
|
|
2107
|
+
for (const record of records) {
|
|
2108
|
+
if (record.labels.actions.add.length === 0 && record.labels.actions.remove.length === 0) continue;
|
|
2109
|
+
actions.push({
|
|
2110
|
+
kind: record.kind,
|
|
2111
|
+
issue: record.issue_number,
|
|
2112
|
+
plan_id: record.plan_id,
|
|
2113
|
+
task_id: record.task_id || null,
|
|
2114
|
+
add: record.labels.actions.add,
|
|
2115
|
+
remove: record.labels.actions.remove,
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
return actions;
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
function blockingStateOutput(tasks, parents) {
|
|
2122
|
+
return {
|
|
2123
|
+
non_workable_tasks: tasks.map((task) => ({
|
|
2124
|
+
issue: task.issue_number,
|
|
2125
|
+
task_id: task.task_id,
|
|
2126
|
+
plan_id: task.plan_id,
|
|
2127
|
+
labels: task.labels.virtual,
|
|
2128
|
+
reasons: task.workability.reasons,
|
|
2129
|
+
blockers: {
|
|
2130
|
+
task: openIssueNumbers(task.open_blockers),
|
|
2131
|
+
parent: openIssueNumbers(task.parent?.open_blockers || []),
|
|
2132
|
+
},
|
|
2133
|
+
})),
|
|
2134
|
+
parent_reconciliation: parents.map((parent) => ({
|
|
2135
|
+
issue: parent.issue_number,
|
|
2136
|
+
plan_id: parent.plan_id,
|
|
2137
|
+
ready: parent.reconciliation.ready,
|
|
2138
|
+
reasons: parent.reconciliation.reasons,
|
|
2139
|
+
})),
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
function buildReadOnly(cwd, opts, adapterOrFactory = null) {
|
|
2144
|
+
if (opts.completePhase) return buildCompletePhaseTail(cwd, opts);
|
|
2145
|
+
const selector = parseSelector(opts.selector);
|
|
2146
|
+
const effectiveOpts = {
|
|
2147
|
+
...opts,
|
|
2148
|
+
repo: opts.repo || selector.repo || null,
|
|
2149
|
+
};
|
|
2150
|
+
const scopes = loadScopes(cwd, effectiveOpts, selector);
|
|
2151
|
+
const adapters = new Map();
|
|
2152
|
+
const adapterForRepo = (repo) => {
|
|
2153
|
+
if (adapterOrFactory && typeof adapterOrFactory === 'function') return adapterOrFactory(repo);
|
|
2154
|
+
if (adapterOrFactory) return adapterOrFactory;
|
|
2155
|
+
if (!adapters.has(repo)) adapters.set(repo, new GhCliTaskIssueAdapter({ cwd, repo }));
|
|
2156
|
+
return adapters.get(repo);
|
|
2157
|
+
};
|
|
2158
|
+
|
|
2159
|
+
const records = collectRecords(scopes, adapterForRepo);
|
|
2160
|
+
const allRecords = [...records.parents, ...records.tasks];
|
|
2161
|
+
const preflightErrors = allRecords.flatMap((record) => record.errors.map((err) => ({
|
|
2162
|
+
issue: record.issue_number,
|
|
2163
|
+
operation: err.operation,
|
|
2164
|
+
message: err.message,
|
|
2165
|
+
})));
|
|
2166
|
+
|
|
2167
|
+
let selected = null;
|
|
2168
|
+
let action = null;
|
|
2169
|
+
let reconciliation = {
|
|
2170
|
+
ready: false,
|
|
2171
|
+
permission_required: false,
|
|
2172
|
+
plans: records.parents.filter((parent) => parent.reconciliation.ready).map(parentOutput),
|
|
2173
|
+
};
|
|
2174
|
+
|
|
2175
|
+
if (opts.reconcile) {
|
|
2176
|
+
if (selector.mode === 'explicit') {
|
|
2177
|
+
const matches = resolveExplicitParent(selector, records.parents, records.tasks);
|
|
2178
|
+
if (matches.length === 1) {
|
|
2179
|
+
selected = parentOutput(matches[0]);
|
|
2180
|
+
action = selected.reconciliation?.ready ? 'preview_reconciliation_ready' : 'report_unworkable_reconciliation';
|
|
2181
|
+
reconciliation = {
|
|
2182
|
+
ready: Boolean(selected.reconciliation?.ready),
|
|
2183
|
+
permission_required: Boolean(selected.reconciliation?.ready),
|
|
2184
|
+
plans: [selected],
|
|
2185
|
+
};
|
|
2186
|
+
} else if (matches.length > 1) {
|
|
2187
|
+
selected = {
|
|
2188
|
+
kind: 'parent_plan',
|
|
2189
|
+
resolved: false,
|
|
2190
|
+
reconciliation: {
|
|
2191
|
+
ready: false,
|
|
2192
|
+
permission_required: false,
|
|
2193
|
+
reasons: [{
|
|
2194
|
+
code: 'selector_ambiguous',
|
|
2195
|
+
message: `Selector ${selector.raw} resolved to multiple parent plan issues: ${matches.map((parent) => `#${parent.issue_number}`).join(', ')}.`,
|
|
2196
|
+
}],
|
|
2197
|
+
},
|
|
2198
|
+
};
|
|
2199
|
+
action = 'report_unresolved_reconciliation_selector';
|
|
2200
|
+
} else {
|
|
2201
|
+
selected = {
|
|
2202
|
+
kind: 'parent_plan',
|
|
2203
|
+
resolved: false,
|
|
2204
|
+
reconciliation: {
|
|
2205
|
+
ready: false,
|
|
2206
|
+
permission_required: false,
|
|
2207
|
+
reasons: [{
|
|
2208
|
+
code: 'selector_not_found',
|
|
2209
|
+
message: `Selector ${selector.raw} did not match any exported parent plan issue in the loaded manifest scope.`,
|
|
2210
|
+
}],
|
|
2211
|
+
},
|
|
2212
|
+
};
|
|
2213
|
+
action = 'report_unresolved_reconciliation_selector';
|
|
2214
|
+
}
|
|
2215
|
+
} else {
|
|
2216
|
+
const reconcile = records.parents.filter((parent) => parent.reconciliation.ready).sort(compareParents)[0];
|
|
2217
|
+
if (reconcile) {
|
|
2218
|
+
selected = parentOutput(reconcile);
|
|
2219
|
+
action = 'request_reconciliation_permission';
|
|
2220
|
+
reconciliation = {
|
|
2221
|
+
ready: true,
|
|
2222
|
+
permission_required: true,
|
|
2223
|
+
plans: [selected],
|
|
2224
|
+
};
|
|
2225
|
+
} else {
|
|
2226
|
+
action = 'report_blocking_state';
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
} else if (selector.mode === 'explicit') {
|
|
2230
|
+
const matches = resolveExplicitTask(selector, records.tasks, records.parents);
|
|
2231
|
+
if (matches.length === 1) {
|
|
2232
|
+
selected = taskOutput(matches[0]);
|
|
2233
|
+
action = selected.workability.workable ? 'report_workable_task' : 'report_unworkable_task';
|
|
2234
|
+
} else if (matches.length > 1) {
|
|
2235
|
+
selected = {
|
|
2236
|
+
kind: 'task',
|
|
2237
|
+
resolved: false,
|
|
2238
|
+
workability: {
|
|
2239
|
+
workable: false,
|
|
2240
|
+
reasons: [{
|
|
2241
|
+
code: 'selector_ambiguous',
|
|
2242
|
+
message: `Selector ${selector.raw} resolved to multiple task issues: ${matches.map((task) => `#${task.issue_number}`).join(', ')}.`,
|
|
2243
|
+
}],
|
|
2244
|
+
skipped_checks: [],
|
|
2245
|
+
},
|
|
2246
|
+
};
|
|
2247
|
+
action = 'report_unresolved_selector';
|
|
2248
|
+
} else {
|
|
2249
|
+
selected = {
|
|
2250
|
+
kind: 'task',
|
|
2251
|
+
resolved: false,
|
|
2252
|
+
workability: {
|
|
2253
|
+
workable: false,
|
|
2254
|
+
reasons: [{
|
|
2255
|
+
code: 'selector_not_found',
|
|
2256
|
+
message: `Selector ${selector.raw} did not match any exported child task issue in the loaded manifest scope.`,
|
|
2257
|
+
}],
|
|
2258
|
+
skipped_checks: [],
|
|
2259
|
+
},
|
|
2260
|
+
};
|
|
2261
|
+
action = 'report_unresolved_selector';
|
|
2262
|
+
}
|
|
2263
|
+
} else {
|
|
2264
|
+
const automatic = selectAutomatic(records.tasks, records.parents);
|
|
2265
|
+
if (automatic.kind === 'task') {
|
|
2266
|
+
selected = taskOutput(automatic.record);
|
|
2267
|
+
action = 'report_next_actionable_task';
|
|
2268
|
+
} else if (automatic.kind === 'reconciliation_permission') {
|
|
2269
|
+
selected = parentOutput(automatic.record);
|
|
2270
|
+
action = 'request_reconciliation_permission';
|
|
2271
|
+
reconciliation = {
|
|
2272
|
+
ready: true,
|
|
2273
|
+
permission_required: true,
|
|
2274
|
+
plans: [selected],
|
|
2275
|
+
};
|
|
2276
|
+
} else {
|
|
2277
|
+
action = 'report_blocking_state';
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
return {
|
|
2282
|
+
ok: true,
|
|
2283
|
+
version: 1,
|
|
2284
|
+
mode: 'read-only',
|
|
2285
|
+
writes: false,
|
|
2286
|
+
implementation: false,
|
|
2287
|
+
pr_creation: false,
|
|
2288
|
+
selector,
|
|
2289
|
+
scope: scopes.map((scope) => ({
|
|
2290
|
+
repo: scope.repo,
|
|
2291
|
+
phase: scope.phase.phaseSlug,
|
|
2292
|
+
phase_number: scope.phase.phaseNumber,
|
|
2293
|
+
manifest: scope.manifest.path,
|
|
2294
|
+
})),
|
|
2295
|
+
preflight: {
|
|
2296
|
+
ok: preflightErrors.length === 0,
|
|
2297
|
+
checked_parent_plans: records.parents.length,
|
|
2298
|
+
checked_tasks: records.tasks.length,
|
|
2299
|
+
label_actions: labelActionSummaries(allRecords),
|
|
2300
|
+
errors: preflightErrors,
|
|
2301
|
+
},
|
|
2302
|
+
action,
|
|
2303
|
+
selected,
|
|
2304
|
+
reconciliation,
|
|
2305
|
+
blocking_state: selected ? null : blockingStateOutput(records.tasks, records.parents),
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
function adapterFactoryFor(cwd, adapterOrFactory) {
|
|
2310
|
+
const adapters = new Map();
|
|
2311
|
+
return (repo) => {
|
|
2312
|
+
if (adapterOrFactory && typeof adapterOrFactory === 'function') return adapterOrFactory(repo);
|
|
2313
|
+
if (adapterOrFactory) return adapterOrFactory;
|
|
2314
|
+
if (!adapters.has(repo)) adapters.set(repo, new GhCliTaskIssueAdapter({ cwd, repo }));
|
|
2315
|
+
return adapters.get(repo);
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
function loadExecutionState(cwd, opts, adapterOrFactory = null) {
|
|
2320
|
+
const selector = parseSelector(opts.selector);
|
|
2321
|
+
const effectiveOpts = {
|
|
2322
|
+
...opts,
|
|
2323
|
+
repo: opts.repo || selector.repo || null,
|
|
2324
|
+
};
|
|
2325
|
+
const scopes = loadScopes(cwd, effectiveOpts, selector);
|
|
2326
|
+
const adapterForRepo = adapterFactoryFor(cwd, adapterOrFactory);
|
|
2327
|
+
const records = collectRecords(scopes, adapterForRepo);
|
|
2328
|
+
return {
|
|
2329
|
+
selector,
|
|
2330
|
+
scopes,
|
|
2331
|
+
adapterForRepo,
|
|
2332
|
+
records,
|
|
2333
|
+
};
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
function resolveExecutionSelection(selector, records) {
|
|
2337
|
+
if (selector.mode === 'explicit') {
|
|
2338
|
+
const matches = resolveExplicitTask(selector, records.tasks, records.parents);
|
|
2339
|
+
if (matches.length === 1) {
|
|
2340
|
+
const record = matches[0];
|
|
2341
|
+
if (record.kind === 'resolution_error') return { kind: 'unresolved', record };
|
|
2342
|
+
return { kind: 'task', record };
|
|
2343
|
+
}
|
|
2344
|
+
if (matches.length > 1) {
|
|
2345
|
+
return {
|
|
2346
|
+
kind: 'unresolved',
|
|
2347
|
+
record: {
|
|
2348
|
+
kind: 'resolution_error',
|
|
2349
|
+
workability: {
|
|
2350
|
+
workable: false,
|
|
2351
|
+
reasons: [{
|
|
2352
|
+
code: 'selector_ambiguous',
|
|
2353
|
+
message: `Selector ${selector.raw} resolved to multiple task issues: ${matches.map((task) => `#${task.issue_number}`).join(', ')}.`,
|
|
2354
|
+
}],
|
|
2355
|
+
skipped_checks: [],
|
|
2356
|
+
},
|
|
2357
|
+
},
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
return {
|
|
2361
|
+
kind: 'unresolved',
|
|
2362
|
+
record: {
|
|
2363
|
+
kind: 'resolution_error',
|
|
2364
|
+
workability: {
|
|
2365
|
+
workable: false,
|
|
2366
|
+
reasons: [{
|
|
2367
|
+
code: 'selector_not_found',
|
|
2368
|
+
message: `Selector ${selector.raw} did not match any exported child task issue in the loaded manifest scope.`,
|
|
2369
|
+
}],
|
|
2370
|
+
skipped_checks: [],
|
|
2371
|
+
},
|
|
2372
|
+
},
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
return selectAutomatic(records.tasks, records.parents);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
function executeTaskRecord(cwd, record, adapter, deps = {}) {
|
|
2379
|
+
if (isCheckpointTask(record)) {
|
|
2380
|
+
throw new TaskExecutionError(
|
|
2381
|
+
`${record.task_id} is a human-in-the-loop checkpoint task and cannot be executed. Resolve it by closing the checkpoint issue after recording the human decision/result.`,
|
|
2382
|
+
'checkpoint_task_not_executable',
|
|
2383
|
+
{ issue: record.issue_number, task_id: record.task_id },
|
|
2384
|
+
);
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
const claim = claimTaskIssue(adapter, record, deps);
|
|
2388
|
+
record.labels.virtual = claim.labels;
|
|
2389
|
+
record.labels.current = claim.labels;
|
|
2390
|
+
|
|
2391
|
+
const worktree = ensureTaskWorktree(cwd, record, deps);
|
|
2392
|
+
const feedback = reviewFeedback(adapter, record);
|
|
2393
|
+
const attempts = [];
|
|
2394
|
+
let executorResult = null;
|
|
2395
|
+
let validation = null;
|
|
2396
|
+
let changedFiles = [];
|
|
2397
|
+
let executorEvidence = null;
|
|
2398
|
+
let previousFindings = null;
|
|
2399
|
+
const retryBudget = deps.retryBudget ?? DEFAULT_EXECUTOR_RETRY_BUDGET;
|
|
2400
|
+
|
|
2401
|
+
for (let attempt = 0; attempt <= retryBudget; attempt += 1) {
|
|
2402
|
+
const context = executorContext(record, worktree, feedback, previousFindings);
|
|
2403
|
+
executorResult = runTaskExecutor(context, deps);
|
|
2404
|
+
changedFiles = listChangedFiles(worktree, deps);
|
|
2405
|
+
validation = validateTask(worktree.path, record, changedFiles, deps);
|
|
2406
|
+
attempts.push({
|
|
2407
|
+
attempt: attempt + 1,
|
|
2408
|
+
executor: executorResult,
|
|
2409
|
+
changed_files: changedFiles,
|
|
2410
|
+
validation,
|
|
2411
|
+
});
|
|
2412
|
+
if (validation.ok) break;
|
|
2413
|
+
previousFindings = validation.failed;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
executorEvidence = validateExecutorEvidence(worktree, executorResult, deps);
|
|
2417
|
+
if (!executorEvidence.ok) {
|
|
2418
|
+
const issue_update = markExecutorEvidenceFailedWithoutPr(adapter, record, validation, executorEvidence);
|
|
2419
|
+
return {
|
|
2420
|
+
action: 'validation_failed_no_pr',
|
|
2421
|
+
claim,
|
|
2422
|
+
worktree,
|
|
2423
|
+
review_feedback: feedback,
|
|
2424
|
+
attempts,
|
|
2425
|
+
changed_files: changedFiles,
|
|
2426
|
+
validation,
|
|
2427
|
+
executor_evidence: executorEvidence,
|
|
2428
|
+
useful_changes: false,
|
|
2429
|
+
pushed: null,
|
|
2430
|
+
pr: null,
|
|
2431
|
+
issue_update,
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
const pushed = pushTaskBranch(worktree, deps);
|
|
2436
|
+
const ready = validation.ok;
|
|
2437
|
+
const pr = openOrUpdatePullRequest(adapter, record, worktree, validation, executorResult, ready);
|
|
2438
|
+
const issue_update = finalizeIssueAfterPr(adapter, record, pr, validation, ready);
|
|
2439
|
+
|
|
2440
|
+
return {
|
|
2441
|
+
action: ready ? 'ready_pr_opened_or_updated' : 'draft_pr_opened_or_updated',
|
|
2442
|
+
claim,
|
|
2443
|
+
worktree,
|
|
2444
|
+
review_feedback: feedback,
|
|
2445
|
+
attempts,
|
|
2446
|
+
changed_files: changedFiles,
|
|
2447
|
+
validation,
|
|
2448
|
+
executor_evidence: executorEvidence,
|
|
2449
|
+
useful_changes: true,
|
|
2450
|
+
pushed,
|
|
2451
|
+
pr,
|
|
2452
|
+
issue_update,
|
|
2453
|
+
};
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
function ensureReconciliationWorktree(cwd, record, deps = {}) {
|
|
2457
|
+
if (deps.ensureReconciliationWorktree) return deps.ensureReconciliationWorktree({ cwd, record });
|
|
2458
|
+
|
|
2459
|
+
const branch = record.branch_name || reconciliationBranchName(record.plan_id, record.issue_number);
|
|
2460
|
+
const root = deps.worktreeRoot || defaultWorktreeRoot(cwd);
|
|
2461
|
+
const worktreePath = path.join(root, safeWorktreeLeaf(branch));
|
|
2462
|
+
fs.mkdirSync(root, { recursive: true });
|
|
2463
|
+
|
|
2464
|
+
const baseRef = defaultBranchRef(cwd);
|
|
2465
|
+
const existing = worktreeForBranch(cwd, branch);
|
|
2466
|
+
if (existing) {
|
|
2467
|
+
const status = runGit(existing.path, ['status', '--porcelain']).stdout;
|
|
2468
|
+
if (status) {
|
|
2469
|
+
throw new TaskExecutionError(`Reconciliation worktree ${existing.path} has uncommitted changes.`, 'dirty_reconciliation_worktree', { path: existing.path });
|
|
2470
|
+
}
|
|
2471
|
+
const rebase = runGit(existing.path, ['rebase', baseRef], { allowFailure: true });
|
|
2472
|
+
if (!rebase.ok) {
|
|
2473
|
+
runGit(existing.path, ['rebase', '--abort'], { allowFailure: true });
|
|
2474
|
+
throw new TaskExecutionError(`Could not rebase ${branch} onto ${baseRef}: ${rebase.stderr}`, 'reconciliation_branch_rebase_conflict');
|
|
2475
|
+
}
|
|
2476
|
+
return {
|
|
2477
|
+
path: existing.path,
|
|
2478
|
+
branch,
|
|
2479
|
+
base_ref: baseRef,
|
|
2480
|
+
reused: true,
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
if (fs.existsSync(worktreePath)) {
|
|
2485
|
+
throw new TaskExecutionError(`Reconciliation worktree path already exists without matching branch: ${worktreePath}`, 'worktree_path_collision', { path: worktreePath });
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
if (branchExists(cwd, branch)) {
|
|
2489
|
+
runGit(cwd, ['worktree', 'add', worktreePath, branch]);
|
|
2490
|
+
const rebase = runGit(worktreePath, ['rebase', baseRef], { allowFailure: true });
|
|
2491
|
+
if (!rebase.ok) {
|
|
2492
|
+
runGit(worktreePath, ['rebase', '--abort'], { allowFailure: true });
|
|
2493
|
+
throw new TaskExecutionError(`Could not rebase ${branch} onto ${baseRef}: ${rebase.stderr}`, 'reconciliation_branch_rebase_conflict');
|
|
2494
|
+
}
|
|
2495
|
+
} else {
|
|
2496
|
+
runGit(cwd, ['worktree', 'add', '-b', branch, worktreePath, baseRef]);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
return {
|
|
2500
|
+
path: worktreePath,
|
|
2501
|
+
branch,
|
|
2502
|
+
base_ref: baseRef,
|
|
2503
|
+
reused: false,
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
function runPlanVerification(worktreePath, record, deps = {}) {
|
|
2508
|
+
if (deps.runPlanVerification) return deps.runPlanVerification(worktreePath, record);
|
|
2509
|
+
const declaredVerification = String(record.plan.verification || '').trim();
|
|
2510
|
+
if (isResolvedCheckpointOnlyPlan(record)) {
|
|
2511
|
+
return {
|
|
2512
|
+
ok: true,
|
|
2513
|
+
skipped: true,
|
|
2514
|
+
skip_reason: 'resolved_human_checkpoint_only_plan',
|
|
2515
|
+
command: '',
|
|
2516
|
+
declared_verification: declaredVerification,
|
|
2517
|
+
status: 0,
|
|
2518
|
+
stdout: '',
|
|
2519
|
+
stderr: '',
|
|
2520
|
+
};
|
|
2521
|
+
}
|
|
2522
|
+
const command = declaredVerification;
|
|
2523
|
+
if (!command) {
|
|
2524
|
+
return {
|
|
2525
|
+
ok: true,
|
|
2526
|
+
skipped: true,
|
|
2527
|
+
skip_reason: 'no_plan_verification_declared',
|
|
2528
|
+
command: '',
|
|
2529
|
+
declared_verification: '',
|
|
2530
|
+
status: 0,
|
|
2531
|
+
stdout: '',
|
|
2532
|
+
stderr: '',
|
|
2533
|
+
};
|
|
2534
|
+
}
|
|
2535
|
+
const result = runShellCommand(command, worktreePath, deps);
|
|
2536
|
+
return {
|
|
2537
|
+
ok: result.status === 0,
|
|
2538
|
+
skipped: false,
|
|
2539
|
+
command,
|
|
2540
|
+
declared_verification: command,
|
|
2541
|
+
status: result.status,
|
|
2542
|
+
stdout: String(result.stdout || '').trim(),
|
|
2543
|
+
stderr: String(result.stderr || result.error || '').trim(),
|
|
2544
|
+
};
|
|
2545
|
+
}
|
|
2546
|
+
|
|
2547
|
+
function isResolvedCheckpointOnlyPlan(record) {
|
|
2548
|
+
const tasks = record?.tasks || [];
|
|
2549
|
+
return tasks.length > 0 &&
|
|
2550
|
+
tasks.every((task) => isCheckpointTask(task) && isResolvedCheckpointTask(task));
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
function singleLine(text) {
|
|
2554
|
+
return String(text || '').replace(/\s+/g, ' ').trim();
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
function verificationCommandDisplay(verification) {
|
|
2558
|
+
if (verification.skipped && verification.skip_reason === 'resolved_human_checkpoint_only_plan') {
|
|
2559
|
+
return 'not run (resolved human checkpoint-only plan)';
|
|
2560
|
+
}
|
|
2561
|
+
return verification.command ? `\`${verification.command}\`` : 'not declared';
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
function appendVerificationDetails(lines, verification) {
|
|
2565
|
+
lines.push(
|
|
2566
|
+
`- Command: ${verificationCommandDisplay(verification)}`,
|
|
2567
|
+
`- Result: ${verification.ok ? 'passed' : 'failed'}`,
|
|
2568
|
+
);
|
|
2569
|
+
|
|
2570
|
+
const declared = singleLine(verification.declared_verification);
|
|
2571
|
+
if (declared && declared !== verification.command) {
|
|
2572
|
+
lines.push(`- Declared verification: ${declared}`);
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
if (verification.skipped && verification.skip_reason === 'resolved_human_checkpoint_only_plan') {
|
|
2576
|
+
lines.push('- Note: resolved checkpoint issue closure satisfied plan verification.');
|
|
2577
|
+
} else if (verification.skipped) {
|
|
2578
|
+
lines.push('- Note: no plan-level verification command was declared.');
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
|
|
2582
|
+
function yamlInlineArray(items) {
|
|
2583
|
+
const values = (items || []).map((item) => String(item).trim()).filter(Boolean);
|
|
2584
|
+
if (values.length === 0) return '[]';
|
|
2585
|
+
return `[${values.join(', ')}]`;
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
function mergedPrRefs(record) {
|
|
2589
|
+
return record.tasks.flatMap((task) =>
|
|
2590
|
+
task.linked_prs.merged.map((pr) => ({
|
|
2591
|
+
task_id: task.task_id,
|
|
2592
|
+
issue: task.issue_number,
|
|
2593
|
+
pr: pr.number || null,
|
|
2594
|
+
url: pr.url || null,
|
|
2595
|
+
merged_at: pr.mergedAt || null,
|
|
2596
|
+
})),
|
|
2597
|
+
);
|
|
2598
|
+
}
|
|
2599
|
+
|
|
2600
|
+
function renderReconciliationSummary(record, verification, deps = {}) {
|
|
2601
|
+
const completed = (deps.now ? deps.now() : new Date()).toISOString().split('T')[0];
|
|
2602
|
+
const taskCount = record.tasks.length;
|
|
2603
|
+
const prs = mergedPrRefs(record);
|
|
2604
|
+
const requirements = record.plan.requirements || [];
|
|
2605
|
+
const phase = record.scope.phase.phaseNumber || record.scope.phase.phaseSlug;
|
|
2606
|
+
const planPart = String(record.plan_id).split('-').slice(1).join('-') || record.plan_id;
|
|
2607
|
+
const title = `Phase ${phase} Plan ${planPart}: Issue-Driven Task Reconciliation Summary`;
|
|
2608
|
+
const lines = [
|
|
2609
|
+
'---',
|
|
2610
|
+
`phase: ${record.scope.phase.phaseSlug}`,
|
|
2611
|
+
`plan: ${record.plan_id}`,
|
|
2612
|
+
'subsystem: issue-driven-task-execution',
|
|
2613
|
+
'tags: [github-issues, task-reconciliation]',
|
|
2614
|
+
'requires: []',
|
|
2615
|
+
'provides: []',
|
|
2616
|
+
'affects: []',
|
|
2617
|
+
'tech-stack:',
|
|
2618
|
+
' added: []',
|
|
2619
|
+
' patterns: []',
|
|
2620
|
+
'key-files:',
|
|
2621
|
+
' created: []',
|
|
2622
|
+
' modified: []',
|
|
2623
|
+
'key-decisions: []',
|
|
2624
|
+
`requirements-completed: ${yamlInlineArray(requirements)}`,
|
|
2625
|
+
'duration: issue-driven',
|
|
2626
|
+
`completed: ${completed}`,
|
|
2627
|
+
'---',
|
|
2628
|
+
'',
|
|
2629
|
+
`# ${title}`,
|
|
2630
|
+
'',
|
|
2631
|
+
`Completed parent plan \`${record.plan_id}\` through exported GitHub task issues.`,
|
|
2632
|
+
'',
|
|
2633
|
+
'## Execution Summary',
|
|
2634
|
+
'',
|
|
2635
|
+
`- Parent issue: #${record.issue_number}`,
|
|
2636
|
+
`- Source plan: \`${sourcePathForPlan(record.plan)}\``,
|
|
2637
|
+
`- Tasks reconciled: ${taskCount}`,
|
|
2638
|
+
`- Requirements completed: ${requirements.length ? requirements.map((req) => `\`${req}\``).join(', ') : 'none declared'}`,
|
|
2639
|
+
'',
|
|
2640
|
+
'## Child Task Evidence',
|
|
2641
|
+
'',
|
|
2642
|
+
];
|
|
2643
|
+
if (prs.length === 0) {
|
|
2644
|
+
lines.push('- No merged child task PRs were detected.');
|
|
2645
|
+
} else {
|
|
2646
|
+
for (const pr of prs) {
|
|
2647
|
+
const link = pr.url ? `[PR #${pr.pr}](${pr.url})` : `PR #${pr.pr || 'unknown'}`;
|
|
2648
|
+
lines.push(`- \`${pr.task_id}\` via task issue #${pr.issue}: ${link}`);
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
lines.push(
|
|
2652
|
+
'',
|
|
2653
|
+
'## Plan Verification',
|
|
2654
|
+
'',
|
|
2655
|
+
);
|
|
2656
|
+
appendVerificationDetails(lines, verification);
|
|
2657
|
+
if (verification.stdout) lines.push('', '### Stdout', '', '```text', verification.stdout, '```');
|
|
2658
|
+
if (verification.stderr) lines.push('', '### Stderr', '', '```text', verification.stderr, '```');
|
|
2659
|
+
lines.push(
|
|
2660
|
+
'',
|
|
2661
|
+
'## Issues Encountered',
|
|
2662
|
+
'',
|
|
2663
|
+
'None.',
|
|
2664
|
+
'',
|
|
2665
|
+
'## Next',
|
|
2666
|
+
'',
|
|
2667
|
+
'Plan reconciliation complete. Continue with phase completion when every plan in this phase has a summary.',
|
|
2668
|
+
'',
|
|
2669
|
+
);
|
|
2670
|
+
return lines.join('\n');
|
|
2671
|
+
}
|
|
2672
|
+
|
|
2673
|
+
function writeReconciliationSummary(worktreePath, record, verification, deps = {}) {
|
|
2674
|
+
const relPath = summaryPathForPlan(record.plan);
|
|
2675
|
+
const absPath = path.join(worktreePath, relPath);
|
|
2676
|
+
fs.mkdirSync(path.dirname(absPath), { recursive: true });
|
|
2677
|
+
const content = renderReconciliationSummary(record, verification, deps);
|
|
2678
|
+
fs.writeFileSync(absPath, `${content.replace(/\s+$/g, '')}\n`, 'utf8');
|
|
2679
|
+
return {
|
|
2680
|
+
path: relPath,
|
|
2681
|
+
bytes: Buffer.byteLength(content, 'utf8'),
|
|
2682
|
+
};
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
function runGtdSdkQuery(worktreePath, args, deps = {}) {
|
|
2686
|
+
if (deps.runGtdSdkQuery) return deps.runGtdSdkQuery(args, worktreePath);
|
|
2687
|
+
const sdkPath = path.resolve(__dirname, '..', '..', '..', 'bin', 'gtd-sdk.js');
|
|
2688
|
+
const useLocalShim = fs.existsSync(sdkPath);
|
|
2689
|
+
const result = childProcess.spawnSync(useLocalShim ? process.execPath : 'gtd-sdk', useLocalShim ? [sdkPath, 'query', ...args] : ['query', ...args], {
|
|
2690
|
+
cwd: worktreePath,
|
|
2691
|
+
encoding: 'utf8',
|
|
2692
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
2693
|
+
env: process.env,
|
|
2694
|
+
});
|
|
2695
|
+
return {
|
|
2696
|
+
ok: result.status === 0,
|
|
2697
|
+
status: result.status,
|
|
2698
|
+
command: ['gtd-sdk', 'query', ...args].join(' '),
|
|
2699
|
+
stdout: String(result.stdout || '').trim(),
|
|
2700
|
+
stderr: String(result.stderr || result.error || '').trim(),
|
|
2701
|
+
};
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
function requireSdkOk(result) {
|
|
2705
|
+
if (result?.ok) return result;
|
|
2706
|
+
throw new TaskExecutionError(result?.stderr || `${result?.command || 'gtd-sdk query'} failed`, 'canonical_state_update_failed', result);
|
|
2707
|
+
}
|
|
2708
|
+
|
|
2709
|
+
function updateCanonicalPlanState(worktreePath, record, deps = {}) {
|
|
2710
|
+
const phase = record.scope.phase.phaseNumber || record.scope.phase.phaseSlug;
|
|
2711
|
+
const planPart = String(record.plan_id).split('-').slice(1).join('-') || record.plan_id;
|
|
2712
|
+
const operations = [];
|
|
2713
|
+
const run = (args) => {
|
|
2714
|
+
const result = runGtdSdkQuery(worktreePath, args, deps);
|
|
2715
|
+
operations.push(result);
|
|
2716
|
+
requireSdkOk(result);
|
|
2717
|
+
};
|
|
2718
|
+
|
|
2719
|
+
run(['state.advance-plan']);
|
|
2720
|
+
run(['state.update-progress']);
|
|
2721
|
+
run([
|
|
2722
|
+
'state.record-metric',
|
|
2723
|
+
'--phase',
|
|
2724
|
+
String(phase),
|
|
2725
|
+
'--plan',
|
|
2726
|
+
String(planPart),
|
|
2727
|
+
'--duration',
|
|
2728
|
+
'issue-driven',
|
|
2729
|
+
'--tasks',
|
|
2730
|
+
String(record.tasks.length),
|
|
2731
|
+
'--files',
|
|
2732
|
+
'0',
|
|
2733
|
+
]);
|
|
2734
|
+
run(['roadmap.update-plan-progress', String(phase)]);
|
|
2735
|
+
if (record.plan.requirements?.length) {
|
|
2736
|
+
run(['requirements.mark-complete', ...record.plan.requirements]);
|
|
2737
|
+
}
|
|
2738
|
+
run([
|
|
2739
|
+
'state.record-session',
|
|
2740
|
+
'--stopped-at',
|
|
2741
|
+
`Completed ${record.plan_id}-PLAN.md via issue-driven reconciliation`,
|
|
2742
|
+
'--resume-file',
|
|
2743
|
+
'None',
|
|
2744
|
+
]);
|
|
2745
|
+
|
|
2746
|
+
return operations;
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
function commitReconciliationArtifacts(worktree, record, summary, deps = {}) {
|
|
2750
|
+
if (deps.commitReconciliationArtifacts) return deps.commitReconciliationArtifacts(worktree, record, summary);
|
|
2751
|
+
const candidates = [
|
|
2752
|
+
summary.path,
|
|
2753
|
+
'.planning/STATE.md',
|
|
2754
|
+
'.planning/ROADMAP.md',
|
|
2755
|
+
'.planning/REQUIREMENTS.md',
|
|
2756
|
+
].filter((relPath) => fs.existsSync(path.join(worktree.path, relPath)));
|
|
2757
|
+
runGit(worktree.path, ['add', ...candidates]);
|
|
2758
|
+
const status = runGit(worktree.path, ['status', '--porcelain']).stdout;
|
|
2759
|
+
if (!status) {
|
|
2760
|
+
return {
|
|
2761
|
+
committed: false,
|
|
2762
|
+
pushed: false,
|
|
2763
|
+
files: candidates,
|
|
2764
|
+
message: 'No reconciliation artifact changes to commit.',
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
const message = `Reconcile GTD plan ${record.plan_id}`;
|
|
2768
|
+
runGit(worktree.path, ['commit', '-m', message]);
|
|
2769
|
+
runGit(worktree.path, ['push', '--set-upstream', 'origin', worktree.branch]);
|
|
2770
|
+
return {
|
|
2771
|
+
committed: true,
|
|
2772
|
+
pushed: true,
|
|
2773
|
+
files: candidates,
|
|
2774
|
+
message,
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
|
|
2778
|
+
function reconciliationPrBody(record, summary, verification) {
|
|
2779
|
+
const lines = [
|
|
2780
|
+
`## GTD Plan Reconciliation`,
|
|
2781
|
+
'',
|
|
2782
|
+
`- Parent issue: #${record.issue_number}`,
|
|
2783
|
+
`- Plan ID: \`${record.plan_id}\``,
|
|
2784
|
+
`- Source plan: \`${sourcePathForPlan(record.plan)}\``,
|
|
2785
|
+
`- Summary: \`${summary.path}\``,
|
|
2786
|
+
'',
|
|
2787
|
+
'## Child Task Evidence',
|
|
2788
|
+
'',
|
|
2789
|
+
];
|
|
2790
|
+
for (const task of record.tasks) {
|
|
2791
|
+
const prs = task.linked_prs.merged.map((pr) => pr.url || `#${pr.number}`).join(', ') || 'none';
|
|
2792
|
+
lines.push(`- \`${task.task_id}\`: Refs #${task.issue_number}; merged PRs ${prs}`);
|
|
2793
|
+
}
|
|
2794
|
+
lines.push(
|
|
2795
|
+
'',
|
|
2796
|
+
'## Verification',
|
|
2797
|
+
'',
|
|
2798
|
+
);
|
|
2799
|
+
appendVerificationDetails(lines, verification);
|
|
2800
|
+
lines.push('', `Closes #${record.issue_number}`);
|
|
2801
|
+
return lines.join('\n');
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
function openReconciliationPullRequest(adapter, record, worktree, summary, verification) {
|
|
2805
|
+
if (!adapter || typeof adapter.createPullRequest !== 'function') {
|
|
2806
|
+
throw new TaskExecutionError('GitHub PR creation is unavailable.', 'github_pr_unavailable');
|
|
2807
|
+
}
|
|
2808
|
+
return callWrite(`create_reconciliation_pull_request:${worktree.branch}`, () => adapter.createPullRequest({
|
|
2809
|
+
title: `[GTD ${record.plan_id}] Reconcile completed task issues`,
|
|
2810
|
+
body: reconciliationPrBody(record, summary, verification),
|
|
2811
|
+
head: worktree.branch,
|
|
2812
|
+
base: worktree.base_ref.replace(/^origin\//, ''),
|
|
2813
|
+
draft: false,
|
|
2814
|
+
labels: [],
|
|
2815
|
+
}));
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
function markReconciliationFailed(adapter, record, verification) {
|
|
2819
|
+
const labels = mergeLabelSet(record.labels.virtual, ['gtd:reconcile-failed'], [
|
|
2820
|
+
'gtd:ready-for-reconcile',
|
|
2821
|
+
'gtd:reconcile-pr-open',
|
|
2822
|
+
'gtd:ready',
|
|
2823
|
+
]);
|
|
2824
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
2825
|
+
commentIssue(adapter, record.issue_number, [
|
|
2826
|
+
'Parent plan reconciliation failed plan-level verification. Canonical GTD state was not updated.',
|
|
2827
|
+
'',
|
|
2828
|
+
`Command: ${verification.command ? `\`${verification.command}\`` : 'not declared'}`,
|
|
2829
|
+
`Status: ${verification.status}`,
|
|
2830
|
+
verification.stderr ? `\nStderr:\n\n\`\`\`text\n${verification.stderr}\n\`\`\`` : '',
|
|
2831
|
+
verification.stdout ? `\nStdout:\n\n\`\`\`text\n${verification.stdout}\n\`\`\`` : '',
|
|
2832
|
+
].filter(Boolean).join('\n'));
|
|
2833
|
+
return {
|
|
2834
|
+
labels,
|
|
2835
|
+
comment_posted: true,
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
|
|
2839
|
+
function finalizeReconciliationIssue(adapter, record, pr) {
|
|
2840
|
+
const labels = mergeLabelSet(record.labels.virtual, ['gtd:reconcile-pr-open'], [
|
|
2841
|
+
'gtd:ready-for-reconcile',
|
|
2842
|
+
'gtd:reconcile-failed',
|
|
2843
|
+
'gtd:ready',
|
|
2844
|
+
'gtd:blocked',
|
|
2845
|
+
]);
|
|
2846
|
+
setIssueLabels(adapter, record.issue_number, labels);
|
|
2847
|
+
commentIssue(adapter, record.issue_number, [
|
|
2848
|
+
'Parent plan reconciliation PR opened.',
|
|
2849
|
+
'',
|
|
2850
|
+
`PR: ${pr.url || `#${pr.number}`}`,
|
|
2851
|
+
'',
|
|
2852
|
+
'Canonical GTD artifacts will be considered complete after this PR is merged and synced.',
|
|
2853
|
+
].join('\n'));
|
|
2854
|
+
return {
|
|
2855
|
+
labels,
|
|
2856
|
+
comment_posted: true,
|
|
2857
|
+
};
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
function executeReconciliationRecord(cwd, record, adapter, deps = {}) {
|
|
2861
|
+
if (!record.reconciliation.ready) {
|
|
2862
|
+
return {
|
|
2863
|
+
action: 'reconciliation_not_ready',
|
|
2864
|
+
reasons: record.reconciliation.reasons,
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
const worktree = ensureReconciliationWorktree(cwd, record, deps);
|
|
2868
|
+
const verification = runPlanVerification(worktree.path, record, deps);
|
|
2869
|
+
if (!verification.ok) {
|
|
2870
|
+
const issue_update = markReconciliationFailed(adapter, record, verification);
|
|
2871
|
+
return {
|
|
2872
|
+
action: 'reconciliation_verification_failed',
|
|
2873
|
+
worktree,
|
|
2874
|
+
verification,
|
|
2875
|
+
summary: null,
|
|
2876
|
+
canonical_state: [],
|
|
2877
|
+
commit: null,
|
|
2878
|
+
pr: null,
|
|
2879
|
+
issue_update,
|
|
2880
|
+
};
|
|
2881
|
+
}
|
|
2882
|
+
|
|
2883
|
+
const summary = writeReconciliationSummary(worktree.path, record, verification, deps);
|
|
2884
|
+
const canonicalState = updateCanonicalPlanState(worktree.path, record, deps);
|
|
2885
|
+
const commit = commitReconciliationArtifacts(worktree, record, summary, deps);
|
|
2886
|
+
const pr = openReconciliationPullRequest(adapter, record, worktree, summary, verification);
|
|
2887
|
+
const issue_update = finalizeReconciliationIssue(adapter, record, pr);
|
|
2888
|
+
|
|
2889
|
+
return {
|
|
2890
|
+
action: 'reconciliation_pr_opened',
|
|
2891
|
+
worktree,
|
|
2892
|
+
verification,
|
|
2893
|
+
summary,
|
|
2894
|
+
canonical_state: canonicalState,
|
|
2895
|
+
commit,
|
|
2896
|
+
pr,
|
|
2897
|
+
issue_update,
|
|
2898
|
+
};
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
function resolveReconciliationSelection(selector, records) {
|
|
2902
|
+
if (selector.mode === 'explicit') {
|
|
2903
|
+
const matches = resolveExplicitParent(selector, records.parents, records.tasks);
|
|
2904
|
+
if (matches.length === 1) {
|
|
2905
|
+
const record = matches[0];
|
|
2906
|
+
if (record.kind === 'resolution_error') return { kind: 'unresolved', record };
|
|
2907
|
+
return { kind: 'reconciliation', record };
|
|
2908
|
+
}
|
|
2909
|
+
if (matches.length > 1) {
|
|
2910
|
+
return {
|
|
2911
|
+
kind: 'unresolved',
|
|
2912
|
+
record: {
|
|
2913
|
+
kind: 'resolution_error',
|
|
2914
|
+
reconciliation: {
|
|
2915
|
+
ready: false,
|
|
2916
|
+
permission_required: false,
|
|
2917
|
+
reasons: [{
|
|
2918
|
+
code: 'selector_ambiguous',
|
|
2919
|
+
message: `Selector ${selector.raw} resolved to multiple parent plan issues: ${matches.map((parent) => `#${parent.issue_number}`).join(', ')}.`,
|
|
2920
|
+
}],
|
|
2921
|
+
},
|
|
2922
|
+
},
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
return {
|
|
2926
|
+
kind: 'unresolved',
|
|
2927
|
+
record: {
|
|
2928
|
+
kind: 'resolution_error',
|
|
2929
|
+
reconciliation: {
|
|
2930
|
+
ready: false,
|
|
2931
|
+
permission_required: false,
|
|
2932
|
+
reasons: [{
|
|
2933
|
+
code: 'selector_not_found',
|
|
2934
|
+
message: `Selector ${selector.raw} did not match any exported parent plan issue in the loaded manifest scope.`,
|
|
2935
|
+
}],
|
|
2936
|
+
},
|
|
2937
|
+
},
|
|
2938
|
+
};
|
|
2939
|
+
}
|
|
2940
|
+
const ready = records.parents.filter((parent) => parent.reconciliation.ready).sort(compareParents)[0];
|
|
2941
|
+
if (ready) return { kind: 'reconciliation', record: ready };
|
|
2942
|
+
return { kind: 'none', record: null };
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
function phaseSummaryStatus(cwd, phaseArg) {
|
|
2946
|
+
const source = loadExportSource(cwd, { phase: phaseArg });
|
|
2947
|
+
const plans = source.plans.map((plan) => {
|
|
2948
|
+
const summary = summaryPathForPlan(plan);
|
|
2949
|
+
return {
|
|
2950
|
+
plan_id: plan.id,
|
|
2951
|
+
source_path: sourcePathForPlan(plan),
|
|
2952
|
+
summary_path: summary,
|
|
2953
|
+
summary_exists: fs.existsSync(path.join(cwd, summary)),
|
|
2954
|
+
};
|
|
2955
|
+
});
|
|
2956
|
+
return {
|
|
2957
|
+
phase: source.phase.phaseSlug,
|
|
2958
|
+
phase_number: source.phase.phaseNumber,
|
|
2959
|
+
manifest: source.manifest.path,
|
|
2960
|
+
plan_count: plans.length,
|
|
2961
|
+
summary_count: plans.filter((plan) => plan.summary_exists).length,
|
|
2962
|
+
plans,
|
|
2963
|
+
missing_summaries: plans.filter((plan) => !plan.summary_exists),
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
|
|
2967
|
+
function buildCompletePhaseTail(cwd, opts, deps = {}) {
|
|
2968
|
+
const status = phaseSummaryStatus(cwd, opts.completePhase);
|
|
2969
|
+
const ready = status.missing_summaries.length === 0 && status.plan_count > 0;
|
|
2970
|
+
const phaseRef = status.phase_number || status.phase;
|
|
2971
|
+
const finalizationCommand = `${formatGtdSlashFor(cwd, 'work-task-issue')} --complete-phase ${phaseRef} --execute`;
|
|
2972
|
+
const base = {
|
|
2973
|
+
ok: true,
|
|
2974
|
+
version: 1,
|
|
2975
|
+
mode: opts.mode || 'read-only',
|
|
2976
|
+
writes: false,
|
|
2977
|
+
implementation: false,
|
|
2978
|
+
pr_creation: false,
|
|
2979
|
+
action: null,
|
|
2980
|
+
phase_completion: {
|
|
2981
|
+
ready,
|
|
2982
|
+
...status,
|
|
2983
|
+
finalization_command: finalizationCommand,
|
|
2984
|
+
finalization_scope: 'post_phase_gates_only',
|
|
2985
|
+
required_gates: [
|
|
2986
|
+
'code-review',
|
|
2987
|
+
'regression',
|
|
2988
|
+
'schema-drift',
|
|
2989
|
+
'codebase-drift',
|
|
2990
|
+
'gtd-verifier',
|
|
2991
|
+
'phase.complete',
|
|
2992
|
+
],
|
|
2993
|
+
next_verify_work_command: ready
|
|
2994
|
+
? `${formatGtdSlashFor(cwd, 'verify-work')} ${phaseRef}`
|
|
2995
|
+
: null,
|
|
2996
|
+
},
|
|
2997
|
+
};
|
|
2998
|
+
|
|
2999
|
+
if (!ready) {
|
|
3000
|
+
return {
|
|
3001
|
+
...base,
|
|
3002
|
+
action: 'phase_completion_blocked_missing_summaries',
|
|
3003
|
+
};
|
|
3004
|
+
}
|
|
3005
|
+
if (opts.mode !== 'execute') {
|
|
3006
|
+
return {
|
|
3007
|
+
...base,
|
|
3008
|
+
action: 'preview_phase_completion_finalization',
|
|
3009
|
+
};
|
|
3010
|
+
}
|
|
3011
|
+
const runFinalization = deps.runPhaseFinalization || deps.runPhaseCompletionTail;
|
|
3012
|
+
if (runFinalization) {
|
|
3013
|
+
const execution = runFinalization(cwd, {
|
|
3014
|
+
...status,
|
|
3015
|
+
finalization_command: finalizationCommand,
|
|
3016
|
+
finalization_scope: 'post_phase_gates_only',
|
|
3017
|
+
required_gates: base.phase_completion.required_gates,
|
|
3018
|
+
});
|
|
3019
|
+
return {
|
|
3020
|
+
...base,
|
|
3021
|
+
writes: Boolean(execution?.writes),
|
|
3022
|
+
action: execution?.action || 'phase_completion_finalization_executed',
|
|
3023
|
+
execution,
|
|
3024
|
+
};
|
|
3025
|
+
}
|
|
3026
|
+
return {
|
|
3027
|
+
...base,
|
|
3028
|
+
action: 'phase_completion_finalization_requires_workflow_gates',
|
|
3029
|
+
note: `Continue through ${finalizationCommand}; this path runs only post-phase finalization gates and does not rerun implementation tasks.`,
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
|
|
3033
|
+
function buildExecution(cwd, opts, adapterOrFactory = null, deps = {}) {
|
|
3034
|
+
if (opts.completePhase) return buildCompletePhaseTail(cwd, opts, deps);
|
|
3035
|
+
const state = loadExecutionState(cwd, opts, adapterOrFactory);
|
|
3036
|
+
const allRecords = [...state.records.parents, ...state.records.tasks];
|
|
3037
|
+
const readErrors = allRecords.flatMap((record) => record.errors.map((err) => ({
|
|
3038
|
+
issue: record.issue_number,
|
|
3039
|
+
operation: err.operation,
|
|
3040
|
+
message: err.message,
|
|
3041
|
+
})));
|
|
3042
|
+
const labelSync = applyStateSync(state.records, state.adapterForRepo, cwd);
|
|
3043
|
+
const selection = opts.reconcile
|
|
3044
|
+
? resolveReconciliationSelection(state.selector, state.records)
|
|
3045
|
+
: resolveExecutionSelection(state.selector, state.records);
|
|
3046
|
+
const reconciliation = {
|
|
3047
|
+
ready: false,
|
|
3048
|
+
permission_required: false,
|
|
3049
|
+
plans: state.records.parents.filter((parent) => parent.reconciliation.ready).map(parentOutput),
|
|
3050
|
+
};
|
|
3051
|
+
|
|
3052
|
+
const base = {
|
|
3053
|
+
ok: true,
|
|
3054
|
+
version: 1,
|
|
3055
|
+
mode: 'execute',
|
|
3056
|
+
writes: true,
|
|
3057
|
+
implementation: false,
|
|
3058
|
+
pr_creation: false,
|
|
3059
|
+
selector: state.selector,
|
|
3060
|
+
scope: state.scopes.map((scope) => ({
|
|
3061
|
+
repo: scope.repo,
|
|
3062
|
+
phase: scope.phase.phaseSlug,
|
|
3063
|
+
phase_number: scope.phase.phaseNumber,
|
|
3064
|
+
manifest: scope.manifest.path,
|
|
3065
|
+
})),
|
|
3066
|
+
preflight: {
|
|
3067
|
+
ok: readErrors.length === 0,
|
|
3068
|
+
checked_parent_plans: state.records.parents.length,
|
|
3069
|
+
checked_tasks: state.records.tasks.length,
|
|
3070
|
+
label_sync: labelSync,
|
|
3071
|
+
errors: readErrors,
|
|
3072
|
+
},
|
|
3073
|
+
reconciliation,
|
|
3074
|
+
blocking_state: null,
|
|
3075
|
+
selected: null,
|
|
3076
|
+
execution: null,
|
|
3077
|
+
action: null,
|
|
3078
|
+
};
|
|
3079
|
+
|
|
3080
|
+
if (selection.kind === 'task') {
|
|
3081
|
+
const record = selection.record;
|
|
3082
|
+
base.selected = taskOutput(record);
|
|
3083
|
+
if (!record.workability.workable) {
|
|
3084
|
+
base.action = 'report_unworkable_task';
|
|
3085
|
+
return base;
|
|
3086
|
+
}
|
|
3087
|
+
const adapter = state.adapterForRepo(record.scope.repo);
|
|
3088
|
+
base.execution = executeTaskRecord(cwd, record, adapter, deps);
|
|
3089
|
+
base.implementation = true;
|
|
3090
|
+
base.pr_creation = Boolean(base.execution.pr);
|
|
3091
|
+
base.action = base.execution.action;
|
|
3092
|
+
return base;
|
|
3093
|
+
}
|
|
3094
|
+
|
|
3095
|
+
if (selection.kind === 'reconciliation') {
|
|
3096
|
+
const record = selection.record;
|
|
3097
|
+
base.selected = parentOutput(record);
|
|
3098
|
+
base.reconciliation = {
|
|
3099
|
+
ready: record.reconciliation.ready,
|
|
3100
|
+
permission_required: false,
|
|
3101
|
+
plans: [base.selected],
|
|
3102
|
+
};
|
|
3103
|
+
if (!record.reconciliation.ready) {
|
|
3104
|
+
base.action = 'report_unworkable_reconciliation';
|
|
3105
|
+
return base;
|
|
3106
|
+
}
|
|
3107
|
+
const adapter = state.adapterForRepo(record.scope.repo);
|
|
3108
|
+
base.execution = executeReconciliationRecord(cwd, record, adapter, deps);
|
|
3109
|
+
base.implementation = false;
|
|
3110
|
+
base.pr_creation = Boolean(base.execution.pr);
|
|
3111
|
+
base.action = base.execution.action;
|
|
3112
|
+
return base;
|
|
3113
|
+
}
|
|
3114
|
+
|
|
3115
|
+
if (selection.kind === 'reconciliation_permission') {
|
|
3116
|
+
const selected = parentOutput(selection.record);
|
|
3117
|
+
base.selected = selected;
|
|
3118
|
+
base.action = 'request_reconciliation_permission';
|
|
3119
|
+
base.reconciliation = {
|
|
3120
|
+
ready: true,
|
|
3121
|
+
permission_required: true,
|
|
3122
|
+
plans: [selected],
|
|
3123
|
+
};
|
|
3124
|
+
return base;
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3127
|
+
if (selection.kind === 'unresolved') {
|
|
3128
|
+
base.selected = opts.reconcile ? parentOutput(selection.record) : taskOutput(selection.record);
|
|
3129
|
+
base.action = 'report_unresolved_selector';
|
|
3130
|
+
return base;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
base.action = 'report_blocking_state';
|
|
3134
|
+
base.blocking_state = blockingStateOutput(state.records.tasks, state.records.parents);
|
|
3135
|
+
return base;
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
class GhCliTaskIssueAdapter {
|
|
3139
|
+
constructor({ cwd, repo }) {
|
|
3140
|
+
this.cwd = cwd;
|
|
3141
|
+
this.repo = repo;
|
|
3142
|
+
}
|
|
3143
|
+
|
|
3144
|
+
runGh(args, input = null, operation = null, allow404 = false) {
|
|
3145
|
+
return runGhCommand({
|
|
3146
|
+
cwd: this.cwd,
|
|
3147
|
+
args,
|
|
3148
|
+
input,
|
|
3149
|
+
operation,
|
|
3150
|
+
allow404,
|
|
3151
|
+
ErrorClass: GitHubTaskIssueError,
|
|
3152
|
+
missingGhMessage: 'GitHub CLI `gh` was not found; install and authenticate gh before running work-task-issue.',
|
|
3153
|
+
});
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
api(method, endpoint, body = null, operation = null, allow404 = false) {
|
|
3157
|
+
return ghApi({
|
|
3158
|
+
cwd: this.cwd,
|
|
3159
|
+
repo: this.repo,
|
|
3160
|
+
method,
|
|
3161
|
+
endpoint,
|
|
3162
|
+
body,
|
|
3163
|
+
operation,
|
|
3164
|
+
allow404,
|
|
3165
|
+
ErrorClass: GitHubTaskIssueError,
|
|
3166
|
+
missingGhMessage: 'GitHub CLI `gh` was not found; install and authenticate gh before running work-task-issue.',
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
repoEndpoint(suffix) {
|
|
3171
|
+
return ghRepoEndpoint(this.repo, suffix);
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
getIssue(number) {
|
|
3175
|
+
return this.api('GET', this.repoEndpoint(`issues/${number}`), null, `get_issue:${number}`, true);
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
setIssueLabels(number, labels) {
|
|
3179
|
+
return this.api('PATCH', this.repoEndpoint(`issues/${number}`), { labels }, `set_issue_labels:${number}`);
|
|
3180
|
+
}
|
|
3181
|
+
|
|
3182
|
+
updateIssueState(number, state) {
|
|
3183
|
+
return this.api('PATCH', this.repoEndpoint(`issues/${number}`), { state }, `update_issue_state:${number}:${state}`);
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
commentIssue(number, body) {
|
|
3187
|
+
return this.api('POST', this.repoEndpoint(`issues/${number}/comments`), { body }, `comment_issue:${number}`);
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
listBlockedBy(issueNumber) {
|
|
3191
|
+
return this.api('GET', this.repoEndpoint(`issues/${issueNumber}/dependencies/blocked_by?per_page=100`), null, `list_blocked_by:${issueNumber}`);
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
listPullRequestsForIssue(issueNumber, branchName) {
|
|
3195
|
+
const fields = 'number,title,state,isDraft,mergedAt,headRefName,url,reviewDecision,body';
|
|
3196
|
+
const queries = [
|
|
3197
|
+
`Closes #${issueNumber}`,
|
|
3198
|
+
`Fixes #${issueNumber}`,
|
|
3199
|
+
`Resolves #${issueNumber}`,
|
|
3200
|
+
branchName ? `head:${branchName}` : null,
|
|
3201
|
+
].filter(Boolean);
|
|
3202
|
+
const prs = [];
|
|
3203
|
+
|
|
3204
|
+
for (const query of queries) {
|
|
3205
|
+
const stdout = this.runGh([
|
|
3206
|
+
'pr',
|
|
3207
|
+
'list',
|
|
3208
|
+
'--repo',
|
|
3209
|
+
this.repo,
|
|
3210
|
+
'--state',
|
|
3211
|
+
'all',
|
|
3212
|
+
'--limit',
|
|
3213
|
+
'50',
|
|
3214
|
+
'--search',
|
|
3215
|
+
query,
|
|
3216
|
+
'--json',
|
|
3217
|
+
fields,
|
|
3218
|
+
], null, `list_pull_requests_for_issue:${issueNumber}`);
|
|
3219
|
+
const parsed = stdout ? JSON.parse(stdout) : [];
|
|
3220
|
+
for (const pr of parsed) {
|
|
3221
|
+
const body = String(pr.body || '');
|
|
3222
|
+
if (
|
|
3223
|
+
pr.headRefName === branchName ||
|
|
3224
|
+
body.includes(`#${issueNumber}`) ||
|
|
3225
|
+
body.includes(`/${issueNumber}`)
|
|
3226
|
+
) {
|
|
3227
|
+
prs.push(pr);
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
return dedupePrs(prs);
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
listPullRequestFeedback(prNumber) {
|
|
3236
|
+
const stdout = this.runGh([
|
|
3237
|
+
'pr',
|
|
3238
|
+
'view',
|
|
3239
|
+
String(prNumber),
|
|
3240
|
+
'--repo',
|
|
3241
|
+
this.repo,
|
|
3242
|
+
'--comments',
|
|
3243
|
+
'--json',
|
|
3244
|
+
'comments,reviews',
|
|
3245
|
+
], null, `list_pull_request_feedback:${prNumber}`);
|
|
3246
|
+
const parsed = stdout ? JSON.parse(stdout) : {};
|
|
3247
|
+
const comments = (parsed.comments || []).map((comment) => ({
|
|
3248
|
+
kind: 'comment',
|
|
3249
|
+
author: comment.author?.login || null,
|
|
3250
|
+
body: comment.body || '',
|
|
3251
|
+
createdAt: comment.createdAt || null,
|
|
3252
|
+
}));
|
|
3253
|
+
const reviews = (parsed.reviews || []).map((review) => ({
|
|
3254
|
+
kind: 'review',
|
|
3255
|
+
author: review.author?.login || null,
|
|
3256
|
+
state: review.state || null,
|
|
3257
|
+
body: review.body || '',
|
|
3258
|
+
submittedAt: review.submittedAt || null,
|
|
3259
|
+
}));
|
|
3260
|
+
const reviewComments = this.api(
|
|
3261
|
+
'GET',
|
|
3262
|
+
this.repoEndpoint(`pulls/${prNumber}/comments?per_page=100`),
|
|
3263
|
+
null,
|
|
3264
|
+
`list_pull_request_review_comments:${prNumber}`,
|
|
3265
|
+
true,
|
|
3266
|
+
) || [];
|
|
3267
|
+
return [
|
|
3268
|
+
...comments,
|
|
3269
|
+
...reviews,
|
|
3270
|
+
...reviewComments.map((comment) => ({
|
|
3271
|
+
kind: 'review_comment',
|
|
3272
|
+
author: comment.user?.login || null,
|
|
3273
|
+
body: comment.body || '',
|
|
3274
|
+
path: comment.path || null,
|
|
3275
|
+
line: comment.line || comment.original_line || null,
|
|
3276
|
+
createdAt: comment.created_at || null,
|
|
3277
|
+
})),
|
|
3278
|
+
];
|
|
3279
|
+
}
|
|
3280
|
+
|
|
3281
|
+
viewPullRequest(numberOrUrl) {
|
|
3282
|
+
const stdout = this.runGh([
|
|
3283
|
+
'pr',
|
|
3284
|
+
'view',
|
|
3285
|
+
String(numberOrUrl),
|
|
3286
|
+
'--repo',
|
|
3287
|
+
this.repo,
|
|
3288
|
+
'--json',
|
|
3289
|
+
'number,title,state,isDraft,mergedAt,headRefName,baseRefName,url,reviewDecision,body',
|
|
3290
|
+
], null, `view_pull_request:${numberOrUrl}`);
|
|
3291
|
+
return stdout ? normalizePr(JSON.parse(stdout)) : null;
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
listPullRequestCommits(prNumber) {
|
|
3295
|
+
const stdout = this.runGh([
|
|
3296
|
+
'pr',
|
|
3297
|
+
'view',
|
|
3298
|
+
String(prNumber),
|
|
3299
|
+
'--repo',
|
|
3300
|
+
this.repo,
|
|
3301
|
+
'--json',
|
|
3302
|
+
'commits',
|
|
3303
|
+
], null, `list_pull_request_commits:${prNumber}`);
|
|
3304
|
+
const parsed = stdout ? JSON.parse(stdout) : {};
|
|
3305
|
+
return (parsed.commits || []).map((commit) => ({
|
|
3306
|
+
oid: commit.oid || commit.sha || null,
|
|
3307
|
+
messageHeadline: commit.messageHeadline || '',
|
|
3308
|
+
messageBody: commit.messageBody || '',
|
|
3309
|
+
authors: commit.authors || [],
|
|
3310
|
+
}));
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
listPullRequestChecks(prNumber) {
|
|
3314
|
+
const stdout = this.runGh([
|
|
3315
|
+
'pr',
|
|
3316
|
+
'view',
|
|
3317
|
+
String(prNumber),
|
|
3318
|
+
'--repo',
|
|
3319
|
+
this.repo,
|
|
3320
|
+
'--json',
|
|
3321
|
+
'statusCheckRollup',
|
|
3322
|
+
], null, `list_pull_request_checks:${prNumber}`);
|
|
3323
|
+
const parsed = stdout ? JSON.parse(stdout) : {};
|
|
3324
|
+
return (parsed.statusCheckRollup || []).map((check) => ({
|
|
3325
|
+
name: check.name || check.context || '',
|
|
3326
|
+
status: check.status || '',
|
|
3327
|
+
conclusion: check.conclusion || '',
|
|
3328
|
+
state: check.state || '',
|
|
3329
|
+
}));
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
createPullRequest({ title, body, head, base, draft, labels }) {
|
|
3333
|
+
return withTemporaryPrBodyFile(body, (bodyFile) => {
|
|
3334
|
+
const args = [
|
|
3335
|
+
'pr',
|
|
3336
|
+
'create',
|
|
3337
|
+
'--repo',
|
|
3338
|
+
this.repo,
|
|
3339
|
+
'--base',
|
|
3340
|
+
base,
|
|
3341
|
+
'--head',
|
|
3342
|
+
head,
|
|
3343
|
+
'--title',
|
|
3344
|
+
title,
|
|
3345
|
+
'--body-file',
|
|
3346
|
+
bodyFile,
|
|
3347
|
+
];
|
|
3348
|
+
if (draft) args.push('--draft');
|
|
3349
|
+
for (const label of labels || []) args.push('--label', label);
|
|
3350
|
+
const url = this.runGh(args, null, `create_pull_request:${head}`);
|
|
3351
|
+
return this.viewPullRequest(url);
|
|
3352
|
+
});
|
|
3353
|
+
}
|
|
3354
|
+
|
|
3355
|
+
updatePullRequest(number, { title, body, draft, labels }) {
|
|
3356
|
+
withTemporaryPrBodyFile(body, (bodyFile) => {
|
|
3357
|
+
const args = [
|
|
3358
|
+
'pr',
|
|
3359
|
+
'edit',
|
|
3360
|
+
String(number),
|
|
3361
|
+
'--repo',
|
|
3362
|
+
this.repo,
|
|
3363
|
+
'--title',
|
|
3364
|
+
title,
|
|
3365
|
+
'--body-file',
|
|
3366
|
+
bodyFile,
|
|
3367
|
+
];
|
|
3368
|
+
for (const label of labels || []) args.push('--add-label', label);
|
|
3369
|
+
this.runGh(args, null, `update_pull_request:${number}`);
|
|
3370
|
+
});
|
|
3371
|
+
if (draft === false) {
|
|
3372
|
+
this.runGh(['pr', 'ready', String(number), '--repo', this.repo], null, `mark_pull_request_ready:${number}`, true);
|
|
3373
|
+
}
|
|
3374
|
+
return this.viewPullRequest(number);
|
|
3375
|
+
}
|
|
3376
|
+
|
|
3377
|
+
reopenPullRequest(number) {
|
|
3378
|
+
this.runGh(['pr', 'reopen', String(number), '--repo', this.repo], null, `reopen_pull_request:${number}`);
|
|
3379
|
+
return this.viewPullRequest(number);
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
mergePullRequest(number, { method = 'squash', subject = null, body = null } = {}) {
|
|
3383
|
+
const args = [
|
|
3384
|
+
'pr',
|
|
3385
|
+
'merge',
|
|
3386
|
+
String(number),
|
|
3387
|
+
'--repo',
|
|
3388
|
+
this.repo,
|
|
3389
|
+
];
|
|
3390
|
+
if (method === 'squash') args.push('--squash');
|
|
3391
|
+
else if (method === 'merge') args.push('--merge');
|
|
3392
|
+
else if (method === 'rebase') args.push('--rebase');
|
|
3393
|
+
if (subject) args.push('--subject', subject);
|
|
3394
|
+
if (body) args.push('--body', body);
|
|
3395
|
+
this.runGh(args, null, `merge_pull_request:${number}`);
|
|
3396
|
+
return this.viewPullRequest(number);
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
function cmdWorkTaskIssue(cwd, args, raw) {
|
|
3401
|
+
const opts = parseArgs(args);
|
|
3402
|
+
try {
|
|
3403
|
+
output(opts.mode === 'execute' ? buildExecution(cwd, opts) : buildReadOnly(cwd, opts), raw);
|
|
3404
|
+
} catch (err) {
|
|
3405
|
+
error(err.message || String(err), ERROR_REASON.UNKNOWN);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
export {
|
|
3410
|
+
buildExecution,
|
|
3411
|
+
buildReadOnly,
|
|
3412
|
+
cmdWorkTaskIssue,
|
|
3413
|
+
GhCliTaskIssueAdapter,
|
|
3414
|
+
GitHubTaskIssueError,
|
|
3415
|
+
TaskExecutionError,
|
|
3416
|
+
executorContext,
|
|
3417
|
+
executeReconciliationRecord,
|
|
3418
|
+
loadExecutionState,
|
|
3419
|
+
taskOutput,
|
|
3420
|
+
parentOutput,
|
|
3421
|
+
compareRecords,
|
|
3422
|
+
resolveExplicitParent,
|
|
3423
|
+
buildCompletePhaseTail,
|
|
3424
|
+
validateDiffScope,
|
|
3425
|
+
validateExecutorEvidence,
|
|
3426
|
+
validateTask,
|
|
3427
|
+
parseArgs,
|
|
3428
|
+
parseSelector,
|
|
3429
|
+
};
|