gsd-pi 2.65.0-dev.5c8557b → 2.65.0-dev.6cc5110
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/dist/mcp-server.js +6 -2
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
- package/dist/resources/extensions/gsd/auto-start.js +42 -11
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +21 -15
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +4 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +20 -0
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/db-writer.js +13 -3
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +11 -2
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/json-persistence.js +5 -2
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +12 -5
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +112 -22
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
- package/dist/resources/extensions/gsd/undo.js +3 -2
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +4 -7
- package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +20 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
- package/src/resources/extensions/gsd/auto-start.ts +45 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +19 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +4 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -0
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -3
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +13 -2
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/json-persistence.ts +6 -3
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/pre-execution-checks.ts +15 -7
- package/src/resources/extensions/gsd/preferences-types.ts +25 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +4 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +112 -20
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +218 -20
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/undo.ts +3 -2
- package/src/resources/extensions/gsd/workflow-events.ts +1 -1
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +4 -6
- package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → iueakR5x5bQbax2sGz8Yr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{qq3YfHPfyqvh3DIMVmsRH → iueakR5x5bQbax2sGz8Yr}/_ssgManifest.js +0 -0
|
@@ -14,9 +14,11 @@ import {
|
|
|
14
14
|
resolveProjectRoot,
|
|
15
15
|
setActiveMilestoneId,
|
|
16
16
|
SLICE_BRANCH_RE,
|
|
17
|
+
_resetServiceCache,
|
|
17
18
|
} from "../worktree.ts";
|
|
18
19
|
import { readIntegrationBranch } from "../git-service.ts";
|
|
19
20
|
import { _resetHasChangesCache } from "../native-git-bridge.ts";
|
|
21
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
20
22
|
import { describe, test } from 'node:test';
|
|
21
23
|
import assert from 'node:assert/strict';
|
|
22
24
|
|
|
@@ -165,15 +167,30 @@ describe('worktree', async () => {
|
|
|
165
167
|
run("git checkout -b my-feature", repo);
|
|
166
168
|
captureIntegrationBranch(repo, "M001");
|
|
167
169
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
// Isolate from user's global preferences (which may have git.main_branch set).
|
|
171
|
+
// Reset caches so getService() creates a fresh instance with empty preferences.
|
|
172
|
+
const originalHome = process.env.HOME;
|
|
173
|
+
const fakeHome = mkdtempSync(join(tmpdir(), "gsd-fake-home-"));
|
|
174
|
+
process.env.HOME = fakeHome;
|
|
175
|
+
_clearGsdRootCache();
|
|
176
|
+
_resetServiceCache();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// Without milestone set, getMainBranch returns "main"
|
|
180
|
+
setActiveMilestoneId(repo, null);
|
|
181
|
+
assert.deepStrictEqual(getMainBranch(repo), "main",
|
|
182
|
+
"getMainBranch returns main without milestone set");
|
|
183
|
+
|
|
184
|
+
// With milestone set, getMainBranch returns feature branch
|
|
185
|
+
setActiveMilestoneId(repo, "M001");
|
|
186
|
+
assert.deepStrictEqual(getMainBranch(repo), "my-feature",
|
|
187
|
+
"getMainBranch returns integration branch with milestone set");
|
|
188
|
+
} finally {
|
|
189
|
+
process.env.HOME = originalHome;
|
|
190
|
+
_clearGsdRootCache();
|
|
191
|
+
_resetServiceCache();
|
|
192
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
193
|
+
}
|
|
177
194
|
|
|
178
195
|
rmSync(repo, { recursive: true, force: true });
|
|
179
196
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3441: guided flow must treat a roadmap with zero
|
|
3
|
+
* parseable slices the same as no roadmap — offer "Create roadmap" not "Go auto".
|
|
4
|
+
*/
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
test("guided-flow checks roadmap slice count before offering auto (#3441)", () => {
|
|
11
|
+
const src = readFileSync(
|
|
12
|
+
join(import.meta.dirname, "..", "guided-flow.ts"),
|
|
13
|
+
"utf-8",
|
|
14
|
+
);
|
|
15
|
+
assert.ok(
|
|
16
|
+
src.includes("roadmapHasSlices") || src.includes("parseRoadmapSlices"),
|
|
17
|
+
"Guided flow must parse roadmap for slices before deciding which options to show",
|
|
18
|
+
);
|
|
19
|
+
});
|
|
@@ -23,7 +23,7 @@ import { invalidateStateCache } from "../state.js";
|
|
|
23
23
|
import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
|
|
24
24
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
25
|
import { appendEvent } from "../workflow-events.js";
|
|
26
|
-
import { logWarning } from "../workflow-logger.js";
|
|
26
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
27
27
|
|
|
28
28
|
export interface CompleteMilestoneParams {
|
|
29
29
|
milestoneId: string;
|
|
@@ -218,9 +218,19 @@ export async function handleCompleteMilestone(
|
|
|
218
218
|
clearParseCache();
|
|
219
219
|
|
|
220
220
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
221
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
222
|
+
// the event log entry (critical for worktree reconciliation).
|
|
221
223
|
try {
|
|
222
224
|
await renderAllProjections(basePath, params.milestoneId);
|
|
225
|
+
} catch (projErr) {
|
|
226
|
+
logWarning("tool", `complete-milestone projection warning: ${(projErr as Error).message}`);
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
223
229
|
writeManifest(basePath);
|
|
230
|
+
} catch (mfErr) {
|
|
231
|
+
logWarning("tool", `complete-milestone manifest warning: ${(mfErr as Error).message}`);
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
224
234
|
appendEvent(basePath, {
|
|
225
235
|
cmd: "complete-milestone",
|
|
226
236
|
params: { milestoneId: params.milestoneId },
|
|
@@ -229,8 +239,8 @@ export async function handleCompleteMilestone(
|
|
|
229
239
|
actor_name: params.actorName,
|
|
230
240
|
trigger_reason: params.triggerReason,
|
|
231
241
|
});
|
|
232
|
-
} catch (
|
|
233
|
-
|
|
242
|
+
} catch (eventErr) {
|
|
243
|
+
logError("tool", `complete-milestone event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
234
244
|
}
|
|
235
245
|
|
|
236
246
|
return {
|
|
@@ -30,7 +30,7 @@ import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
|
|
|
30
30
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
31
31
|
import { writeManifest } from "../workflow-manifest.js";
|
|
32
32
|
import { appendEvent } from "../workflow-events.js";
|
|
33
|
-
import { logWarning } from "../workflow-logger.js";
|
|
33
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
34
34
|
|
|
35
35
|
export interface CompleteSliceResult {
|
|
36
36
|
sliceId: string;
|
|
@@ -233,8 +233,18 @@ export async function handleCompleteSlice(
|
|
|
233
233
|
return { error: ownershipErr };
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
// ── Verification content gate (#3580) ──────────────────────────────────
|
|
237
|
+
// Reject completion when the provided verification/UAT clearly indicates
|
|
238
|
+
// the slice is blocked or failed. Prevents prompt regressions from
|
|
239
|
+
// silently advancing blocked slices.
|
|
240
|
+
const BLOCKED_SIGNALS = /\b(status:\s*blocked|verification_result:\s*failed|slice is blocked|cannot complete|verification failed)\b/i;
|
|
241
|
+
if (BLOCKED_SIGNALS.test(params.verification || "") || BLOCKED_SIGNALS.test(params.uatContent || "")) {
|
|
242
|
+
return { error: `slice verification indicates blocked/failed state — do not complete a slice that has not passed verification. Address the blockers and re-verify first.` };
|
|
243
|
+
}
|
|
244
|
+
|
|
236
245
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
237
246
|
const completedAt = new Date().toISOString();
|
|
247
|
+
const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
|
|
238
248
|
let guardError: string | null = null;
|
|
239
249
|
|
|
240
250
|
transaction(() => {
|
|
@@ -268,8 +278,8 @@ export async function handleCompleteSlice(
|
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
// All guards passed — perform writes
|
|
271
|
-
insertMilestone({ id: params.milestoneId });
|
|
272
|
-
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
|
|
281
|
+
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
282
|
+
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
273
283
|
updateSliceStatus(params.milestoneId, params.sliceId, "complete", completedAt);
|
|
274
284
|
});
|
|
275
285
|
|
|
@@ -312,7 +322,7 @@ export async function handleCompleteSlice(
|
|
|
312
322
|
} catch (renderErr) {
|
|
313
323
|
// Disk render failed — roll back DB status so state stays consistent
|
|
314
324
|
logWarning("tool", `complete_slice — disk render failed for ${params.milestoneId}/${params.sliceId}, rolling back DB status`, { error: (renderErr as Error).message });
|
|
315
|
-
updateSliceStatus(params.milestoneId, params.sliceId,
|
|
325
|
+
updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
|
|
316
326
|
invalidateStateCache();
|
|
317
327
|
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
318
328
|
}
|
|
@@ -326,9 +336,19 @@ export async function handleCompleteSlice(
|
|
|
326
336
|
clearParseCache();
|
|
327
337
|
|
|
328
338
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
339
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
340
|
+
// the event log entry (critical for worktree reconciliation).
|
|
329
341
|
try {
|
|
330
342
|
await renderAllProjections(basePath, params.milestoneId);
|
|
343
|
+
} catch (projErr) {
|
|
344
|
+
logWarning("tool", `complete-slice projection warning for ${params.milestoneId}/${params.sliceId}: ${(projErr as Error).message}`);
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
331
347
|
writeManifest(basePath);
|
|
348
|
+
} catch (mfErr) {
|
|
349
|
+
logWarning("tool", `complete-slice manifest warning: ${(mfErr as Error).message}`);
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
332
352
|
appendEvent(basePath, {
|
|
333
353
|
cmd: "complete-slice",
|
|
334
354
|
params: { milestoneId: params.milestoneId, sliceId: params.sliceId },
|
|
@@ -337,8 +357,8 @@ export async function handleCompleteSlice(
|
|
|
337
357
|
actor_name: params.actorName,
|
|
338
358
|
trigger_reason: params.triggerReason,
|
|
339
359
|
});
|
|
340
|
-
} catch (
|
|
341
|
-
|
|
360
|
+
} catch (eventErr) {
|
|
361
|
+
logError("tool", `complete-slice event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
342
362
|
}
|
|
343
363
|
|
|
344
364
|
return {
|
|
@@ -33,7 +33,7 @@ import { renderPlanCheckboxes } from "../markdown-renderer.js";
|
|
|
33
33
|
import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
|
|
34
34
|
import { writeManifest } from "../workflow-manifest.js";
|
|
35
35
|
import { appendEvent } from "../workflow-events.js";
|
|
36
|
-
import { logWarning } from "../workflow-logger.js";
|
|
36
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
37
37
|
|
|
38
38
|
export interface CompleteTaskResult {
|
|
39
39
|
taskId: string;
|
|
@@ -44,6 +44,18 @@ export interface CompleteTaskResult {
|
|
|
44
44
|
|
|
45
45
|
import type { TaskRow } from "../gsd-db.js";
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Normalize a list parameter that may arrive as a string (newline-delimited
|
|
49
|
+
* bullet list from the LLM) into a string array (#3361).
|
|
50
|
+
*/
|
|
51
|
+
function normalizeListParam(value: unknown): string[] {
|
|
52
|
+
if (Array.isArray(value)) return value.map(String);
|
|
53
|
+
if (typeof value === "string" && value.trim()) {
|
|
54
|
+
return value.split(/\n/).map(s => s.replace(/^[\s\-*•]+/, "").trim()).filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
/**
|
|
48
60
|
* Build a TaskRow-shaped object from CompleteTaskParams so the unified
|
|
49
61
|
* renderSummaryContent() can be used at completion time (#2720).
|
|
@@ -63,8 +75,8 @@ function paramsToTaskRow(params: CompleteTaskParams, completedAt: string): TaskR
|
|
|
63
75
|
blocker_discovered: params.blockerDiscovered ?? false,
|
|
64
76
|
deviations: params.deviations ?? "",
|
|
65
77
|
known_issues: params.knownIssues ?? "",
|
|
66
|
-
key_files: params.keyFiles
|
|
67
|
-
key_decisions: params.keyDecisions
|
|
78
|
+
key_files: normalizeListParam(params.keyFiles),
|
|
79
|
+
key_decisions: normalizeListParam(params.keyDecisions),
|
|
68
80
|
full_summary_md: "",
|
|
69
81
|
description: "",
|
|
70
82
|
estimate: "",
|
|
@@ -140,8 +152,8 @@ export async function handleCompleteTask(
|
|
|
140
152
|
}
|
|
141
153
|
|
|
142
154
|
// All guards passed — perform writes
|
|
143
|
-
insertMilestone({ id: params.milestoneId });
|
|
144
|
-
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
|
|
155
|
+
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
156
|
+
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
145
157
|
insertTask({
|
|
146
158
|
id: params.taskId,
|
|
147
159
|
sliceId: params.sliceId,
|
|
@@ -230,9 +242,19 @@ export async function handleCompleteTask(
|
|
|
230
242
|
clearParseCache();
|
|
231
243
|
|
|
232
244
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
245
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
246
|
+
// the event log entry (critical for worktree reconciliation).
|
|
233
247
|
try {
|
|
234
248
|
await renderAllProjections(basePath, params.milestoneId);
|
|
249
|
+
} catch (projErr) {
|
|
250
|
+
logWarning("tool", `complete-task projection warning: ${(projErr as Error).message}`);
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
235
253
|
writeManifest(basePath);
|
|
254
|
+
} catch (mfErr) {
|
|
255
|
+
logWarning("tool", `complete-task manifest warning: ${(mfErr as Error).message}`);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
236
258
|
appendEvent(basePath, {
|
|
237
259
|
cmd: "complete-task",
|
|
238
260
|
params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
|
|
@@ -241,8 +263,8 @@ export async function handleCompleteTask(
|
|
|
241
263
|
actor_name: params.actorName,
|
|
242
264
|
trigger_reason: params.triggerReason,
|
|
243
265
|
});
|
|
244
|
-
} catch (
|
|
245
|
-
|
|
266
|
+
} catch (eventErr) {
|
|
267
|
+
logError("tool", `complete-task event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
246
268
|
}
|
|
247
269
|
|
|
248
270
|
return {
|
|
@@ -48,13 +48,13 @@ export interface PlanMilestoneParams {
|
|
|
48
48
|
keyRisks?: Array<{ risk: string; whyItMatters: string }>;
|
|
49
49
|
/** @optional — defaults to [] when omitted */
|
|
50
50
|
proofStrategy?: Array<{ riskOrUnknown: string; retireIn: string; whatWillBeProven: string }>;
|
|
51
|
-
/** @optional — defaults to "
|
|
51
|
+
/** @optional — defaults to "" when omitted */
|
|
52
52
|
verificationContract?: string;
|
|
53
|
-
/** @optional — defaults to "
|
|
53
|
+
/** @optional — defaults to "" when omitted */
|
|
54
54
|
verificationIntegration?: string;
|
|
55
|
-
/** @optional — defaults to "
|
|
55
|
+
/** @optional — defaults to "" when omitted */
|
|
56
56
|
verificationOperational?: string;
|
|
57
|
-
/** @optional — defaults to "
|
|
57
|
+
/** @optional — defaults to "" when omitted */
|
|
58
58
|
verificationUat?: string;
|
|
59
59
|
/** @optional — defaults to [] when omitted */
|
|
60
60
|
definitionOfDone?: string[];
|
|
@@ -168,10 +168,10 @@ function validateParams(params: PlanMilestoneParams): PlanMilestoneParams {
|
|
|
168
168
|
successCriteria: params.successCriteria ? validateStringArray(params.successCriteria, "successCriteria") : [],
|
|
169
169
|
keyRisks: params.keyRisks ? validateRiskEntries(params.keyRisks) : [],
|
|
170
170
|
proofStrategy: params.proofStrategy ? validateProofStrategy(params.proofStrategy) : [],
|
|
171
|
-
verificationContract: params.verificationContract ?? "
|
|
172
|
-
verificationIntegration: params.verificationIntegration ?? "
|
|
173
|
-
verificationOperational: params.verificationOperational ?? "
|
|
174
|
-
verificationUat: params.verificationUat ?? "
|
|
171
|
+
verificationContract: params.verificationContract ?? "",
|
|
172
|
+
verificationIntegration: params.verificationIntegration ?? "",
|
|
173
|
+
verificationOperational: params.verificationOperational ?? "",
|
|
174
|
+
verificationUat: params.verificationUat ?? "",
|
|
175
175
|
definitionOfDone: params.definitionOfDone ? validateStringArray(params.definitionOfDone, "definitionOfDone") : [],
|
|
176
176
|
requirementCoverage: params.requirementCoverage ?? "Not provided.",
|
|
177
177
|
boundaryMapMarkdown: params.boundaryMapMarkdown ?? "Not provided.",
|
|
@@ -256,7 +256,8 @@ export async function handlePlanMilestone(
|
|
|
256
256
|
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
257
257
|
});
|
|
258
258
|
|
|
259
|
-
for (
|
|
259
|
+
for (let i = 0; i < params.slices.length; i++) {
|
|
260
|
+
const slice = params.slices[i]!;
|
|
260
261
|
// Preserve completed/done status on re-plan (#2558).
|
|
261
262
|
// Without this, a re-plan after milestone transition would reset
|
|
262
263
|
// already-completed slices back to "pending".
|
|
@@ -272,6 +273,7 @@ export async function handlePlanMilestone(
|
|
|
272
273
|
risk: slice.risk,
|
|
273
274
|
depends: slice.depends,
|
|
274
275
|
demo: slice.demo,
|
|
276
|
+
sequence: i + 1, // Preserve agent-ordered sequence (#3356)
|
|
275
277
|
});
|
|
276
278
|
upsertSlicePlanning(params.milestoneId, slice.sliceId, {
|
|
277
279
|
goal: slice.goal,
|
|
@@ -186,8 +186,10 @@ export async function handleReassessRoadmap(
|
|
|
186
186
|
});
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
// Insert new slices
|
|
190
|
-
|
|
189
|
+
// Insert new slices — assign sequence after existing slices (#3356)
|
|
190
|
+
const existingCount = getMilestoneSlices(params.milestoneId).length;
|
|
191
|
+
for (let i = 0; i < params.sliceChanges.added.length; i++) {
|
|
192
|
+
const added = params.sliceChanges.added[i]!;
|
|
191
193
|
insertSlice({
|
|
192
194
|
id: added.sliceId,
|
|
193
195
|
milestoneId: params.milestoneId,
|
|
@@ -196,6 +198,7 @@ export async function handleReassessRoadmap(
|
|
|
196
198
|
risk: added.risk,
|
|
197
199
|
depends: added.depends,
|
|
198
200
|
demo: added.demo ?? "",
|
|
201
|
+
sequence: existingCount + i + 1,
|
|
199
202
|
});
|
|
200
203
|
}
|
|
201
204
|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// GSD — reopen-milestone tool handler
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* reopen-milestone handler — the core operation behind gsd_milestone_reopen.
|
|
5
|
+
*
|
|
6
|
+
* Resets a closed milestone back to "active", all of its slices to
|
|
7
|
+
* "in_progress", and all tasks to "pending". Cleans up stale filesystem
|
|
8
|
+
* artifacts so the DB-filesystem reconciler does not auto-correct
|
|
9
|
+
* entities back to "complete".
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
getMilestone,
|
|
14
|
+
getMilestoneSlices,
|
|
15
|
+
getSliceTasks,
|
|
16
|
+
updateMilestoneStatus,
|
|
17
|
+
updateSliceStatus,
|
|
18
|
+
updateTaskStatus,
|
|
19
|
+
transaction,
|
|
20
|
+
} from "../gsd-db.js";
|
|
21
|
+
import { invalidateStateCache } from "../state.js";
|
|
22
|
+
import { isClosedStatus } from "../status-guards.js";
|
|
23
|
+
import { renderAllProjections } from "../workflow-projections.js";
|
|
24
|
+
import { writeManifest } from "../workflow-manifest.js";
|
|
25
|
+
import { appendEvent } from "../workflow-events.js";
|
|
26
|
+
import { logWarning } from "../workflow-logger.js";
|
|
27
|
+
import { debugLog } from "../debug-logger.js";
|
|
28
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import { resolveMilestonePath, resolveSlicePath, resolveTasksDir, clearPathCache } from "../paths.js";
|
|
31
|
+
|
|
32
|
+
export interface ReopenMilestoneParams {
|
|
33
|
+
milestoneId: string;
|
|
34
|
+
reason?: string;
|
|
35
|
+
/** Optional caller-provided identity for audit trail */
|
|
36
|
+
actorName?: string;
|
|
37
|
+
/** Optional caller-provided reason this action was triggered */
|
|
38
|
+
triggerReason?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ReopenMilestoneResult {
|
|
42
|
+
milestoneId: string;
|
|
43
|
+
slicesReset: number;
|
|
44
|
+
tasksReset: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function handleReopenMilestone(
|
|
48
|
+
params: ReopenMilestoneParams,
|
|
49
|
+
basePath: string,
|
|
50
|
+
): Promise<ReopenMilestoneResult | { error: string }> {
|
|
51
|
+
// ── Validate required fields ────────────────────────────────────────────
|
|
52
|
+
if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
|
|
53
|
+
return { error: "milestoneId is required and must be a non-empty string" };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
57
|
+
let guardError: string | null = null;
|
|
58
|
+
let slicesResetCount = 0;
|
|
59
|
+
let tasksResetCount = 0;
|
|
60
|
+
|
|
61
|
+
transaction(() => {
|
|
62
|
+
const milestone = getMilestone(params.milestoneId);
|
|
63
|
+
if (!milestone) {
|
|
64
|
+
guardError = `milestone not found: ${params.milestoneId}`;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (!isClosedStatus(milestone.status)) {
|
|
68
|
+
guardError = `milestone ${params.milestoneId} is not closed (status: ${milestone.status}) — nothing to reopen`;
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
updateMilestoneStatus(params.milestoneId, "active", null);
|
|
73
|
+
|
|
74
|
+
const slices = getMilestoneSlices(params.milestoneId);
|
|
75
|
+
slicesResetCount = slices.length;
|
|
76
|
+
|
|
77
|
+
for (const slice of slices) {
|
|
78
|
+
updateSliceStatus(params.milestoneId, slice.id, "in_progress");
|
|
79
|
+
const tasks = getSliceTasks(params.milestoneId, slice.id);
|
|
80
|
+
tasksResetCount += tasks.length;
|
|
81
|
+
for (const task of tasks) {
|
|
82
|
+
updateTaskStatus(params.milestoneId, slice.id, task.id, "pending");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (guardError) {
|
|
88
|
+
return { error: guardError };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Invalidate caches ────────────────────────────────────────────────────
|
|
92
|
+
invalidateStateCache();
|
|
93
|
+
|
|
94
|
+
// ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
|
|
95
|
+
// Without this, the DB-filesystem reconciler sees SUMMARY.md files and
|
|
96
|
+
// auto-corrects entities back to "complete", making reopen a no-op (#3161).
|
|
97
|
+
try {
|
|
98
|
+
const milestoneDir = resolveMilestonePath(basePath, params.milestoneId);
|
|
99
|
+
if (milestoneDir) {
|
|
100
|
+
const milestoneSummary = join(milestoneDir, `${params.milestoneId}-SUMMARY.md`);
|
|
101
|
+
if (existsSync(milestoneSummary)) unlinkSync(milestoneSummary);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const slices = getMilestoneSlices(params.milestoneId);
|
|
105
|
+
for (const slice of slices) {
|
|
106
|
+
const sliceDir = resolveSlicePath(basePath, params.milestoneId, slice.id);
|
|
107
|
+
if (sliceDir) {
|
|
108
|
+
const sliceSummary = join(sliceDir, `${slice.id}-SUMMARY.md`);
|
|
109
|
+
if (existsSync(sliceSummary)) unlinkSync(sliceSummary);
|
|
110
|
+
const sliceUat = join(sliceDir, `${slice.id}-UAT.md`);
|
|
111
|
+
if (existsSync(sliceUat)) unlinkSync(sliceUat);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const tasksDir = resolveTasksDir(basePath, params.milestoneId, slice.id);
|
|
115
|
+
if (tasksDir) {
|
|
116
|
+
const tasks = getSliceTasks(params.milestoneId, slice.id);
|
|
117
|
+
for (const task of tasks) {
|
|
118
|
+
const taskSummary = join(tasksDir, `${task.id}-SUMMARY.md`);
|
|
119
|
+
if (existsSync(taskSummary)) unlinkSync(taskSummary);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} catch (err) { debugLog("reopen-milestone-cleanup-failed", { milestoneId: params.milestoneId, error: String(err) }); }
|
|
124
|
+
clearPathCache();
|
|
125
|
+
|
|
126
|
+
// ── Post-mutation hook ───────────────────────────────────────────────────
|
|
127
|
+
try {
|
|
128
|
+
await renderAllProjections(basePath, params.milestoneId);
|
|
129
|
+
writeManifest(basePath);
|
|
130
|
+
appendEvent(basePath, {
|
|
131
|
+
cmd: "reopen-milestone",
|
|
132
|
+
params: {
|
|
133
|
+
milestoneId: params.milestoneId,
|
|
134
|
+
reason: params.reason ?? null,
|
|
135
|
+
slicesReset: slicesResetCount,
|
|
136
|
+
tasksReset: tasksResetCount,
|
|
137
|
+
},
|
|
138
|
+
ts: new Date().toISOString(),
|
|
139
|
+
actor: "agent",
|
|
140
|
+
actor_name: params.actorName,
|
|
141
|
+
trigger_reason: params.triggerReason,
|
|
142
|
+
});
|
|
143
|
+
} catch (hookErr) {
|
|
144
|
+
logWarning("tool", `reopen-milestone post-mutation hook warning: ${(hookErr as Error).message}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
milestoneId: params.milestoneId,
|
|
149
|
+
slicesReset: slicesResetCount,
|
|
150
|
+
tasksReset: tasksResetCount,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
@@ -25,6 +25,9 @@ import { renderAllProjections } from "../workflow-projections.js";
|
|
|
25
25
|
import { writeManifest } from "../workflow-manifest.js";
|
|
26
26
|
import { appendEvent } from "../workflow-events.js";
|
|
27
27
|
import { logWarning } from "../workflow-logger.js";
|
|
28
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
|
|
28
31
|
|
|
29
32
|
export interface ReopenSliceParams {
|
|
30
33
|
milestoneId: string;
|
|
@@ -96,6 +99,30 @@ export async function handleReopenSlice(
|
|
|
96
99
|
// ── Invalidate caches ────────────────────────────────────────────────────
|
|
97
100
|
invalidateStateCache();
|
|
98
101
|
|
|
102
|
+
// ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
|
|
103
|
+
// Without this, the DB-filesystem reconciler sees SUMMARY.md files and
|
|
104
|
+
// auto-corrects tasks back to "complete", making reopen a no-op (#3161).
|
|
105
|
+
try {
|
|
106
|
+
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
107
|
+
if (tasksDir) {
|
|
108
|
+
const tasks = getSliceTasks(params.milestoneId, params.sliceId);
|
|
109
|
+
for (const task of tasks) {
|
|
110
|
+
const summaryPath = join(tasksDir, `${task.id}-SUMMARY.md`);
|
|
111
|
+
if (existsSync(summaryPath)) unlinkSync(summaryPath);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const sliceDir = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
115
|
+
if (sliceDir) {
|
|
116
|
+
const sliceSummary = join(sliceDir, `${params.sliceId}-SUMMARY.md`);
|
|
117
|
+
if (existsSync(sliceSummary)) unlinkSync(sliceSummary);
|
|
118
|
+
const sliceUat = join(sliceDir, `${params.sliceId}-UAT.md`);
|
|
119
|
+
if (existsSync(sliceUat)) unlinkSync(sliceUat);
|
|
120
|
+
}
|
|
121
|
+
} catch (cleanupErr) {
|
|
122
|
+
logWarning("tool", `reopen-slice artifact cleanup warning: ${(cleanupErr as Error).message}`);
|
|
123
|
+
}
|
|
124
|
+
clearPathCache();
|
|
125
|
+
|
|
99
126
|
// ── Post-mutation hook ───────────────────────────────────────────────────
|
|
100
127
|
try {
|
|
101
128
|
await renderAllProjections(basePath, params.milestoneId);
|
|
@@ -23,6 +23,9 @@ import { renderAllProjections } from "../workflow-projections.js";
|
|
|
23
23
|
import { writeManifest } from "../workflow-manifest.js";
|
|
24
24
|
import { appendEvent } from "../workflow-events.js";
|
|
25
25
|
import { logWarning } from "../workflow-logger.js";
|
|
26
|
+
import { existsSync, unlinkSync } from "node:fs";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
import { resolveTasksDir, clearPathCache } from "../paths.js";
|
|
26
29
|
|
|
27
30
|
export interface ReopenTaskParams {
|
|
28
31
|
milestoneId: string;
|
|
@@ -100,6 +103,20 @@ export async function handleReopenTask(
|
|
|
100
103
|
// ── Invalidate caches ────────────────────────────────────────────────────
|
|
101
104
|
invalidateStateCache();
|
|
102
105
|
|
|
106
|
+
// ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
|
|
107
|
+
// Without this, the DB-filesystem reconciler sees the SUMMARY.md and
|
|
108
|
+
// auto-corrects the task back to "complete", making reopen a no-op (#3161).
|
|
109
|
+
try {
|
|
110
|
+
const tasksDir = resolveTasksDir(basePath, params.milestoneId, params.sliceId);
|
|
111
|
+
if (tasksDir) {
|
|
112
|
+
const summaryPath = join(tasksDir, `${params.taskId}-SUMMARY.md`);
|
|
113
|
+
if (existsSync(summaryPath)) unlinkSync(summaryPath);
|
|
114
|
+
}
|
|
115
|
+
} catch (cleanupErr) {
|
|
116
|
+
logWarning("tool", `reopen-task artifact cleanup warning: ${(cleanupErr as Error).message}`);
|
|
117
|
+
}
|
|
118
|
+
clearPathCache();
|
|
119
|
+
|
|
103
120
|
// ── Post-mutation hook ───────────────────────────────────────────────────
|
|
104
121
|
try {
|
|
105
122
|
await renderAllProjections(basePath, params.milestoneId);
|