gsd-pi 2.44.0-dev.d25d507 → 2.45.0-dev.1afbdaa
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/help-text.js +1 -1
- package/dist/loader.js +34 -0
- package/dist/resources/extensions/gsd/activity-log.js +7 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +63 -77
- package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
- package/dist/resources/extensions/gsd/auto/session.js +0 -11
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +23 -5
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
- package/dist/resources/extensions/gsd/auto.js +42 -60
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +170 -11
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/context.js +0 -4
- package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
- package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
- package/dist/resources/extensions/gsd/db-writer.js +40 -22
- package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
- package/dist/resources/extensions/gsd/doctor.js +13 -3
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +28 -4
- package/dist/resources/extensions/gsd/guided-flow.js +1 -2
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
- package/dist/resources/extensions/gsd/preferences-types.js +2 -2
- package/dist/resources/extensions/gsd/preferences.js +8 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +5 -3
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
- package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
- package/dist/resources/extensions/gsd/prompts/rethink.md +83 -0
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/repo-identity.js +45 -7
- package/dist/resources/extensions/gsd/rethink.js +115 -0
- package/dist/resources/extensions/gsd/session-lock.js +1 -3
- package/dist/resources/extensions/gsd/state.js +48 -3
- package/dist/resources/extensions/gsd/sync-lock.js +89 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
- package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
- package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
- package/dist/resources/extensions/gsd/tools/plan-slice.js +31 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +28 -1
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +34 -2
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
- package/dist/resources/extensions/gsd/workflow-events.js +102 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
- package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
- package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
- package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
- package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
- package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
- package/dist/resources/extensions/gsd/write-intercept.js +84 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/resources/extensions/voice/index.js +11 -16
- package/dist/resources/extensions/voice/linux-ready.js +67 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +14 -14
- 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 +2 -2
- 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 +2 -2
- 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.js +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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- 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 +4 -4
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +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 +14 -14
- 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 +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/app/{page-b9367c5ae13b99c6.js → page-6654a8cca61a3d1c.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
- package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
- package/package.json +2 -1
- package/packages/native/dist/stream-process/index.js +2 -2
- package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
- package/packages/native/src/stream-process/index.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
- package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
- package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
- package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
- package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
- package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
- package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
- package/src/resources/extensions/gsd/auto/phases.ts +69 -91
- package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
- package/src/resources/extensions/gsd/auto/session.ts +0 -18
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +26 -5
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
- package/src/resources/extensions/gsd/auto.ts +44 -86
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +162 -11
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/context.ts +0 -5
- package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
- package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
- package/src/resources/extensions/gsd/db-writer.ts +41 -27
- package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
- package/src/resources/extensions/gsd/doctor-types.ts +7 -1
- package/src/resources/extensions/gsd/doctor.ts +13 -4
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +32 -4
- package/src/resources/extensions/gsd/guided-flow.ts +1 -2
- package/src/resources/extensions/gsd/journal.ts +6 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
- package/src/resources/extensions/gsd/preferences-types.ts +2 -2
- package/src/resources/extensions/gsd/preferences.ts +7 -3
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -10
- package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +5 -3
- package/src/resources/extensions/gsd/prompts/queue.md +2 -2
- package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
- package/src/resources/extensions/gsd/prompts/rethink.md +83 -0
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/repo-identity.ts +46 -7
- package/src/resources/extensions/gsd/rethink.ts +154 -0
- package/src/resources/extensions/gsd/session-lock.ts +0 -4
- package/src/resources/extensions/gsd/state.ts +49 -1
- package/src/resources/extensions/gsd/sync-lock.ts +94 -0
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
- package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
- package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
- package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
- package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
- package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +26 -21
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
- package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
- package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +40 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +37 -1
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +41 -1
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/types.ts +8 -0
- package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
- package/src/resources/extensions/gsd/workflow-events.ts +154 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
- package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
- package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
- package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
- package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
- package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
- package/src/resources/extensions/gsd/write-intercept.ts +90 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- package/src/resources/extensions/voice/index.ts +11 -21
- package/src/resources/extensions/voice/linux-ready.ts +87 -0
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
- package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
- package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
- /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{tokoGmfkYfWf1_Yl_Gz7i → j-BskPs0nxxPeYY-bSrab}/_ssgManifest.js +0 -0
|
@@ -188,10 +188,20 @@ Examples:
|
|
|
188
188
|
await handleFast(trimmed.replace(/^fast\s*/, "").trim(), ctx);
|
|
189
189
|
return true;
|
|
190
190
|
}
|
|
191
|
+
if (trimmed === "mcp" || trimmed.startsWith("mcp ")) {
|
|
192
|
+
const { handleMcpStatus } = await import("../../commands-mcp-status.js");
|
|
193
|
+
await handleMcpStatus(trimmed.replace(/^mcp\s*/, "").trim(), ctx);
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
191
196
|
if (trimmed === "extensions" || trimmed.startsWith("extensions ")) {
|
|
192
197
|
const { handleExtensions } = await import("../../commands-extensions.js");
|
|
193
198
|
await handleExtensions(trimmed.replace(/^extensions\s*/, "").trim(), ctx);
|
|
194
199
|
return true;
|
|
195
200
|
}
|
|
201
|
+
if (trimmed === "rethink") {
|
|
202
|
+
const { handleRethink } = await import("../../rethink.js");
|
|
203
|
+
await handleRethink(trimmed, ctx, pi);
|
|
204
|
+
return true;
|
|
205
|
+
}
|
|
196
206
|
return false;
|
|
197
207
|
}
|
|
@@ -44,7 +44,7 @@ export async function handleParallelCommand(trimmed, _ctx, pi) {
|
|
|
44
44
|
}
|
|
45
45
|
const lines = ["# Parallel Workers\n"];
|
|
46
46
|
for (const worker of workers) {
|
|
47
|
-
lines.push(`- **${worker.milestoneId}** (${worker.title}) — ${worker.state} —
|
|
47
|
+
lines.push(`- **${worker.milestoneId}** (${worker.title}) — ${worker.state} — $${worker.cost.toFixed(2)}`);
|
|
48
48
|
}
|
|
49
49
|
const state = getOrchestratorState();
|
|
50
50
|
if (state) {
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Status — `/gsd mcp` command handler.
|
|
3
|
+
*
|
|
4
|
+
* Shows configured MCP servers, their connection status, and available tools.
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* /gsd mcp — Overview of all servers (alias: /gsd mcp status)
|
|
8
|
+
* /gsd mcp status — Same as bare /gsd mcp
|
|
9
|
+
* /gsd mcp check <srv> — Detailed status for a specific server
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
function readMcpConfigs() {
|
|
14
|
+
const servers = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const configPaths = [
|
|
17
|
+
join(process.cwd(), ".mcp.json"),
|
|
18
|
+
join(process.cwd(), ".gsd", "mcp.json"),
|
|
19
|
+
];
|
|
20
|
+
for (const configPath of configPaths) {
|
|
21
|
+
try {
|
|
22
|
+
if (!existsSync(configPath))
|
|
23
|
+
continue;
|
|
24
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
25
|
+
const data = JSON.parse(raw);
|
|
26
|
+
const mcpServers = (data.mcpServers ?? data.servers);
|
|
27
|
+
if (!mcpServers || typeof mcpServers !== "object")
|
|
28
|
+
continue;
|
|
29
|
+
for (const [name, config] of Object.entries(mcpServers)) {
|
|
30
|
+
if (seen.has(name))
|
|
31
|
+
continue;
|
|
32
|
+
seen.add(name);
|
|
33
|
+
const hasCommand = typeof config.command === "string";
|
|
34
|
+
const hasUrl = typeof config.url === "string";
|
|
35
|
+
const transport = hasCommand
|
|
36
|
+
? "stdio"
|
|
37
|
+
: hasUrl
|
|
38
|
+
? "http"
|
|
39
|
+
: "unknown";
|
|
40
|
+
servers.push({
|
|
41
|
+
name,
|
|
42
|
+
transport,
|
|
43
|
+
...(hasCommand && {
|
|
44
|
+
command: config.command,
|
|
45
|
+
args: Array.isArray(config.args) ? config.args : undefined,
|
|
46
|
+
}),
|
|
47
|
+
...(hasUrl && { url: config.url }),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Non-fatal — config file may not exist or be malformed
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return servers;
|
|
56
|
+
}
|
|
57
|
+
// ─── Formatters (exported for testing) ──────────────────────────────────────
|
|
58
|
+
export function formatMcpStatusReport(servers) {
|
|
59
|
+
if (servers.length === 0) {
|
|
60
|
+
return [
|
|
61
|
+
"No MCP servers configured.",
|
|
62
|
+
"",
|
|
63
|
+
"Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
|
|
64
|
+
"See: https://modelcontextprotocol.io/quickstart",
|
|
65
|
+
].join("\n");
|
|
66
|
+
}
|
|
67
|
+
const lines = [`MCP Server Status — ${servers.length} server(s)\n`];
|
|
68
|
+
for (const s of servers) {
|
|
69
|
+
const icon = s.error ? "✗" : s.connected ? "✓" : "○";
|
|
70
|
+
const status = s.error
|
|
71
|
+
? `error: ${s.error}`
|
|
72
|
+
: s.connected
|
|
73
|
+
? `connected — ${s.toolCount} tools`
|
|
74
|
+
: "disconnected";
|
|
75
|
+
lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}`);
|
|
76
|
+
}
|
|
77
|
+
lines.push("");
|
|
78
|
+
lines.push("Use /gsd mcp check <server> for details on a specific server.");
|
|
79
|
+
lines.push("Use mcp_discover to connect and list tools for a server.");
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
export function formatMcpServerDetail(server) {
|
|
83
|
+
const lines = [`MCP Server: ${server.name}\n`];
|
|
84
|
+
lines.push(` Transport: ${server.transport}`);
|
|
85
|
+
if (server.error) {
|
|
86
|
+
lines.push(` Status: error`);
|
|
87
|
+
lines.push(` Error: ${server.error}`);
|
|
88
|
+
}
|
|
89
|
+
else if (server.connected) {
|
|
90
|
+
lines.push(` Status: connected`);
|
|
91
|
+
lines.push(` Tools: ${server.toolCount}`);
|
|
92
|
+
if (server.tools.length > 0) {
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push(" Available tools:");
|
|
95
|
+
for (const tool of server.tools) {
|
|
96
|
+
lines.push(` - ${tool}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
lines.push(` Status: disconnected`);
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
|
|
104
|
+
}
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
// ─── Command handler ────────────────────────────────────────────────────────
|
|
108
|
+
/**
|
|
109
|
+
* Handle `/gsd mcp [status|check <server>]`.
|
|
110
|
+
*/
|
|
111
|
+
export async function handleMcpStatus(args, ctx) {
|
|
112
|
+
const trimmed = args.trim().toLowerCase();
|
|
113
|
+
const configs = readMcpConfigs();
|
|
114
|
+
// /gsd mcp check <server>
|
|
115
|
+
if (trimmed.startsWith("check ")) {
|
|
116
|
+
const serverName = args.trim().slice("check ".length).trim();
|
|
117
|
+
const config = configs.find((c) => c.name === serverName);
|
|
118
|
+
if (!config) {
|
|
119
|
+
const available = configs.map((c) => c.name).join(", ") || "(none)";
|
|
120
|
+
ctx.ui.notify(`Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`, "warning");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Try to get connection/tool info from the mcp-client module if available
|
|
124
|
+
let connected = false;
|
|
125
|
+
let toolNames = [];
|
|
126
|
+
let error;
|
|
127
|
+
try {
|
|
128
|
+
const mcpClient = await import("../mcp-client/index.js");
|
|
129
|
+
// Access the module's connection state if exported; fall back gracefully
|
|
130
|
+
const mod = mcpClient;
|
|
131
|
+
if (typeof mod.getConnectionStatus === "function") {
|
|
132
|
+
const status = mod.getConnectionStatus(serverName);
|
|
133
|
+
connected = status.connected;
|
|
134
|
+
toolNames = status.tools;
|
|
135
|
+
error = status.error;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// mcp-client may not expose status helpers — that's fine
|
|
140
|
+
}
|
|
141
|
+
ctx.ui.notify(formatMcpServerDetail({
|
|
142
|
+
name: config.name,
|
|
143
|
+
transport: config.transport,
|
|
144
|
+
connected,
|
|
145
|
+
toolCount: toolNames.length,
|
|
146
|
+
tools: toolNames,
|
|
147
|
+
error,
|
|
148
|
+
}), "info");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// /gsd mcp or /gsd mcp status
|
|
152
|
+
if (!trimmed || trimmed === "status") {
|
|
153
|
+
// Build status for each server
|
|
154
|
+
const statuses = [];
|
|
155
|
+
for (const config of configs) {
|
|
156
|
+
let connected = false;
|
|
157
|
+
let toolCount = 0;
|
|
158
|
+
let error;
|
|
159
|
+
try {
|
|
160
|
+
const mcpClient = await import("../mcp-client/index.js");
|
|
161
|
+
const mod = mcpClient;
|
|
162
|
+
if (typeof mod.getConnectionStatus === "function") {
|
|
163
|
+
const status = mod.getConnectionStatus(config.name);
|
|
164
|
+
connected = status.connected;
|
|
165
|
+
toolCount = status.tools.length;
|
|
166
|
+
error = status.error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// Fall back to unknown state
|
|
171
|
+
}
|
|
172
|
+
statuses.push({
|
|
173
|
+
name: config.name,
|
|
174
|
+
transport: config.transport,
|
|
175
|
+
connected,
|
|
176
|
+
toolCount,
|
|
177
|
+
error,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
ctx.ui.notify(formatMcpStatusReport(statuses), "info");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Unknown subcommand
|
|
184
|
+
ctx.ui.notify("Usage: /gsd mcp [status|check <server>]\n\n" +
|
|
185
|
+
" status Show all MCP server statuses (default)\n" +
|
|
186
|
+
" check <server> Detailed status for a specific server", "warning");
|
|
187
|
+
}
|
|
@@ -18,7 +18,7 @@ function lockPath(basePath) {
|
|
|
18
18
|
return join(gsdRoot(basePath), LOCK_FILE);
|
|
19
19
|
}
|
|
20
20
|
/** Write or update the lock file with current auto-mode state. */
|
|
21
|
-
export function writeLock(basePath, unitType, unitId,
|
|
21
|
+
export function writeLock(basePath, unitType, unitId, sessionFile) {
|
|
22
22
|
try {
|
|
23
23
|
const data = {
|
|
24
24
|
pid: process.pid,
|
|
@@ -26,7 +26,6 @@ export function writeLock(basePath, unitType, unitId, completedUnits, sessionFil
|
|
|
26
26
|
unitType,
|
|
27
27
|
unitId,
|
|
28
28
|
unitStartedAt: new Date().toISOString(),
|
|
29
|
-
completedUnits,
|
|
30
29
|
sessionFile,
|
|
31
30
|
};
|
|
32
31
|
const lp = lockPath(basePath);
|
|
@@ -90,11 +89,10 @@ export function formatCrashInfo(lock) {
|
|
|
90
89
|
`Previous auto-mode session was interrupted.`,
|
|
91
90
|
` Was executing: ${lock.unitType} (${lock.unitId})`,
|
|
92
91
|
` Started at: ${lock.unitStartedAt}`,
|
|
93
|
-
` Units completed before crash: ${lock.completedUnits}`,
|
|
94
92
|
` PID: ${lock.pid}`,
|
|
95
93
|
];
|
|
96
94
|
// Add recovery guidance based on what was happening when it crashed
|
|
97
|
-
if (lock.unitType === "starting" && lock.unitId === "bootstrap"
|
|
95
|
+
if (lock.unitType === "starting" && lock.unitId === "bootstrap") {
|
|
98
96
|
lines.push(`No work was lost. Run /gsd auto to restart.`);
|
|
99
97
|
}
|
|
100
98
|
else if (lock.unitType.includes("research") || lock.unitType.includes("plan")) {
|
|
@@ -81,18 +81,11 @@ export class GSDDashboardOverlay {
|
|
|
81
81
|
const currentUnit = dashData.currentUnit
|
|
82
82
|
? `${dashData.currentUnit.type}:${dashData.currentUnit.id}:${dashData.currentUnit.startedAt}`
|
|
83
83
|
: "-";
|
|
84
|
-
const lastCompleted = dashData.completedUnits.length > 0
|
|
85
|
-
? dashData.completedUnits[dashData.completedUnits.length - 1]
|
|
86
|
-
: null;
|
|
87
|
-
const completedKey = lastCompleted
|
|
88
|
-
? `${dashData.completedUnits.length}:${lastCompleted.type}:${lastCompleted.id}:${lastCompleted.finishedAt}`
|
|
89
|
-
: "0";
|
|
90
84
|
return [
|
|
91
85
|
base,
|
|
92
86
|
dashData.active ? "1" : "0",
|
|
93
87
|
dashData.paused ? "1" : "0",
|
|
94
88
|
currentUnit,
|
|
95
|
-
completedKey,
|
|
96
89
|
].join("|");
|
|
97
90
|
}
|
|
98
91
|
async refreshDashboard(initial = false) {
|
|
@@ -393,43 +386,6 @@ export class GSDDashboardOverlay {
|
|
|
393
386
|
else {
|
|
394
387
|
lines.push(centered(th.fg("dim", "No active milestone.")));
|
|
395
388
|
}
|
|
396
|
-
if (this.dashData.completedUnits.length > 0) {
|
|
397
|
-
lines.push(blank());
|
|
398
|
-
lines.push(hr());
|
|
399
|
-
lines.push(row(th.fg("text", th.bold("Completed"))));
|
|
400
|
-
lines.push(blank());
|
|
401
|
-
// Build ledger lookup for budget indicators (last entry wins for retries)
|
|
402
|
-
const ledgerLookup = new Map();
|
|
403
|
-
const currentLedger = getLedger();
|
|
404
|
-
if (currentLedger) {
|
|
405
|
-
for (const lu of currentLedger.units) {
|
|
406
|
-
ledgerLookup.set(`${lu.type}:${lu.id}`, lu);
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
const recent = [...this.dashData.completedUnits].reverse().slice(0, 10);
|
|
410
|
-
for (const u of recent) {
|
|
411
|
-
// Budget indicators from ledger — use warning glyph for pressured units
|
|
412
|
-
const ledgerEntry = ledgerLookup.get(`${u.type}:${u.id}`);
|
|
413
|
-
const hadPressure = ledgerEntry?.continueHereFired === true;
|
|
414
|
-
const hadTruncation = (ledgerEntry?.truncationSections ?? 0) > 0;
|
|
415
|
-
const unitGlyph = hadPressure
|
|
416
|
-
? th.fg(STATUS_COLOR.warning, STATUS_GLYPH.warning)
|
|
417
|
-
: th.fg(STATUS_COLOR.done, STATUS_GLYPH.done);
|
|
418
|
-
const left = ` ${unitGlyph} ${th.fg("muted", unitLabel(u.type))} ${th.fg("muted", u.id)}`;
|
|
419
|
-
let budgetMarkers = "";
|
|
420
|
-
if (hadTruncation) {
|
|
421
|
-
budgetMarkers += th.fg("warning", ` ▼${ledgerEntry.truncationSections}`);
|
|
422
|
-
}
|
|
423
|
-
if (hadPressure) {
|
|
424
|
-
budgetMarkers += th.fg("error", " → wrap-up");
|
|
425
|
-
}
|
|
426
|
-
const right = th.fg("dim", formatDuration(u.finishedAt - u.startedAt));
|
|
427
|
-
lines.push(row(joinColumns(`${left}${budgetMarkers}`, right, contentWidth)));
|
|
428
|
-
}
|
|
429
|
-
if (this.dashData.completedUnits.length > 10) {
|
|
430
|
-
lines.push(row(th.fg("dim", ` ...and ${this.dashData.completedUnits.length - 10} more`)));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
389
|
const ledger = getLedger();
|
|
434
390
|
if (ledger && ledger.units.length > 0) {
|
|
435
391
|
const totals = getProjectTotals(ledger.units);
|
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
// Critical invariant: generated markdown must round-trip through
|
|
9
9
|
// parseDecisionsTable() and parseRequirementsSections() with field fidelity.
|
|
10
10
|
import { resolve } from 'node:path';
|
|
11
|
-
import { readFileSync, existsSync } from 'node:fs';
|
|
11
|
+
import { readFileSync, existsSync, statSync } from 'node:fs';
|
|
12
12
|
import { resolveGsdRootFile } from './paths.js';
|
|
13
13
|
import { saveFile } from './files.js';
|
|
14
14
|
import { GSDError, GSD_STALE_STATE, GSD_IO_ERROR } from './errors.js';
|
|
15
|
+
import { logWarning, logError } from './workflow-logger.js';
|
|
15
16
|
import { invalidateStateCache } from './state.js';
|
|
16
17
|
import { clearPathCache } from './paths.js';
|
|
17
18
|
import { clearParseCache } from './files.js';
|
|
@@ -200,7 +201,7 @@ export async function nextDecisionId() {
|
|
|
200
201
|
return `D${String(next).padStart(3, '0')}`;
|
|
201
202
|
}
|
|
202
203
|
catch (err) {
|
|
203
|
-
|
|
204
|
+
logError('manifest', 'nextDecisionId failed', { fn: 'nextDecisionId', error: String(err.message) });
|
|
204
205
|
return 'D001';
|
|
205
206
|
}
|
|
206
207
|
}
|
|
@@ -269,7 +270,7 @@ export async function saveDecisionToDb(fields, basePath) {
|
|
|
269
270
|
await saveFile(filePath, md);
|
|
270
271
|
}
|
|
271
272
|
catch (diskErr) {
|
|
272
|
-
|
|
273
|
+
logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveDecisionToDb', error: String(diskErr.message) });
|
|
273
274
|
adapter?.prepare('DELETE FROM decisions WHERE id = :id').run({ ':id': id });
|
|
274
275
|
throw diskErr;
|
|
275
276
|
}
|
|
@@ -281,7 +282,7 @@ export async function saveDecisionToDb(fields, basePath) {
|
|
|
281
282
|
return { id };
|
|
282
283
|
}
|
|
283
284
|
catch (err) {
|
|
284
|
-
|
|
285
|
+
logError('manifest', 'saveDecisionToDb failed', { fn: 'saveDecisionToDb', error: String(err.message) });
|
|
285
286
|
throw err;
|
|
286
287
|
}
|
|
287
288
|
}
|
|
@@ -333,7 +334,7 @@ export async function updateRequirementInDb(id, updates, basePath) {
|
|
|
333
334
|
await saveFile(filePath, md);
|
|
334
335
|
}
|
|
335
336
|
catch (diskErr) {
|
|
336
|
-
|
|
337
|
+
logError('manifest', 'disk write failed, reverting DB row', { fn: 'updateRequirementInDb', error: String(diskErr.message) });
|
|
337
338
|
db.upsertRequirement(existing);
|
|
338
339
|
throw diskErr;
|
|
339
340
|
}
|
|
@@ -344,7 +345,7 @@ export async function updateRequirementInDb(id, updates, basePath) {
|
|
|
344
345
|
clearParseCache();
|
|
345
346
|
}
|
|
346
347
|
catch (err) {
|
|
347
|
-
|
|
348
|
+
logError('manifest', 'updateRequirementInDb failed', { fn: 'updateRequirementInDb', error: String(err.message) });
|
|
348
349
|
throw err;
|
|
349
350
|
}
|
|
350
351
|
}
|
|
@@ -356,28 +357,45 @@ export async function updateRequirementInDb(id, updates, basePath) {
|
|
|
356
357
|
export async function saveArtifactToDb(opts, basePath) {
|
|
357
358
|
try {
|
|
358
359
|
const db = await import('./gsd-db.js');
|
|
360
|
+
// Guard against path traversal before any reads/writes
|
|
361
|
+
const gsdDir = resolve(basePath, '.gsd');
|
|
362
|
+
const fullPath = resolve(basePath, '.gsd', opts.path);
|
|
363
|
+
if (!fullPath.startsWith(gsdDir)) {
|
|
364
|
+
throw new GSDError(GSD_IO_ERROR, `saveArtifactToDb: path escapes .gsd/ directory: ${opts.path}`);
|
|
365
|
+
}
|
|
366
|
+
// Shrinkage guard: if the file already exists and the new content is
|
|
367
|
+
// significantly smaller (<50%), preserve the richer file on disk and
|
|
368
|
+
// store its content in the DB instead of the abbreviated version.
|
|
369
|
+
let dbContent = opts.content;
|
|
370
|
+
let skipDiskWrite = false;
|
|
371
|
+
if (existsSync(fullPath)) {
|
|
372
|
+
const existingSize = statSync(fullPath).size;
|
|
373
|
+
const newSize = Buffer.byteLength(opts.content, 'utf-8');
|
|
374
|
+
if (existingSize > 0 && newSize < existingSize * 0.5) {
|
|
375
|
+
logWarning('manifest', `new content (${newSize}B) is <50% of existing file (${existingSize}B), preserving disk file`, { fn: 'saveArtifactToDb', path: opts.path });
|
|
376
|
+
dbContent = readFileSync(fullPath, 'utf-8');
|
|
377
|
+
skipDiskWrite = true;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
359
380
|
db.insertArtifact({
|
|
360
381
|
path: opts.path,
|
|
361
382
|
artifact_type: opts.artifact_type,
|
|
362
383
|
milestone_id: opts.milestone_id ?? null,
|
|
363
384
|
slice_id: opts.slice_id ?? null,
|
|
364
385
|
task_id: opts.task_id ?? null,
|
|
365
|
-
full_content:
|
|
386
|
+
full_content: dbContent,
|
|
366
387
|
});
|
|
367
|
-
// Write the file to disk (
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const rollbackAdapter = db._getAdapter();
|
|
379
|
-
rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
|
|
380
|
-
throw diskErr;
|
|
388
|
+
// Write the file to disk (only if we're not preserving a richer existing file)
|
|
389
|
+
if (!skipDiskWrite) {
|
|
390
|
+
try {
|
|
391
|
+
await saveFile(fullPath, opts.content);
|
|
392
|
+
}
|
|
393
|
+
catch (diskErr) {
|
|
394
|
+
logError('manifest', 'disk write failed, rolling back DB row', { fn: 'saveArtifactToDb', error: String(diskErr.message) });
|
|
395
|
+
const rollbackAdapter = db._getAdapter();
|
|
396
|
+
rollbackAdapter?.prepare('DELETE FROM artifacts WHERE path = :path').run({ ':path': opts.path });
|
|
397
|
+
throw diskErr;
|
|
398
|
+
}
|
|
381
399
|
}
|
|
382
400
|
// Invalidate file-read caches so deriveState() sees the updated markdown.
|
|
383
401
|
// Do NOT clear the artifacts table — we just wrote to it intentionally.
|
|
@@ -386,7 +404,7 @@ export async function saveArtifactToDb(opts, basePath) {
|
|
|
386
404
|
clearParseCache();
|
|
387
405
|
}
|
|
388
406
|
catch (err) {
|
|
389
|
-
|
|
407
|
+
logError('manifest', 'saveArtifactToDb failed', { fn: 'saveArtifactToDb', error: String(err.message) });
|
|
390
408
|
throw err;
|
|
391
409
|
}
|
|
392
410
|
}
|
|
@@ -3,7 +3,7 @@ import { basename, dirname, join, sep } from "node:path";
|
|
|
3
3
|
import { readRepoMeta, externalProjectsRoot, cleanNumberedGsdVariants } from "./repo-identity.js";
|
|
4
4
|
import { loadFile } from "./files.js";
|
|
5
5
|
import { parseRoadmap as parseLegacyRoadmap } from "./parsers-legacy.js";
|
|
6
|
-
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
6
|
+
import { isDbAvailable, _getAdapter, getMilestoneSlices } from "./gsd-db.js";
|
|
7
7
|
import { resolveMilestoneFile, milestonesDir, gsdRoot, resolveGsdRootFile } from "./paths.js";
|
|
8
8
|
import { deriveState, isMilestoneComplete } from "./state.js";
|
|
9
9
|
import { saveFile } from "./files.js";
|
|
@@ -17,7 +17,9 @@ import { getAllWorktreeHealth } from "./worktree-health.js";
|
|
|
17
17
|
import { readAllSessionStatuses, isSessionStale, removeSessionStatus } from "./session-status-io.js";
|
|
18
18
|
import { recoverFailedMigration } from "./migrate-external.js";
|
|
19
19
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
20
|
-
|
|
20
|
+
import { readEvents } from "./workflow-events.js";
|
|
21
|
+
import { renderAllProjections } from "./workflow-projections.js";
|
|
22
|
+
export async function checkGitHealth(basePath, issues, fixesApplied, shouldFix, isolationMode = "none") {
|
|
21
23
|
// Degrade gracefully if not a git repo
|
|
22
24
|
if (!nativeIsRepo(basePath)) {
|
|
23
25
|
return; // Not a git repo — skip all git health checks
|
|
@@ -1067,3 +1069,166 @@ export async function checkGlobalHealth(issues, fixesApplied, shouldFix) {
|
|
|
1067
1069
|
// Non-fatal — global health check must not block per-project doctor
|
|
1068
1070
|
}
|
|
1069
1071
|
}
|
|
1072
|
+
// ── Engine Health Checks ────────────────────────────────────────────────────
|
|
1073
|
+
// DB constraint violation detection and projection drift checks.
|
|
1074
|
+
export async function checkEngineHealth(basePath, issues, fixesApplied) {
|
|
1075
|
+
// ── DB constraint violation detection (full doctor only, not pre-dispatch per D-10) ──
|
|
1076
|
+
try {
|
|
1077
|
+
if (isDbAvailable()) {
|
|
1078
|
+
const adapter = _getAdapter();
|
|
1079
|
+
// a. Orphaned tasks (task.slice_id points to non-existent slice)
|
|
1080
|
+
try {
|
|
1081
|
+
const orphanedTasks = adapter
|
|
1082
|
+
.prepare(`SELECT t.id, t.slice_id, t.milestone_id
|
|
1083
|
+
FROM tasks t
|
|
1084
|
+
LEFT JOIN slices s ON t.milestone_id = s.milestone_id AND t.slice_id = s.id
|
|
1085
|
+
WHERE s.id IS NULL`)
|
|
1086
|
+
.all();
|
|
1087
|
+
for (const row of orphanedTasks) {
|
|
1088
|
+
issues.push({
|
|
1089
|
+
severity: "error",
|
|
1090
|
+
code: "db_orphaned_task",
|
|
1091
|
+
scope: "task",
|
|
1092
|
+
unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
|
|
1093
|
+
message: `Task ${row.id} references slice ${row.slice_id} in milestone ${row.milestone_id} but no such slice exists in the database`,
|
|
1094
|
+
fixable: false,
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
catch {
|
|
1099
|
+
// Non-fatal — orphaned task check failed
|
|
1100
|
+
}
|
|
1101
|
+
// b. Orphaned slices (slice.milestone_id points to non-existent milestone)
|
|
1102
|
+
try {
|
|
1103
|
+
const orphanedSlices = adapter
|
|
1104
|
+
.prepare(`SELECT s.id, s.milestone_id
|
|
1105
|
+
FROM slices s
|
|
1106
|
+
LEFT JOIN milestones m ON s.milestone_id = m.id
|
|
1107
|
+
WHERE m.id IS NULL`)
|
|
1108
|
+
.all();
|
|
1109
|
+
for (const row of orphanedSlices) {
|
|
1110
|
+
issues.push({
|
|
1111
|
+
severity: "error",
|
|
1112
|
+
code: "db_orphaned_slice",
|
|
1113
|
+
scope: "slice",
|
|
1114
|
+
unitId: `${row.milestone_id}/${row.id}`,
|
|
1115
|
+
message: `Slice ${row.id} references milestone ${row.milestone_id} but no such milestone exists in the database`,
|
|
1116
|
+
fixable: false,
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
catch {
|
|
1121
|
+
// Non-fatal — orphaned slice check failed
|
|
1122
|
+
}
|
|
1123
|
+
// c. Tasks marked complete without summaries
|
|
1124
|
+
try {
|
|
1125
|
+
const doneTasks = adapter
|
|
1126
|
+
.prepare(`SELECT id, slice_id, milestone_id FROM tasks
|
|
1127
|
+
WHERE status = 'done' AND (summary IS NULL OR summary = '')`)
|
|
1128
|
+
.all();
|
|
1129
|
+
for (const row of doneTasks) {
|
|
1130
|
+
issues.push({
|
|
1131
|
+
severity: "warning",
|
|
1132
|
+
code: "db_done_task_no_summary",
|
|
1133
|
+
scope: "task",
|
|
1134
|
+
unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
|
|
1135
|
+
message: `Task ${row.id} is marked done but has no summary in the database`,
|
|
1136
|
+
fixable: false,
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
catch {
|
|
1141
|
+
// Non-fatal — done-task-no-summary check failed
|
|
1142
|
+
}
|
|
1143
|
+
// d. Duplicate entity IDs (safety check)
|
|
1144
|
+
try {
|
|
1145
|
+
const dupMilestones = adapter
|
|
1146
|
+
.prepare("SELECT id, COUNT(*) as cnt FROM milestones GROUP BY id HAVING cnt > 1")
|
|
1147
|
+
.all();
|
|
1148
|
+
for (const row of dupMilestones) {
|
|
1149
|
+
issues.push({
|
|
1150
|
+
severity: "error",
|
|
1151
|
+
code: "db_duplicate_id",
|
|
1152
|
+
scope: "milestone",
|
|
1153
|
+
unitId: row.id,
|
|
1154
|
+
message: `Duplicate milestone ID "${row.id}" appears ${row.cnt} times in the database`,
|
|
1155
|
+
fixable: false,
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
const dupSlices = adapter
|
|
1159
|
+
.prepare("SELECT id, milestone_id, COUNT(*) as cnt FROM slices GROUP BY id, milestone_id HAVING cnt > 1")
|
|
1160
|
+
.all();
|
|
1161
|
+
for (const row of dupSlices) {
|
|
1162
|
+
issues.push({
|
|
1163
|
+
severity: "error",
|
|
1164
|
+
code: "db_duplicate_id",
|
|
1165
|
+
scope: "slice",
|
|
1166
|
+
unitId: `${row.milestone_id}/${row.id}`,
|
|
1167
|
+
message: `Duplicate slice ID "${row.id}" in milestone ${row.milestone_id} appears ${row.cnt} times`,
|
|
1168
|
+
fixable: false,
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
const dupTasks = adapter
|
|
1172
|
+
.prepare("SELECT id, slice_id, milestone_id, COUNT(*) as cnt FROM tasks GROUP BY id, slice_id, milestone_id HAVING cnt > 1")
|
|
1173
|
+
.all();
|
|
1174
|
+
for (const row of dupTasks) {
|
|
1175
|
+
issues.push({
|
|
1176
|
+
severity: "error",
|
|
1177
|
+
code: "db_duplicate_id",
|
|
1178
|
+
scope: "task",
|
|
1179
|
+
unitId: `${row.milestone_id}/${row.slice_id}/${row.id}`,
|
|
1180
|
+
message: `Duplicate task ID "${row.id}" in slice ${row.slice_id} appears ${row.cnt} times`,
|
|
1181
|
+
fixable: false,
|
|
1182
|
+
});
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
catch {
|
|
1186
|
+
// Non-fatal — duplicate ID check failed
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
catch {
|
|
1191
|
+
// Non-fatal — DB constraint checks failed entirely
|
|
1192
|
+
}
|
|
1193
|
+
// ── Projection drift detection ──────────────────────────────────────────
|
|
1194
|
+
// If the DB is available, check whether markdown projections are stale
|
|
1195
|
+
// relative to the event log and re-render them.
|
|
1196
|
+
try {
|
|
1197
|
+
if (isDbAvailable()) {
|
|
1198
|
+
const eventLogPath = join(basePath, ".gsd", "event-log.jsonl");
|
|
1199
|
+
const events = readEvents(eventLogPath);
|
|
1200
|
+
if (events.length > 0) {
|
|
1201
|
+
const lastEventTs = new Date(events[events.length - 1].ts).getTime();
|
|
1202
|
+
const state = await deriveState(basePath);
|
|
1203
|
+
for (const milestone of state.registry) {
|
|
1204
|
+
if (milestone.status === "complete")
|
|
1205
|
+
continue;
|
|
1206
|
+
const roadmapPath = resolveMilestoneFile(basePath, milestone.id, "ROADMAP");
|
|
1207
|
+
if (!roadmapPath || !existsSync(roadmapPath)) {
|
|
1208
|
+
try {
|
|
1209
|
+
await renderAllProjections(basePath, milestone.id);
|
|
1210
|
+
fixesApplied.push(`re-rendered missing projections for ${milestone.id}`);
|
|
1211
|
+
}
|
|
1212
|
+
catch {
|
|
1213
|
+
// Non-fatal — projection re-render failed
|
|
1214
|
+
}
|
|
1215
|
+
continue;
|
|
1216
|
+
}
|
|
1217
|
+
const projectionMtime = statSync(roadmapPath).mtimeMs;
|
|
1218
|
+
if (lastEventTs > projectionMtime) {
|
|
1219
|
+
try {
|
|
1220
|
+
await renderAllProjections(basePath, milestone.id);
|
|
1221
|
+
fixesApplied.push(`re-rendered stale projections for ${milestone.id}`);
|
|
1222
|
+
}
|
|
1223
|
+
catch {
|
|
1224
|
+
// Non-fatal — projection re-render failed
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
catch {
|
|
1232
|
+
// Non-fatal — projection drift check must never block doctor
|
|
1233
|
+
}
|
|
1234
|
+
}
|