@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
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Runtime state derivation from GSD workflow database and legacy files.
|
|
3
3
|
// GSD Extension — State Derivation
|
|
4
|
-
// DB-authoritative runtime derivation
|
|
5
|
-
// Pure TypeScript, zero Pi dependencies.
|
|
4
|
+
// DB-authoritative runtime derivation; legacy filesystem fallback in _deriveStateImpl only.
|
|
6
5
|
|
|
7
6
|
import type {
|
|
8
7
|
GSDState,
|
|
@@ -47,8 +46,6 @@ import { findMilestoneIds } from './milestone-ids.js';
|
|
|
47
46
|
import { loadQueueOrder, sortByQueueOrder } from './queue-order.js';
|
|
48
47
|
import { isClosedStatus, isDeferredStatus } from './status-guards.js';
|
|
49
48
|
import { nativeBatchParseGsdFiles, type BatchParsedFile } from './native-parser-bridge.js';
|
|
50
|
-
import { autoHealSketchFlags } from './state-reconciliation/drift/sketch-flag.js';
|
|
51
|
-
|
|
52
49
|
import { join, resolve } from 'path';
|
|
53
50
|
import { existsSync, readdirSync } from 'node:fs';
|
|
54
51
|
import { debugCount, debugTime } from './debug-logger.js';
|
|
@@ -56,6 +53,25 @@ import { logWarning } from './workflow-logger.js';
|
|
|
56
53
|
import { extractVerdict } from './verdict-parser.js';
|
|
57
54
|
import { detectPendingEscalation } from './escalation.js';
|
|
58
55
|
import { isTerminalMilestoneSummaryContent } from './milestone-summary-classifier.js';
|
|
56
|
+
import { interruptedWorkNextAction, detectInterruptedWork } from './state/derive/interrupted-work.js';
|
|
57
|
+
import {
|
|
58
|
+
deriveState,
|
|
59
|
+
getDeriveTelemetry,
|
|
60
|
+
invalidateStateCache,
|
|
61
|
+
resetDeriveTelemetry,
|
|
62
|
+
type DeriveStateOptions,
|
|
63
|
+
} from './state/derive/index.js';
|
|
64
|
+
import { deriveStateFromDb } from './state/derive/from-db.js';
|
|
65
|
+
import { getRequestedMilestoneLock, syncQueueOrderProjectionToDb } from './state/derive/db-open.js';
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
deriveState,
|
|
69
|
+
deriveStateFromDb,
|
|
70
|
+
getDeriveTelemetry,
|
|
71
|
+
invalidateStateCache,
|
|
72
|
+
resetDeriveTelemetry,
|
|
73
|
+
type DeriveStateOptions,
|
|
74
|
+
};
|
|
59
75
|
|
|
60
76
|
import {
|
|
61
77
|
isDbAvailable,
|
|
@@ -206,111 +222,6 @@ async function isTerminalMilestoneSummaryFile(
|
|
|
206
222
|
return content != null && isTerminalMilestoneSummaryContent(content);
|
|
207
223
|
}
|
|
208
224
|
|
|
209
|
-
// ─── State Derivation ──────────────────────────────────────────────────────
|
|
210
|
-
|
|
211
|
-
// ── deriveState memoization ─────────────────────────────────────────────────
|
|
212
|
-
// Cache the most recent deriveState() result keyed by basePath. Within a single
|
|
213
|
-
// dispatch cycle (~100ms window), repeated calls return the cached value instead
|
|
214
|
-
// of re-reading the entire .gsd/ tree from disk.
|
|
215
|
-
|
|
216
|
-
interface StateCache {
|
|
217
|
-
basePath: string;
|
|
218
|
-
result: GSDState;
|
|
219
|
-
timestamp: number;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const CACHE_TTL_MS = 100;
|
|
223
|
-
let _stateCache: StateCache | null = null;
|
|
224
|
-
|
|
225
|
-
// ── Telemetry counters for derive-path observability ────────────────────────
|
|
226
|
-
let _telemetry = { dbDeriveCount: 0 };
|
|
227
|
-
export function getDeriveTelemetry() { return { ..._telemetry }; }
|
|
228
|
-
export function resetDeriveTelemetry() { _telemetry = { dbDeriveCount: 0 }; }
|
|
229
|
-
|
|
230
|
-
async function loadRecentDecisions(basePath: string): Promise<string[]> {
|
|
231
|
-
const decisionsPath = resolveGsdRootFile(basePath, "DECISIONS");
|
|
232
|
-
const content = await loadFile(decisionsPath);
|
|
233
|
-
if (!content) return [];
|
|
234
|
-
|
|
235
|
-
const fromTable = content
|
|
236
|
-
.split("\n")
|
|
237
|
-
.map((line) => line.trim())
|
|
238
|
-
.filter((line) => line.startsWith("|"))
|
|
239
|
-
.map((line) => {
|
|
240
|
-
const cells = line
|
|
241
|
-
.split("|")
|
|
242
|
-
.map((cell) => cell.trim())
|
|
243
|
-
.filter((cell) => cell.length > 0);
|
|
244
|
-
if (cells.length < 6) return null;
|
|
245
|
-
const id = cells[0];
|
|
246
|
-
if (!/^D\d+$/i.test(id)) return null;
|
|
247
|
-
const whenContext = cells[1];
|
|
248
|
-
const decision = cells[3];
|
|
249
|
-
const choice = cells[4];
|
|
250
|
-
if (!decision || !choice) return null;
|
|
251
|
-
return `${id} (${whenContext}): ${decision} -> ${choice}`;
|
|
252
|
-
})
|
|
253
|
-
.filter((value): value is string => value != null);
|
|
254
|
-
|
|
255
|
-
if (fromTable.length > 0) return fromTable.slice(-5);
|
|
256
|
-
|
|
257
|
-
const fromBullets = content
|
|
258
|
-
.split("\n")
|
|
259
|
-
.map((line) => line.trim())
|
|
260
|
-
.filter((line) => /^-\s+/.test(line))
|
|
261
|
-
.map((line) => line.replace(/^-+\s+/, ""))
|
|
262
|
-
.filter((line) => /^D\d+\b/i.test(line));
|
|
263
|
-
|
|
264
|
-
return fromBullets.slice(-5);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Invalidate the deriveState() cache. Call this whenever planning files on disk
|
|
269
|
-
* may have changed (unit completion, merges, file writes).
|
|
270
|
-
*/
|
|
271
|
-
export function invalidateStateCache(): void {
|
|
272
|
-
_stateCache = null;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function syncQueueOrderProjectionToDb(basePath: string): void {
|
|
276
|
-
const queueOrder = loadQueueOrder(basePath);
|
|
277
|
-
if (!queueOrder) return;
|
|
278
|
-
|
|
279
|
-
const currentIds = getAllMilestones().map((m) => m.id);
|
|
280
|
-
const desiredIds = sortByQueueOrder(currentIds, queueOrder);
|
|
281
|
-
if (currentIds.length === desiredIds.length && currentIds.every((id, i) => id === desiredIds[i])) return;
|
|
282
|
-
|
|
283
|
-
setMilestoneQueueOrder(desiredIds);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function ensureExistingWorkflowDbOpen(basePath: string): boolean {
|
|
287
|
-
const opened = isDbAvailable() || openExistingWorkflowDatabase(basePath).ok;
|
|
288
|
-
if (opened) syncQueueOrderProjectionToDb(basePath);
|
|
289
|
-
return opened;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function buildDbUnavailableState(): GSDState {
|
|
293
|
-
return {
|
|
294
|
-
activeMilestone: null,
|
|
295
|
-
activeSlice: null,
|
|
296
|
-
activeTask: null,
|
|
297
|
-
phase: "pre-planning",
|
|
298
|
-
recentDecisions: [],
|
|
299
|
-
blockers: ["DB unavailable — runtime markdown state derivation is disabled"],
|
|
300
|
-
nextAction: "Open or create the canonical GSD database before deriving workflow state. If this project only has markdown state, run /gsd migrate explicitly.",
|
|
301
|
-
registry: [],
|
|
302
|
-
requirements: { active: 0, validated: 0, deferred: 0, outOfScope: 0, blocked: 0, total: 0 },
|
|
303
|
-
progress: { milestones: { done: 0, total: 0 } },
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Returns the ID of the first incomplete milestone, or null if all are complete.
|
|
309
|
-
*/
|
|
310
|
-
function getRequestedMilestoneLock(): string | undefined {
|
|
311
|
-
const lock = process.env.GSD_MILESTONE_LOCK?.trim();
|
|
312
|
-
return lock || undefined;
|
|
313
|
-
}
|
|
314
225
|
|
|
315
226
|
export async function getActiveMilestoneId(basePath: string): Promise<string | null> {
|
|
316
227
|
// Milestone-scoped execution. Parallel workers and explicit solo commands
|
|
@@ -368,85 +279,6 @@ export async function getActiveMilestoneId(basePath: string): Promise<string | n
|
|
|
368
279
|
return null;
|
|
369
280
|
}
|
|
370
281
|
|
|
371
|
-
/**
|
|
372
|
-
* Options for deriveState read-path routing.
|
|
373
|
-
*
|
|
374
|
-
* `projectRootForReads`: canonical project root (e.g. from
|
|
375
|
-
* `s.canonicalProjectRoot`) used for both the cache key and the artifact-read
|
|
376
|
-
* root in `_deriveStateImpl`. When omitted, behavior is identical to the
|
|
377
|
-
* single-arg signature (back-compat for all existing callers).
|
|
378
|
-
*
|
|
379
|
-
* Typed as an object literal (not `string | DeriveStateOptions`) so accidental
|
|
380
|
-
* `deriveState(path, "string")` is rejected at compile time.
|
|
381
|
-
*/
|
|
382
|
-
export interface DeriveStateOptions {
|
|
383
|
-
projectRootForReads?: string;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Reconstruct GSD state from the authoritative DB.
|
|
388
|
-
* STATE.md is a rendered cache of this output.
|
|
389
|
-
*
|
|
390
|
-
* When DB is available, queries milestone/slice/task tables directly.
|
|
391
|
-
* Runtime must not silently infer state from markdown. Use explicit recovery
|
|
392
|
-
* or `/gsd migrate` when markdown is the intended source.
|
|
393
|
-
*/
|
|
394
|
-
export async function deriveState(
|
|
395
|
-
basePath: string,
|
|
396
|
-
opts?: DeriveStateOptions,
|
|
397
|
-
): Promise<GSDState> {
|
|
398
|
-
// Use the canonical project root (when provided) as the cache key so that
|
|
399
|
-
// two calls with different basePath strings (e.g. worktree path vs project
|
|
400
|
-
// root) but the same canonical .gsd/ share a single cache entry. The same
|
|
401
|
-
// key is used for both the lookup AND the write below — keying lookup on
|
|
402
|
-
// canonical-root while writing on basePath would silently return stale
|
|
403
|
-
// results across path-form alternation.
|
|
404
|
-
const cacheKey = opts?.projectRootForReads ?? basePath;
|
|
405
|
-
|
|
406
|
-
// Return cached result if within the TTL window for the same cacheKey
|
|
407
|
-
if (
|
|
408
|
-
_stateCache &&
|
|
409
|
-
_stateCache.basePath === cacheKey &&
|
|
410
|
-
Date.now() - _stateCache.timestamp < CACHE_TTL_MS
|
|
411
|
-
) {
|
|
412
|
-
return _stateCache.result;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const stopTimer = debugTime("derive-state-impl");
|
|
416
|
-
let result: GSDState;
|
|
417
|
-
|
|
418
|
-
// DB-backed derivation is authoritative whenever the DB is open. Runtime
|
|
419
|
-
// degrade must not infer state from ROADMAP.md, PLAN.md, SUMMARY.md,
|
|
420
|
-
// REQUIREMENTS.md, or flag files.
|
|
421
|
-
ensureExistingWorkflowDbOpen(basePath);
|
|
422
|
-
|
|
423
|
-
if (isDbAvailable()) {
|
|
424
|
-
const stopDbTimer = debugTime("derive-state-db");
|
|
425
|
-
result = await deriveStateFromDb(basePath, opts?.projectRootForReads ?? basePath);
|
|
426
|
-
stopDbTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
|
|
427
|
-
_telemetry.dbDeriveCount++;
|
|
428
|
-
} else {
|
|
429
|
-
if (wasWorkflowDatabaseOpenAttempted()) {
|
|
430
|
-
logWarning("state", "DB unavailable — refusing implicit markdown state derivation");
|
|
431
|
-
}
|
|
432
|
-
result = buildDbUnavailableState();
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
result.recentDecisions = await loadRecentDecisions(cacheKey);
|
|
436
|
-
stopTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
|
|
437
|
-
debugCount("deriveStateCalls");
|
|
438
|
-
_stateCache = { basePath: cacheKey, result, timestamp: Date.now() };
|
|
439
|
-
return result;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
/**
|
|
443
|
-
* Extract milestone title from CONTEXT.md or CONTEXT-DRAFT.md heading.
|
|
444
|
-
* Falls back to the provided fallback (usually the milestone ID).
|
|
445
|
-
*/
|
|
446
|
-
/**
|
|
447
|
-
* Strip the "M001: " prefix from a milestone title to get the human-readable name.
|
|
448
|
-
* Used by both DB and filesystem paths for consistency.
|
|
449
|
-
*/
|
|
450
282
|
function stripMilestonePrefix(title: string): string {
|
|
451
283
|
return title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, '') || title;
|
|
452
284
|
}
|
|
@@ -459,541 +291,6 @@ function extractContextTitle(content: string | null, fallback: string): string {
|
|
|
459
291
|
return stripMilestonePrefix(h1.slice(2).trim()) || fallback;
|
|
460
292
|
}
|
|
461
293
|
|
|
462
|
-
// ─── DB-backed State Derivation ────────────────────────────────────────────
|
|
463
|
-
|
|
464
|
-
// isStatusDone replaced by isClosedStatus from status-guards.ts (single source of truth).
|
|
465
|
-
// Alias kept for backward compatibility within this file.
|
|
466
|
-
const isStatusDone = isClosedStatus;
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Derive GSD state from the milestones/slices/tasks DB tables.
|
|
470
|
-
* Markdown files are projections only in this path; they are never imported,
|
|
471
|
-
* reconciled, or used as completion signals.
|
|
472
|
-
*/
|
|
473
|
-
|
|
474
|
-
function buildCompletenessSet(basePath: string, milestones: MilestoneRow[]) {
|
|
475
|
-
const completeMilestoneIds = new Set<string>();
|
|
476
|
-
const parkedMilestoneIds = new Set<string>();
|
|
477
|
-
|
|
478
|
-
// DB-authoritative: a milestone is only "complete" when its DB row says so.
|
|
479
|
-
// SUMMARY-file presence is NOT a completion signal here — an orphan SUMMARY
|
|
480
|
-
// (crashed complete-milestone turn, partial merge, manual edit) must not
|
|
481
|
-
// flip derived state to complete and cascade into a false auto-merge (#4179).
|
|
482
|
-
for (const m of milestones) {
|
|
483
|
-
if (m.status === 'parked') {
|
|
484
|
-
parkedMilestoneIds.add(m.id);
|
|
485
|
-
continue;
|
|
486
|
-
}
|
|
487
|
-
if (isStatusDone(m.status)) {
|
|
488
|
-
completeMilestoneIds.add(m.id);
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
return { completeMilestoneIds, parkedMilestoneIds };
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function milestoneArtifactExistsInResolvedDir(
|
|
496
|
-
milestoneDir: string | null,
|
|
497
|
-
milestoneId: string,
|
|
498
|
-
suffix: string,
|
|
499
|
-
): boolean {
|
|
500
|
-
if (!milestoneDir) return false;
|
|
501
|
-
const flatPath = join(milestoneDir, buildMilestoneFileName(milestoneId, suffix));
|
|
502
|
-
return existsSync(flatPath) || resolveFile(milestoneDir, milestoneId, suffix) !== null;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
async function buildRegistryAndFindActive(
|
|
506
|
-
basePath: string,
|
|
507
|
-
milestones: MilestoneRow[],
|
|
508
|
-
completeMilestoneIds: Set<string>,
|
|
509
|
-
parkedMilestoneIds: Set<string>
|
|
510
|
-
) {
|
|
511
|
-
const registry: MilestoneRegistryEntry[] = [];
|
|
512
|
-
let activeMilestone: ActiveRef | null = null;
|
|
513
|
-
let activeMilestoneSlices: SliceRow[] = [];
|
|
514
|
-
let activeMilestoneFound = false;
|
|
515
|
-
let activeMilestoneHasDraft = false;
|
|
516
|
-
let firstDeferredQueuedShell: { id: string; title: string; deps: string[]; hasDraftContext: boolean } | null = null;
|
|
517
|
-
|
|
518
|
-
const activeMilestoneIds = milestones
|
|
519
|
-
.filter((m) => !parkedMilestoneIds.has(m.id))
|
|
520
|
-
.map((m) => m.id);
|
|
521
|
-
const slicesByMilestone = getSlicesByMilestoneIds(activeMilestoneIds);
|
|
522
|
-
|
|
523
|
-
for (const m of milestones) {
|
|
524
|
-
if (parkedMilestoneIds.has(m.id)) {
|
|
525
|
-
registry.push({ id: m.id, title: stripMilestonePrefix(m.title) || m.id, status: 'parked' });
|
|
526
|
-
continue;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const slices = slicesByMilestone.get(m.id) ?? [];
|
|
530
|
-
|
|
531
|
-
// DB-authoritative completeness (#4179): only trust completeMilestoneIds,
|
|
532
|
-
// which is itself derived from DB status. SUMMARY-file presence alone must
|
|
533
|
-
// not imply completion.
|
|
534
|
-
if (completeMilestoneIds.has(m.id)) {
|
|
535
|
-
const title = stripMilestonePrefix(m.title) || m.id;
|
|
536
|
-
registry.push({ id: m.id, title, status: 'complete' });
|
|
537
|
-
continue;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
const allSlicesDone = slices.length > 0 && slices.every(s => isStatusDone(s.status));
|
|
541
|
-
|
|
542
|
-
const title = stripMilestonePrefix(m.title) || m.id;
|
|
543
|
-
const milestoneDir = resolveMilestonePath(basePath, m.id);
|
|
544
|
-
const hasContext = milestoneArtifactExistsInResolvedDir(milestoneDir, m.id, "CONTEXT");
|
|
545
|
-
const hasDraftContext = !hasContext && milestoneArtifactExistsInResolvedDir(milestoneDir, m.id, "CONTEXT-DRAFT");
|
|
546
|
-
const readiness = classifyMilestoneReadiness({
|
|
547
|
-
status: m.status,
|
|
548
|
-
hasContext,
|
|
549
|
-
hasDraftContext,
|
|
550
|
-
sliceCount: slices.length,
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
if (!activeMilestoneFound) {
|
|
554
|
-
const deps = m.depends_on;
|
|
555
|
-
const depsUnmet = deps.some(dep => !completeMilestoneIds.has(dep));
|
|
556
|
-
|
|
557
|
-
if (depsUnmet) {
|
|
558
|
-
registry.push({ id: m.id, title, status: 'pending', dependsOn: deps });
|
|
559
|
-
continue;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
if (readiness.kind === 'queued-shell') {
|
|
563
|
-
if (!firstDeferredQueuedShell) {
|
|
564
|
-
firstDeferredQueuedShell = { id: m.id, title, deps, hasDraftContext: readiness.hasDraftContext };
|
|
565
|
-
}
|
|
566
|
-
registry.push({ id: m.id, title, status: 'pending', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
567
|
-
continue;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
if (allSlicesDone) {
|
|
571
|
-
activeMilestone = { id: m.id, title };
|
|
572
|
-
activeMilestoneSlices = slices;
|
|
573
|
-
activeMilestoneFound = true;
|
|
574
|
-
registry.push({ id: m.id, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
575
|
-
continue;
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
if (readinessNeedsDiscussion(readiness)) activeMilestoneHasDraft = true;
|
|
579
|
-
|
|
580
|
-
activeMilestone = { id: m.id, title };
|
|
581
|
-
activeMilestoneSlices = slices;
|
|
582
|
-
activeMilestoneFound = true;
|
|
583
|
-
registry.push({ id: m.id, title, status: 'active', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
584
|
-
} else {
|
|
585
|
-
const deps = m.depends_on;
|
|
586
|
-
registry.push({ id: m.id, title, status: 'pending', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (!activeMilestoneFound && firstDeferredQueuedShell) {
|
|
591
|
-
const shell = firstDeferredQueuedShell;
|
|
592
|
-
activeMilestone = { id: shell.id, title: shell.title };
|
|
593
|
-
activeMilestoneSlices = [];
|
|
594
|
-
activeMilestoneFound = true;
|
|
595
|
-
if (shell.hasDraftContext) activeMilestoneHasDraft = true;
|
|
596
|
-
const entry = registry.find(e => e.id === shell.id);
|
|
597
|
-
if (entry) entry.status = 'active';
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
return { registry, activeMilestone, activeMilestoneSlices, activeMilestoneHasDraft };
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
function handleNoActiveMilestone(
|
|
604
|
-
registry: MilestoneRegistryEntry[],
|
|
605
|
-
requirements: any,
|
|
606
|
-
milestoneProgress: { done: number, total: number }
|
|
607
|
-
): GSDState {
|
|
608
|
-
const pendingEntries = registry.filter(e => e.status === 'pending');
|
|
609
|
-
const parkedEntries = registry.filter(e => e.status === 'parked');
|
|
610
|
-
|
|
611
|
-
if (pendingEntries.length > 0) {
|
|
612
|
-
const blockerDetails = pendingEntries
|
|
613
|
-
.filter(e => e.dependsOn && e.dependsOn.length > 0)
|
|
614
|
-
.map(e => `${e.id} is waiting on unmet deps: ${e.dependsOn!.join(', ')}`);
|
|
615
|
-
return {
|
|
616
|
-
activeMilestone: null, activeSlice: null, activeTask: null,
|
|
617
|
-
phase: 'blocked',
|
|
618
|
-
recentDecisions: [], blockers: blockerDetails.length > 0
|
|
619
|
-
? blockerDetails
|
|
620
|
-
: ['All remaining milestones are dep-blocked but no deps listed — check CONTEXT.md files'],
|
|
621
|
-
nextAction: 'Resolve milestone dependencies before proceeding.',
|
|
622
|
-
registry, requirements,
|
|
623
|
-
progress: { milestones: milestoneProgress },
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
if (parkedEntries.length > 0) {
|
|
628
|
-
const parkedIds = parkedEntries.map(e => e.id).join(', ');
|
|
629
|
-
return {
|
|
630
|
-
activeMilestone: null, activeSlice: null, activeTask: null,
|
|
631
|
-
phase: 'pre-planning',
|
|
632
|
-
recentDecisions: [], blockers: [],
|
|
633
|
-
nextAction: `All remaining milestones are parked (${parkedIds}). Run /gsd unpark <id> or create a new milestone.`,
|
|
634
|
-
registry, requirements,
|
|
635
|
-
progress: { milestones: milestoneProgress },
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
if (registry.length === 0) {
|
|
640
|
-
return {
|
|
641
|
-
activeMilestone: null, activeSlice: null, activeTask: null,
|
|
642
|
-
phase: 'pre-planning',
|
|
643
|
-
recentDecisions: [], blockers: [],
|
|
644
|
-
nextAction: 'No milestones found. Run /gsd to create one.',
|
|
645
|
-
registry: [], requirements,
|
|
646
|
-
progress: { milestones: { done: 0, total: 0 } },
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
const lastEntry = registry[registry.length - 1];
|
|
651
|
-
const unmappedActive = countUnmappedActiveRequirements();
|
|
652
|
-
const completionNote = formatCompletePhaseNextAction(unmappedActive);
|
|
653
|
-
return {
|
|
654
|
-
activeMilestone: null,
|
|
655
|
-
lastCompletedMilestone: lastEntry ? { id: lastEntry.id, title: lastEntry.title } : null,
|
|
656
|
-
activeSlice: null, activeTask: null,
|
|
657
|
-
phase: 'complete',
|
|
658
|
-
recentDecisions: [], blockers: [],
|
|
659
|
-
nextAction: completionNote,
|
|
660
|
-
registry, requirements,
|
|
661
|
-
progress: { milestones: milestoneProgress },
|
|
662
|
-
};
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
async function handleAllSlicesDone(
|
|
666
|
-
basePath: string,
|
|
667
|
-
activeMilestone: ActiveRef,
|
|
668
|
-
registry: MilestoneRegistryEntry[],
|
|
669
|
-
requirements: any,
|
|
670
|
-
milestoneProgress: { done: number, total: number },
|
|
671
|
-
sliceProgress: { done: number, total: number }
|
|
672
|
-
): Promise<GSDState> {
|
|
673
|
-
const validation = getLatestAssessmentByScope(activeMilestone.id, "milestone-validation");
|
|
674
|
-
const verdict = typeof validation?.status === "string" ? validation.status : undefined;
|
|
675
|
-
const validationTerminal = verdict != null && verdict !== "";
|
|
676
|
-
|
|
677
|
-
if (!validationTerminal) {
|
|
678
|
-
return {
|
|
679
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
680
|
-
phase: 'validating-milestone',
|
|
681
|
-
recentDecisions: [], blockers: [],
|
|
682
|
-
nextAction: `Validate milestone ${activeMilestone.id} before completion.`,
|
|
683
|
-
registry, requirements,
|
|
684
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
685
|
-
};
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// All roadmap slices are done (enforced by caller) and verdict is
|
|
689
|
-
// needs-remediation — remediation cannot progress without new slices.
|
|
690
|
-
// Return blocked instead of re-dispatching validate-milestone (#4506).
|
|
691
|
-
if (verdict === 'needs-attention') {
|
|
692
|
-
return {
|
|
693
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
694
|
-
phase: 'blocked',
|
|
695
|
-
recentDecisions: [],
|
|
696
|
-
blockers: [formatNeedsAttentionBlocker(activeMilestone.id)],
|
|
697
|
-
nextAction: `Resolve ${activeMilestone.id} validation attention before proceeding.`,
|
|
698
|
-
registry, requirements,
|
|
699
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
700
|
-
};
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
if (verdict === 'needs-remediation') {
|
|
704
|
-
return {
|
|
705
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
706
|
-
phase: 'blocked',
|
|
707
|
-
recentDecisions: [],
|
|
708
|
-
blockers: [formatNeedsRemediationBlocker(activeMilestone.id)],
|
|
709
|
-
nextAction: `Resolve ${activeMilestone.id} remediation before proceeding.`,
|
|
710
|
-
registry, requirements,
|
|
711
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
712
|
-
};
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
return {
|
|
716
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
717
|
-
phase: 'completing-milestone',
|
|
718
|
-
recentDecisions: [], blockers: [],
|
|
719
|
-
nextAction: `All slices complete in ${activeMilestone.id}. Write milestone summary.`,
|
|
720
|
-
registry, requirements,
|
|
721
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
function resolveSliceDependencies(activeMilestoneSlices: SliceRow[]): { activeSlice: ActiveRef | null, activeSliceRow: SliceRow | null } {
|
|
726
|
-
const doneSliceIds = new Set(
|
|
727
|
-
activeMilestoneSlices.filter(s => isStatusDone(s.status)).map(s => s.id)
|
|
728
|
-
);
|
|
729
|
-
|
|
730
|
-
const sliceLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_SLICE_LOCK : undefined;
|
|
731
|
-
if (sliceLock) {
|
|
732
|
-
const lockedSlice = activeMilestoneSlices.find(s => s.id === sliceLock);
|
|
733
|
-
if (lockedSlice) {
|
|
734
|
-
return { activeSlice: { id: lockedSlice.id, title: lockedSlice.title }, activeSliceRow: lockedSlice };
|
|
735
|
-
} else {
|
|
736
|
-
logWarning("state", `GSD_SLICE_LOCK=${sliceLock} not found in active slices — worker has no assigned work`);
|
|
737
|
-
return { activeSlice: null, activeSliceRow: null };
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
for (const s of activeMilestoneSlices) {
|
|
742
|
-
if (isStatusDone(s.status)) continue;
|
|
743
|
-
if (isDeferredStatus(s.status)) continue;
|
|
744
|
-
if (s.depends.every(dep => doneSliceIds.has(dep))) {
|
|
745
|
-
return { activeSlice: { id: s.id, title: s.title }, activeSliceRow: s };
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
return { activeSlice: null, activeSliceRow: null };
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
async function detectBlockers(basePath: string, milestoneId: string, sliceId: string, tasks: TaskRow[]): Promise<string | null> {
|
|
753
|
-
const completedTasks = tasks.filter(t => isStatusDone(t.status));
|
|
754
|
-
for (const ct of completedTasks) {
|
|
755
|
-
if (ct.blocker_discovered) {
|
|
756
|
-
return ct.id;
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
return null;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
function checkReplanTrigger(basePath: string, milestoneId: string, sliceId: string): boolean {
|
|
763
|
-
const sliceRow = getSlice(milestoneId, sliceId);
|
|
764
|
-
return !!sliceRow?.replan_triggered_at;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
export async function deriveStateFromDb(
|
|
768
|
-
basePath: string,
|
|
769
|
-
artifactReadRoot: string = basePath,
|
|
770
|
-
): Promise<GSDState> {
|
|
771
|
-
if (!ensureExistingWorkflowDbOpen(basePath)) {
|
|
772
|
-
return buildDbUnavailableState();
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
const requirements = getRequirementCounts();
|
|
776
|
-
|
|
777
|
-
const allMilestones = getAllMilestones();
|
|
778
|
-
|
|
779
|
-
const milestoneLock = getRequestedMilestoneLock();
|
|
780
|
-
const milestones = milestoneLock
|
|
781
|
-
? allMilestones.filter(m => m.id === milestoneLock)
|
|
782
|
-
: allMilestones;
|
|
783
|
-
|
|
784
|
-
if (milestones.length === 0) {
|
|
785
|
-
return {
|
|
786
|
-
activeMilestone: null, activeSlice: null, activeTask: null,
|
|
787
|
-
phase: 'pre-planning', recentDecisions: [], blockers: [],
|
|
788
|
-
nextAction: 'No milestones found. Run /gsd to create one.',
|
|
789
|
-
registry: [], requirements,
|
|
790
|
-
progress: { milestones: { done: 0, total: 0 } },
|
|
791
|
-
};
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
const { completeMilestoneIds, parkedMilestoneIds } = buildCompletenessSet(basePath, milestones);
|
|
795
|
-
|
|
796
|
-
const registryContext = await buildRegistryAndFindActive(basePath, milestones, completeMilestoneIds, parkedMilestoneIds);
|
|
797
|
-
const { registry, activeMilestone, activeMilestoneSlices, activeMilestoneHasDraft } = registryContext;
|
|
798
|
-
|
|
799
|
-
const milestoneProgress = {
|
|
800
|
-
done: registry.filter(e => e.status === 'complete').length,
|
|
801
|
-
total: registry.length,
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
if (!activeMilestone) {
|
|
805
|
-
return handleNoActiveMilestone(registry, requirements, milestoneProgress);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
if (activeMilestoneSlices.length === 0) {
|
|
809
|
-
const phase = activeMilestoneHasDraft ? 'needs-discussion' as const : 'pre-planning' as const;
|
|
810
|
-
const nextAction = activeMilestoneHasDraft
|
|
811
|
-
? `Discuss draft context for milestone ${activeMilestone.id}.`
|
|
812
|
-
: `Plan milestone ${activeMilestone.id}.`;
|
|
813
|
-
return {
|
|
814
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
815
|
-
phase, recentDecisions: [], blockers: [],
|
|
816
|
-
nextAction, registry, requirements,
|
|
817
|
-
progress: { milestones: milestoneProgress },
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
const allSlicesDone = activeMilestoneSlices.every(s => isStatusDone(s.status));
|
|
822
|
-
const sliceProgress = {
|
|
823
|
-
done: activeMilestoneSlices.filter(s => isStatusDone(s.status)).length,
|
|
824
|
-
total: activeMilestoneSlices.length,
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
if (allSlicesDone) {
|
|
828
|
-
return handleAllSlicesDone(basePath, activeMilestone, registry, requirements, milestoneProgress, sliceProgress);
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
const activeSliceContext = resolveSliceDependencies(activeMilestoneSlices);
|
|
832
|
-
if (!activeSliceContext.activeSlice) {
|
|
833
|
-
// If locked slice wasn't found, it returns null but logs warning, we need to return 'blocked'
|
|
834
|
-
const sliceLock = process.env.GSD_PARALLEL_WORKER ? process.env.GSD_SLICE_LOCK : undefined;
|
|
835
|
-
if (sliceLock) {
|
|
836
|
-
return {
|
|
837
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
838
|
-
phase: 'blocked', recentDecisions: [], blockers: [`GSD_SLICE_LOCK=${sliceLock} not found in active milestone slices`],
|
|
839
|
-
nextAction: 'Slice lock references a non-existent slice — check orchestrator dispatch.',
|
|
840
|
-
registry, requirements,
|
|
841
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
842
|
-
};
|
|
843
|
-
}
|
|
844
|
-
return {
|
|
845
|
-
activeMilestone, activeSlice: null, activeTask: null,
|
|
846
|
-
phase: 'blocked', recentDecisions: [], blockers: ['No slice eligible — check dependency ordering'],
|
|
847
|
-
nextAction: 'Resolve dependency blockers or plan next slice.',
|
|
848
|
-
registry, requirements,
|
|
849
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
const { activeSlice } = activeSliceContext;
|
|
853
|
-
let activeSliceRow = activeSliceContext.activeSliceRow;
|
|
854
|
-
|
|
855
|
-
// Heal stale sketch flags before honoring the DB-authoritative sketch gate.
|
|
856
|
-
// This recovers if PLAN.md exists but is_sketch was never flipped to 0.
|
|
857
|
-
if (activeMilestone?.id) {
|
|
858
|
-
autoHealSketchFlags(activeMilestone.id, (sid) => {
|
|
859
|
-
const planPath = resolveSliceFile(artifactReadRoot, activeMilestone.id, sid, "PLAN");
|
|
860
|
-
return planPath !== null && existsSync(planPath);
|
|
861
|
-
});
|
|
862
|
-
activeSliceRow = getSlice(activeMilestone.id, activeSlice.id);
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
// ADR-011: DB slice metadata is authoritative for sketch refinement.
|
|
866
|
-
// PLAN.md and preference flags are projections/configuration and are
|
|
867
|
-
// deliberately not used to infer whether the slice itself is a sketch.
|
|
868
|
-
if (activeSliceRow?.is_sketch === 1) {
|
|
869
|
-
return {
|
|
870
|
-
activeMilestone, activeSlice, activeTask: null,
|
|
871
|
-
phase: 'refining', recentDecisions: [], blockers: [],
|
|
872
|
-
nextAction: `Refine sketch slice ${activeSlice.id} (${activeSlice.title}) using prior slice context.`,
|
|
873
|
-
registry, requirements,
|
|
874
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress },
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
const tasks = getSliceTasks(activeMilestone.id, activeSlice.id);
|
|
879
|
-
|
|
880
|
-
const taskProgress = {
|
|
881
|
-
done: tasks.filter(t => isStatusDone(t.status)).length,
|
|
882
|
-
total: tasks.length,
|
|
883
|
-
};
|
|
884
|
-
|
|
885
|
-
const activeTaskRow = tasks.find(t => !isStatusDone(t.status));
|
|
886
|
-
|
|
887
|
-
if (!activeTaskRow && tasks.length > 0) {
|
|
888
|
-
return {
|
|
889
|
-
activeMilestone, activeSlice, activeTask: null,
|
|
890
|
-
phase: 'summarizing', recentDecisions: [], blockers: [],
|
|
891
|
-
nextAction: `All tasks done in ${activeSlice.id}. Write slice summary and complete slice.`,
|
|
892
|
-
registry, requirements,
|
|
893
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
if (!activeTaskRow) {
|
|
898
|
-
return {
|
|
899
|
-
activeMilestone, activeSlice, activeTask: null,
|
|
900
|
-
phase: 'planning', recentDecisions: [], blockers: [],
|
|
901
|
-
nextAction: `Slice ${activeSlice.id} has no DB tasks. Plan slice tasks before execution.`,
|
|
902
|
-
registry, requirements,
|
|
903
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
const activeTask: ActiveRef = { id: activeTaskRow.id, title: activeTaskRow.title };
|
|
908
|
-
|
|
909
|
-
// ── Quality gate evaluation check ──────────────────────────────────
|
|
910
|
-
// Pause before execution only when gates owned by the `gate-evaluate`
|
|
911
|
-
// turn (Q3/Q4) are still pending. Q8 is also `scope:"slice"` but is
|
|
912
|
-
// owned by `complete-slice`, so it must NOT block the evaluating-gates
|
|
913
|
-
// phase — otherwise auto-loop stalls forever waiting for a gate that
|
|
914
|
-
// this turn never evaluates. See gate-registry.ts for the ownership map.
|
|
915
|
-
// Slices with zero gate rows (pre-feature or simple) skip straight through.
|
|
916
|
-
const pendingGateCount = getPendingGateCountForTurn(
|
|
917
|
-
activeMilestone.id,
|
|
918
|
-
activeSlice.id,
|
|
919
|
-
"gate-evaluate",
|
|
920
|
-
);
|
|
921
|
-
if (pendingGateCount > 0) {
|
|
922
|
-
return {
|
|
923
|
-
activeMilestone, activeSlice, activeTask: null,
|
|
924
|
-
phase: 'evaluating-gates', recentDecisions: [], blockers: [],
|
|
925
|
-
nextAction: `Evaluate ${pendingGateCount} quality gate(s) for ${activeSlice.id} before execution.`,
|
|
926
|
-
registry, requirements,
|
|
927
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
const blockerTaskId = await detectBlockers(basePath, activeMilestone.id, activeSlice.id, tasks);
|
|
932
|
-
if (blockerTaskId) {
|
|
933
|
-
const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
|
|
934
|
-
if (replanHistory.length === 0) {
|
|
935
|
-
return {
|
|
936
|
-
activeMilestone, activeSlice, activeTask,
|
|
937
|
-
phase: 'replanning-slice', recentDecisions: [],
|
|
938
|
-
blockers: [`Task ${blockerTaskId} discovered a blocker requiring slice replan`],
|
|
939
|
-
nextAction: `Task ${blockerTaskId} reported blocker_discovered. Replan slice ${activeSlice.id} before continuing.`,
|
|
940
|
-
activeWorkspace: undefined,
|
|
941
|
-
registry, requirements,
|
|
942
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
// ADR-011 Phase 2: pause-on-escalation takes precedence over dispatching the
|
|
948
|
-
// next task. `awaiting_review` tasks (continueWithDefault=true) still pause
|
|
949
|
-
// here so silence is never treated as consent.
|
|
950
|
-
//
|
|
951
|
-
// We do NOT gate this on `phases.mid_execution_escalation` — creation of
|
|
952
|
-
// new escalations is gated at the write site (tools/complete-task.ts:315),
|
|
953
|
-
// but any escalation_pending row already persisted in the DB must be
|
|
954
|
-
// honored even if the user later toggles the flag off. Otherwise those
|
|
955
|
-
// rows would silently orphan, the loop would advance past the paused task,
|
|
956
|
-
// and the user's prior resolution never lands.
|
|
957
|
-
const escalatingTaskId = detectPendingEscalation(tasks, basePath);
|
|
958
|
-
if (escalatingTaskId) {
|
|
959
|
-
return {
|
|
960
|
-
activeMilestone, activeSlice, activeTask,
|
|
961
|
-
phase: 'escalating-task', recentDecisions: [],
|
|
962
|
-
blockers: [`Task ${escalatingTaskId} requires a user decision before the loop can proceed`],
|
|
963
|
-
nextAction: `Run /gsd escalate show ${escalatingTaskId} to review, then /gsd escalate resolve ${escalatingTaskId} <choice> to proceed.`,
|
|
964
|
-
activeWorkspace: undefined,
|
|
965
|
-
registry, requirements,
|
|
966
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
if (!blockerTaskId) {
|
|
971
|
-
const isTriggered = checkReplanTrigger(basePath, activeMilestone.id, activeSlice.id);
|
|
972
|
-
if (isTriggered) {
|
|
973
|
-
const replanHistory = getReplanHistory(activeMilestone.id, activeSlice.id);
|
|
974
|
-
if (replanHistory.length === 0) {
|
|
975
|
-
return {
|
|
976
|
-
activeMilestone, activeSlice, activeTask,
|
|
977
|
-
phase: 'replanning-slice', recentDecisions: [],
|
|
978
|
-
blockers: ['Triage replan trigger detected — slice replan required'],
|
|
979
|
-
nextAction: `Triage replan triggered for slice ${activeSlice.id}. Replan before continuing.`,
|
|
980
|
-
activeWorkspace: undefined,
|
|
981
|
-
registry, requirements,
|
|
982
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
return {
|
|
989
|
-
activeMilestone, activeSlice, activeTask,
|
|
990
|
-
phase: 'executing', recentDecisions: [], blockers: [],
|
|
991
|
-
nextAction: `Execute ${activeTask.id}: ${activeTask.title} in slice ${activeSlice.id}.`,
|
|
992
|
-
registry, requirements,
|
|
993
|
-
progress: { milestones: milestoneProgress, slices: sliceProgress, tasks: taskProgress },
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
|
|
997
294
|
|
|
998
295
|
// LEGACY: Filesystem-based state derivation for unmigrated projects.
|
|
999
296
|
// DB-backed projects use deriveStateFromDb() above. Target: extract to
|
|
@@ -1744,12 +1041,12 @@ export async function _deriveStateImpl(
|
|
|
1744
1041
|
}
|
|
1745
1042
|
}
|
|
1746
1043
|
|
|
1747
|
-
// Check for interrupted work
|
|
1748
|
-
const
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1044
|
+
// Check for interrupted work (legacy filesystem path only)
|
|
1045
|
+
const hasInterrupted = await detectInterruptedWork(
|
|
1046
|
+
basePath,
|
|
1047
|
+
activeMilestone.id,
|
|
1048
|
+
activeSlice.id,
|
|
1049
|
+
);
|
|
1753
1050
|
|
|
1754
1051
|
return {
|
|
1755
1052
|
activeMilestone,
|
|
@@ -1758,9 +1055,12 @@ export async function _deriveStateImpl(
|
|
|
1758
1055
|
phase: 'executing',
|
|
1759
1056
|
recentDecisions: [],
|
|
1760
1057
|
blockers: [],
|
|
1761
|
-
nextAction:
|
|
1762
|
-
|
|
1763
|
-
|
|
1058
|
+
nextAction: interruptedWorkNextAction(
|
|
1059
|
+
activeTask.id,
|
|
1060
|
+
activeTask.title,
|
|
1061
|
+
activeSlice.id,
|
|
1062
|
+
hasInterrupted,
|
|
1063
|
+
),
|
|
1764
1064
|
registry,
|
|
1765
1065
|
requirements,
|
|
1766
1066
|
progress: {
|