@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
|
@@ -8,7 +8,12 @@ import type { ExtensionAPI } from "@gsd/pi-coding-agent";
|
|
|
8
8
|
import { createBashTool, createEditTool, createReadTool, createWriteTool } from "@gsd/pi-coding-agent";
|
|
9
9
|
|
|
10
10
|
import { logWarning } from "../workflow-logger.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getWorkflowDatabaseStatus,
|
|
13
|
+
openWorkflowDatabase,
|
|
14
|
+
type WorkflowDatabaseOpenResult,
|
|
15
|
+
type WorkflowDatabaseStatus,
|
|
16
|
+
} from "../db-workspace.js";
|
|
12
17
|
import { getAutoWorktreePath } from "../auto-worktree.js";
|
|
13
18
|
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
14
19
|
import { worktreesDirs } from "../worktree-placement.js";
|
|
@@ -69,15 +74,60 @@ export function resolveWorkflowToolBasePath(
|
|
|
69
74
|
|
|
70
75
|
export { resolveProjectRootDbPath } from "../db-workspace.js";
|
|
71
76
|
|
|
77
|
+
type WorkflowDatabaseOpenFailure = Extract<WorkflowDatabaseOpenResult, { ok: false }>;
|
|
78
|
+
|
|
79
|
+
function sqliteProviderHint(status: WorkflowDatabaseStatus, nodeVersion: string): string {
|
|
80
|
+
if (status.provider) return `Provider: ${status.provider}.`;
|
|
81
|
+
|
|
82
|
+
const major = Number.parseInt(nodeVersion.split(".")[0] ?? "", 10);
|
|
83
|
+
if (Number.isFinite(major) && major < 22) {
|
|
84
|
+
return (
|
|
85
|
+
`No SQLite provider available. Upgrade Node to >= 22.0.0 (current: v${nodeVersion}), ` +
|
|
86
|
+
"use the packaged GSD runtime, or install/restore better-sqlite3 in this runtime."
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return (
|
|
91
|
+
"No SQLite provider available. Use a Node build with node:sqlite enabled, " +
|
|
92
|
+
"run the packaged GSD runtime, or install/restore better-sqlite3 in this runtime."
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function dbOpenPhaseHint(status: WorkflowDatabaseStatus): string {
|
|
97
|
+
if (status.lastPhase === "open") return "The database file could not be opened";
|
|
98
|
+
if (status.lastPhase === "initSchema") return "The database schema could not be initialized";
|
|
99
|
+
if (status.lastPhase === "vacuum-recovery") return "Corruption recovery (VACUUM) failed";
|
|
100
|
+
if (status.attempted) return "The database could not be opened";
|
|
101
|
+
return "The database provider could not be loaded";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function formatWorkflowDatabaseOpenFailure(
|
|
105
|
+
result: WorkflowDatabaseOpenFailure,
|
|
106
|
+
status?: WorkflowDatabaseStatus,
|
|
107
|
+
nodeVersion: string = process.versions.node,
|
|
108
|
+
): string {
|
|
109
|
+
if (result.reason === "missing-gsd-dir") {
|
|
110
|
+
return `ensureDbOpen failed — no .gsd directory found at ${result.location.projectGsd}`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (result.reason === "missing-database") {
|
|
114
|
+
return `ensureDbOpen failed — no GSD database found at ${result.location.projectDb}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const resolvedStatus = status ?? getWorkflowDatabaseStatus();
|
|
118
|
+
const detail = result.error?.message ?? resolvedStatus.lastError?.message ?? "";
|
|
119
|
+
const detailSuffix = detail ? ` (${detail})` : "";
|
|
120
|
+
return (
|
|
121
|
+
`ensureDbOpen failed for ${result.location.projectDb}: ` +
|
|
122
|
+
`${dbOpenPhaseHint(resolvedStatus)}${detailSuffix}. ${sqliteProviderHint(resolvedStatus, nodeVersion)}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
72
126
|
export async function ensureDbOpen(basePath: string = safeWorkspaceCwd()): Promise<boolean> {
|
|
73
127
|
const result = openWorkflowDatabase(basePath);
|
|
74
128
|
if (result.ok) return true;
|
|
75
129
|
|
|
76
|
-
|
|
77
|
-
logWarning("bootstrap", "ensureDbOpen failed — no .gsd directory found");
|
|
78
|
-
} else {
|
|
79
|
-
logWarning("bootstrap", `ensureDbOpen failed: ${result.error?.message ?? "open failed"}`);
|
|
80
|
-
}
|
|
130
|
+
logWarning("bootstrap", formatWorkflowDatabaseOpenFailure(result));
|
|
81
131
|
return false;
|
|
82
132
|
}
|
|
83
133
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
2
2
|
|
|
3
|
-
import { checkRemoteAutoSession, isAutoActive, isAutoPaused, stopAutoRemote } from "../auto.js";
|
|
3
|
+
import { checkRemoteAutoSession, forceStopAutoRemote, isAutoActive, isAutoPaused, stopAutoRemote } from "../auto.js";
|
|
4
4
|
import { validateDirectory } from "../validate-directory.js";
|
|
5
5
|
import { resolveProjectRoot } from "../worktree.js";
|
|
6
6
|
import { showNextAction } from "../../shared/tui.js";
|
|
@@ -155,5 +155,19 @@ export async function guardRemoteSession(
|
|
|
155
155
|
return false;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
if (choice === "force") {
|
|
159
|
+
const result = forceStopAutoRemote(projectRoot());
|
|
160
|
+
if (result.error) {
|
|
161
|
+
ctx.ui.notify(`Failed to force-stop remote auto-mode: ${result.error}`, "error");
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (result.found) {
|
|
165
|
+
ctx.ui.notify(`Force-stopped auto-mode session (PID ${result.pid}). Starting a new session.`, "warning");
|
|
166
|
+
} else {
|
|
167
|
+
ctx.ui.notify("Remote session is no longer running. Starting a new session.", "info");
|
|
168
|
+
}
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return false;
|
|
159
173
|
}
|
|
@@ -102,7 +102,7 @@ export function formatMcpStatusReport(servers: McpServerStatus[]): string {
|
|
|
102
102
|
: s.connected
|
|
103
103
|
? `connected — ${s.toolCount} tools`
|
|
104
104
|
: s.available
|
|
105
|
-
? `available — ${s.toolCount} tools`
|
|
105
|
+
? `probe available — ${s.toolCount} tools`
|
|
106
106
|
: "disconnected";
|
|
107
107
|
const warningText = s.envWarnings?.length ? ` — ${s.envWarnings.length} warning(s)` : "";
|
|
108
108
|
lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}${warningText}`);
|
|
@@ -128,7 +128,7 @@ export function formatMcpServerDetail(server: McpServerDetail): string {
|
|
|
128
128
|
lines.push(` Status: error`);
|
|
129
129
|
lines.push(` Error: ${server.error}`);
|
|
130
130
|
} else if (server.connected || server.available) {
|
|
131
|
-
lines.push(` Status: ${server.connected ? "connected" : "available"}`);
|
|
131
|
+
lines.push(` Status: ${server.connected ? "connected" : "probe available"}`);
|
|
132
132
|
lines.push(` Tools: ${server.toolCount}`);
|
|
133
133
|
if (server.tools.length > 0) {
|
|
134
134
|
lines.push("");
|
|
@@ -80,13 +80,13 @@ function datePrefix(): string {
|
|
|
80
80
|
|
|
81
81
|
// ─── State Types ─────────────────────────────────────────────────────────────
|
|
82
82
|
|
|
83
|
-
interface WorkflowPhaseState {
|
|
83
|
+
export interface WorkflowPhaseState {
|
|
84
84
|
name: string;
|
|
85
85
|
index: number;
|
|
86
86
|
status: "pending" | "active" | "completed";
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
interface WorkflowState {
|
|
89
|
+
export interface WorkflowState {
|
|
90
90
|
template: string;
|
|
91
91
|
templateName: string;
|
|
92
92
|
description: string;
|
|
@@ -99,6 +99,13 @@ interface WorkflowState {
|
|
|
99
99
|
artifactDir: string;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
export function isWorkflowStateComplete(state: WorkflowState): boolean {
|
|
103
|
+
if (state.completedAt) return true;
|
|
104
|
+
return Array.isArray(state.phases) &&
|
|
105
|
+
state.phases.length > 0 &&
|
|
106
|
+
state.phases.every((phase) => phase.status === "completed");
|
|
107
|
+
}
|
|
108
|
+
|
|
102
109
|
/**
|
|
103
110
|
* Write a STATE.json file to track workflow execution state.
|
|
104
111
|
*/
|
|
@@ -133,7 +140,7 @@ function writeWorkflowState(
|
|
|
133
140
|
* Scan all workflow artifact directories for in-progress STATE.json files.
|
|
134
141
|
* Returns workflows that were started but not completed.
|
|
135
142
|
*/
|
|
136
|
-
function findInProgressWorkflows(basePath: string): WorkflowState[] {
|
|
143
|
+
export function findInProgressWorkflows(basePath: string): WorkflowState[] {
|
|
137
144
|
const workflowsRoot = join(gsdRoot(basePath), "workflows");
|
|
138
145
|
if (!existsSync(workflowsRoot)) return [];
|
|
139
146
|
|
|
@@ -152,7 +159,7 @@ function findInProgressWorkflows(basePath: string): WorkflowState[] {
|
|
|
152
159
|
try {
|
|
153
160
|
const raw = readFileSync(statePath, "utf-8");
|
|
154
161
|
const state = JSON.parse(raw) as WorkflowState;
|
|
155
|
-
if (!state
|
|
162
|
+
if (!isWorkflowStateComplete(state)) {
|
|
156
163
|
results.push(state);
|
|
157
164
|
}
|
|
158
165
|
} catch { /* corrupted state file — skip */ }
|
|
@@ -223,6 +223,7 @@ export function writeLock(
|
|
|
223
223
|
* stale session-file pointer.
|
|
224
224
|
*/
|
|
225
225
|
export function clearLock(basePath: string): void {
|
|
226
|
+
const legacyLock = readLegacyLock(basePath);
|
|
226
227
|
clearLegacyLockFile(basePath);
|
|
227
228
|
|
|
228
229
|
if (!isDbAvailable()) return;
|
|
@@ -235,8 +236,15 @@ export function clearLock(basePath: string): void {
|
|
|
235
236
|
deleteRuntimeKv("worker", staleWorker.worker_id, SESSION_FILE_KV_KEY);
|
|
236
237
|
return;
|
|
237
238
|
}
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
if (legacyLock?.pid) {
|
|
240
|
+
markWorkerStoppingByPid(projectRoot, legacyLock.pid);
|
|
241
|
+
const workerByLegacyPid = getAllAutoWorkers().find(
|
|
242
|
+
(w) =>
|
|
243
|
+
w.pid === legacyLock.pid
|
|
244
|
+
&& normalizeRealPath(w.project_root_realpath) === projectRoot,
|
|
245
|
+
);
|
|
246
|
+
if (workerByLegacyPid) forceReleaseLeasesForWorker(workerByLegacyPid.worker_id);
|
|
247
|
+
}
|
|
240
248
|
const worker = findActiveWorkerForCurrentProcess(projectRoot);
|
|
241
249
|
if (worker) deleteRuntimeKv("worker", worker.worker_id, SESSION_FILE_KV_KEY);
|
|
242
250
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: GSD engine — connection ownership, lifecycle, schema/migrations,
|
|
3
3
|
// and transaction primitives for the single-writer layer. The shared handle
|
|
4
|
-
// (currentDb) lives here;
|
|
5
|
-
// (db/queries.ts) read
|
|
4
|
+
// (currentDb) lives here; domain writers, allowlisted coordination/runtime
|
|
5
|
+
// writers, schema/migration helpers, and the Query Module (db/queries.ts) read
|
|
6
|
+
// it through getDb()/getDbOrNull().
|
|
6
7
|
//
|
|
7
8
|
// This file legitimately holds DDL and BEGIN/COMMIT control, so it is
|
|
8
|
-
// allowlisted in tests/single-writer-invariant.test.ts alongside
|
|
9
|
+
// allowlisted in tests/single-writer-invariant.test.ts alongside the explicit
|
|
10
|
+
// writer layer.
|
|
9
11
|
import { createRequire } from "node:module";
|
|
10
12
|
import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
|
|
11
13
|
import { dirname, join } from "node:path";
|
|
@@ -16,7 +18,7 @@ import { createDbAdapter, type DbAdapter } from "../db-adapter.js";
|
|
|
16
18
|
import { createBaseSchemaObjects } from "../db-base-schema.js";
|
|
17
19
|
import { createCoordinationTablesV24 } from "../db-coordination-schema.js";
|
|
18
20
|
import { createDbConnectionCache, type DbConnectionCacheEntry } from "../db-connection-cache.js";
|
|
19
|
-
import { backupDatabaseBeforeMigration } from "../db-migration-backup.js";
|
|
21
|
+
import { backupDatabaseBeforeMigration, isMigrationBackupError } from "../db-migration-backup.js";
|
|
20
22
|
import {
|
|
21
23
|
applyMigrationV2Artifacts,
|
|
22
24
|
applyMigrationV3Memories,
|
|
@@ -601,8 +603,9 @@ export function openDatabase(path: string): boolean {
|
|
|
601
603
|
initSchema(adapter, fileBacked, path);
|
|
602
604
|
} catch (err) {
|
|
603
605
|
// Corrupt freelist: DDL fails with "malformed" but VACUUM can rebuild.
|
|
604
|
-
//
|
|
605
|
-
|
|
606
|
+
// Pre-migration backup failures are already pre-DDL and must propagate
|
|
607
|
+
// instead of being masked by VACUUM recovery (see #2519).
|
|
608
|
+
if (shouldAttemptVacuumRecovery(fileBacked, err)) {
|
|
606
609
|
try {
|
|
607
610
|
adapter.exec("VACUUM");
|
|
608
611
|
initSchema(adapter, fileBacked, path);
|
|
@@ -634,6 +637,12 @@ export function openDatabase(path: string): boolean {
|
|
|
634
637
|
return true;
|
|
635
638
|
}
|
|
636
639
|
|
|
640
|
+
function shouldAttemptVacuumRecovery(fileBacked: boolean, err: unknown): boolean {
|
|
641
|
+
return fileBacked && err instanceof Error && err.message.includes("malformed") && !isMigrationBackupError(err);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export const _shouldAttemptVacuumRecoveryForTest = shouldAttemptVacuumRecovery;
|
|
645
|
+
|
|
637
646
|
export function closeDatabase(): void {
|
|
638
647
|
if (currentDb) {
|
|
639
648
|
try {
|
|
@@ -735,6 +744,7 @@ function createTransactionControls(db: DbAdapter) {
|
|
|
735
744
|
return {
|
|
736
745
|
begin: () => db.exec("BEGIN"),
|
|
737
746
|
beginRead: () => db.exec("BEGIN DEFERRED"),
|
|
747
|
+
beginImmediate: () => db.exec("BEGIN IMMEDIATE"),
|
|
738
748
|
commit: () => db.exec("COMMIT"),
|
|
739
749
|
rollback: () => db.exec("ROLLBACK"),
|
|
740
750
|
};
|
|
@@ -755,6 +765,16 @@ export function transaction<T>(fn: () => T): T {
|
|
|
755
765
|
return _transactionRunner.transaction(createTransactionControls(currentDb), fn);
|
|
756
766
|
}
|
|
757
767
|
|
|
768
|
+
/**
|
|
769
|
+
* Run a BEGIN IMMEDIATE write transaction for operations that need SQLite's
|
|
770
|
+
* reserved writer lock before issuing updates. Re-entrant like transaction():
|
|
771
|
+
* nested calls run inside the outer transaction without a nested BEGIN.
|
|
772
|
+
*/
|
|
773
|
+
export function immediateTransaction<T>(fn: () => T): T {
|
|
774
|
+
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
775
|
+
return _transactionRunner.immediateTransaction(createTransactionControls(currentDb), fn);
|
|
776
|
+
}
|
|
777
|
+
|
|
758
778
|
/**
|
|
759
779
|
* Wrap a block of reads in a DEFERRED transaction so that all SELECTs observe
|
|
760
780
|
* a consistent snapshot of the DB even if a concurrent writer commits between
|
|
@@ -270,6 +270,35 @@ export function getMilestoneSlices(milestoneId: string): SliceRow[] {
|
|
|
270
270
|
return rows.map(rowToSlice);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
|
+
/**
|
|
274
|
+
* Load slices for many milestones in a single query. Returns a Map keyed by
|
|
275
|
+
* milestone_id, preserving `ORDER BY sequence, id` within each bucket.
|
|
276
|
+
*/
|
|
277
|
+
export function getSlicesByMilestoneIds(milestoneIds: readonly string[]): Map<string, SliceRow[]> {
|
|
278
|
+
const db = getDbOrNull();
|
|
279
|
+
if (!db || milestoneIds.length === 0) return new Map();
|
|
280
|
+
const idList = [...milestoneIds];
|
|
281
|
+
const placeholders = idList.map((_, i) => `:mid${i}`).join(",");
|
|
282
|
+
const params: Record<string, unknown> = {};
|
|
283
|
+
idList.forEach((id, i) => {
|
|
284
|
+
params[`:mid${i}`] = id;
|
|
285
|
+
});
|
|
286
|
+
const rows = db
|
|
287
|
+
.prepare(`SELECT * FROM slices WHERE milestone_id IN (${placeholders}) ORDER BY milestone_id, sequence, id`)
|
|
288
|
+
.all(params) as Record<string, unknown>[];
|
|
289
|
+
const byMilestone = new Map<string, SliceRow[]>();
|
|
290
|
+
for (const row of rows) {
|
|
291
|
+
const slice = rowToSlice(row);
|
|
292
|
+
const bucket = byMilestone.get(slice.milestone_id);
|
|
293
|
+
if (bucket) {
|
|
294
|
+
bucket.push(slice);
|
|
295
|
+
} else {
|
|
296
|
+
byMilestone.set(slice.milestone_id, [slice]);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return byMilestone;
|
|
300
|
+
}
|
|
301
|
+
|
|
273
302
|
/** Dispatch-eligibility shape consumed by decision-path callers (ADR-017). */
|
|
274
303
|
export interface MilestoneSliceSummary {
|
|
275
304
|
id: string;
|
|
@@ -9,6 +9,26 @@ export interface MigrationBackupDeps {
|
|
|
9
9
|
logWarning(scope: string, message: string): void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/** Marks pre-migration backup failures so DB-open recovery cannot mask them. */
|
|
13
|
+
export class MigrationBackupError extends Error {
|
|
14
|
+
constructor(message: string, cause?: unknown) {
|
|
15
|
+
super(message, { cause });
|
|
16
|
+
this.name = "MigrationBackupError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Returns true for errors raised while checkpointing or copying a migration backup. */
|
|
21
|
+
export function isMigrationBackupError(err: unknown): err is MigrationBackupError {
|
|
22
|
+
return err instanceof MigrationBackupError;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a same-version backup before file-backed schema migrations.
|
|
27
|
+
*
|
|
28
|
+
* Existing same-version backups are reused. New backups fail closed: WAL
|
|
29
|
+
* checkpoint failures, incomplete checkpoints, and copy failures are logged
|
|
30
|
+
* and then rethrown before migration DDL runs.
|
|
31
|
+
*/
|
|
12
32
|
export function backupDatabaseBeforeMigration(
|
|
13
33
|
db: DbAdapter,
|
|
14
34
|
dbPath: string | null,
|
|
@@ -21,14 +41,43 @@ export function backupDatabaseBeforeMigration(
|
|
|
21
41
|
const backupPath = `${dbPath}.backup-v${currentVersion}`;
|
|
22
42
|
if (deps.existsSync(backupPath)) return;
|
|
23
43
|
|
|
24
|
-
|
|
25
|
-
db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
|
|
26
|
-
} catch {
|
|
27
|
-
// Checkpoint is best effort; copying the base file is still better than no backup.
|
|
28
|
-
}
|
|
44
|
+
checkpointWal(db);
|
|
29
45
|
deps.copyFileSync(dbPath, backupPath);
|
|
30
46
|
} catch (backupErr) {
|
|
31
|
-
const
|
|
32
|
-
deps.logWarning("db", `Pre-migration backup failed: ${message}`);
|
|
47
|
+
const error = toMigrationBackupError(backupErr);
|
|
48
|
+
deps.logWarning("db", `Pre-migration backup failed: ${error.message}`);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function checkpointWal(db: DbAdapter): void {
|
|
54
|
+
const row = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
|
|
55
|
+
if (!isCheckpointComplete(row)) {
|
|
56
|
+
const busy = formatCheckpointValue(row, "busy");
|
|
57
|
+
const log = formatCheckpointValue(row, "log");
|
|
58
|
+
const checkpointed = formatCheckpointValue(row, "checkpointed");
|
|
59
|
+
throw new MigrationBackupError(
|
|
60
|
+
`WAL checkpoint incomplete: busy=${busy} log=${log} checkpointed=${checkpointed}`,
|
|
61
|
+
);
|
|
33
62
|
}
|
|
34
63
|
}
|
|
64
|
+
|
|
65
|
+
function isCheckpointComplete(row: Record<string, unknown> | undefined): boolean {
|
|
66
|
+
if (!row) return false;
|
|
67
|
+
const busy = Number(row["busy"]);
|
|
68
|
+
const log = Number(row["log"]);
|
|
69
|
+
const checkpointed = Number(row["checkpointed"]);
|
|
70
|
+
if (!Number.isFinite(busy) || !Number.isFinite(log) || !Number.isFinite(checkpointed)) return false;
|
|
71
|
+
return busy === 0 && log === checkpointed;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function formatCheckpointValue(row: Record<string, unknown> | undefined, key: string): string {
|
|
75
|
+
const value = row?.[key];
|
|
76
|
+
return value === undefined ? "unknown" : String(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function toMigrationBackupError(err: unknown): MigrationBackupError {
|
|
80
|
+
if (isMigrationBackupError(err)) return err;
|
|
81
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
82
|
+
return new MigrationBackupError(message, err);
|
|
83
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export interface DbTransactionControls {
|
|
5
5
|
begin(): void;
|
|
6
6
|
beginRead(): void;
|
|
7
|
+
/** Starts a write transaction that obtains SQLite's reserved lock up front. */
|
|
8
|
+
beginImmediate?(): void;
|
|
7
9
|
commit(): void;
|
|
8
10
|
rollback(): void;
|
|
9
11
|
}
|
|
@@ -16,45 +18,47 @@ export class DbTransactionRunner {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
transaction<T>(controls: DbTransactionControls, fn: () => T): T {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
21
|
+
return this.runTransaction(controls, () => controls.begin(), fn);
|
|
22
|
+
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
controls.rollback();
|
|
31
|
-
throw err;
|
|
32
|
-
} finally {
|
|
33
|
-
this.depth--;
|
|
24
|
+
/**
|
|
25
|
+
* Run a BEGIN IMMEDIATE transaction through the same depth counter as regular
|
|
26
|
+
* transactions so callers can compose it inside existing transaction scopes.
|
|
27
|
+
*/
|
|
28
|
+
immediateTransaction<T>(controls: DbTransactionControls, fn: () => T): T {
|
|
29
|
+
if (!controls.beginImmediate) {
|
|
30
|
+
throw new Error("db transaction controls do not support immediate transactions");
|
|
34
31
|
}
|
|
32
|
+
|
|
33
|
+
return this.runTransaction(controls, () => controls.beginImmediate!(), fn);
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
readTransaction<T>(
|
|
38
37
|
controls: DbTransactionControls,
|
|
39
38
|
fn: () => T,
|
|
40
39
|
logRollbackError: (error: Error) => void,
|
|
40
|
+
): T {
|
|
41
|
+
return this.runTransaction(controls, () => controls.beginRead(), fn, logRollbackError);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private runTransaction<T>(
|
|
45
|
+
controls: DbTransactionControls,
|
|
46
|
+
begin: () => void,
|
|
47
|
+
fn: () => T,
|
|
48
|
+
logRollbackError?: (error: Error) => void,
|
|
41
49
|
): T {
|
|
42
50
|
if (this.depth > 0) {
|
|
43
51
|
return this.runNested(fn);
|
|
44
52
|
}
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
begin();
|
|
47
55
|
this.depth++;
|
|
48
56
|
try {
|
|
49
57
|
const result = fn();
|
|
50
58
|
controls.commit();
|
|
51
59
|
return result;
|
|
52
60
|
} catch (err) {
|
|
53
|
-
|
|
54
|
-
controls.rollback();
|
|
55
|
-
} catch (rollbackErr) {
|
|
56
|
-
logRollbackError(rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr)));
|
|
57
|
-
}
|
|
61
|
+
this.rollback(controls, logRollbackError);
|
|
58
62
|
throw err;
|
|
59
63
|
} finally {
|
|
60
64
|
this.depth--;
|
|
@@ -69,6 +73,19 @@ export class DbTransactionRunner {
|
|
|
69
73
|
this.depth--;
|
|
70
74
|
}
|
|
71
75
|
}
|
|
76
|
+
|
|
77
|
+
private rollback(controls: DbTransactionControls, logRollbackError?: (error: Error) => void): void {
|
|
78
|
+
if (!logRollbackError) {
|
|
79
|
+
controls.rollback();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
controls.rollback();
|
|
85
|
+
} catch (rollbackErr) {
|
|
86
|
+
logRollbackError(rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr)));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
export function createDbTransactionRunner(): DbTransactionRunner {
|
|
@@ -714,31 +714,23 @@ async function mirrorDecisionToMemory(
|
|
|
714
714
|
/**
|
|
715
715
|
* Extract a milestone/slice reference from a deferral decision.
|
|
716
716
|
*
|
|
717
|
-
* Detects deferrals
|
|
718
|
-
* - scope contains "defer" (e.g., "deferral", "defer")
|
|
719
|
-
* - choice or decision contains "defer" + an M###/S## pattern
|
|
717
|
+
* Detects deferrals when the slice reference is part of the deferral phrase.
|
|
720
718
|
*
|
|
721
719
|
* Returns { milestoneId, sliceId } if found, null otherwise.
|
|
722
720
|
*/
|
|
723
721
|
export function extractDeferredSliceRef(
|
|
724
722
|
fields: Pick<SaveDecisionFields, 'scope' | 'decision' | 'choice'>,
|
|
725
723
|
): { milestoneId: string; sliceId: string } | null {
|
|
726
|
-
const
|
|
727
|
-
/\bdefer(?:ral|red|ring|s)?\b/i
|
|
728
|
-
|
|
729
|
-
/\
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (choiceMatch) {
|
|
737
|
-
return { milestoneId: choiceMatch[1], sliceId: choiceMatch[2] };
|
|
738
|
-
}
|
|
739
|
-
const decisionMatch = fields.decision.match(slicePattern);
|
|
740
|
-
if (decisionMatch) {
|
|
741
|
-
return { milestoneId: decisionMatch[1], sliceId: decisionMatch[2] };
|
|
724
|
+
const defersSlicePattern =
|
|
725
|
+
/\bdefer(?:ral|red|ring|s)?\b\s+(?:(?:of|the)\s+)*(?:slice\s+)?\b(M\d{3,4})\/(S\d{2,3})\b/i;
|
|
726
|
+
const sliceIsDeferredPattern =
|
|
727
|
+
/\b(M\d{3,4})\/(S\d{2,3})\b\s+(?:is|was|will be|should be|can be)\s+defer(?:red|ring)?\b/i;
|
|
728
|
+
|
|
729
|
+
for (const text of [fields.choice, fields.decision, fields.scope]) {
|
|
730
|
+
const match = text.match(defersSlicePattern) ?? text.match(sliceIsDeferredPattern);
|
|
731
|
+
if (match) {
|
|
732
|
+
return { milestoneId: match[1], sliceId: match[2] };
|
|
733
|
+
}
|
|
742
734
|
}
|
|
743
735
|
|
|
744
736
|
return null;
|
|
@@ -6,8 +6,9 @@ import { isDbAvailable, _getAdapter } from "./gsd-db.js";
|
|
|
6
6
|
import { isAfter, latestExplicitReopenAt } from "./milestone-reopen-events.js";
|
|
7
7
|
import { resolveGsdPathContract, resolveMilestoneFile } from "./paths.js";
|
|
8
8
|
import { deriveState } from "./state.js";
|
|
9
|
+
import { workflowEventLogPath } from "./workflow-event-ledger.js";
|
|
9
10
|
import { readEvents } from "./workflow-events.js";
|
|
10
|
-
import {
|
|
11
|
+
import { flushWorkflowProjections } from "./projection-flush.js";
|
|
11
12
|
|
|
12
13
|
export async function checkEngineHealth(
|
|
13
14
|
basePath: string,
|
|
@@ -260,7 +261,7 @@ export async function checkEngineHealth(
|
|
|
260
261
|
// relative to the event log and re-render them.
|
|
261
262
|
try {
|
|
262
263
|
if (isDbAvailable()) {
|
|
263
|
-
const eventLogPath =
|
|
264
|
+
const eventLogPath = workflowEventLogPath(basePath);
|
|
264
265
|
const events = readEvents(eventLogPath);
|
|
265
266
|
if (events.length > 0) {
|
|
266
267
|
const lastEventTs = new Date(events[events.length - 1]!.ts).getTime();
|
|
@@ -270,7 +271,7 @@ export async function checkEngineHealth(
|
|
|
270
271
|
const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
|
|
271
272
|
if (!roadmapPath || !existsSync(roadmapPath)) {
|
|
272
273
|
try {
|
|
273
|
-
await
|
|
274
|
+
await flushWorkflowProjections(basePath, { milestoneId: milestone.id });
|
|
274
275
|
fixesApplied.push(`re-rendered missing projections for ${milestone.id}`);
|
|
275
276
|
} catch {
|
|
276
277
|
// Non-fatal — projection re-render failed
|
|
@@ -280,7 +281,7 @@ export async function checkEngineHealth(
|
|
|
280
281
|
const projectionMtime = statSync(roadmapPath).mtimeMs;
|
|
281
282
|
if (lastEventTs > projectionMtime) {
|
|
282
283
|
try {
|
|
283
|
-
await
|
|
284
|
+
await flushWorkflowProjections(basePath, { milestoneId: milestone.id });
|
|
284
285
|
fixesApplied.push(`re-rendered stale projections for ${milestone.id}`);
|
|
285
286
|
} catch {
|
|
286
287
|
// Non-fatal — projection re-render failed
|