@opengsd/gsd-pi 1.3.0-dev.65546769 → 1.3.0-dev.72e3af2a
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +11 -2
- package/dist/resources/extensions/google-cli/stream-adapter.js +82 -15
- package/dist/resources/extensions/gsd/artifact-verification.js +427 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +12 -3
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +28 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +20 -19
- package/dist/resources/extensions/gsd/auto-prompts.js +26 -11
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -507
- package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -5
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +103 -13
- package/dist/resources/extensions/gsd/bootstrap/core-session-tools.js +38 -0
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +6 -1
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +10 -19
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -19
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +68 -10
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -1
- package/dist/resources/extensions/gsd/commands-context.js +19 -1
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +16 -10
- package/dist/resources/extensions/gsd/commands-worktree.js +12 -10
- package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -3
- package/dist/resources/extensions/gsd/db/queries.js +60 -0
- package/dist/resources/extensions/gsd/db-workspace.js +55 -3
- package/dist/resources/extensions/gsd/doctor-providers.js +92 -8
- package/dist/resources/extensions/gsd/exec-sandbox.js +45 -9
- package/dist/resources/extensions/gsd/forensics.js +2 -32
- package/dist/resources/extensions/gsd/git-service.js +4 -4
- package/dist/resources/extensions/gsd/guided-flow-queue.js +66 -5
- package/dist/resources/extensions/gsd/health-widget.js +55 -29
- package/dist/resources/extensions/gsd/layout-policy.js +3 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +8 -9
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +44 -21
- package/dist/resources/extensions/gsd/migration-auto-check.js +22 -0
- package/dist/resources/extensions/gsd/milestone-ids.js +32 -2
- package/dist/resources/extensions/gsd/milestone-implementation-evidence.js +26 -20
- package/dist/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/dist/resources/extensions/gsd/quick.js +45 -2
- package/dist/resources/extensions/gsd/session-forensics.js +11 -1
- package/dist/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/dist/resources/extensions/gsd/state/derive/cache.js +28 -0
- package/dist/resources/extensions/gsd/state/derive/db-open.js +39 -0
- package/dist/resources/extensions/gsd/state/derive/from-db.js +452 -0
- package/dist/resources/extensions/gsd/state/derive/index.js +75 -0
- package/dist/resources/extensions/gsd/state/derive/interrupted-work.js +21 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +45 -2
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +48 -23
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +32 -28
- package/dist/resources/extensions/gsd/state.js +12 -611
- package/dist/resources/extensions/gsd/tools/complete-slice.js +2 -2
- package/dist/resources/extensions/gsd/tools/complete-task.js +43 -14
- package/dist/resources/extensions/gsd/tools/exec-tool.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +23 -7
- package/dist/resources/extensions/gsd/unit-registry.js +32 -4
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +33 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +9 -4
- package/dist/resources/extensions/gsd/workflow-projections.js +19 -14
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +30 -1
- package/dist/resources/extensions/gsd/worktree-manager.js +44 -2
- 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 +10 -10
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +9 -9
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page_client-reference-manifest.js +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/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/{2659.b7b129ee6a769448.js → 2659.58e950899a9bb82f.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/2772.a7c1fcc69a4685ef.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{3616.3c60753b8ffcbd2e.js → 3616.61a2af74bb8833c8.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{4283.8e446784528ed9dc.js → 4283.d0d9e0a955e441cb.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{5826.a46ecdd1cfe8dabc.js → 5826.5421d66c72b9f34e.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/{8785.481aa5869991b760.js → 8785.e29b3134cab1d153.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/8937.640dc9c2aaa1dfad.js +10 -0
- package/dist/web/standalone/.next/static/chunks/app/{page-6644fc6ee8ca1247.js → page-72a856634ad14c10.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-9c401904f87ded16.js +1 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +1 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +2 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/agent-session.d.ts +1 -0
- package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/agent-session.js +3 -0
- package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts +41 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js +62 -0
- package/packages/gsd-agent-core/dist/extension-ui-snapshot.js.map +1 -0
- package/packages/gsd-agent-core/dist/index.d.ts +2 -0
- package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/index.js +2 -0
- package/packages/gsd-agent-core/dist/index.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-events.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +1 -0
- package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts +5 -0
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +60 -3
- package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
- package/packages/gsd-agent-core/dist/transcript-store.d.ts +58 -0
- package/packages/gsd-agent-core/dist/transcript-store.d.ts.map +1 -0
- package/packages/gsd-agent-core/dist/transcript-store.js +132 -0
- package/packages/gsd-agent-core/dist/transcript-store.js.map +1 -0
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +2 -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 +25 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts +4 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js +7 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller-latency.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -24
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -829
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts +58 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js +312 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-handoff-filter.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts +31 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js +130 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-pinned-zone.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts +15 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js +258 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-segment-walker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts +13 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js +118 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-tool-rollup.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts +54 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js +20 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-ui-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +4 -1
- 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 +9 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts +56 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js +44 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/streaming-render-state.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js +77 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/tui-transcript-tracker.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +18 -0
- package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/README.md +1 -1
- package/packages/mcp-server/dist/server.d.ts +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +3 -3
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +13 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +34 -20
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/README.md +3 -2
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js +94 -0
- package/packages/pi-coding-agent/dist/core/session-manager-context.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js +244 -0
- package/packages/pi-coding-agent/dist/core/session-manager-list.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts +12 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js +84 -0
- package/packages/pi-coding-agent/dist/core/session-manager-migration.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts +135 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js +2 -0
- package/packages/pi-coding-agent/dist/core/session-manager-types.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts +6 -154
- package/packages/pi-coding-agent/dist/core/session-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.js +22 -459
- package/packages/pi-coding-agent/dist/core/session-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts +75 -75
- package/packages/pi-coding-agent/dist/theme/theme-schema.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.js +1 -1
- package/packages/pi-coding-agent/dist/theme/theme-schema.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 +11 -7
- 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/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme-schema.d.ts +75 -75
- package/pkg/dist/theme/theme-schema.d.ts.map +1 -1
- package/pkg/dist/theme/theme-schema.js +1 -1
- package/pkg/dist/theme/theme-schema.js.map +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +11 -7
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +20 -2
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +80 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +106 -19
- package/src/resources/extensions/gsd/artifact-verification.ts +464 -0
- package/src/resources/extensions/gsd/auto/orchestrator.ts +25 -11
- package/src/resources/extensions/gsd/auto/session.ts +5 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +47 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +21 -23
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -12
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -508
- package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -5
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +3 -2
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +125 -12
- package/src/resources/extensions/gsd/bootstrap/core-session-tools.ts +43 -0
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +6 -1
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -19
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +52 -18
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +74 -10
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -1
- package/src/resources/extensions/gsd/commands-context.ts +18 -1
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +14 -9
- package/src/resources/extensions/gsd/commands-worktree.ts +12 -10
- package/src/resources/extensions/gsd/dashboard-overlay.ts +32 -3
- package/src/resources/extensions/gsd/db/queries.ts +79 -0
- package/src/resources/extensions/gsd/db-workspace.ts +61 -3
- package/src/resources/extensions/gsd/doctor-providers.ts +103 -9
- package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
- package/src/resources/extensions/gsd/forensics.ts +2 -33
- package/src/resources/extensions/gsd/git-service.ts +5 -5
- package/src/resources/extensions/gsd/guided-flow-queue.ts +89 -4
- package/src/resources/extensions/gsd/health-widget.ts +69 -32
- package/src/resources/extensions/gsd/layout-policy.ts +2 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +8 -11
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +51 -19
- package/src/resources/extensions/gsd/migration-auto-check.ts +23 -0
- package/src/resources/extensions/gsd/milestone-ids.ts +31 -2
- package/src/resources/extensions/gsd/milestone-implementation-evidence.ts +35 -21
- package/src/resources/extensions/gsd/prompts/code-review.md +6 -4
- package/src/resources/extensions/gsd/quick.ts +43 -2
- package/src/resources/extensions/gsd/session-forensics.ts +11 -1
- package/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md +1 -1
- package/src/resources/extensions/gsd/state/derive/cache.ts +46 -0
- package/src/resources/extensions/gsd/state/derive/db-open.ts +45 -0
- package/src/resources/extensions/gsd/state/derive/from-db.ts +561 -0
- package/src/resources/extensions/gsd/state/derive/index.ts +104 -0
- package/src/resources/extensions/gsd/state/derive/interrupted-work.ts +31 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +81 -7
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +50 -24
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +43 -28
- package/src/resources/extensions/gsd/state.ts +32 -732
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +98 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +111 -1
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/commands-gsd-core.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +48 -8
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +55 -2
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/doctor-forensics-db-open-regression.test.ts +70 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +45 -1
- package/src/resources/extensions/gsd/tests/forensics-error-filter.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +268 -3
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +119 -1
- package/src/resources/extensions/gsd/tests/integration/queue-active-milestone-context-budget.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/integration/quick-branch-lifecycle.test.ts +56 -9
- package/src/resources/extensions/gsd/tests/knowledge-cold-start.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +43 -1
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +54 -1
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +50 -14
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +195 -1
- package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +185 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +193 -14
- package/src/resources/extensions/gsd/tests/unmerged-milestone-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +151 -2
- package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +39 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +2 -2
- package/src/resources/extensions/gsd/tools/complete-task.ts +53 -15
- package/src/resources/extensions/gsd/tools/exec-tool.ts +7 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +33 -7
- package/src/resources/extensions/gsd/unit-registry.ts +32 -4
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +41 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +13 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +20 -14
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +31 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -1
- package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +0 -1
- package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +0 -10
- package/dist/web/standalone/.next/static/chunks/webpack-f46ea08200a0227e.js +0 -1
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → O7xDYXO0r4zFhIzY1hrWV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BTKtGFF1Y-hvVJEGhBRo9 → O7xDYXO0r4zFhIzY1hrWV}/_ssgManifest.js +0 -0
|
@@ -1671,19 +1671,25 @@ export function serializePreferencesToFrontmatter(prefs) {
|
|
|
1671
1671
|
const entries = Object.entries(item);
|
|
1672
1672
|
if (entries.length > 0) {
|
|
1673
1673
|
const [firstKey, firstVal] = entries[0];
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
const
|
|
1677
|
-
|
|
1678
|
-
lines.push(`${prefix} ${k}:`);
|
|
1679
|
-
for (const arrItem of v) {
|
|
1680
|
-
lines.push(`${prefix} - ${yamlSafeString(arrItem)}`);
|
|
1681
|
-
}
|
|
1674
|
+
if (Array.isArray(firstVal)) {
|
|
1675
|
+
lines.push(`${prefix} - ${firstKey}:`);
|
|
1676
|
+
for (const arrItem of firstVal) {
|
|
1677
|
+
lines.push(`${prefix} - ${yamlSafeString(arrItem)}`);
|
|
1682
1678
|
}
|
|
1683
|
-
|
|
1684
|
-
|
|
1679
|
+
}
|
|
1680
|
+
else if (typeof firstVal === "object" && firstVal !== null) {
|
|
1681
|
+
lines.push(`${prefix} - ${firstKey}:`);
|
|
1682
|
+
for (const [k, v] of Object.entries(firstVal)) {
|
|
1683
|
+
serializeValue(k, v, indent + 3);
|
|
1685
1684
|
}
|
|
1686
1685
|
}
|
|
1686
|
+
else {
|
|
1687
|
+
lines.push(`${prefix} - ${firstKey}: ${yamlSafeString(firstVal)}`);
|
|
1688
|
+
}
|
|
1689
|
+
for (let i = 1; i < entries.length; i++) {
|
|
1690
|
+
const [k, v] = entries[i];
|
|
1691
|
+
serializeValue(k, v, indent + 2);
|
|
1692
|
+
}
|
|
1687
1693
|
}
|
|
1688
1694
|
}
|
|
1689
1695
|
else {
|
|
@@ -12,9 +12,9 @@ import { inferCommitType } from "./git-service.js";
|
|
|
12
12
|
import { autoCommitCurrentBranch } from "./worktree.js";
|
|
13
13
|
import { GSDError, GSD_GIT_ERROR } from "./errors.js";
|
|
14
14
|
// ─── Status helper ─────────────────────────────────────────────────────────
|
|
15
|
-
function getStatus(basePath, name, wtPath) {
|
|
16
|
-
const diff = diffWorktreeAll(basePath, name);
|
|
17
|
-
const numstat = diffWorktreeNumstat(basePath, name);
|
|
15
|
+
function getStatus(basePath, name, wtPath, mainBranch) {
|
|
16
|
+
const diff = diffWorktreeAll(basePath, name, undefined, mainBranch);
|
|
17
|
+
const numstat = diffWorktreeNumstat(basePath, name, undefined, mainBranch);
|
|
18
18
|
const filesChanged = diff.added.length + diff.modified.length + diff.removed.length;
|
|
19
19
|
let linesAdded = 0;
|
|
20
20
|
let linesRemoved = 0;
|
|
@@ -31,8 +31,7 @@ function getStatus(basePath, name, wtPath) {
|
|
|
31
31
|
}
|
|
32
32
|
let commits = 0;
|
|
33
33
|
try {
|
|
34
|
-
|
|
35
|
-
commits = nativeCommitCountBetween(basePath, main, worktreeBranchName(name));
|
|
34
|
+
commits = nativeCommitCountBetween(basePath, mainBranch, worktreeBranchName(name));
|
|
36
35
|
}
|
|
37
36
|
catch {
|
|
38
37
|
// commit count unavailable → leave at 0
|
|
@@ -88,7 +87,8 @@ export function formatCleanKeepReason(status) {
|
|
|
88
87
|
async function handleList(ctx) {
|
|
89
88
|
const basePath = projectRoot();
|
|
90
89
|
const worktrees = listWorktrees(basePath);
|
|
91
|
-
const
|
|
90
|
+
const mainBranch = worktrees.length > 0 ? nativeDetectMainBranch(basePath) : "";
|
|
91
|
+
const statuses = worktrees.map((wt) => getStatus(basePath, wt.name, wt.path, mainBranch));
|
|
92
92
|
ctx.ui.notify(formatWorktreeList(statuses), "info");
|
|
93
93
|
}
|
|
94
94
|
// ─── Subcommand: merge ──────────────────────────────────────────────────────
|
|
@@ -117,7 +117,8 @@ async function handleMerge(args, ctx) {
|
|
|
117
117
|
ctx.ui.notify(`Worktree "${target}" not found.\n\nAvailable: ${available}`, "error");
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
|
-
const
|
|
120
|
+
const mainBranch = nativeDetectMainBranch(basePath);
|
|
121
|
+
const status = getStatus(basePath, target, wt.path, mainBranch);
|
|
121
122
|
if (status.filesChanged === 0 && !status.uncommitted) {
|
|
122
123
|
try {
|
|
123
124
|
removeWorktree(basePath, target, { deleteBranch: true });
|
|
@@ -144,7 +145,6 @@ async function handleMerge(args, ctx) {
|
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
147
|
const commitType = inferCommitType(target);
|
|
147
|
-
const mainBranch = nativeDetectMainBranch(basePath);
|
|
148
148
|
const commitMessage = `${commitType}: merge worktree ${target}\n\nGSD-Worktree: ${target}`;
|
|
149
149
|
try {
|
|
150
150
|
mergeWorktreeToMain(basePath, target, commitMessage);
|
|
@@ -191,8 +191,9 @@ async function handleClean(ctx) {
|
|
|
191
191
|
}
|
|
192
192
|
const removed = [];
|
|
193
193
|
const kept = [];
|
|
194
|
+
const mainBranch = nativeDetectMainBranch(basePath);
|
|
194
195
|
for (const wt of worktrees) {
|
|
195
|
-
const status = getStatus(basePath, wt.name, wt.path);
|
|
196
|
+
const status = getStatus(basePath, wt.name, wt.path, mainBranch);
|
|
196
197
|
if (status.filesChanged === 0 && !status.uncommitted) {
|
|
197
198
|
try {
|
|
198
199
|
removeWorktree(basePath, wt.name, { deleteBranch: true });
|
|
@@ -238,7 +239,8 @@ async function handleRemove(args, ctx) {
|
|
|
238
239
|
ctx.ui.notify(`Worktree "${name}" not found.\n\nAvailable: ${available}`, "error");
|
|
239
240
|
return;
|
|
240
241
|
}
|
|
241
|
-
const
|
|
242
|
+
const mainBranch = nativeDetectMainBranch(basePath);
|
|
243
|
+
const status = getStatus(basePath, name, wt.path, mainBranch);
|
|
242
244
|
if ((status.filesChanged > 0 || status.uncommitted) && !force) {
|
|
243
245
|
ctx.ui.notify([
|
|
244
246
|
`Worktree "${name}" has pending changes (${formatCleanKeepReason(status)}).`,
|
|
@@ -21,7 +21,7 @@ import { getWorkerBatches, hasActiveWorkers } from "../subagent/worker-registry.
|
|
|
21
21
|
import { formatDuration, padRight, joinColumns, centerLine, fitColumns, STATUS_GLYPH, STATUS_COLOR } from "../shared/mod.js";
|
|
22
22
|
import { estimateTimeRemaining } from "./auto-dashboard.js";
|
|
23
23
|
import { computeProgressScore } from "./progress-score.js";
|
|
24
|
-
import {
|
|
24
|
+
import { runEnvironmentChecksAsync } from "./doctor-environment.js";
|
|
25
25
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
26
26
|
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
27
27
|
export function unitLabel(type) {
|
|
@@ -62,6 +62,9 @@ export class GSDDashboardOverlay {
|
|
|
62
62
|
loading = true;
|
|
63
63
|
loadedDashboardIdentity;
|
|
64
64
|
refreshInFlight = null;
|
|
65
|
+
envRefreshInFlight = null;
|
|
66
|
+
cachedEnvBasePath;
|
|
67
|
+
cachedEnvIssues = [];
|
|
65
68
|
disposed = false;
|
|
66
69
|
resizeHandler = null;
|
|
67
70
|
cachedMetrics = null;
|
|
@@ -155,11 +158,38 @@ export class GSDDashboardOverlay {
|
|
|
155
158
|
if (initial) {
|
|
156
159
|
this.loading = false;
|
|
157
160
|
}
|
|
161
|
+
this.scheduleEnvironmentRefresh(this.dashData.basePath || process.cwd());
|
|
158
162
|
if (identityChanged) {
|
|
159
163
|
this.invalidate();
|
|
160
164
|
}
|
|
161
165
|
this.tui.requestRender();
|
|
162
166
|
}
|
|
167
|
+
scheduleEnvironmentRefresh(basePath) {
|
|
168
|
+
if (this.cachedEnvBasePath !== basePath) {
|
|
169
|
+
this.cachedEnvBasePath = basePath;
|
|
170
|
+
this.cachedEnvIssues = [];
|
|
171
|
+
this.invalidate();
|
|
172
|
+
}
|
|
173
|
+
if (this.envRefreshInFlight || this.disposed)
|
|
174
|
+
return;
|
|
175
|
+
this.envRefreshInFlight = this.refreshEnvironmentHealth(basePath)
|
|
176
|
+
.finally(() => {
|
|
177
|
+
this.envRefreshInFlight = null;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
async refreshEnvironmentHealth(basePath) {
|
|
181
|
+
try {
|
|
182
|
+
const envResults = await runEnvironmentChecksAsync(basePath);
|
|
183
|
+
if (this.disposed || this.cachedEnvBasePath !== basePath)
|
|
184
|
+
return;
|
|
185
|
+
this.cachedEnvIssues = envResults.filter(r => r.status !== "ok");
|
|
186
|
+
this.invalidate();
|
|
187
|
+
this.tui.requestRender();
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// Non-fatal — keep last known environment issues
|
|
191
|
+
}
|
|
192
|
+
}
|
|
163
193
|
async loadData() {
|
|
164
194
|
const base = this.dashData.basePath || process.cwd();
|
|
165
195
|
try {
|
|
@@ -540,8 +570,7 @@ export class GSDDashboardOverlay {
|
|
|
540
570
|
}
|
|
541
571
|
}
|
|
542
572
|
// Environment health section (#1221) — only show issues
|
|
543
|
-
const
|
|
544
|
-
const envIssues = envResults.filter(r => r.status !== "ok");
|
|
573
|
+
const envIssues = this.cachedEnvIssues;
|
|
545
574
|
if (envIssues.length > 0) {
|
|
546
575
|
lines.push(blank());
|
|
547
576
|
lines.push(hr());
|
|
@@ -12,6 +12,7 @@ import { rowToActiveDecision, rowToActiveRequirement, rowToDecision, rowToRequir
|
|
|
12
12
|
import { rowToGate } from "../db-gate-rows.js";
|
|
13
13
|
import { rowToArtifact, rowToMilestone } from "../db-milestone-artifact-rows.js";
|
|
14
14
|
import { rowToSlice, rowToTask } from "../db-task-slice-rows.js";
|
|
15
|
+
import { TERMINAL_STATUS_SQL } from "./sql-constants.js";
|
|
15
16
|
function parseStringArrayColumn(raw) {
|
|
16
17
|
if (Array.isArray(raw))
|
|
17
18
|
return raw.filter((entry) => typeof entry === "string");
|
|
@@ -35,6 +36,44 @@ function parseStringArrayColumn(raw) {
|
|
|
35
36
|
function normalizeRepoPath(file) {
|
|
36
37
|
return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
|
|
37
38
|
}
|
|
39
|
+
function numberColumn(row, column) {
|
|
40
|
+
const value = row?.[column];
|
|
41
|
+
if (typeof value === "number")
|
|
42
|
+
return value;
|
|
43
|
+
if (typeof value === "bigint")
|
|
44
|
+
return Number(value);
|
|
45
|
+
if (typeof value === "string") {
|
|
46
|
+
const parsed = Number(value);
|
|
47
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
48
|
+
}
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
51
|
+
function getCompletionCount(table) {
|
|
52
|
+
const row = getDbOrNull().prepare(`SELECT
|
|
53
|
+
COUNT(*) AS total,
|
|
54
|
+
COALESCE(SUM(CASE WHEN status IN (${TERMINAL_STATUS_SQL}) THEN 1 ELSE 0 END), 0) AS completed
|
|
55
|
+
FROM ${table}`).get();
|
|
56
|
+
return {
|
|
57
|
+
completed: numberColumn(row, "completed"),
|
|
58
|
+
total: numberColumn(row, "total"),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export function getHierarchyCompletionCounts() {
|
|
62
|
+
if (!getDbOrNull()) {
|
|
63
|
+
return { milestones: 0, milestonesTotal: 0, slices: 0, slicesTotal: 0, tasks: 0, tasksTotal: 0 };
|
|
64
|
+
}
|
|
65
|
+
const milestones = getCompletionCount("milestones");
|
|
66
|
+
const slices = getCompletionCount("slices");
|
|
67
|
+
const tasks = getCompletionCount("tasks");
|
|
68
|
+
return {
|
|
69
|
+
milestones: milestones.completed,
|
|
70
|
+
milestonesTotal: milestones.total,
|
|
71
|
+
slices: slices.completed,
|
|
72
|
+
slicesTotal: slices.total,
|
|
73
|
+
tasks: tasks.completed,
|
|
74
|
+
tasksTotal: tasks.total,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
38
77
|
export function getDecisionById(id) {
|
|
39
78
|
if (!getDbOrNull())
|
|
40
79
|
return null;
|
|
@@ -391,6 +430,27 @@ export function getAssessment(path) {
|
|
|
391
430
|
const row = getDbOrNull().prepare(`SELECT * FROM assessments WHERE path = :path`).get({ ":path": path });
|
|
392
431
|
return row ?? null;
|
|
393
432
|
}
|
|
433
|
+
/**
|
|
434
|
+
* Look up a slice's `run-uat` assessment by (milestoneId, sliceId) identity,
|
|
435
|
+
* independent of the artifact `path`. Used as a DB fallback by the UAT
|
|
436
|
+
* closeout gate when a path migration orphans the ASSESSMENT markdown from its
|
|
437
|
+
* canonical expected path (ADR-017: DB-authoritative UAT sign-off).
|
|
438
|
+
*
|
|
439
|
+
* `status` holds the normalized verdict (`pass`/`fail`/…) written by
|
|
440
|
+
* `executeUatResultSave`; `fullContent` carries the ASSESSMENT body so callers
|
|
441
|
+
* can derive `uatType` without re-reading a file that may not exist.
|
|
442
|
+
*/
|
|
443
|
+
export function getSliceRunUatAssessment(milestoneId, sliceId) {
|
|
444
|
+
if (!getDbOrNull())
|
|
445
|
+
return null;
|
|
446
|
+
const row = getDbOrNull().prepare(`SELECT status, full_content AS fullContent FROM assessments
|
|
447
|
+
WHERE milestone_id = :mid AND slice_id = :sid AND scope = 'run-uat'
|
|
448
|
+
ORDER BY created_at DESC, ROWID DESC
|
|
449
|
+
LIMIT 1`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
450
|
+
if (!row)
|
|
451
|
+
return null;
|
|
452
|
+
return { status: String(row["status"] ?? ""), fullContent: String(row["fullContent"] ?? "") };
|
|
453
|
+
}
|
|
394
454
|
export function getLatestAssessmentByScope(milestoneId, scope) {
|
|
395
455
|
if (!getDbOrNull())
|
|
396
456
|
return null;
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Workspace-facing Interface for opening and maintaining the workflow database.
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
|
-
import { dirname } from "node:path";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
5
|
import { backupDatabaseSnapshot, checkpointDatabase, closeAllDatabases, closeDatabase, closeDatabaseByWorkspace, getDbPath, getDbStatus, getDbProvider, isDbAvailable, openDatabase, openDatabaseByScope, openDatabaseByWorkspace, openIsolatedDatabase, refreshOpenDatabaseFromDisk, vacuumDatabase, wasDbOpenAttempted, } from "./gsd-db.js";
|
|
6
|
-
import { resolveGsdPathContract } from "./paths.js";
|
|
7
|
-
import { setLogBasePath } from "./workflow-logger.js";
|
|
6
|
+
import { resolveGsdPathContract, gsdRoot } from "./paths.js";
|
|
7
|
+
import { logWarning, setLogBasePath } from "./workflow-logger.js";
|
|
8
|
+
/**
|
|
9
|
+
* Global SQLite handle invariants:
|
|
10
|
+
*
|
|
11
|
+
* - `openWorkflowDatabase` / `openDatabase` switch the process-global handle consumed by
|
|
12
|
+
* deriveState, dispatch, reconciliation repairs, and domain writers. Only one active
|
|
13
|
+
* project database should own the global handle at a time.
|
|
14
|
+
* - `openWorkflowDatabaseIsolated` opens a caller-owned connection that does not clobber
|
|
15
|
+
* the global handle. Use for read-only observers (parallel monitor) and other background
|
|
16
|
+
* probes that must not disturb the active workflow session.
|
|
17
|
+
* - Reconciliation repairs that write markdown/DB state must use `ensureWorkflowDbForBase`
|
|
18
|
+
* so repairs target the correct project; those paths intentionally re-open the global handle.
|
|
19
|
+
* - Pair ad-hoc project switches with `closeWorkflowDatabase()` or restore via
|
|
20
|
+
* `ensureWorkflowDbForBase(..., { refresh: true })` before returning to derive/dispatch.
|
|
21
|
+
*/
|
|
8
22
|
export function resolveWorkflowDatabaseLocation(basePath) {
|
|
9
23
|
const contract = resolveGsdPathContract(basePath);
|
|
10
24
|
return {
|
|
@@ -104,6 +118,44 @@ export function getWorkflowDatabasePath() {
|
|
|
104
118
|
export function refreshWorkflowDatabaseFromDisk() {
|
|
105
119
|
return refreshOpenDatabaseFromDisk();
|
|
106
120
|
}
|
|
121
|
+
export function expectedWorkflowDbPathForBase(basePath) {
|
|
122
|
+
return join(gsdRoot(basePath), "gsd.db");
|
|
123
|
+
}
|
|
124
|
+
export function ensureWorkflowDbAtPath(dbPath) {
|
|
125
|
+
if (!dbPath || dbPath === ":memory:")
|
|
126
|
+
return isDbAvailable();
|
|
127
|
+
if (isDbAvailable() && getWorkflowDatabasePath() === dbPath)
|
|
128
|
+
return true;
|
|
129
|
+
if (!existsSync(dbPath))
|
|
130
|
+
return false;
|
|
131
|
+
try {
|
|
132
|
+
return openWorkflowDatabasePath(dbPath);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
logWarning("reconcile", `ensureWorkflowDbAtPath could not reopen DB: ${err.message}`);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function ensureWorkflowDbForBase(basePath, options = {}) {
|
|
140
|
+
const dbPath = expectedWorkflowDbPathForBase(basePath);
|
|
141
|
+
if (!existsSync(dbPath))
|
|
142
|
+
return false;
|
|
143
|
+
try {
|
|
144
|
+
if (options.refresh) {
|
|
145
|
+
if (isDbAvailable() && getWorkflowDatabasePath() === dbPath && refreshWorkflowDatabaseFromDisk()) {
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
return openWorkflowDatabasePath(dbPath);
|
|
149
|
+
}
|
|
150
|
+
if (isDbAvailable() && getWorkflowDatabasePath() === dbPath)
|
|
151
|
+
return true;
|
|
152
|
+
return openWorkflowDatabasePath(dbPath);
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
logWarning("reconcile", `ensureWorkflowDbForBase could not reopen DB: ${err.message}`);
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
107
159
|
export function checkpointWorkflowDatabase() {
|
|
108
160
|
checkpointDatabase();
|
|
109
161
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* - Optional search/tool integrations (Brave, Tavily, Jina, Context7)
|
|
12
12
|
*/
|
|
13
13
|
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import { access, readFile } from "node:fs/promises";
|
|
14
15
|
import { delimiter, join } from "node:path";
|
|
15
16
|
import { AuthStorage } from "@gsd/pi-coding-agent";
|
|
16
17
|
import { getEnvApiKey } from "@gsd/pi-ai";
|
|
@@ -133,15 +134,11 @@ const CLI_AUTH_PATH_CHECK_PROVIDERS = new Set([
|
|
|
133
134
|
"google-gemini-cli",
|
|
134
135
|
"google-antigravity",
|
|
135
136
|
]);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* Fast filesystem scan — no subprocess, no network, sub-1ms.
|
|
139
|
-
*/
|
|
140
|
-
function isCliBinaryInPath(providerId) {
|
|
137
|
+
let asyncCliBinaryPathCache = null;
|
|
138
|
+
function cliExecutableNames(providerId) {
|
|
141
139
|
const binaries = CLI_BINARY_MAP[providerId];
|
|
142
140
|
if (!binaries)
|
|
143
|
-
return
|
|
144
|
-
const pathDirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
141
|
+
return [];
|
|
145
142
|
// On Windows, command shims are commonly installed as .cmd/.exe/.bat/.com.
|
|
146
143
|
// Scan PATHEXT candidates in addition to the bare binary name.
|
|
147
144
|
const executableNames = [...binaries];
|
|
@@ -160,8 +157,45 @@ function isCliBinaryInPath(providerId) {
|
|
|
160
157
|
}
|
|
161
158
|
}
|
|
162
159
|
}
|
|
160
|
+
return executableNames;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Check if a CLI provider's binary exists anywhere in PATH.
|
|
164
|
+
* Fast filesystem scan — no subprocess, no network, sub-1ms.
|
|
165
|
+
*/
|
|
166
|
+
function isCliBinaryInPath(providerId) {
|
|
167
|
+
const cached = asyncCliBinaryPathCache?.get(providerId);
|
|
168
|
+
if (cached !== undefined)
|
|
169
|
+
return cached;
|
|
170
|
+
const executableNames = cliExecutableNames(providerId);
|
|
171
|
+
if (executableNames.length === 0)
|
|
172
|
+
return false;
|
|
173
|
+
const pathDirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
163
174
|
return pathDirs.some(dir => executableNames.some(name => existsSync(join(dir, name))));
|
|
164
175
|
}
|
|
176
|
+
async function isCliBinaryInPathAsync(providerId) {
|
|
177
|
+
const executableNames = cliExecutableNames(providerId);
|
|
178
|
+
if (executableNames.length === 0)
|
|
179
|
+
return false;
|
|
180
|
+
const pathDirs = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
|
|
181
|
+
const candidates = pathDirs.flatMap(dir => executableNames.map(name => join(dir, name)));
|
|
182
|
+
if (candidates.length === 0)
|
|
183
|
+
return false;
|
|
184
|
+
try {
|
|
185
|
+
await Promise.any(candidates.map(candidate => access(candidate)));
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function loadCliBinaryPathCache() {
|
|
193
|
+
const entries = await Promise.all(Object.keys(CLI_BINARY_MAP).map(async (providerId) => [
|
|
194
|
+
providerId,
|
|
195
|
+
await isCliBinaryInPathAsync(providerId),
|
|
196
|
+
]));
|
|
197
|
+
return new Map(entries);
|
|
198
|
+
}
|
|
165
199
|
function modelsJsonPaths() {
|
|
166
200
|
const home = homedir();
|
|
167
201
|
return [
|
|
@@ -170,7 +204,11 @@ function modelsJsonPaths() {
|
|
|
170
204
|
join(home, ".pi", "agent", "models.json"),
|
|
171
205
|
];
|
|
172
206
|
}
|
|
207
|
+
let asyncModelsJsonApiKeyCache = null;
|
|
173
208
|
function hasModelsJsonApiKey(providerId) {
|
|
209
|
+
if (asyncModelsJsonApiKeyCache) {
|
|
210
|
+
return asyncModelsJsonApiKeyCache.has(providerId);
|
|
211
|
+
}
|
|
174
212
|
for (const path of modelsJsonPaths()) {
|
|
175
213
|
if (!existsSync(path))
|
|
176
214
|
continue;
|
|
@@ -187,7 +225,25 @@ function hasModelsJsonApiKey(providerId) {
|
|
|
187
225
|
}
|
|
188
226
|
return false;
|
|
189
227
|
}
|
|
190
|
-
function
|
|
228
|
+
async function loadModelsJsonApiKeyCache() {
|
|
229
|
+
const providersWithKeys = new Set();
|
|
230
|
+
for (const path of modelsJsonPaths()) {
|
|
231
|
+
try {
|
|
232
|
+
const parsed = JSON.parse(await readFile(path, "utf-8"));
|
|
233
|
+
for (const [providerId, provider] of Object.entries(parsed.providers ?? {})) {
|
|
234
|
+
const apiKey = provider.apiKey;
|
|
235
|
+
if (typeof apiKey === "string" && apiKey.trim().length > 0) {
|
|
236
|
+
providersWithKeys.add(providerId);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// Missing or malformed models.json should not break dashboard health checks.
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return providersWithKeys;
|
|
245
|
+
}
|
|
246
|
+
function resolveKeyFromAuthOrEnv(providerId) {
|
|
191
247
|
const info = PROVIDER_REGISTRY.find(p => p.id === providerId);
|
|
192
248
|
if (providerId === "anthropic-vertex" && process.env.ANTHROPIC_VERTEX_PROJECT_ID) {
|
|
193
249
|
return { found: true, source: "env", backedOff: false };
|
|
@@ -234,6 +290,12 @@ function resolveKey(providerId) {
|
|
|
234
290
|
if (info?.envVar && process.env[info.envVar]) {
|
|
235
291
|
return { found: true, source: "env", backedOff: false };
|
|
236
292
|
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function resolveKey(providerId) {
|
|
296
|
+
const direct = resolveKeyFromAuthOrEnv(providerId);
|
|
297
|
+
if (direct)
|
|
298
|
+
return direct;
|
|
237
299
|
if (hasModelsJsonApiKey(providerId)) {
|
|
238
300
|
return { found: true, source: "models.json", backedOff: false };
|
|
239
301
|
}
|
|
@@ -432,6 +494,28 @@ export function runProviderChecks() {
|
|
|
432
494
|
results.push(...checkOptionalProviders());
|
|
433
495
|
return results;
|
|
434
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* Non-blocking equivalent of `runProviderChecks` for the health-widget
|
|
499
|
+
* background refresh. PATH checks and custom models.json discovery use async
|
|
500
|
+
* filesystem APIs so periodic widget refreshes do not stall the input loop.
|
|
501
|
+
*/
|
|
502
|
+
export async function runProviderChecksAsync() {
|
|
503
|
+
const [cliCache, modelsJsonCache] = await Promise.all([
|
|
504
|
+
loadCliBinaryPathCache(),
|
|
505
|
+
loadModelsJsonApiKeyCache(),
|
|
506
|
+
]);
|
|
507
|
+
const previousCliCache = asyncCliBinaryPathCache;
|
|
508
|
+
const previousModelsJsonCache = asyncModelsJsonApiKeyCache;
|
|
509
|
+
asyncCliBinaryPathCache = cliCache;
|
|
510
|
+
asyncModelsJsonApiKeyCache = modelsJsonCache;
|
|
511
|
+
try {
|
|
512
|
+
return runProviderChecks();
|
|
513
|
+
}
|
|
514
|
+
finally {
|
|
515
|
+
asyncCliBinaryPathCache = previousCliCache;
|
|
516
|
+
asyncModelsJsonApiKeyCache = previousModelsJsonCache;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
435
519
|
/**
|
|
436
520
|
* Format provider check results as a human-readable report string.
|
|
437
521
|
*/
|
|
@@ -180,10 +180,22 @@ export function runExecSandbox(request, opts) {
|
|
|
180
180
|
const effectiveGraceMs = opts.kill_grace_ms ?? SIGKILL_GRACE_MS;
|
|
181
181
|
const effectiveForceResolveDelay = opts.force_resolve_delay_ms ?? (effectiveGraceMs + HARD_DEADLINE_MS);
|
|
182
182
|
let timedOut = false;
|
|
183
|
+
let aborted = false;
|
|
183
184
|
let settled = false;
|
|
185
|
+
let killInitiated = false;
|
|
186
|
+
let timer;
|
|
184
187
|
let forceResolveTimer;
|
|
185
|
-
|
|
186
|
-
|
|
188
|
+
let abortListener;
|
|
189
|
+
const removeAbortListener = () => {
|
|
190
|
+
if (opts.signal && abortListener) {
|
|
191
|
+
opts.signal.removeEventListener("abort", abortListener);
|
|
192
|
+
abortListener = undefined;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const initiateKill = () => {
|
|
196
|
+
if (killInitiated)
|
|
197
|
+
return;
|
|
198
|
+
killInitiated = true;
|
|
187
199
|
// killProcessTree handles both platforms and kills the whole tree: on Unix
|
|
188
200
|
// it signals the process group (SIGTERM -> grace -> SIGKILL); on Windows it
|
|
189
201
|
// force-kills the tree via taskkill /F /T. Using child.kill("SIGTERM") here
|
|
@@ -201,14 +213,14 @@ export function runExecSandbox(request, opts) {
|
|
|
201
213
|
finalize(null, "SIGKILL", true);
|
|
202
214
|
}, effectiveForceResolveDelay);
|
|
203
215
|
forceResolveTimer.unref?.();
|
|
204
|
-
}
|
|
205
|
-
timer.unref?.();
|
|
216
|
+
};
|
|
206
217
|
const finalize = (exitCode, signal, forceResolved = false) => {
|
|
207
218
|
if (settled)
|
|
208
219
|
return;
|
|
209
220
|
settled = true;
|
|
210
221
|
clearTimeout(timer);
|
|
211
222
|
clearTimeout(forceResolveTimer);
|
|
223
|
+
removeAbortListener();
|
|
212
224
|
const duration = Date.now() - started;
|
|
213
225
|
const stdoutBuf = Buffer.concat(stdoutChunks);
|
|
214
226
|
const stderrBuf = Buffer.concat(stderrChunks);
|
|
@@ -219,17 +231,20 @@ export function runExecSandbox(request, opts) {
|
|
|
219
231
|
const digestBody = tail(stdoutBuf, opts.digest_chars);
|
|
220
232
|
const digest = digestBody.length > 0
|
|
221
233
|
? digestBody
|
|
222
|
-
:
|
|
223
|
-
? "[no stdout —
|
|
224
|
-
:
|
|
225
|
-
?
|
|
226
|
-
:
|
|
234
|
+
: aborted
|
|
235
|
+
? "[no stdout — aborted]"
|
|
236
|
+
: timedOut
|
|
237
|
+
? "[no stdout — timed out]"
|
|
238
|
+
: stderrBuf.length > 0
|
|
239
|
+
? `[no stdout — tail of stderr]\n${tail(stderrBuf, opts.digest_chars)}`
|
|
240
|
+
: "[no output]";
|
|
227
241
|
const result = {
|
|
228
242
|
id,
|
|
229
243
|
runtime: request.runtime,
|
|
230
244
|
exit_code: exitCode,
|
|
231
245
|
signal,
|
|
232
246
|
timed_out: timedOut,
|
|
247
|
+
aborted,
|
|
233
248
|
force_resolved: forceResolved,
|
|
234
249
|
duration_ms: duration,
|
|
235
250
|
stdout_bytes: stdoutBytes,
|
|
@@ -244,6 +259,26 @@ export function runExecSandbox(request, opts) {
|
|
|
244
259
|
writeMeta(metaPath, result, request, now);
|
|
245
260
|
resolveP(result);
|
|
246
261
|
};
|
|
262
|
+
timer = setTimeout(() => {
|
|
263
|
+
timedOut = true;
|
|
264
|
+
initiateKill();
|
|
265
|
+
}, timeoutMs);
|
|
266
|
+
timer.unref?.();
|
|
267
|
+
if (opts.signal) {
|
|
268
|
+
abortListener = () => {
|
|
269
|
+
if (settled || timedOut)
|
|
270
|
+
return;
|
|
271
|
+
aborted = true;
|
|
272
|
+
clearTimeout(timer);
|
|
273
|
+
initiateKill();
|
|
274
|
+
};
|
|
275
|
+
if (opts.signal.aborted) {
|
|
276
|
+
abortListener();
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
opts.signal.addEventListener("abort", abortListener, { once: true });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
247
282
|
child.on("error", (err) => {
|
|
248
283
|
const message = err instanceof Error ? err.message : String(err);
|
|
249
284
|
const line = `child error: ${message}\n`;
|
|
@@ -274,6 +309,7 @@ function writeMeta(path, result, request, now) {
|
|
|
274
309
|
exit_code: result.exit_code,
|
|
275
310
|
signal: result.signal,
|
|
276
311
|
timed_out: result.timed_out,
|
|
312
|
+
aborted: result.aborted === true,
|
|
277
313
|
force_resolved: result.force_resolved,
|
|
278
314
|
duration_ms: result.duration_ms,
|
|
279
315
|
stdout_bytes: result.stdout_bytes,
|
|
@@ -22,8 +22,7 @@ import { deriveState } from "./state.js";
|
|
|
22
22
|
import { isAutoActive } from "./auto.js";
|
|
23
23
|
import { loadPrompt } from "./prompt-loader.js";
|
|
24
24
|
import { gsdRoot } from "./paths.js";
|
|
25
|
-
import { isDbAvailable,
|
|
26
|
-
import { isClosedStatus } from "./status-guards.js";
|
|
25
|
+
import { isDbAvailable, getHierarchyCompletionCounts } from "./gsd-db.js";
|
|
27
26
|
import { formatDuration } from "../shared/format-utils.js";
|
|
28
27
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
29
28
|
import { clearGSDPreferencesCache, loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
@@ -593,36 +592,7 @@ function loadCompletedKeys(basePath) {
|
|
|
593
592
|
function getDbCompletionCounts() {
|
|
594
593
|
if (!isDbAvailable())
|
|
595
594
|
return null;
|
|
596
|
-
|
|
597
|
-
let completedMilestones = 0;
|
|
598
|
-
let totalSlices = 0;
|
|
599
|
-
let completedSlices = 0;
|
|
600
|
-
let totalTasks = 0;
|
|
601
|
-
let completedTasks = 0;
|
|
602
|
-
for (const m of milestones) {
|
|
603
|
-
if (isClosedStatus(m.status))
|
|
604
|
-
completedMilestones++;
|
|
605
|
-
const slices = getMilestoneSlices(m.id);
|
|
606
|
-
for (const s of slices) {
|
|
607
|
-
totalSlices++;
|
|
608
|
-
if (isClosedStatus(s.status))
|
|
609
|
-
completedSlices++;
|
|
610
|
-
const tasks = getSliceTasks(m.id, s.id);
|
|
611
|
-
for (const t of tasks) {
|
|
612
|
-
totalTasks++;
|
|
613
|
-
if (isClosedStatus(t.status))
|
|
614
|
-
completedTasks++;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
return {
|
|
619
|
-
milestones: completedMilestones,
|
|
620
|
-
milestonesTotal: milestones.length,
|
|
621
|
-
slices: completedSlices,
|
|
622
|
-
slicesTotal: totalSlices,
|
|
623
|
-
tasks: completedTasks,
|
|
624
|
-
tasksTotal: totalTasks,
|
|
625
|
-
};
|
|
595
|
+
return getHierarchyCompletionCounts();
|
|
626
596
|
}
|
|
627
597
|
// ─── Anomaly Detectors ───────────────────────────────────────────────────────
|
|
628
598
|
/**
|
|
@@ -225,6 +225,7 @@ export const RUNTIME_EXCLUSION_PATHS = [
|
|
|
225
225
|
".gsd/event-log.jsonl",
|
|
226
226
|
".gsd/DISCUSSION-MANIFEST.json",
|
|
227
227
|
];
|
|
228
|
+
const runtimeFilesCleanedUpRepos = new Set();
|
|
228
229
|
// ─── Integration Branch Metadata ───────────────────────────────────────────
|
|
229
230
|
/**
|
|
230
231
|
* Path to the milestone metadata file that stores the integration branch.
|
|
@@ -565,7 +566,8 @@ export class GitServiceImpl {
|
|
|
565
566
|
// and the worktree is torn down. This prevents a mid-execution behavioral
|
|
566
567
|
// discontinuity where the first half of a milestone has .gsd/ artifacts
|
|
567
568
|
// committed but the second half doesn't (#1326).
|
|
568
|
-
|
|
569
|
+
const cleanupRepoKey = resolve(this.basePath);
|
|
570
|
+
if (!runtimeFilesCleanedUpRepos.has(cleanupRepoKey)) {
|
|
569
571
|
let cleaned = false;
|
|
570
572
|
for (const exclusion of RUNTIME_EXCLUSION_PATHS) {
|
|
571
573
|
const removed = nativeRmCached(this.basePath, [exclusion]);
|
|
@@ -575,7 +577,7 @@ export class GitServiceImpl {
|
|
|
575
577
|
if (cleaned) {
|
|
576
578
|
nativeCommit(this.basePath, "chore: untrack .gsd/ runtime files from git index", { allowEmpty: false });
|
|
577
579
|
}
|
|
578
|
-
|
|
580
|
+
runtimeFilesCleanedUpRepos.add(cleanupRepoKey);
|
|
579
581
|
}
|
|
580
582
|
// Stage everything using pathspec exclusions so excluded paths are never
|
|
581
583
|
// hashed by git. The old approach of `git add -A` followed by unstaging
|
|
@@ -683,8 +685,6 @@ export class GitServiceImpl {
|
|
|
683
685
|
return false;
|
|
684
686
|
}
|
|
685
687
|
}
|
|
686
|
-
/** Tracks whether runtime file cleanup has run this session. */
|
|
687
|
-
_runtimeFilesCleanedUp = false;
|
|
688
688
|
/**
|
|
689
689
|
* Stage files (smart staging) and commit.
|
|
690
690
|
* Returns the commit message string on success, or null if nothing to commit.
|