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
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3607 — tighten verifyExpectedArtifact legacy branch
|
|
3
|
+
*
|
|
4
|
+
* The legacy (pre-migration) fallback in verifyExpectedArtifact previously
|
|
5
|
+
* accepted either a heading match (### T01 --) or a checked checkbox as proof
|
|
6
|
+
* that gsd_complete_task ran. A heading alone does not prove completion —
|
|
7
|
+
* it could result from a rogue write.
|
|
8
|
+
*
|
|
9
|
+
* The fix removes the hdRe heading regex and requires only a checked checkbox
|
|
10
|
+
* (cbRe) in the legacy branch, ensuring that only actual tool-completed tasks
|
|
11
|
+
* are treated as verified.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { describe, it } from 'node:test'
|
|
15
|
+
import assert from 'node:assert/strict'
|
|
16
|
+
import { readFileSync } from 'node:fs'
|
|
17
|
+
import { resolve } from 'node:path'
|
|
18
|
+
|
|
19
|
+
const src = readFileSync(
|
|
20
|
+
resolve(process.cwd(), 'src', 'resources', 'extensions', 'gsd', 'auto-recovery.ts'),
|
|
21
|
+
'utf-8',
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
describe('verifyExpectedArtifact legacy branch tightened (#3607)', () => {
|
|
25
|
+
it('legacy branch does NOT define hdRe heading regex', () => {
|
|
26
|
+
// Find the legacy fallback section
|
|
27
|
+
const legacyIdx = src.indexOf('LEGACY: Pre-migration fallback')
|
|
28
|
+
assert.ok(legacyIdx !== -1, 'LEGACY comment must exist')
|
|
29
|
+
|
|
30
|
+
// Check the code within a reasonable window after the LEGACY comment
|
|
31
|
+
const legacyBlock = src.slice(legacyIdx, legacyIdx + 600)
|
|
32
|
+
|
|
33
|
+
assert.ok(
|
|
34
|
+
!legacyBlock.includes('hdRe'),
|
|
35
|
+
'hdRe heading regex must NOT exist in legacy branch — heading alone is not proof of completion',
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('legacy branch requires checked checkbox via cbRe', () => {
|
|
40
|
+
const legacyIdx = src.indexOf('LEGACY: Pre-migration fallback')
|
|
41
|
+
assert.ok(legacyIdx !== -1)
|
|
42
|
+
|
|
43
|
+
const legacyBlock = src.slice(legacyIdx, legacyIdx + 600)
|
|
44
|
+
|
|
45
|
+
assert.ok(
|
|
46
|
+
legacyBlock.includes('cbRe'),
|
|
47
|
+
'cbRe checked-checkbox regex must exist in legacy branch',
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
// cbRe must match checked checkboxes [x] or [X]
|
|
51
|
+
assert.ok(
|
|
52
|
+
legacyBlock.includes('[xX]'),
|
|
53
|
+
'cbRe must match both [x] and [X] checkbox variants',
|
|
54
|
+
)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('legacy branch returns false when no plan file exists', () => {
|
|
58
|
+
const legacyIdx = src.indexOf('LEGACY: Pre-migration fallback')
|
|
59
|
+
assert.ok(legacyIdx !== -1)
|
|
60
|
+
|
|
61
|
+
const legacyBlock = src.slice(legacyIdx, legacyIdx + 1000)
|
|
62
|
+
|
|
63
|
+
// The else branch: no plan file means cannot verify
|
|
64
|
+
assert.ok(
|
|
65
|
+
legacyBlock.includes('no plan file'),
|
|
66
|
+
'missing plan file must be handled with return false',
|
|
67
|
+
)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('DB available but task not found returns false', () => {
|
|
71
|
+
const legacyIdx = src.indexOf('LEGACY: Pre-migration fallback')
|
|
72
|
+
assert.ok(legacyIdx !== -1)
|
|
73
|
+
|
|
74
|
+
const legacyBlock = src.slice(legacyIdx, legacyIdx + 1000)
|
|
75
|
+
|
|
76
|
+
assert.ok(
|
|
77
|
+
legacyBlock.includes('DB available but task row not found'),
|
|
78
|
+
'must handle case where DB is available but task row is missing',
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
// The comment should be followed by a return false
|
|
82
|
+
const commentIdx = legacyBlock.indexOf('DB available but task row not found')
|
|
83
|
+
const afterComment = legacyBlock.slice(commentIdx, commentIdx + 200)
|
|
84
|
+
assert.ok(
|
|
85
|
+
afterComment.includes('return false'),
|
|
86
|
+
'missing task row when DB available must return false',
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
})
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// GSD State Machine — Wave 1 Critical Regression Tests
|
|
2
|
+
// Validates fixes for event log format mismatch, skipped milestone status,
|
|
3
|
+
// dead code removal, and replan disk-file fallback.
|
|
4
|
+
|
|
5
|
+
import { describe, test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { extractEntityKey } from "../workflow-reconcile.js";
|
|
8
|
+
import { isClosedStatus } from "../status-guards.js";
|
|
9
|
+
import type { WorkflowEvent } from "../workflow-events.js";
|
|
10
|
+
|
|
11
|
+
// ── Fix 1: Event log cmd format — hyphens and underscores both accepted ──
|
|
12
|
+
|
|
13
|
+
describe("extractEntityKey normalizes cmd format", () => {
|
|
14
|
+
const baseEvent = { params: {}, ts: "", hash: "", actor: "agent" as const, session_id: "" };
|
|
15
|
+
|
|
16
|
+
test("accepts hyphenated complete-task", () => {
|
|
17
|
+
const event: WorkflowEvent = { ...baseEvent, cmd: "complete-task", params: { taskId: "T01" } };
|
|
18
|
+
const key = extractEntityKey(event);
|
|
19
|
+
assert.deepStrictEqual(key, { type: "task", id: "T01" });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("accepts underscored complete_task (legacy)", () => {
|
|
23
|
+
const event: WorkflowEvent = { ...baseEvent, cmd: "complete_task", params: { taskId: "T01" } };
|
|
24
|
+
const key = extractEntityKey(event);
|
|
25
|
+
assert.deepStrictEqual(key, { type: "task", id: "T01" });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("accepts hyphenated complete-slice", () => {
|
|
29
|
+
const event: WorkflowEvent = { ...baseEvent, cmd: "complete-slice", params: { sliceId: "S01" } };
|
|
30
|
+
const key = extractEntityKey(event);
|
|
31
|
+
assert.deepStrictEqual(key, { type: "slice", id: "S01" });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("accepts hyphenated complete-milestone", () => {
|
|
35
|
+
const event: WorkflowEvent = { ...baseEvent, cmd: "complete-milestone", params: { milestoneId: "M001" } };
|
|
36
|
+
const key = extractEntityKey(event);
|
|
37
|
+
assert.deepStrictEqual(key, { type: "milestone", id: "M001" });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ── Fix 3: getActiveMilestoneId must skip "skipped" milestones ──
|
|
42
|
+
|
|
43
|
+
describe("isClosedStatus includes skipped", () => {
|
|
44
|
+
test("complete is closed", () => assert.ok(isClosedStatus("complete")));
|
|
45
|
+
test("done is closed", () => assert.ok(isClosedStatus("done")));
|
|
46
|
+
test("skipped is closed", () => assert.ok(isClosedStatus("skipped")));
|
|
47
|
+
test("pending is not closed", () => assert.ok(!isClosedStatus("pending")));
|
|
48
|
+
test("active is not closed", () => assert.ok(!isClosedStatus("active")));
|
|
49
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// GSD State Machine — Wave 2 Event Log Regression Tests
|
|
2
|
+
// Validates fixes for appendEvent isolation, entity replay handlers,
|
|
3
|
+
// and post-reconcile cache invalidation.
|
|
4
|
+
|
|
5
|
+
import { describe, test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { extractEntityKey } from "../workflow-reconcile.js";
|
|
8
|
+
import type { WorkflowEvent } from "../workflow-events.js";
|
|
9
|
+
|
|
10
|
+
const base = { params: {}, ts: "", hash: "", actor: "agent" as const, session_id: "" };
|
|
11
|
+
|
|
12
|
+
// ── Fix 8: New entity event types handled by extractEntityKey ──
|
|
13
|
+
|
|
14
|
+
describe("extractEntityKey handles plan events", () => {
|
|
15
|
+
test("plan-milestone → milestone type", () => {
|
|
16
|
+
const event: WorkflowEvent = { ...base, cmd: "plan-milestone", params: { milestoneId: "M001" } };
|
|
17
|
+
const key = extractEntityKey(event);
|
|
18
|
+
assert.deepStrictEqual(key, { type: "milestone", id: "M001" });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("plan-task → task type", () => {
|
|
22
|
+
const event: WorkflowEvent = { ...base, cmd: "plan-task", params: { taskId: "T01" } };
|
|
23
|
+
const key = extractEntityKey(event);
|
|
24
|
+
assert.deepStrictEqual(key, { type: "task", id: "T01" });
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("plan-slice preserves slice_plan type (conflict isolation)", () => {
|
|
28
|
+
const event: WorkflowEvent = { ...base, cmd: "plan-slice", params: { sliceId: "S01" } };
|
|
29
|
+
const key = extractEntityKey(event);
|
|
30
|
+
assert.deepStrictEqual(key, { type: "slice_plan", id: "S01" });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("replan-slice → slice type", () => {
|
|
34
|
+
const event: WorkflowEvent = { ...base, cmd: "replan-slice", params: { sliceId: "S01" } };
|
|
35
|
+
const key = extractEntityKey(event);
|
|
36
|
+
assert.deepStrictEqual(key, { type: "slice", id: "S01" });
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ── Fix 8b: Unknown commands return null (don't crash) ──
|
|
41
|
+
|
|
42
|
+
describe("extractEntityKey handles unknown commands gracefully", () => {
|
|
43
|
+
test("unknown-command returns null", () => {
|
|
44
|
+
const event: WorkflowEvent = { ...base, cmd: "unknown-future-cmd", params: { foo: "bar" } };
|
|
45
|
+
const key = extractEntityKey(event);
|
|
46
|
+
assert.strictEqual(key, null);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// GSD State Machine — Wave 3 Session Regression Tests
|
|
2
|
+
// Validates tri-state hasImplementationArtifacts and AutoSession.consecutiveCompleteBootstraps.
|
|
3
|
+
|
|
4
|
+
import { describe, test } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { hasImplementationArtifacts } from "../auto-recovery.js";
|
|
7
|
+
import { AutoSession } from "../auto/session.js";
|
|
8
|
+
|
|
9
|
+
// ── Fix 9: hasImplementationArtifacts returns tri-state ──
|
|
10
|
+
|
|
11
|
+
describe("hasImplementationArtifacts tri-state return", () => {
|
|
12
|
+
test("returns 'unknown' for non-git directory", () => {
|
|
13
|
+
const result = hasImplementationArtifacts("/tmp/not-a-git-repo-" + Date.now());
|
|
14
|
+
assert.strictEqual(result, "unknown");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("return type is one of present/absent/unknown", () => {
|
|
18
|
+
const result = hasImplementationArtifacts(process.cwd());
|
|
19
|
+
assert.ok(
|
|
20
|
+
result === "present" || result === "absent" || result === "unknown",
|
|
21
|
+
`Expected present/absent/unknown, got: ${result}`,
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// ── Fix 11: consecutiveCompleteBootstraps is per-session ──
|
|
27
|
+
|
|
28
|
+
describe("AutoSession.consecutiveCompleteBootstraps", () => {
|
|
29
|
+
test("initial value is 0", () => {
|
|
30
|
+
const s = new AutoSession();
|
|
31
|
+
assert.strictEqual(s.consecutiveCompleteBootstraps, 0);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("reset() clears the counter", () => {
|
|
35
|
+
const s = new AutoSession();
|
|
36
|
+
s.consecutiveCompleteBootstraps = 5;
|
|
37
|
+
s.reset();
|
|
38
|
+
assert.strictEqual(s.consecutiveCompleteBootstraps, 0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("two sessions have independent counters", () => {
|
|
42
|
+
const s1 = new AutoSession();
|
|
43
|
+
const s2 = new AutoSession();
|
|
44
|
+
s1.consecutiveCompleteBootstraps = 3;
|
|
45
|
+
assert.strictEqual(s2.consecutiveCompleteBootstraps, 0);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// GSD State Machine — Wave 4 Write Safety Regression Tests
|
|
2
|
+
// Validates randomized tmp suffix in json-persistence and atomic writes.
|
|
3
|
+
|
|
4
|
+
import { describe, test } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { mkdtempSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { saveJsonFile, loadJsonFile } from "../json-persistence.js";
|
|
10
|
+
|
|
11
|
+
// ── Fix 15: json-persistence uses randomized tmp suffix ──
|
|
12
|
+
|
|
13
|
+
describe("saveJsonFile atomic write", () => {
|
|
14
|
+
test("writes JSON file correctly", () => {
|
|
15
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-json-test-"));
|
|
16
|
+
try {
|
|
17
|
+
const file = join(tmp, "test.json");
|
|
18
|
+
saveJsonFile(file, { key: "value" });
|
|
19
|
+
const content = JSON.parse(readFileSync(file, "utf-8"));
|
|
20
|
+
assert.deepStrictEqual(content, { key: "value" });
|
|
21
|
+
} finally {
|
|
22
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("no .tmp file left after successful write", () => {
|
|
27
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-json-test-"));
|
|
28
|
+
try {
|
|
29
|
+
const file = join(tmp, "test.json");
|
|
30
|
+
saveJsonFile(file, { data: 123 });
|
|
31
|
+
const files = readdirSync(tmp);
|
|
32
|
+
const tmpFiles = files.filter((f: string) => f.includes(".tmp"));
|
|
33
|
+
assert.strictEqual(tmpFiles.length, 0, "No .tmp files should remain after write");
|
|
34
|
+
} finally {
|
|
35
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("concurrent writes don't corrupt data", () => {
|
|
40
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-json-test-"));
|
|
41
|
+
try {
|
|
42
|
+
const file = join(tmp, "shared.json");
|
|
43
|
+
// Write two different values rapidly — both should succeed without corruption
|
|
44
|
+
saveJsonFile(file, { writer: "first" });
|
|
45
|
+
saveJsonFile(file, { writer: "second" });
|
|
46
|
+
const content = JSON.parse(readFileSync(file, "utf-8"));
|
|
47
|
+
assert.strictEqual(content.writer, "second");
|
|
48
|
+
} finally {
|
|
49
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("round-trip through loadJsonFile", () => {
|
|
54
|
+
const tmp = mkdtempSync(join(tmpdir(), "gsd-json-test-"));
|
|
55
|
+
try {
|
|
56
|
+
const file = join(tmp, "roundtrip.json");
|
|
57
|
+
const data = { items: [1, 2, 3], name: "test" };
|
|
58
|
+
saveJsonFile(file, data);
|
|
59
|
+
const loaded = loadJsonFile(
|
|
60
|
+
file,
|
|
61
|
+
(d): d is typeof data => typeof d === "object" && d !== null && "items" in d,
|
|
62
|
+
() => ({ items: [], name: "" }),
|
|
63
|
+
);
|
|
64
|
+
assert.deepStrictEqual(loaded.items, [1, 2, 3]);
|
|
65
|
+
assert.strictEqual(loaded.name, "test");
|
|
66
|
+
} finally {
|
|
67
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker model override — tests for parallel.worker_model preference.
|
|
3
|
+
*
|
|
4
|
+
* Verifies validation, resolveParallelConfig pass-through, and type definitions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import test from "node:test";
|
|
8
|
+
import assert from "node:assert/strict";
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
|
|
15
|
+
const typesSrc = readFileSync(join(__dirname, "..", "types.ts"), "utf-8");
|
|
16
|
+
const validationSrc = readFileSync(join(__dirname, "..", "preferences-validation.ts"), "utf-8");
|
|
17
|
+
const preferencesSrc = readFileSync(join(__dirname, "..", "preferences.ts"), "utf-8");
|
|
18
|
+
|
|
19
|
+
// ─── Type definition ──────────────────────────────────────────────────────
|
|
20
|
+
|
|
21
|
+
test("ParallelConfig includes worker_model optional field", () => {
|
|
22
|
+
assert.ok(
|
|
23
|
+
typesSrc.includes("worker_model?: string"),
|
|
24
|
+
"ParallelConfig should have optional worker_model field",
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ─── Validation ───────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
test("validatePreferences accepts valid worker_model string", () => {
|
|
31
|
+
assert.ok(
|
|
32
|
+
validationSrc.includes("p.worker_model"),
|
|
33
|
+
"validation should check parallel.worker_model",
|
|
34
|
+
);
|
|
35
|
+
assert.ok(
|
|
36
|
+
validationSrc.includes('parallel.worker_model must be a non-empty string'),
|
|
37
|
+
"validation should reject invalid worker_model",
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ─── resolveParallelConfig ────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
test("resolveParallelConfig passes through worker_model", () => {
|
|
44
|
+
assert.ok(
|
|
45
|
+
preferencesSrc.includes("worker_model: prefs?.parallel?.worker_model"),
|
|
46
|
+
"resolveParallelConfig should pass through worker_model",
|
|
47
|
+
);
|
|
48
|
+
});
|
|
@@ -90,18 +90,21 @@ describe("workflow-logger audit persistence", () => {
|
|
|
90
90
|
assert.ok(ctx, "context should exist");
|
|
91
91
|
assert.equal(ctx.fn, "saveDecisionToDb");
|
|
92
92
|
assert.equal(ctx.tool, "gsd_decision_save");
|
|
93
|
-
assert.equal(ctx.error,
|
|
93
|
+
assert.equal(ctx.error, "SQLITE_BUSY: database is locked", "error key should be preserved in persisted context");
|
|
94
94
|
assert.equal(ctx.file, undefined, "file key must be stripped from persisted context");
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
-
test("persisted errors
|
|
97
|
+
test("persisted errors preserve error key but strip other unsafe keys", () => {
|
|
98
98
|
logError("bootstrap", "ensureDbOpen failed", {
|
|
99
99
|
error: "ENOENT",
|
|
100
100
|
cwd: "/home/user/project",
|
|
101
101
|
});
|
|
102
102
|
const lines = readAuditLines(tmp);
|
|
103
103
|
assert.equal(lines.length, 1);
|
|
104
|
-
|
|
104
|
+
const ctx = lines[0].context as Record<string, string>;
|
|
105
|
+
assert.ok(ctx, "context should exist when error key is present");
|
|
106
|
+
assert.equal(ctx.error, "ENOENT", "error key should be preserved");
|
|
107
|
+
assert.equal(ctx.cwd, undefined, "cwd key must be stripped");
|
|
105
108
|
});
|
|
106
109
|
|
|
107
110
|
test("mixed warnings and errors only persist errors", () => {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worktree-expected-warnings.test.ts — #3665
|
|
3
|
+
*
|
|
4
|
+
* Verify that auto-worktree.ts and worktree-manager.ts suppress expected
|
|
5
|
+
* ENOENT and EISDIR conditions instead of logging misleading warnings.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, test } from "node:test";
|
|
9
|
+
import assert from "node:assert/strict";
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join, dirname } from "node:path";
|
|
12
|
+
import { fileURLToPath } from "node:url";
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const autoWorktreeFile = join(__dirname, "..", "auto-worktree.ts");
|
|
16
|
+
const worktreeManagerFile = join(__dirname, "..", "worktree-manager.ts");
|
|
17
|
+
|
|
18
|
+
describe("worktree expected-condition warning suppression (#3665)", () => {
|
|
19
|
+
const autoSource = readFileSync(autoWorktreeFile, "utf-8");
|
|
20
|
+
|
|
21
|
+
test("auto-worktree.ts checks for ENOENT before logging unlink warning", () => {
|
|
22
|
+
assert.match(autoSource, /code\s*!==\s*["']ENOENT["']/);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("auto-worktree.ts checks for EISDIR before logging unlink warning", () => {
|
|
26
|
+
assert.match(autoSource, /code\s*!==\s*["']EISDIR["']/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("auto-worktree.ts references issue #3597", () => {
|
|
30
|
+
assert.match(autoSource, /#3597/);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const managerSource = readFileSync(worktreeManagerFile, "utf-8");
|
|
34
|
+
|
|
35
|
+
test("worktree-manager.ts checks isDirectory() before reading .git file", () => {
|
|
36
|
+
assert.match(managerSource, /lstatSync\(gitPath\)\.isDirectory\(\)/);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -26,9 +26,11 @@ import {
|
|
|
26
26
|
getSliceBranchName,
|
|
27
27
|
autoCommitCurrentBranch,
|
|
28
28
|
SLICE_BRANCH_RE,
|
|
29
|
+
_resetServiceCache,
|
|
29
30
|
} from "../worktree.ts";
|
|
30
31
|
|
|
31
32
|
import { deriveState } from "../state.ts";
|
|
33
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
32
34
|
import { describe, test } from 'node:test';
|
|
33
35
|
import assert from 'node:assert/strict';
|
|
34
36
|
|
|
@@ -74,6 +76,14 @@ run("git add .", base);
|
|
|
74
76
|
run('git commit -m "chore: init"', base);
|
|
75
77
|
|
|
76
78
|
describe('worktree-integration', async () => {
|
|
79
|
+
// Isolate from user's global preferences (which may have git.main_branch set).
|
|
80
|
+
// Reset caches so getService() creates a fresh instance with empty preferences.
|
|
81
|
+
const originalHome = process.env.HOME;
|
|
82
|
+
const fakeHome = mkdtempSync(join(tmpdir(), "gsd-fake-home-"));
|
|
83
|
+
process.env.HOME = fakeHome;
|
|
84
|
+
_clearGsdRootCache();
|
|
85
|
+
_resetServiceCache();
|
|
86
|
+
|
|
77
87
|
// ── Verify main tree baseline ──────────────────────────────────────────────
|
|
78
88
|
|
|
79
89
|
console.log("\n=== Main tree baseline ===");
|
|
@@ -197,4 +207,10 @@ describe('worktree-integration', async () => {
|
|
|
197
207
|
assert.deepStrictEqual(listWorktrees(base).length, 0, "all worktrees removed");
|
|
198
208
|
|
|
199
209
|
rmSync(base, { recursive: true, force: true });
|
|
210
|
+
|
|
211
|
+
// Restore HOME and reset caches
|
|
212
|
+
process.env.HOME = originalHome;
|
|
213
|
+
_clearGsdRootCache();
|
|
214
|
+
_resetServiceCache();
|
|
215
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
200
216
|
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3461: createAutoWorktree must use git.main_branch
|
|
3
|
+
* preference when META.json integration branch is absent.
|
|
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("auto-worktree.ts includes main_branch preference in startPoint fallback (#3461)", () => {
|
|
11
|
+
const src = readFileSync(
|
|
12
|
+
join(import.meta.dirname, "..", "auto-worktree.ts"),
|
|
13
|
+
"utf-8",
|
|
14
|
+
);
|
|
15
|
+
// The fix adds gitPrefs?.main_branch to the startPoint fallback chain
|
|
16
|
+
assert.ok(
|
|
17
|
+
src.includes("gitPrefs?.main_branch") || src.includes("prefs.main_branch"),
|
|
18
|
+
"createAutoWorktree must check git.main_branch preference before falling back to nativeDetectMainBranch",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
@@ -221,7 +221,8 @@ describe('worktree-sync-milestones', async () => {
|
|
|
221
221
|
|
|
222
222
|
try {
|
|
223
223
|
// Build worktree milestone structure with slice-level and task-level files
|
|
224
|
-
|
|
224
|
+
// Use M002 as the milestone to sync, M001 as the "current" being merged (skipped)
|
|
225
|
+
const wtSliceDir = join(wtBase, '.gsd', 'milestones', 'M002', 'slices', 'S01');
|
|
225
226
|
const wtTasksDir = join(wtSliceDir, 'tasks');
|
|
226
227
|
mkdirSync(wtTasksDir, { recursive: true });
|
|
227
228
|
writeFileSync(join(wtSliceDir, 'S01-SUMMARY.md'), '# S01 Summary');
|
|
@@ -229,11 +230,12 @@ describe('worktree-sync-milestones', async () => {
|
|
|
229
230
|
writeFileSync(join(wtTasksDir, 'T02-SUMMARY.md'), '# T02 Summary');
|
|
230
231
|
|
|
231
232
|
// Main project root starts with only the milestone directory (no slices yet)
|
|
232
|
-
mkdirSync(join(mainBase, '.gsd', 'milestones', '
|
|
233
|
+
mkdirSync(join(mainBase, '.gsd', 'milestones', 'M002'), { recursive: true });
|
|
233
234
|
|
|
235
|
+
// Pass M001 as milestoneId (the one being merged/skipped), M002 should still sync
|
|
234
236
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M001');
|
|
235
237
|
|
|
236
|
-
const mainSliceDir = join(mainBase, '.gsd', 'milestones', '
|
|
238
|
+
const mainSliceDir = join(mainBase, '.gsd', 'milestones', 'M002', 'slices', 'S01');
|
|
237
239
|
const mainTasksDir = join(mainSliceDir, 'tasks');
|
|
238
240
|
|
|
239
241
|
assert.ok(
|
|
@@ -341,16 +343,16 @@ describe('worktree-sync-milestones', async () => {
|
|
|
341
343
|
'M002 missing in main before sync',
|
|
342
344
|
);
|
|
343
345
|
|
|
344
|
-
// Sync with milestoneId = M001 (the current milestone)
|
|
346
|
+
// Sync with milestoneId = M001 (the current milestone being merged — skipped)
|
|
345
347
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M001');
|
|
346
348
|
|
|
347
|
-
// M001 should be
|
|
349
|
+
// M001 should be SKIPPED (current milestone being merged — #3641)
|
|
348
350
|
assert.ok(
|
|
349
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M001', 'M001-SUMMARY.md')),
|
|
350
|
-
'M001 SUMMARY synced to
|
|
351
|
+
!existsSync(join(mainBase, '.gsd', 'milestones', 'M001', 'M001-SUMMARY.md')),
|
|
352
|
+
'M001 SUMMARY NOT synced (current milestone skipped to prevent merge conflicts)',
|
|
351
353
|
);
|
|
352
354
|
|
|
353
|
-
// M002 should
|
|
355
|
+
// M002 should be synced (other milestone — not skipped)
|
|
354
356
|
assert.ok(
|
|
355
357
|
existsSync(join(mainBase, '.gsd', 'milestones', 'M002-abc123', 'M002-abc123-CONTEXT.md')),
|
|
356
358
|
'M002 CONTEXT synced to main (next-milestone fix)',
|
|
@@ -407,20 +409,17 @@ describe('worktree-sync-milestones', async () => {
|
|
|
407
409
|
writeFileSync(join(wtBase, '.gsd', 'REQUIREMENTS.md'), '# Requirements\n## R001-R089\n## R090 — SCIM\n## R091 — WebAuthn');
|
|
408
410
|
writeFileSync(join(wtBase, '.gsd', 'PROJECT.md'), '# Project\nMilestones: M001-M007');
|
|
409
411
|
|
|
410
|
-
// Sync with milestoneId = M006 (the completing milestone)
|
|
412
|
+
// Sync with milestoneId = M006 (the completing milestone — skipped by sync)
|
|
411
413
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M006-589wvh');
|
|
412
414
|
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', 'M006-589wvh-SUMMARY.md')),
|
|
416
|
-
'M006 SUMMARY synced',
|
|
417
|
-
);
|
|
415
|
+
// M006 is the current milestone being merged — it should be SKIPPED (#3641)
|
|
416
|
+
// Its files are already in the milestone branch and would conflict with squash merge.
|
|
418
417
|
assert.ok(
|
|
419
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', '
|
|
420
|
-
'M006
|
|
418
|
+
!existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', 'M006-589wvh-SUMMARY.md')),
|
|
419
|
+
'M006 SUMMARY NOT synced (current milestone skipped)',
|
|
421
420
|
);
|
|
422
421
|
|
|
423
|
-
// Verify M007 artifacts synced (the critical fix)
|
|
422
|
+
// Verify M007 artifacts synced (the critical fix — other milestones still sync)
|
|
424
423
|
assert.ok(
|
|
425
424
|
existsSync(join(mainBase, '.gsd', 'milestones', 'M007-wortc8', 'M007-wortc8-CONTEXT.md')),
|
|
426
425
|
'M007 CONTEXT synced to main (next-milestone)',
|
|
@@ -47,7 +47,8 @@ function writeFile(dir: string, relativePath: string, content: string): void {
|
|
|
47
47
|
test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#1678)", () => {
|
|
48
48
|
const mainBase = makeTempDir("main");
|
|
49
49
|
const wtBase = makeTempDir("wt");
|
|
50
|
-
const
|
|
50
|
+
const currentMid = "M000"; // milestone being merged (skipped by sync)
|
|
51
|
+
const mid = "M001"; // other milestone that should be synced
|
|
51
52
|
|
|
52
53
|
try {
|
|
53
54
|
// Set up worktree with milestone, slice, and task files
|
|
@@ -64,8 +65,8 @@ test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#167
|
|
|
64
65
|
// Set up main with empty .gsd
|
|
65
66
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
66
67
|
|
|
67
|
-
// Run sync
|
|
68
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
68
|
+
// Run sync — currentMid is skipped, mid (M001) should be synced
|
|
69
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
69
70
|
|
|
70
71
|
// Verify milestone-level files synced
|
|
71
72
|
assert.ok(
|
|
@@ -126,7 +127,8 @@ test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#167
|
|
|
126
127
|
test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
127
128
|
const mainBase = makeTempDir("main");
|
|
128
129
|
const wtBase = makeTempDir("wt");
|
|
129
|
-
const
|
|
130
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
131
|
+
const mid = "M002"; // other milestone that should be synced
|
|
130
132
|
|
|
131
133
|
try {
|
|
132
134
|
// Set up two slices with tasks
|
|
@@ -139,7 +141,7 @@ test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
|
139
141
|
|
|
140
142
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
141
143
|
|
|
142
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
144
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
143
145
|
|
|
144
146
|
// All task summaries from both slices should be synced
|
|
145
147
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
|
|
@@ -160,7 +162,8 @@ test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
|
160
162
|
test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
161
163
|
const mainBase = makeTempDir("main");
|
|
162
164
|
const wtBase = makeTempDir("wt");
|
|
163
|
-
const
|
|
165
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
166
|
+
const mid = "M003"; // other milestone that should be synced
|
|
164
167
|
|
|
165
168
|
try {
|
|
166
169
|
// Slice with no tasks/ subdirectory (legitimate case: pre-planning)
|
|
@@ -168,7 +171,7 @@ test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
|
168
171
|
|
|
169
172
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
170
173
|
|
|
171
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
174
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
172
175
|
|
|
173
176
|
// Should sync the slice file without errors
|
|
174
177
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`)));
|
|
@@ -183,7 +186,8 @@ test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
|
183
186
|
test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
|
|
184
187
|
const mainBase = makeTempDir("main");
|
|
185
188
|
const wtBase = makeTempDir("wt");
|
|
186
|
-
const
|
|
189
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
190
|
+
const mid = "M004"; // other milestone that should be synced
|
|
187
191
|
|
|
188
192
|
try {
|
|
189
193
|
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`, "# Plan\n");
|
|
@@ -194,7 +198,7 @@ test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
|
|
|
194
198
|
|
|
195
199
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
196
200
|
|
|
197
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
201
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
198
202
|
|
|
199
203
|
// Only .md files should be synced
|
|
200
204
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
|