@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
|
@@ -12,7 +12,7 @@ import { loadFile } from "./files.js";
|
|
|
12
12
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
13
13
|
import { deriveState } from "./state.js";
|
|
14
14
|
import { invalidateAllCaches } from "./cache.js";
|
|
15
|
-
import { gsdRoot, resolveMilestoneFile, resolveGsdRootFile, relGsdRootFile, } from "./paths.js";
|
|
15
|
+
import { gsdRoot, resolveMilestoneFile, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, } from "./paths.js";
|
|
16
16
|
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
17
17
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
18
18
|
import { nativeAddPaths, nativeCommit } from "./native-git-bridge.js";
|
|
@@ -20,6 +20,9 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
20
20
|
import { saveQueueOrder } from "./queue-order.js";
|
|
21
21
|
import { findMilestoneIds, nextMilestoneId } from "./milestone-ids.js";
|
|
22
22
|
import { isFutureMilestoneStatus } from "./status-guards.js";
|
|
23
|
+
const QUEUE_ARTIFACT_EXCERPT_MAX_CHARS = 20_000;
|
|
24
|
+
const QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS = 120_000;
|
|
25
|
+
const QUEUE_CONTEXT_SECTION_SEPARATOR = "\n\n---\n\n";
|
|
23
26
|
// ─── Queue Entry Point ──────────────────────────────────────────────────────
|
|
24
27
|
/**
|
|
25
28
|
* Queue future milestones via conversational intake.
|
|
@@ -215,7 +218,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
215
218
|
if (contextFile) {
|
|
216
219
|
const content = await loadFile(contextFile);
|
|
217
220
|
if (content) {
|
|
218
|
-
parts.push(`\n**Context:**\n${content
|
|
221
|
+
parts.push(`\n**Context:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "CONTEXT"))}`);
|
|
219
222
|
}
|
|
220
223
|
}
|
|
221
224
|
else {
|
|
@@ -224,7 +227,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
224
227
|
if (draftFile) {
|
|
225
228
|
const draftContent = await loadFile(draftFile);
|
|
226
229
|
if (draftContent) {
|
|
227
|
-
parts.push(`\n**Draft context available:**\n${draftContent
|
|
230
|
+
parts.push(`\n**Draft context available:**\n${summarizeArtifactForQueue(draftContent, relMilestoneFile(basePath, mid, "CONTEXT-DRAFT"))}`);
|
|
228
231
|
}
|
|
229
232
|
}
|
|
230
233
|
}
|
|
@@ -235,7 +238,7 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
235
238
|
if (roadmapFile) {
|
|
236
239
|
const content = await loadFile(roadmapFile);
|
|
237
240
|
if (content) {
|
|
238
|
-
parts.push(`\n**Roadmap:**\n${content
|
|
241
|
+
parts.push(`\n**Roadmap:**\n${summarizeArtifactForQueue(content, relMilestoneFile(basePath, mid, "ROADMAP"))}`);
|
|
239
242
|
}
|
|
240
243
|
}
|
|
241
244
|
}
|
|
@@ -249,7 +252,65 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
249
252
|
sections.push(`### Previous Queue Entries\nSource: \`${relGsdRootFile("QUEUE")}\`\n\n${queueContent.trim()}`);
|
|
250
253
|
}
|
|
251
254
|
}
|
|
252
|
-
return sections
|
|
255
|
+
return capExistingMilestonesContext(sections);
|
|
256
|
+
}
|
|
257
|
+
function summarizeArtifactForQueue(content, sourcePath, cap = QUEUE_ARTIFACT_EXCERPT_MAX_CHARS) {
|
|
258
|
+
const trimmed = content.trim();
|
|
259
|
+
if (trimmed.length <= cap) {
|
|
260
|
+
return `Source: \`${sourcePath}\`\n\n${trimmed}`;
|
|
261
|
+
}
|
|
262
|
+
const excerpt = trimmed.slice(0, cap).trimEnd();
|
|
263
|
+
const omittedChars = trimmed.length - excerpt.length;
|
|
264
|
+
return [
|
|
265
|
+
`Source: \`${sourcePath}\``,
|
|
266
|
+
"",
|
|
267
|
+
excerpt,
|
|
268
|
+
"",
|
|
269
|
+
`[Truncated ${omittedChars} chars. Read \`${sourcePath}\` for full content.]`,
|
|
270
|
+
].join("\n");
|
|
271
|
+
}
|
|
272
|
+
function capExistingMilestonesContext(sections, cap = QUEUE_EXISTING_MILESTONES_CONTEXT_MAX_CHARS) {
|
|
273
|
+
const fullContext = sections.join(QUEUE_CONTEXT_SECTION_SEPARATOR);
|
|
274
|
+
if (fullContext.length <= cap)
|
|
275
|
+
return fullContext;
|
|
276
|
+
const notice = `[Existing milestones context truncated to ${cap} chars. Read source paths in this prompt or the corresponding .gsd artifacts for full details.]`;
|
|
277
|
+
const noticeSuffix = `${QUEUE_CONTEXT_SECTION_SEPARATOR}${notice}`;
|
|
278
|
+
const selected = [];
|
|
279
|
+
for (const section of sections) {
|
|
280
|
+
const candidate = [...selected, section].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
281
|
+
if (candidate.length <= cap) {
|
|
282
|
+
selected.push(section);
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
if (selected.length === sections.length) {
|
|
288
|
+
return selected.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
289
|
+
}
|
|
290
|
+
const compactTail = sections.slice(selected.length).map(compactSectionForQueueBudget);
|
|
291
|
+
const hybrid = [...selected, ...compactTail].join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
292
|
+
if (hybrid.length <= cap)
|
|
293
|
+
return hybrid;
|
|
294
|
+
const compact = sections.map(compactSectionForQueueBudget);
|
|
295
|
+
const compactContext = compact.join(QUEUE_CONTEXT_SECTION_SEPARATOR) + noticeSuffix;
|
|
296
|
+
if (compactContext.length <= cap)
|
|
297
|
+
return compactContext;
|
|
298
|
+
return `${compactContext.slice(0, Math.max(0, cap - notice.length - 2)).trimEnd()}\n\n${notice}`;
|
|
299
|
+
}
|
|
300
|
+
function compactSectionForQueueBudget(section) {
|
|
301
|
+
const lines = section.split("\n");
|
|
302
|
+
const compact = [];
|
|
303
|
+
if (lines[0])
|
|
304
|
+
compact.push(lines[0]);
|
|
305
|
+
const statusLine = lines.find(line => line.startsWith("**Status:**"));
|
|
306
|
+
if (statusLine)
|
|
307
|
+
compact.push(statusLine);
|
|
308
|
+
const sourceLines = lines.filter(line => line.startsWith("Source: `"));
|
|
309
|
+
if (sourceLines.length > 0) {
|
|
310
|
+
compact.push("", "**Sources:**", ...sourceLines);
|
|
311
|
+
compact.push("", "[Artifact excerpts omitted due to total queue/rethink context budget.]");
|
|
312
|
+
}
|
|
313
|
+
return compact.join("\n");
|
|
253
314
|
}
|
|
254
315
|
// ─── Internal Helpers ───────────────────────────────────────────────────────
|
|
255
316
|
/**
|
|
@@ -1,29 +1,61 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Always-on ambient health signal rendered below the editor.
|
|
3
|
-
import {
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { runProviderChecks, runProviderChecksAsync, summariseProviderIssues } from "./doctor-providers.js";
|
|
4
5
|
import { runEnvironmentChecks, runEnvironmentChecksAsync } from "./doctor-environment.js";
|
|
5
6
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
6
|
-
import {
|
|
7
|
+
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
7
8
|
import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
|
|
8
9
|
import { projectRoot } from "./commands/context.js";
|
|
9
10
|
import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
|
|
10
11
|
export const HEALTH_WIDGET_ACTIVE_HINTS = " /gsd auto to run · /gsd status to inspect · /gsd report for snapshots · /gsd notifications for history · /gsd help";
|
|
12
|
+
const LAST_COMMIT_LOOKUP_TIMEOUT_MS = 3_000;
|
|
13
|
+
const REFRESH_INTERVAL_MS = 60_000;
|
|
14
|
+
const PROJECT_STATE_CACHE_TTL_MS = REFRESH_INTERVAL_MS;
|
|
11
15
|
// ── Data loader ────────────────────────────────────────────────────────────────
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
const projectStateCache = new Map();
|
|
17
|
+
export function getCachedProjectState(basePath, force) {
|
|
18
|
+
const now = Date.now();
|
|
19
|
+
const cached = projectStateCache.get(basePath);
|
|
20
|
+
if (!force && cached && now - cached.computedAt <= PROJECT_STATE_CACHE_TTL_MS) {
|
|
21
|
+
return cached.state;
|
|
22
|
+
}
|
|
23
|
+
const state = detectHealthWidgetProjectState(basePath);
|
|
24
|
+
projectStateCache.set(basePath, { state, computedAt: now });
|
|
25
|
+
return state;
|
|
26
|
+
}
|
|
27
|
+
function runHealthWidgetGit(basePath, args) {
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
const child = execFile("git", args, {
|
|
30
|
+
cwd: basePath,
|
|
31
|
+
timeout: LAST_COMMIT_LOOKUP_TIMEOUT_MS,
|
|
32
|
+
encoding: "utf-8",
|
|
33
|
+
env: GIT_NO_PROMPT_ENV,
|
|
34
|
+
}, (err, stdout) => resolve(err ? null : String(stdout).trimEnd()));
|
|
35
|
+
child.on("error", () => resolve(null));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
async function loadLastCommitInfoAsync(basePath) {
|
|
16
39
|
try {
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
const epoch = nativeLastCommitEpoch(basePath, branch || "HEAD");
|
|
20
|
-
if (epoch > 0) {
|
|
21
|
-
return { epoch, message: nativeCommitSubject(basePath, branch || "HEAD") || null };
|
|
22
|
-
}
|
|
40
|
+
if ((await runHealthWidgetGit(basePath, ["rev-parse", "--git-dir"])) === null) {
|
|
41
|
+
return { epoch: null, message: null };
|
|
23
42
|
}
|
|
43
|
+
const branch = await runHealthWidgetGit(basePath, ["branch", "--show-current"]);
|
|
44
|
+
const ref = branch || "HEAD";
|
|
45
|
+
const raw = await runHealthWidgetGit(basePath, ["log", "-1", "--format=%ct%x00%s", ref]);
|
|
46
|
+
if (!raw)
|
|
47
|
+
return { epoch: null, message: null };
|
|
48
|
+
const separator = raw.indexOf("\0");
|
|
49
|
+
const epochText = separator >= 0 ? raw.slice(0, separator) : raw;
|
|
50
|
+
const epoch = parseInt(epochText.trim(), 10) || 0;
|
|
51
|
+
if (epoch <= 0)
|
|
52
|
+
return { epoch: null, message: null };
|
|
53
|
+
const message = separator >= 0 ? raw.slice(separator + 1).trim() : "";
|
|
54
|
+
return { epoch, message: message || null };
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return { epoch: null, message: null };
|
|
24
58
|
}
|
|
25
|
-
catch { /* non-fatal */ }
|
|
26
|
-
return { epoch: null, message: null };
|
|
27
59
|
}
|
|
28
60
|
function loadHealthWidgetData(basePath, options) {
|
|
29
61
|
// `includeChecks` gates the expensive subprocess-backed checks (provider +
|
|
@@ -38,7 +70,7 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
38
70
|
let environmentWarningCount = 0;
|
|
39
71
|
let lastCommitEpoch = null;
|
|
40
72
|
let lastCommitMessage = null;
|
|
41
|
-
const projectState =
|
|
73
|
+
const projectState = getCachedProjectState(basePath, options?.forceProjectState);
|
|
42
74
|
try {
|
|
43
75
|
const prefs = loadEffectiveGSDPreferences();
|
|
44
76
|
budgetCeiling = prefs?.preferences?.budget_ceiling;
|
|
@@ -66,12 +98,6 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
66
98
|
}
|
|
67
99
|
catch { /* non-fatal */ }
|
|
68
100
|
}
|
|
69
|
-
// ── Last commit info ── (git spawns — gated like the other expensive checks)
|
|
70
|
-
if (includeChecks) {
|
|
71
|
-
const commit = loadLastCommitInfo(basePath);
|
|
72
|
-
lastCommitEpoch = commit.epoch;
|
|
73
|
-
lastCommitMessage = commit.message;
|
|
74
|
-
}
|
|
75
101
|
return {
|
|
76
102
|
projectState,
|
|
77
103
|
budgetCeiling,
|
|
@@ -85,17 +111,15 @@ function loadHealthWidgetData(basePath, options) {
|
|
|
85
111
|
};
|
|
86
112
|
}
|
|
87
113
|
// Non-blocking variant used by the widget's background refresh: the cheap fields
|
|
88
|
-
// come from the synchronous snapshot, then provider
|
|
89
|
-
// layered in off the event-loop critical path
|
|
90
|
-
// runEnvironmentChecksAsync). Keeps the always-on widget from stalling the UI on
|
|
91
|
-
// its initial enrichment or its 60s refresh.
|
|
114
|
+
// come from the synchronous snapshot, then provider, environment, and last-commit
|
|
115
|
+
// checks are layered in off the event-loop critical path.
|
|
92
116
|
async function loadHealthWidgetDataAsync(basePath) {
|
|
93
117
|
const data = loadHealthWidgetData(basePath, { includeChecks: false });
|
|
94
118
|
let providerIssue = data.providerIssue;
|
|
95
119
|
let environmentErrorCount = 0;
|
|
96
120
|
let environmentWarningCount = 0;
|
|
97
121
|
try {
|
|
98
|
-
providerIssue = summariseProviderIssues(
|
|
122
|
+
providerIssue = summariseProviderIssues(await runProviderChecksAsync());
|
|
99
123
|
}
|
|
100
124
|
catch { /* non-fatal */ }
|
|
101
125
|
try {
|
|
@@ -108,7 +132,7 @@ async function loadHealthWidgetDataAsync(basePath) {
|
|
|
108
132
|
}
|
|
109
133
|
}
|
|
110
134
|
catch { /* non-fatal */ }
|
|
111
|
-
const commit =
|
|
135
|
+
const commit = await loadLastCommitInfoAsync(basePath);
|
|
112
136
|
return {
|
|
113
137
|
...data,
|
|
114
138
|
providerIssue,
|
|
@@ -120,7 +144,6 @@ async function loadHealthWidgetDataAsync(basePath) {
|
|
|
120
144
|
};
|
|
121
145
|
}
|
|
122
146
|
// ── Widget init ────────────────────────────────────────────────────────────────
|
|
123
|
-
const REFRESH_INTERVAL_MS = 60_000;
|
|
124
147
|
/**
|
|
125
148
|
* Initialize the always-on gsd-health widget (belowEditor).
|
|
126
149
|
* Call once from the extension entry point after context is available.
|
|
@@ -129,13 +152,16 @@ export function initHealthWidget(ctx) {
|
|
|
129
152
|
if (!ctx.hasUI)
|
|
130
153
|
return;
|
|
131
154
|
const basePath = projectRoot();
|
|
155
|
+
// Re-init must reflect filesystem changes immediately; the TTL cache is for
|
|
156
|
+
// interval refreshes, not this one-off synchronous paint.
|
|
157
|
+
projectStateCache.delete(basePath);
|
|
132
158
|
// String-array fallback — used in RPC mode (factory is a no-op there).
|
|
133
159
|
// Skip the expensive provider/environment doctor checks here: this runs
|
|
134
160
|
// synchronously on the interactive-startup path, where running them would
|
|
135
161
|
// block first paint by ~0.9s (lsof/docker probes, otherwise run again
|
|
136
162
|
// immediately by the factory below). The factory's async refresh fills in
|
|
137
163
|
// real health once the screen is up.
|
|
138
|
-
const initialData = loadHealthWidgetData(basePath, { includeChecks: false });
|
|
164
|
+
const initialData = loadHealthWidgetData(basePath, { includeChecks: false, forceProjectState: true });
|
|
139
165
|
ctx.ui.setWidget("gsd-health", buildHealthLines(initialData), { placement: "belowEditor" });
|
|
140
166
|
// Factory-based widget for TUI mode — replaces the string-array above
|
|
141
167
|
ctx.ui.setWidget("gsd-health", (_tui, _theme) => {
|
|
@@ -40,8 +40,10 @@ export function dbPath(basePath) {
|
|
|
40
40
|
* Used by the renderer to derive the phase number from the DB's milestone_id.
|
|
41
41
|
*/
|
|
42
42
|
export function milestoneIdToPhaseNum(milestoneId) {
|
|
43
|
-
// No $ anchor: accepts bare (M012)
|
|
43
|
+
// No $ anchor: accepts bare (M012), team-suffixed (M012-abc123), and legacy numeric IDs.
|
|
44
44
|
const m = milestoneId.match(/^M0*(\d+)/i);
|
|
45
|
+
if (!m && /^\d+$/.test(milestoneId))
|
|
46
|
+
return Number.parseInt(milestoneId, 10);
|
|
45
47
|
return m ? Number.parseInt(m[1], 10) : 1;
|
|
46
48
|
}
|
|
47
49
|
/** Team-mode suffix from milestone ids like M001-abc123. */
|
|
@@ -12,7 +12,7 @@ import { readFileSync, existsSync, mkdirSync, statSync, unlinkSync } from "node:
|
|
|
12
12
|
import { logWarning } from "./workflow-logger.js";
|
|
13
13
|
import { isClosedStatus } from "./status-guards.js";
|
|
14
14
|
import { dirname, join, relative } from "node:path";
|
|
15
|
-
import { getAllMilestones, getMilestone, getMilestoneScopedArtifacts, getSliceScopedArtifacts, getMilestoneSlices, getSliceTasks, getTask, getSlice, insertArtifact, deleteArtifactByPath, getGateResults, } from "./gsd-db.js";
|
|
15
|
+
import { getAllMilestones, getMilestone, getMilestoneScopedArtifacts, getSliceScopedArtifacts, getMilestoneSlices, getSliceTasks, getTask, getSlice, insertArtifact, deleteArtifactByPath, getGateResults, isDbAvailable, } from "./gsd-db.js";
|
|
16
16
|
import { resolveSliceFile, resolveSlicePath, resolveTaskFile, resolveTasksDir, gsdProjectionRoot, gsdRoot, buildMilestoneFileName, buildTaskFileName, } from "./paths.js";
|
|
17
17
|
import { saveFile, clearParseCache, registerCacheClearCallback } from "./files.js";
|
|
18
18
|
import { parseRoadmap, parsePlan } from "./parsers-legacy.js";
|
|
@@ -518,13 +518,8 @@ export async function renderRoadmapFromDb(basePath, milestoneId) {
|
|
|
518
518
|
* @returns true if the roadmap was written, false on skip/error
|
|
519
519
|
*/
|
|
520
520
|
export async function renderRoadmapCheckboxes(basePath, milestoneId) {
|
|
521
|
-
const
|
|
522
|
-
|
|
523
|
-
process.stderr.write(`markdown-renderer: no slices found for milestone ${milestoneId}\n`);
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
await renderRoadmapFromDb(basePath, milestoneId);
|
|
527
|
-
return true;
|
|
521
|
+
const rendered = await renderRoadmapFromDb(basePath, milestoneId);
|
|
522
|
+
return !("skipped" in rendered);
|
|
528
523
|
}
|
|
529
524
|
/**
|
|
530
525
|
* Project milestone-level artifacts (CONTEXT, RESEARCH, VALIDATION, etc.) from
|
|
@@ -604,11 +599,15 @@ function isAutoRecoveryPlaceholderPlan(content) {
|
|
|
604
599
|
* projection (the 4S/0T-vs-5S/13T drift class). The artifacts table is an
|
|
605
600
|
* output sink, never a render input.
|
|
606
601
|
*
|
|
607
|
-
* @returns true if the plan was written, false
|
|
602
|
+
* @returns true if the plan was written, false when the DB slice has no tasks
|
|
603
|
+
* @throws when the DB connection is unavailable or the render write fails
|
|
608
604
|
*/
|
|
609
605
|
export async function renderPlanCheckboxes(basePath, milestoneId, sliceId, outputPath) {
|
|
610
606
|
const tasks = getSliceTasks(milestoneId, sliceId);
|
|
611
607
|
if (tasks.length === 0) {
|
|
608
|
+
if (!isDbAvailable()) {
|
|
609
|
+
throw new Error(`database unavailable while rendering plan checkboxes for ${milestoneId}/${sliceId}`);
|
|
610
|
+
}
|
|
612
611
|
process.stderr.write(`markdown-renderer: no tasks found for ${milestoneId}/${sliceId}\n`);
|
|
613
612
|
return false;
|
|
614
613
|
}
|
|
@@ -94,27 +94,48 @@ function getActiveDecisions() {
|
|
|
94
94
|
return [];
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*/
|
|
103
|
-
function memoryHasSourceMarker(markerKey, value) {
|
|
97
|
+
function emptyMemorySourceMarkers() {
|
|
98
|
+
return { decisionIds: new Set(), knowledgeIds: new Set() };
|
|
99
|
+
}
|
|
100
|
+
function getMemorySourceMarkers() {
|
|
101
|
+
const markers = emptyMemorySourceMarkers();
|
|
104
102
|
if (!isDbAvailable())
|
|
105
|
-
return
|
|
103
|
+
return markers;
|
|
106
104
|
const adapter = _getAdapter();
|
|
107
105
|
if (!adapter)
|
|
108
|
-
return
|
|
106
|
+
return markers;
|
|
109
107
|
try {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
.
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
const rows = adapter
|
|
109
|
+
.prepare("SELECT structured_fields FROM memories WHERE structured_fields IS NOT NULL")
|
|
110
|
+
.all();
|
|
111
|
+
for (const row of rows) {
|
|
112
|
+
collectMemorySourceMarker(markers, row["structured_fields"]);
|
|
113
|
+
}
|
|
115
114
|
}
|
|
116
115
|
catch {
|
|
117
|
-
return
|
|
116
|
+
return markers;
|
|
117
|
+
}
|
|
118
|
+
return markers;
|
|
119
|
+
}
|
|
120
|
+
function collectMemorySourceMarker(markers, raw) {
|
|
121
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
122
|
+
return;
|
|
123
|
+
try {
|
|
124
|
+
const parsed = JSON.parse(raw);
|
|
125
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
126
|
+
return;
|
|
127
|
+
const fields = parsed;
|
|
128
|
+
const decisionId = fields["sourceDecisionId"];
|
|
129
|
+
if (typeof decisionId === "string" && decisionId.length > 0) {
|
|
130
|
+
markers.decisionIds.add(decisionId);
|
|
131
|
+
}
|
|
132
|
+
const knowledgeId = fields["sourceKnowledgeId"];
|
|
133
|
+
if (typeof knowledgeId === "string" && knowledgeId.length > 0) {
|
|
134
|
+
markers.knowledgeIds.add(knowledgeId);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return;
|
|
118
139
|
}
|
|
119
140
|
}
|
|
120
141
|
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
@@ -127,10 +148,14 @@ const SAMPLE_LIMIT = 5;
|
|
|
127
148
|
export function scanConsolidationGaps(basePath) {
|
|
128
149
|
// ── Decisions ────────────────────────────────────────────────────────
|
|
129
150
|
const decisions = getActiveDecisions();
|
|
151
|
+
const knowledgeRows = parseKnowledgeRows(knowledgeMdContent(basePath));
|
|
152
|
+
const memorySourceMarkers = decisions.length > 0 || knowledgeRows.length > 0
|
|
153
|
+
? getMemorySourceMarkers()
|
|
154
|
+
: emptyMemorySourceMarkers();
|
|
130
155
|
const decisionSamples = [];
|
|
131
156
|
let decisionMigrated = 0;
|
|
132
157
|
for (const decision of decisions) {
|
|
133
|
-
if (
|
|
158
|
+
if (memorySourceMarkers.decisionIds.has(decision.id)) {
|
|
134
159
|
decisionMigrated += 1;
|
|
135
160
|
continue;
|
|
136
161
|
}
|
|
@@ -142,16 +167,14 @@ export function scanConsolidationGaps(basePath) {
|
|
|
142
167
|
}
|
|
143
168
|
}
|
|
144
169
|
// ── KNOWLEDGE.md ─────────────────────────────────────────────────────
|
|
145
|
-
const knowledgeRows = parseKnowledgeRows(knowledgeMdContent(basePath));
|
|
146
170
|
const knowledgeByTable = { rules: 0, patterns: 0, lessons: 0 };
|
|
147
171
|
const knowledgeSamples = [];
|
|
148
172
|
let knowledgeMigrated = 0;
|
|
149
173
|
for (const row of knowledgeRows) {
|
|
150
174
|
knowledgeByTable[row.table] += 1;
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
if (memoryHasSourceMarker("sourceKnowledgeId", row.id)) {
|
|
175
|
+
// KNOWLEDGE.md backfill writes `sourceKnowledgeId`; rows without that
|
|
176
|
+
// marker are still reported as consolidation gaps.
|
|
177
|
+
if (memorySourceMarkers.knowledgeIds.has(row.id)) {
|
|
155
178
|
knowledgeMigrated += 1;
|
|
156
179
|
continue;
|
|
157
180
|
}
|
|
@@ -45,6 +45,27 @@ function scanHasExtraIdentities(a, b) {
|
|
|
45
45
|
hasExtra(a.slices, b.slices) ||
|
|
46
46
|
hasExtra(a.tasks, b.tasks));
|
|
47
47
|
}
|
|
48
|
+
function paddedMilestoneId(id) {
|
|
49
|
+
return /^\d+$/.test(id) ? `M${id.padStart(3, "0")}` : null;
|
|
50
|
+
}
|
|
51
|
+
function replaceSetPrefix(values, from, to) {
|
|
52
|
+
for (const value of [...values]) {
|
|
53
|
+
if (value !== from && !value.startsWith(`${from}/`))
|
|
54
|
+
continue;
|
|
55
|
+
values.delete(value);
|
|
56
|
+
values.add(`${to}${value.slice(from.length)}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function alignNumericMarkdownIdsWithDb(markdownScan, dbScan) {
|
|
60
|
+
for (const dbId of dbScan.milestones) {
|
|
61
|
+
const paddedId = paddedMilestoneId(dbId);
|
|
62
|
+
if (!paddedId || dbScan.milestones.has(paddedId) || !markdownScan.milestones.has(paddedId))
|
|
63
|
+
continue;
|
|
64
|
+
replaceSetPrefix(markdownScan.milestones, paddedId, dbId);
|
|
65
|
+
replaceSetPrefix(markdownScan.slices, paddedId, dbId);
|
|
66
|
+
replaceSetPrefix(markdownScan.tasks, paddedId, dbId);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
48
69
|
/**
|
|
49
70
|
* True when the DB holds any milestone/slice/task identity the markdown lacks —
|
|
50
71
|
* i.e. a `/gsd recover --confirm` (markdown → DB) would DELETE authoritative DB
|
|
@@ -126,6 +147,7 @@ export async function checkMarkdownHierarchyAgainstDb(basePath) {
|
|
|
126
147
|
refreshWorkflowDatabaseFromDisk();
|
|
127
148
|
const dbScan = scanDbHierarchy();
|
|
128
149
|
const beforeDb = dbScan.counts;
|
|
150
|
+
alignNumericMarkdownIdsWithDb(markdownScan, dbScan);
|
|
129
151
|
// Discussion-phase scratch: a milestone dir with no ROADMAP and no DB row is
|
|
130
152
|
// a pre-registration discussion artifact (CONTEXT/CONTEXT-DRAFT only — the
|
|
131
153
|
// queued DB row is inserted only at discussion handoff). Treating it as
|
|
@@ -123,7 +123,8 @@ export function clearReservedMilestoneIds() {
|
|
|
123
123
|
reservedMilestoneIds.clear();
|
|
124
124
|
}
|
|
125
125
|
// ─── Discovery ──────────────────────────────────────────────────────────────
|
|
126
|
-
function scanMilestoneIdsFromDir(dir) {
|
|
126
|
+
function scanMilestoneIdsFromDir(basePath, dir) {
|
|
127
|
+
const legacyNumericIds = idsWithLegacyNumericDirs(basePath);
|
|
127
128
|
return readdirSync(dir, { withFileTypes: true })
|
|
128
129
|
.filter((d) => d.isDirectory())
|
|
129
130
|
.map((d) => {
|
|
@@ -131,6 +132,12 @@ function scanMilestoneIdsFromDir(dir) {
|
|
|
131
132
|
if (MILESTONE_ID_RE.test(d.name)) {
|
|
132
133
|
return d.name;
|
|
133
134
|
}
|
|
135
|
+
// Legacy recovery/imports may contain bare numeric milestone directories
|
|
136
|
+
// (for example `milestones/15/15-ROADMAP.md`). The DB can preserve that
|
|
137
|
+
// id, and rebuild renders it, so drift scans must see it too.
|
|
138
|
+
if (/^\d+$/.test(d.name)) {
|
|
139
|
+
return d.name;
|
|
140
|
+
}
|
|
134
141
|
// Legacy layout: M001-abcdef-slug descriptor directories
|
|
135
142
|
const legacyMatch = d.name.match(/^(M\d{3}(?:-[a-z0-9]{6})?)-/);
|
|
136
143
|
if (legacyMatch) {
|
|
@@ -144,12 +151,35 @@ function scanMilestoneIdsFromDir(dir) {
|
|
|
144
151
|
if (MILESTONE_ID_RE.test(fromSlug)) {
|
|
145
152
|
return fromSlug;
|
|
146
153
|
}
|
|
154
|
+
const numericId = String(phaseNum);
|
|
155
|
+
if (legacyNumericIds.has(numericId)) {
|
|
156
|
+
return numericId;
|
|
157
|
+
}
|
|
147
158
|
return `M${String(phaseNum).padStart(3, "0")}`;
|
|
148
159
|
}
|
|
149
160
|
return null;
|
|
150
161
|
})
|
|
151
162
|
.filter((id) => id !== null);
|
|
152
163
|
}
|
|
164
|
+
function idsWithLegacyNumericDirs(basePath) {
|
|
165
|
+
const legacyDir = join(gsdProjectionRoot(basePath), "milestones");
|
|
166
|
+
const ids = new Set();
|
|
167
|
+
try {
|
|
168
|
+
for (const entry of readdirSync(legacyDir, { withFileTypes: true })) {
|
|
169
|
+
if (entry.isDirectory() && /^\d+$/.test(entry.name))
|
|
170
|
+
ids.add(entry.name);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
// A missing legacy directory is the common, benign case (nothing to
|
|
175
|
+
// consult). Only surface a real failure when the directory exists but
|
|
176
|
+
// could not be read.
|
|
177
|
+
if (existsSync(legacyDir)) {
|
|
178
|
+
logWarning("engine", `idsWithLegacyNumericDirs: ${legacyDir} exists but readdirSync failed — ${getErrorMessage(err)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return ids;
|
|
182
|
+
}
|
|
153
183
|
/** Scan the milestones directory and return IDs sorted by queue order (or numeric fallback). */
|
|
154
184
|
export function findMilestoneIds(basePath) {
|
|
155
185
|
const root = gsdProjectionRoot(basePath);
|
|
@@ -163,7 +193,7 @@ export function findMilestoneIds(basePath) {
|
|
|
163
193
|
const ids = new Set();
|
|
164
194
|
for (const dir of dirs) {
|
|
165
195
|
try {
|
|
166
|
-
for (const id of scanMilestoneIdsFromDir(dir))
|
|
196
|
+
for (const id of scanMilestoneIdsFromDir(basePath, dir))
|
|
167
197
|
ids.add(id);
|
|
168
198
|
}
|
|
169
199
|
catch (err) {
|
|
@@ -10,6 +10,8 @@ import { logWarning } from "./workflow-logger.js";
|
|
|
10
10
|
import { resolveTasksDir } from "./paths.js";
|
|
11
11
|
/** Large enough for unbounded milestone-history git log scans in big repos. */
|
|
12
12
|
const GIT_LOG_MAX_BUFFER = 16 * 1024 * 1024;
|
|
13
|
+
const LOG_FIELD_SEPARATOR = "\x1f";
|
|
14
|
+
const LOG_RECORD_SEPARATOR = "\x1e";
|
|
13
15
|
/**
|
|
14
16
|
* Check whether a milestone produced implementation artifacts (non-`.gsd/`
|
|
15
17
|
* files) in git history. The primary signal is the branch diff against the
|
|
@@ -179,7 +181,7 @@ function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
|
|
|
179
181
|
// Primary: path-scoped log against .gsd/milestones/<id>. Fast and unbounded
|
|
180
182
|
// by depth when .gsd/ is tracked in git.
|
|
181
183
|
const scoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
182
|
-
"log", "--format=%H%x1f%B%
|
|
184
|
+
"log", "--full-diff", "--name-only", "--format=%x1e%H%x1f%B%x1f", "HEAD", "--", `.gsd/milestones/${milestoneId}`,
|
|
183
185
|
]);
|
|
184
186
|
if (!scoped.ok)
|
|
185
187
|
return scoped;
|
|
@@ -195,7 +197,7 @@ function getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId) {
|
|
|
195
197
|
// reintroducing the rolling-depth failure class removed in #4699 where
|
|
196
198
|
// milestone evidence aged out behind unrelated activity.
|
|
197
199
|
const unscoped = scanGsdTaggedCommits(basePath, milestoneId, [
|
|
198
|
-
"log", "--format=%H%x1f%B%
|
|
200
|
+
"log", "--name-only", "--format=%x1e%H%x1f%B%x1f", "HEAD",
|
|
199
201
|
]);
|
|
200
202
|
if (!unscoped.ok)
|
|
201
203
|
return scoped.matched ? scoped : unscoped;
|
|
@@ -280,8 +282,7 @@ function backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId)
|
|
|
280
282
|
continue;
|
|
281
283
|
if (commitMessageHasGsdTrailer(record.message))
|
|
282
284
|
continue;
|
|
283
|
-
const
|
|
284
|
-
const implementationFiles = commitFiles.map(normalizeRepoPath).filter(isImplementationPath);
|
|
285
|
+
const implementationFiles = record.files.map(normalizeRepoPath).filter(isImplementationPath);
|
|
285
286
|
if (implementationFiles.length === 0)
|
|
286
287
|
continue;
|
|
287
288
|
if (!implementationFiles.some((file) => hintSet.has(file)))
|
|
@@ -306,24 +307,28 @@ function backfillChangedFilesFromUntaggedMilestoneCommits(basePath, milestoneId)
|
|
|
306
307
|
}
|
|
307
308
|
}
|
|
308
309
|
function getCommitRecords(basePath) {
|
|
309
|
-
const logOutput = execFileSync("git", ["log", "--format=%H%x1f%P%x1f%cI%x1f%B%
|
|
310
|
+
const logOutput = execFileSync("git", ["log", "--name-only", "--format=%x1e%H%x1f%P%x1f%cI%x1f%B%x1f", "HEAD"], {
|
|
310
311
|
cwd: basePath,
|
|
311
312
|
stdio: ["ignore", "pipe", "pipe"],
|
|
312
313
|
encoding: "utf-8",
|
|
313
314
|
maxBuffer: GIT_LOG_MAX_BUFFER,
|
|
314
315
|
});
|
|
315
316
|
return logOutput
|
|
316
|
-
.split(
|
|
317
|
-
.map((record) => record.trim())
|
|
317
|
+
.split(LOG_RECORD_SEPARATOR)
|
|
318
318
|
.filter(Boolean)
|
|
319
319
|
.flatMap((record) => {
|
|
320
|
-
const parts = record.split(
|
|
321
|
-
if (parts.length <
|
|
320
|
+
const parts = record.split(LOG_FIELD_SEPARATOR);
|
|
321
|
+
if (parts.length < 5)
|
|
322
322
|
return [];
|
|
323
|
-
const [hash, parents, committedAt
|
|
324
|
-
|
|
323
|
+
const [hash, parents, committedAt] = parts;
|
|
324
|
+
const files = parseNameOnlyFiles(parts.at(-1) ?? "");
|
|
325
|
+
const message = parts.slice(3, -1).join(LOG_FIELD_SEPARATOR);
|
|
326
|
+
return [{ hash: hash.trim(), parents: parents.trim(), committedAt: committedAt.trim(), message, files }];
|
|
325
327
|
});
|
|
326
328
|
}
|
|
329
|
+
function parseNameOnlyFiles(rawFiles) {
|
|
330
|
+
return rawFiles.split(/\r?\n/).map((file) => file.trim()).filter(Boolean);
|
|
331
|
+
}
|
|
327
332
|
function isFullCommitSha(value) {
|
|
328
333
|
return /^[0-9a-f]{40}$/i.test(value);
|
|
329
334
|
}
|
|
@@ -336,23 +341,24 @@ function scanGsdTaggedCommits(basePath, milestoneId, gitArgs) {
|
|
|
336
341
|
maxBuffer: GIT_LOG_MAX_BUFFER,
|
|
337
342
|
});
|
|
338
343
|
const records = logOutput
|
|
339
|
-
.split(
|
|
340
|
-
.map((record) => record.trim())
|
|
344
|
+
.split(LOG_RECORD_SEPARATOR)
|
|
341
345
|
.filter(Boolean)
|
|
342
346
|
.flatMap((record) => {
|
|
343
|
-
const
|
|
344
|
-
if (
|
|
347
|
+
const parts = record.split(LOG_FIELD_SEPARATOR);
|
|
348
|
+
if (parts.length < 3)
|
|
349
|
+
return [];
|
|
350
|
+
const hash = parts[0].trim();
|
|
351
|
+
if (!hash)
|
|
345
352
|
return [];
|
|
346
|
-
const
|
|
347
|
-
const message =
|
|
348
|
-
return [{
|
|
353
|
+
const files = parseNameOnlyFiles(parts.at(-1) ?? "");
|
|
354
|
+
const message = parts.slice(1, -1).join(LOG_FIELD_SEPARATOR);
|
|
355
|
+
return [{ message, files }];
|
|
349
356
|
});
|
|
350
357
|
const files = new Set();
|
|
351
358
|
let matched = false;
|
|
352
|
-
for (const {
|
|
359
|
+
for (const { message, files: commitFiles } of records) {
|
|
353
360
|
if (!commitMessageHasGsdTrailer(message))
|
|
354
361
|
continue;
|
|
355
|
-
const commitFiles = getChangedFilesForCommit(basePath, hash);
|
|
356
362
|
if (!commitMatchesMilestone(basePath, message, milestoneId, commitFiles))
|
|
357
363
|
continue;
|
|
358
364
|
matched = true;
|