@opengsd/gsd-pi 1.2.0-dev.e8563f58 → 1.2.0-dev.fbdca60b
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/cli-model-override.d.ts +15 -0
- package/dist/cli-model-override.js +21 -0
- package/dist/cli.js +1 -18
- package/dist/loader.js +6 -4
- package/dist/register-agent-bundles.d.ts +11 -2
- package/dist/register-agent-bundles.js +18 -4
- package/dist/resource-loader.d.ts +10 -5
- package/dist/resource-loader.js +121 -6
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +3 -2
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +447 -215
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
- package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
- package/dist/resources/extensions/gsd/auto/dispatch-history.js +21 -6
- package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
- package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
- package/dist/resources/extensions/gsd/auto/loop.js +4 -1
- package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +85 -15
- package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
- package/dist/resources/extensions/gsd/auto/phases.js +17 -2329
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
- package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
- package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +3 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +11 -2
- package/dist/resources/extensions/gsd/auto-post-unit.js +18 -6
- package/dist/resources/extensions/gsd/auto-start.js +23 -3
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
- package/dist/resources/extensions/gsd/auto-verification.js +14 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +15 -2
- package/dist/resources/extensions/gsd/auto.js +45 -2
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -7
- package/dist/resources/extensions/gsd/commands/context.js +16 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
- package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
- package/dist/resources/extensions/gsd/db/engine.js +24 -6
- package/dist/resources/extensions/gsd/db/queries.js +30 -0
- package/dist/resources/extensions/gsd/db-migration-backup.js +51 -8
- package/dist/resources/extensions/gsd/db-transaction.js +27 -23
- package/dist/resources/extensions/gsd/db-writer.js +8 -17
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
- package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
- package/dist/resources/extensions/gsd/gsd-db.js +15 -20
- package/dist/resources/extensions/gsd/guided-flow.js +93 -4
- package/dist/resources/extensions/gsd/health-widget.js +87 -28
- package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
- package/dist/resources/extensions/gsd/memory-relations.js +1 -1
- package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
- package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
- package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
- package/dist/resources/extensions/gsd/notifications.js +12 -7
- package/dist/resources/extensions/gsd/projection-flush.js +7 -0
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
- package/dist/resources/extensions/gsd/session-lock.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +3 -6
- package/dist/resources/extensions/gsd/state.js +6 -2
- package/dist/resources/extensions/gsd/tool-contract.js +14 -3
- package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +65 -2
- package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +1 -1
- package/dist/resources/extensions/gsd/unit-registry.js +34 -4
- package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
- package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
- package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
- package/dist/resources/extensions/gsd/workflow-events.js +6 -18
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
- package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
- package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
- package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
- package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
- package/dist/resources/extensions/gsd/worktree.js +8 -1
- package/dist/resources/extensions/mcp-client/manager.js +6 -1
- package/dist/resources/skills/create-skill/SKILL.md +3 -0
- package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/runtime-checks.d.ts +10 -0
- package/dist/runtime-checks.js +27 -0
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- 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/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +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 +7 -7
- package/dist/web/standalone/.next/server/chunks/{5942.js → 1128.js} +1 -1
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +3 -3
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +6 -4
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +8 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +50 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +17 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +12 -3
- package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
- package/packages/mcp-server/dist/cli-runner.js +137 -0
- package/packages/mcp-server/dist/cli-runner.js.map +1 -0
- package/packages/mcp-server/dist/cli.js +2 -53
- package/packages/mcp-server/dist/cli.js.map +1 -1
- package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
- package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
- package/packages/mcp-server/dist/pid-registry.js +459 -0
- package/packages/mcp-server/dist/pid-registry.js.map +1 -0
- package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
- package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
- package/packages/mcp-server/dist/probe-mode.js +10 -0
- package/packages/mcp-server/dist/probe-mode.js.map +1 -0
- package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
- package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
- package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
- package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +62 -43
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +5 -5
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +43 -2
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/README.md +15 -0
- package/packages/pi-tui/dist/index.d.ts +2 -2
- package/packages/pi-tui/dist/index.d.ts.map +1 -1
- package/packages/pi-tui/dist/index.js +2 -2
- package/packages/pi-tui/dist/index.js.map +1 -1
- package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
- package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal-image.js +54 -2
- package/packages/pi-tui/dist/terminal-image.js.map +1 -1
- package/packages/pi-tui/dist/terminal.d.ts +12 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +70 -25
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/dist/tui.d.ts +15 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +106 -21
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +110 -36
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +45 -17
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +7 -2
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +531 -226
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
- package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
- package/src/resources/extensions/gsd/auto/dispatch-history.ts +22 -6
- package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
- package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -1
- package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +95 -15
- package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
- package/src/resources/extensions/gsd/auto/phases.ts +58 -3022
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
- package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
- package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +10 -16
- package/src/resources/extensions/gsd/auto-dispatch.ts +11 -10
- package/src/resources/extensions/gsd/auto-post-unit.ts +21 -6
- package/src/resources/extensions/gsd/auto-start.ts +24 -4
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
- package/src/resources/extensions/gsd/auto-verification.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +15 -2
- package/src/resources/extensions/gsd/auto.ts +56 -2
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +56 -6
- package/src/resources/extensions/gsd/commands/context.ts +16 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
- package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
- package/src/resources/extensions/gsd/db/engine.ts +26 -6
- package/src/resources/extensions/gsd/db/queries.ts +29 -0
- package/src/resources/extensions/gsd/db-migration-backup.ts +56 -7
- package/src/resources/extensions/gsd/db-transaction.ts +37 -20
- package/src/resources/extensions/gsd/db-writer.ts +11 -19
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
- package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
- package/src/resources/extensions/gsd/gsd-db.ts +15 -19
- package/src/resources/extensions/gsd/guided-flow.ts +145 -24
- package/src/resources/extensions/gsd/health-widget.ts +91 -27
- package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
- package/src/resources/extensions/gsd/memory-relations.ts +1 -1
- package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
- package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
- package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
- package/src/resources/extensions/gsd/notifications.ts +13 -6
- package/src/resources/extensions/gsd/projection-flush.ts +20 -0
- package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +3 -1
- package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
- package/src/resources/extensions/gsd/session-lock.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +3 -6
- package/src/resources/extensions/gsd/state.ts +7 -1
- package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +76 -12
- package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +77 -1
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
- package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +68 -19
- package/src/resources/extensions/gsd/tests/db-transaction.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
- package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +18 -6
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
- package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +26 -2
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +170 -48
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
- package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
- package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
- package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
- package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
- package/src/resources/extensions/gsd/tool-contract.ts +38 -3
- package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +90 -2
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
- package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
- package/src/resources/extensions/gsd/unit-context-composer.ts +1 -1
- package/src/resources/extensions/gsd/unit-registry.ts +34 -4
- package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
- package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
- package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
- package/src/resources/extensions/gsd/workflow-events.ts +12 -20
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
- package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
- package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
- package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
- package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
- package/src/resources/extensions/gsd/worktree.ts +7 -1
- package/src/resources/extensions/mcp-client/manager.ts +7 -1
- package/src/resources/skills/create-skill/SKILL.md +3 -0
- package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
- package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
- package/src/resources/skills/gsd-browser/SKILL.md +0 -41
- /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{LDHRKiRBIVZmiuMjrL1Vy → 2T9IOdiiM3o3gZ4UbPi8E}/_ssgManifest.js +0 -0
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Regression tests for auto-unit closeout activity classification.
|
|
3
3
|
|
|
4
|
-
import
|
|
4
|
+
import { mkdtempSync, writeFileSync, rmSync } from "node:fs";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { execSync } from "node:child_process";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import test, { type TestContext } from "node:test";
|
|
5
9
|
import assert from "node:assert/strict";
|
|
6
10
|
|
|
7
11
|
import {
|
|
8
12
|
isSuspiciousGhostCompletion,
|
|
9
13
|
snapshotUnitActivity,
|
|
10
14
|
} from "../auto-unit-closeout.ts";
|
|
15
|
+
import {
|
|
16
|
+
closeUnit,
|
|
17
|
+
type UnitCloseoutRequest,
|
|
18
|
+
type UnitCloseoutDeps,
|
|
19
|
+
} from "../unit-closeout.ts";
|
|
20
|
+
import type { NotifySeverity } from "../notification-store.js";
|
|
11
21
|
|
|
12
22
|
function makeCtx(entries: unknown[]) {
|
|
13
23
|
return {
|
|
@@ -17,6 +27,38 @@ function makeCtx(entries: unknown[]) {
|
|
|
17
27
|
} as any;
|
|
18
28
|
}
|
|
19
29
|
|
|
30
|
+
function createTempGitRepo(t: TestContext): string {
|
|
31
|
+
const dir = mkdtempSync(join(tmpdir(), "closeout-test-"));
|
|
32
|
+
t.after(() => rmSync(dir, { recursive: true, force: true }));
|
|
33
|
+
execSync("git init", { cwd: dir });
|
|
34
|
+
execSync("git config user.email test@test.com", { cwd: dir });
|
|
35
|
+
execSync("git config user.name Test", { cwd: dir });
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function makeMockDeps(overrides: Partial<UnitCloseoutDeps> = {}): UnitCloseoutDeps & { notifications: Array<{ message: string; severity: NotifySeverity }> } {
|
|
40
|
+
const notifications: Array<{ message: string; severity: NotifySeverity }> = [];
|
|
41
|
+
return {
|
|
42
|
+
isolationMode: () => "none",
|
|
43
|
+
currentBranch: () => "main",
|
|
44
|
+
commit: () => null,
|
|
45
|
+
notify: (message, severity) => notifications.push({ message, severity }),
|
|
46
|
+
notifications,
|
|
47
|
+
...overrides,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function baseRequest(overrides: Partial<UnitCloseoutRequest> = {}): UnitCloseoutRequest {
|
|
52
|
+
return {
|
|
53
|
+
basePath: "/tmp/ignored",
|
|
54
|
+
unitType: "complete-milestone",
|
|
55
|
+
unitId: "M001",
|
|
56
|
+
boundary: "milestone",
|
|
57
|
+
outcome: "complete",
|
|
58
|
+
...overrides,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
20
62
|
test("isSuspiciousGhostCompletion rejects fast completions with no assistant output or tools", () => {
|
|
21
63
|
const startedAt = Date.now();
|
|
22
64
|
const ctx = makeCtx([]);
|
|
@@ -66,3 +108,129 @@ test("snapshotUnitActivity counts assistant messages and tool calls", () => {
|
|
|
66
108
|
assistantMessages: 1,
|
|
67
109
|
});
|
|
68
110
|
});
|
|
111
|
+
|
|
112
|
+
test("closeUnit: nothing-to-commit / isolation none", (t) => {
|
|
113
|
+
const dir = createTempGitRepo(t);
|
|
114
|
+
const deps = makeMockDeps({
|
|
115
|
+
isolationMode: () => "none",
|
|
116
|
+
commit: () => null,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
120
|
+
|
|
121
|
+
assert.equal(result.gitVerdict, "nothing-to-commit");
|
|
122
|
+
assert.equal(result.commitMessage, null);
|
|
123
|
+
assert.equal(result.notice, undefined);
|
|
124
|
+
assert.equal(deps.notifications.length, 0);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("closeUnit: committed / isolation none", (t) => {
|
|
128
|
+
const dir = createTempGitRepo(t);
|
|
129
|
+
writeFileSync(join(dir, "file.txt"), "hello");
|
|
130
|
+
execSync("git add file.txt", { cwd: dir });
|
|
131
|
+
|
|
132
|
+
const deps = makeMockDeps({
|
|
133
|
+
isolationMode: () => "none",
|
|
134
|
+
commit: () => "Add file.txt",
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
138
|
+
|
|
139
|
+
assert.equal(result.gitVerdict, "committed");
|
|
140
|
+
assert.equal(result.commitMessage, "Add file.txt");
|
|
141
|
+
assert.equal(result.notice, undefined);
|
|
142
|
+
assert.equal(deps.notifications.length, 0);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("closeUnit: milestone-branch / worktree isolation", (t) => {
|
|
146
|
+
const dir = createTempGitRepo(t);
|
|
147
|
+
const deps = makeMockDeps({
|
|
148
|
+
isolationMode: () => "worktree",
|
|
149
|
+
currentBranch: () => "milestone/M001",
|
|
150
|
+
commit: () => "Complete M001",
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
154
|
+
|
|
155
|
+
assert.equal(result.gitVerdict, "milestone-branch");
|
|
156
|
+
assert.equal(result.commitMessage, "Complete M001");
|
|
157
|
+
assert.ok(result.notice);
|
|
158
|
+
assert.equal(deps.notifications.length, 1);
|
|
159
|
+
assert.equal(deps.notifications[0].severity, "info");
|
|
160
|
+
assert.match(deps.notifications[0].message, /Merge it to the integration branch/);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
test("closeUnit: isolation-bypassed / worktree isolation", (t) => {
|
|
164
|
+
const dir = createTempGitRepo(t);
|
|
165
|
+
const deps = makeMockDeps({
|
|
166
|
+
isolationMode: () => "worktree",
|
|
167
|
+
currentBranch: () => "main",
|
|
168
|
+
commit: () => "Complete M001",
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
172
|
+
|
|
173
|
+
assert.equal(result.gitVerdict, "isolation-bypassed");
|
|
174
|
+
assert.equal(result.commitMessage, "Complete M001");
|
|
175
|
+
assert.ok(result.notice);
|
|
176
|
+
assert.equal(deps.notifications.length, 1);
|
|
177
|
+
assert.equal(deps.notifications[0].severity, "warning");
|
|
178
|
+
assert.match(deps.notifications[0].message, /completed outside a milestone worktree\/branch/);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test("closeUnit: isolation-bypassed / branch isolation", (t) => {
|
|
182
|
+
const dir = createTempGitRepo(t);
|
|
183
|
+
const deps = makeMockDeps({
|
|
184
|
+
isolationMode: () => "branch",
|
|
185
|
+
currentBranch: () => "main",
|
|
186
|
+
commit: () => "Complete M001",
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
190
|
+
|
|
191
|
+
assert.equal(result.gitVerdict, "isolation-bypassed");
|
|
192
|
+
assert.equal(result.commitMessage, "Complete M001");
|
|
193
|
+
assert.ok(result.notice);
|
|
194
|
+
assert.equal(deps.notifications.length, 1);
|
|
195
|
+
assert.equal(deps.notifications[0].severity, "warning");
|
|
196
|
+
assert.match(deps.notifications[0].message, /completed outside a milestone worktree\/branch/);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("closeUnit: commit-failed", (t) => {
|
|
200
|
+
const dir = createTempGitRepo(t);
|
|
201
|
+
const deps = makeMockDeps({
|
|
202
|
+
isolationMode: () => "none",
|
|
203
|
+
commit: () => {
|
|
204
|
+
throw new Error("simulated commit failure");
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const result = closeUnit(baseRequest({ basePath: dir, boundary: "milestone" }), deps);
|
|
209
|
+
|
|
210
|
+
assert.equal(result.gitVerdict, "commit-failed");
|
|
211
|
+
assert.equal(result.commitMessage, null);
|
|
212
|
+
assert.ok(result.notice);
|
|
213
|
+
assert.match(result.notice!, /simulated commit failure/);
|
|
214
|
+
assert.equal(deps.notifications.length, 1);
|
|
215
|
+
assert.equal(deps.notifications[0].severity, "error");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("closeUnit: task boundary ignores isolation verdict", (t) => {
|
|
219
|
+
const dir = createTempGitRepo(t);
|
|
220
|
+
const deps = makeMockDeps({
|
|
221
|
+
isolationMode: () => "worktree",
|
|
222
|
+
currentBranch: () => "main",
|
|
223
|
+
commit: () => "Complete task",
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const result = closeUnit(
|
|
227
|
+
baseRequest({ basePath: dir, boundary: "task", unitType: "execute-task", unitId: "M001/S01/T01" }),
|
|
228
|
+
deps,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
assert.equal(result.gitVerdict, "committed");
|
|
232
|
+
assert.equal(result.commitMessage, "Complete task");
|
|
233
|
+
assert.equal(result.notice, undefined);
|
|
234
|
+
assert.equal(deps.notifications.length, 0);
|
|
235
|
+
});
|
|
236
|
+
|
|
@@ -80,6 +80,20 @@ function createTempProject(): { basePath: string; planPath: string } {
|
|
|
80
80
|
return { basePath, planPath };
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
function writeProjectPreferences(basePath: string, yaml: string): void {
|
|
84
|
+
fs.writeFileSync(path.join(basePath, '.gsd', 'PREFERENCES.md'), `---\n${yaml}---\n`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function withWorkingDirectory<T>(cwd: string, action: () => Promise<T>): Promise<T> {
|
|
88
|
+
const previousCwd = process.cwd();
|
|
89
|
+
process.chdir(cwd);
|
|
90
|
+
try {
|
|
91
|
+
return await action();
|
|
92
|
+
} finally {
|
|
93
|
+
process.chdir(previousCwd);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
83
97
|
function makeValidParams() {
|
|
84
98
|
return {
|
|
85
99
|
taskId: 'T01',
|
|
@@ -104,6 +118,13 @@ function makeValidParams() {
|
|
|
104
118
|
};
|
|
105
119
|
}
|
|
106
120
|
|
|
121
|
+
function makeEscalationOptions() {
|
|
122
|
+
return [
|
|
123
|
+
{ id: 'continue', label: 'Continue', tradeoffs: 'Keeps execution moving with the default path.' },
|
|
124
|
+
{ id: 'pause', label: 'Pause', tradeoffs: 'Stops execution until the blocker is reviewed.' },
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
|
|
107
128
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
108
129
|
// complete-task: Fresh DB is migrated to the current schema version
|
|
109
130
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -359,6 +380,105 @@ console.log('\n=== complete-task: handler happy path ===');
|
|
|
359
380
|
cleanup(dbPath);
|
|
360
381
|
}
|
|
361
382
|
|
|
383
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
384
|
+
// complete-task: hard-blocker escalation with mid-execution escalation disabled
|
|
385
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
386
|
+
|
|
387
|
+
console.log('\n=== complete-task: disabled hard-blocker escalation rolls back completion ===');
|
|
388
|
+
{
|
|
389
|
+
const dbPath = tempDbPath();
|
|
390
|
+
openDatabase(dbPath);
|
|
391
|
+
|
|
392
|
+
const { basePath } = createTempProject();
|
|
393
|
+
writeProjectPreferences(basePath, 'phases:\n mid_execution_escalation: false\n');
|
|
394
|
+
|
|
395
|
+
insertMilestone({ id: 'M001', title: 'Test Milestone' });
|
|
396
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
|
|
397
|
+
|
|
398
|
+
const params = {
|
|
399
|
+
...makeValidParams(),
|
|
400
|
+
blockerDiscovered: true,
|
|
401
|
+
escalation: {
|
|
402
|
+
question: 'Should execution pause for the hard blocker?',
|
|
403
|
+
options: makeEscalationOptions(),
|
|
404
|
+
recommendation: 'pause',
|
|
405
|
+
recommendationRationale: 'The blocker should not be silently advanced.',
|
|
406
|
+
continueWithDefault: false,
|
|
407
|
+
},
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const result = await withWorkingDirectory(basePath, () => handleCompleteTask(params, basePath));
|
|
411
|
+
|
|
412
|
+
assertTrue('error' in result, 'hard-blocker escalation should fail when escalation handling is disabled');
|
|
413
|
+
if ('error' in result) {
|
|
414
|
+
assertMatch(result.error, /hard-blocker escalation/, 'error should mention hard-blocker escalation');
|
|
415
|
+
assertMatch(result.error, /mid_execution_escalation is disabled/, 'error should mention disabled preference');
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const task = getTask('M001', 'S01', 'T01');
|
|
419
|
+
assertTrue(task !== null, 'task row should remain after rollback');
|
|
420
|
+
assertEq(task!.status, 'pending', 'task status should be rolled back to pending');
|
|
421
|
+
assertEq(task!.blocker_discovered, true, 'blocker flag should remain recorded for visibility');
|
|
422
|
+
assertEq(task!.escalation_pending, 0, 'disabled preference should not create a pending escalation flag');
|
|
423
|
+
assertEq(task!.escalation_awaiting_review, 0, 'disabled preference should not create an awaiting-review flag');
|
|
424
|
+
|
|
425
|
+
const adapter = _getAdapter()!;
|
|
426
|
+
const evRows = adapter.prepare(
|
|
427
|
+
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND slice_id = 'S01' AND milestone_id = 'M001'"
|
|
428
|
+
).all();
|
|
429
|
+
assertEq(evRows.length, 0, 'verification evidence should be deleted when completion rolls back');
|
|
430
|
+
|
|
431
|
+
cleanupDir(basePath);
|
|
432
|
+
cleanup(dbPath);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
436
|
+
// complete-task: soft escalation with mid-execution escalation disabled
|
|
437
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
438
|
+
|
|
439
|
+
console.log('\n=== complete-task: disabled soft escalation still completes ===');
|
|
440
|
+
{
|
|
441
|
+
const dbPath = tempDbPath();
|
|
442
|
+
openDatabase(dbPath);
|
|
443
|
+
|
|
444
|
+
const { basePath } = createTempProject();
|
|
445
|
+
writeProjectPreferences(basePath, 'phases:\n mid_execution_escalation: false\n');
|
|
446
|
+
|
|
447
|
+
insertMilestone({ id: 'M001', title: 'Test Milestone' });
|
|
448
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice' });
|
|
449
|
+
|
|
450
|
+
const params = {
|
|
451
|
+
...makeValidParams(),
|
|
452
|
+
escalation: {
|
|
453
|
+
question: 'Should execution continue with the default?',
|
|
454
|
+
options: makeEscalationOptions(),
|
|
455
|
+
recommendation: 'continue',
|
|
456
|
+
recommendationRationale: 'The default path is safe enough to continue.',
|
|
457
|
+
continueWithDefault: true,
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
const result = await withWorkingDirectory(basePath, () => handleCompleteTask(params, basePath));
|
|
462
|
+
|
|
463
|
+
assertTrue(!('error' in result), 'soft escalation should still complete when escalation handling is disabled');
|
|
464
|
+
if (!('error' in result)) {
|
|
465
|
+
assertTrue(!result.escalation, 'disabled preference should not return escalation metadata');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const task = getTask('M001', 'S01', 'T01');
|
|
469
|
+
assertTrue(task !== null, 'task row should exist');
|
|
470
|
+
assertEq(task!.status, 'complete', 'soft escalation should leave task complete');
|
|
471
|
+
|
|
472
|
+
const adapter = _getAdapter()!;
|
|
473
|
+
const evRows = adapter.prepare(
|
|
474
|
+
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND slice_id = 'S01' AND milestone_id = 'M001'"
|
|
475
|
+
).all();
|
|
476
|
+
assertEq(evRows.length, 1, 'verification evidence should remain for soft escalation completion');
|
|
477
|
+
|
|
478
|
+
cleanupDir(basePath);
|
|
479
|
+
cleanup(dbPath);
|
|
480
|
+
}
|
|
481
|
+
|
|
362
482
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
363
483
|
// complete-task: Handler validation errors
|
|
364
484
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -414,6 +534,9 @@ console.log('\n=== complete-task: handler idempotency ===');
|
|
|
414
534
|
// First call should succeed
|
|
415
535
|
const r1 = await handleCompleteTask(params, basePath);
|
|
416
536
|
assertTrue(!('error' in r1), 'first call should succeed');
|
|
537
|
+
if ('error' in r1) {
|
|
538
|
+
throw new Error(r1.error);
|
|
539
|
+
}
|
|
417
540
|
|
|
418
541
|
// Verify complete-task did not duplicate T01. S01-PLAN.md is a projection,
|
|
419
542
|
// so the remaining plan task is not imported implicitly.
|
|
@@ -421,16 +544,29 @@ console.log('\n=== complete-task: handler idempotency ===');
|
|
|
421
544
|
assertEq(tasks.length, 1, 'should only have the completed DB task after first call');
|
|
422
545
|
assertEq(tasks.filter(t => t.id === 'T01').length, 1, 'should have exactly one T01 row after first call');
|
|
423
546
|
|
|
424
|
-
//
|
|
547
|
+
// If the DB row is complete but the projection was lost, the duplicate call
|
|
548
|
+
// should repair the missing summary from full_summary_md instead of forcing a
|
|
549
|
+
// reopen/re-complete loop.
|
|
550
|
+
fs.unlinkSync(r1.summaryPath);
|
|
551
|
+
assertTrue(!fs.existsSync(r1.summaryPath), 'fixture should remove the task summary before repair');
|
|
425
552
|
const r2 = await handleCompleteTask(params, basePath);
|
|
426
|
-
assertTrue('error' in r2, 'second call should
|
|
553
|
+
assertTrue(!('error' in r2), 'second call should repair missing summary for DB-complete task');
|
|
427
554
|
if ('error' in r2) {
|
|
428
|
-
|
|
555
|
+
throw new Error(r2.error);
|
|
556
|
+
}
|
|
557
|
+
assertTrue(fs.existsSync(r2.summaryPath), 'missing summary should be restored on disk');
|
|
558
|
+
assertEq(r2.duplicate, true, 'repair should be reported as a duplicate/no-op state mutation');
|
|
559
|
+
|
|
560
|
+
// Third call with the summary present — state machine guard rejects (task is already complete)
|
|
561
|
+
const r3 = await handleCompleteTask(params, basePath);
|
|
562
|
+
assertTrue('error' in r3, 'third call should return error (task already complete)');
|
|
563
|
+
if ('error' in r3) {
|
|
564
|
+
assertMatch(r3.error, /already complete/, 'error should mention already complete');
|
|
429
565
|
}
|
|
430
566
|
|
|
431
|
-
// Still no duplicate rows from the rejected
|
|
567
|
+
// Still no duplicate rows from the repair or rejected third call.
|
|
432
568
|
const tasksAfter = getSliceTasks('M001', 'S01');
|
|
433
|
-
assertEq(tasksAfter.length, 1, 'should still only have T01 after rejected
|
|
569
|
+
assertEq(tasksAfter.length, 1, 'should still only have T01 after duplicate repair and rejected third call');
|
|
434
570
|
assertEq(tasksAfter.filter(t => t.id === 'T01').length, 1, 'should still have exactly one T01 row');
|
|
435
571
|
|
|
436
572
|
cleanupDir(basePath);
|
|
@@ -3,16 +3,22 @@
|
|
|
3
3
|
|
|
4
4
|
import { describe, test } from "node:test";
|
|
5
5
|
import assert from "node:assert/strict";
|
|
6
|
-
import { backupDatabaseBeforeMigration } from "../db-migration-backup.ts";
|
|
6
|
+
import { MigrationBackupError, backupDatabaseBeforeMigration } from "../db-migration-backup.ts";
|
|
7
7
|
import type { DbAdapter, DbStatement } from "../db-adapter.ts";
|
|
8
8
|
|
|
9
9
|
class FakeStatement implements DbStatement {
|
|
10
|
+
private readonly row: Record<string, unknown> | undefined;
|
|
11
|
+
|
|
12
|
+
constructor(row: Record<string, unknown> | undefined = undefined) {
|
|
13
|
+
this.row = row;
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
run(): unknown {
|
|
11
17
|
return undefined;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
get(): Record<string, unknown> | undefined {
|
|
15
|
-
return
|
|
21
|
+
return this.row;
|
|
16
22
|
}
|
|
17
23
|
|
|
18
24
|
all(): Record<string, unknown>[] {
|
|
@@ -22,15 +28,19 @@ class FakeStatement implements DbStatement {
|
|
|
22
28
|
|
|
23
29
|
class FakeAdapter implements DbAdapter {
|
|
24
30
|
readonly execCalls: string[] = [];
|
|
31
|
+
readonly prepareCalls: string[] = [];
|
|
25
32
|
failCheckpoint = false;
|
|
33
|
+
checkpointRow: Record<string, unknown> = { busy: 0, log: 0, checkpointed: 0 };
|
|
26
34
|
|
|
27
35
|
exec(sql: string): void {
|
|
28
36
|
this.execCalls.push(sql);
|
|
29
37
|
if (this.failCheckpoint) throw new Error("checkpoint failed");
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
prepare(): DbStatement {
|
|
33
|
-
|
|
40
|
+
prepare(sql: string): DbStatement {
|
|
41
|
+
this.prepareCalls.push(sql);
|
|
42
|
+
if (this.failCheckpoint) throw new Error("checkpoint failed");
|
|
43
|
+
return new FakeStatement(this.checkpointRow);
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
close(): void {}
|
|
@@ -73,32 +83,71 @@ describe("db-migration-backup", () => {
|
|
|
73
83
|
logWarning: () => assert.fail("should not warn"),
|
|
74
84
|
});
|
|
75
85
|
|
|
76
|
-
assert.deepEqual(db.
|
|
86
|
+
assert.deepEqual(db.prepareCalls, ["PRAGMA wal_checkpoint(TRUNCATE)"]);
|
|
77
87
|
assert.deepEqual(copies, [["/tmp/gsd.db", "/tmp/gsd.db.backup-v12"]]);
|
|
78
88
|
});
|
|
79
89
|
|
|
80
|
-
test("
|
|
90
|
+
test("throws and skips copying when checkpoint fails", () => {
|
|
81
91
|
const db = new FakeAdapter();
|
|
82
92
|
db.failCheckpoint = true;
|
|
83
93
|
const copies: Array<[string, string]> = [];
|
|
84
94
|
const warnings: string[] = [];
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
assert.throws(
|
|
97
|
+
() =>
|
|
98
|
+
backupDatabaseBeforeMigration(db, "/tmp/gsd.db", 12, {
|
|
99
|
+
existsSync: (path) => path === "/tmp/gsd.db",
|
|
100
|
+
copyFileSync: (src, dest) => copies.push([src, dest]),
|
|
101
|
+
logWarning: (_scope, message) => warnings.push(message),
|
|
102
|
+
}),
|
|
103
|
+
/checkpoint failed/,
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
assert.deepEqual(db.prepareCalls, ["PRAGMA wal_checkpoint(TRUNCATE)"]);
|
|
107
|
+
assert.deepEqual(copies, []);
|
|
108
|
+
assert.equal(warnings.length, 1);
|
|
109
|
+
assert.match(warnings[0], /Pre-migration backup failed: checkpoint failed/);
|
|
110
|
+
});
|
|
91
111
|
|
|
92
|
-
|
|
112
|
+
test("throws and skips copying when checkpoint result is incomplete", () => {
|
|
113
|
+
const db = new FakeAdapter();
|
|
114
|
+
db.checkpointRow = { busy: 1, log: 4, checkpointed: 3 };
|
|
115
|
+
const copies: Array<[string, string]> = [];
|
|
116
|
+
const warnings: string[] = [];
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
assert.throws(
|
|
119
|
+
() =>
|
|
120
|
+
backupDatabaseBeforeMigration(db, "/tmp/gsd.db", 12, {
|
|
121
|
+
existsSync: (path) => path === "/tmp/gsd.db",
|
|
122
|
+
copyFileSync: (src, dest) => copies.push([src, dest]),
|
|
123
|
+
logWarning: (_scope, message) => warnings.push(message),
|
|
124
|
+
}),
|
|
125
|
+
MigrationBackupError,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
assert.deepEqual(db.prepareCalls, ["PRAGMA wal_checkpoint(TRUNCATE)"]);
|
|
129
|
+
assert.deepEqual(copies, []);
|
|
130
|
+
assert.equal(warnings.length, 1);
|
|
131
|
+
assert.match(warnings[0], /Pre-migration backup failed: WAL checkpoint incomplete/);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("throws and warns when copy fails", () => {
|
|
135
|
+
const db = new FakeAdapter();
|
|
136
|
+
const warnings: string[] = [];
|
|
101
137
|
|
|
138
|
+
assert.throws(
|
|
139
|
+
() =>
|
|
140
|
+
backupDatabaseBeforeMigration(db, "/tmp/fail.db", 13, {
|
|
141
|
+
existsSync: (path) => path === "/tmp/fail.db",
|
|
142
|
+
copyFileSync: () => {
|
|
143
|
+
throw new Error("read only");
|
|
144
|
+
},
|
|
145
|
+
logWarning: (_scope, message) => warnings.push(message),
|
|
146
|
+
}),
|
|
147
|
+
/read only/,
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
assert.deepEqual(db.prepareCalls, ["PRAGMA wal_checkpoint(TRUNCATE)"]);
|
|
102
151
|
assert.equal(warnings.length, 1);
|
|
103
152
|
assert.match(warnings[0], /Pre-migration backup failed: read only/);
|
|
104
153
|
});
|
|
@@ -17,6 +17,10 @@ class FakeTransactionControls implements DbTransactionControls {
|
|
|
17
17
|
this.record("BEGIN DEFERRED");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
beginImmediate(): void {
|
|
21
|
+
this.record("BEGIN IMMEDIATE");
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
commit(): void {
|
|
21
25
|
this.record("COMMIT");
|
|
22
26
|
}
|
|
@@ -107,4 +111,59 @@ describe("db-transaction", () => {
|
|
|
107
111
|
assert.equal(rollbackErrors.length, 1);
|
|
108
112
|
assert.match(rollbackErrors[0].message, /failed ROLLBACK/);
|
|
109
113
|
});
|
|
114
|
+
|
|
115
|
+
test("commits successful immediate transactions", () => {
|
|
116
|
+
const runner = createDbTransactionRunner();
|
|
117
|
+
const controls = new FakeTransactionControls();
|
|
118
|
+
|
|
119
|
+
const result = runner.immediateTransaction(controls, () => {
|
|
120
|
+
assert.equal(runner.isInTransaction(), true);
|
|
121
|
+
return "ok";
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
assert.equal(result, "ok");
|
|
125
|
+
assert.equal(runner.isInTransaction(), false);
|
|
126
|
+
assert.deepEqual(controls.calls, ["BEGIN IMMEDIATE", "COMMIT"]);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test("rolls back failed immediate transactions and clears depth", () => {
|
|
130
|
+
const runner = createDbTransactionRunner();
|
|
131
|
+
const controls = new FakeTransactionControls();
|
|
132
|
+
|
|
133
|
+
assert.throws(
|
|
134
|
+
() => runner.immediateTransaction(controls, () => {
|
|
135
|
+
throw new Error("boom");
|
|
136
|
+
}),
|
|
137
|
+
/boom/,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
assert.equal(runner.isInTransaction(), false);
|
|
141
|
+
assert.deepEqual(controls.calls, ["BEGIN IMMEDIATE", "ROLLBACK"]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("nested immediate transactions inside write transactions do not issue nested BEGIN", () => {
|
|
145
|
+
const runner = createDbTransactionRunner();
|
|
146
|
+
const controls = new FakeTransactionControls();
|
|
147
|
+
|
|
148
|
+
runner.transaction(controls, () => {
|
|
149
|
+
runner.immediateTransaction(controls, () => {
|
|
150
|
+
assert.equal(runner.isInTransaction(), true);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
assert.deepEqual(controls.calls, ["BEGIN", "COMMIT"]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("nested write transactions inside immediate transactions do not issue nested BEGIN", () => {
|
|
158
|
+
const runner = createDbTransactionRunner();
|
|
159
|
+
const controls = new FakeTransactionControls();
|
|
160
|
+
|
|
161
|
+
runner.immediateTransaction(controls, () => {
|
|
162
|
+
runner.transaction(controls, () => {
|
|
163
|
+
assert.equal(runner.isInTransaction(), true);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
assert.deepEqual(controls.calls, ["BEGIN IMMEDIATE", "COMMIT"]);
|
|
168
|
+
});
|
|
110
169
|
});
|
|
@@ -920,9 +920,9 @@ describe('db-writer', () => {
|
|
|
920
920
|
decision,
|
|
921
921
|
});
|
|
922
922
|
|
|
923
|
-
test('detects deferral in scope
|
|
923
|
+
test('detects deferral in scope when the scope names the slice', () => {
|
|
924
924
|
const result = extractDeferredSliceRef(
|
|
925
|
-
fields('deferral of
|
|
925
|
+
fields('deferral of slice M001/S03', 'Move low-priority work to backlog', ''),
|
|
926
926
|
);
|
|
927
927
|
assert.deepStrictEqual(result, { milestoneId: 'M001', sliceId: 'S03' });
|
|
928
928
|
});
|
|
@@ -950,14 +950,14 @@ describe('db-writer', () => {
|
|
|
950
950
|
|
|
951
951
|
test('recognises "deferring" variant', () => {
|
|
952
952
|
const result = extractDeferredSliceRef(
|
|
953
|
-
fields('
|
|
953
|
+
fields('slice prioritization', 'deferring M005/S02 until later', ''),
|
|
954
954
|
);
|
|
955
955
|
assert.deepStrictEqual(result, { milestoneId: 'M005', sliceId: 'S02' });
|
|
956
956
|
});
|
|
957
957
|
|
|
958
958
|
test('recognises "defers" variant', () => {
|
|
959
959
|
const result = extractDeferredSliceRef(
|
|
960
|
-
fields('team defers slice
|
|
960
|
+
fields('slice prioritization', 'team defers slice M100/S10', ''),
|
|
961
961
|
);
|
|
962
962
|
assert.deepStrictEqual(result, { milestoneId: 'M100', sliceId: 'S10' });
|
|
963
963
|
});
|
|
@@ -969,6 +969,17 @@ describe('db-writer', () => {
|
|
|
969
969
|
assert.deepStrictEqual(result, { milestoneId: 'M003', sliceId: 'S01' });
|
|
970
970
|
});
|
|
971
971
|
|
|
972
|
+
test('does not treat a planning scope reference as a deferred slice', () => {
|
|
973
|
+
const result = extractDeferredSliceRef(
|
|
974
|
+
fields(
|
|
975
|
+
'planning',
|
|
976
|
+
'Plan S01 as the happy-path money loop only; Defer full duplicate/replay idempotency + polling reconciliation backstop (R006).',
|
|
977
|
+
'M003/S01 scope boundary for the BTC money loop (which requirements land in the first slice vs deferred follow-on slices).',
|
|
978
|
+
),
|
|
979
|
+
);
|
|
980
|
+
assert.strictEqual(result, null);
|
|
981
|
+
});
|
|
982
|
+
|
|
972
983
|
test('returns null when no deferral keyword is present', () => {
|
|
973
984
|
const result = extractDeferredSliceRef(
|
|
974
985
|
fields('approved work', 'M001/S01 is ready', 'proceed with M001/S01'),
|
|
@@ -6,7 +6,8 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
8
8
|
|
|
9
|
-
import { runDispatch
|
|
9
|
+
import { runDispatch } from "../auto/dispatch.ts";
|
|
10
|
+
import { runPreDispatch } from "../auto/pre-dispatch.ts";
|
|
10
11
|
import { AutoSession } from "../auto/session.ts";
|
|
11
12
|
import { resolveUnitSupervisionTimeouts } from "../auto-timers.ts";
|
|
12
13
|
import { bootstrapAutoSession } from "../auto-start.ts";
|