@opengsd/gsd-pi 1.7.0 → 1.8.1-dev.897b3c90
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/README.md +8 -6
- package/dist/cli.js +5 -1
- package/dist/headless-events.d.ts +2 -1
- package/dist/headless-events.js +11 -3
- package/dist/headless-milestone-readiness.d.ts +29 -0
- package/dist/headless-milestone-readiness.js +161 -0
- package/dist/headless.js +25 -2
- package/dist/print-mode-exit.d.ts +12 -0
- package/dist/print-mode-exit.js +14 -0
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +16 -47
- package/dist/resources/extensions/browser-tools/capture.js +2 -77
- package/dist/resources/extensions/browser-tools/screenshot-constraints.js +83 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +17 -2
- package/dist/resources/extensions/claude-code-cli/turn-assembler.js +30 -2
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +74 -19
- package/dist/resources/extensions/gsd/auto-post-unit.js +4 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +35 -1
- package/dist/resources/extensions/gsd/auto.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +78 -4
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +84 -26
- package/dist/resources/extensions/gsd/command-feedback.js +16 -12
- package/dist/resources/extensions/gsd/compat/compat-marker.js +19 -2
- package/dist/resources/extensions/gsd/db/command-queue.js +7 -2
- package/dist/resources/extensions/gsd/db/engine.js +51 -16
- package/dist/resources/extensions/gsd/db/writers/cascades.js +5 -1
- package/dist/resources/extensions/gsd/db/writers/status.js +13 -3
- package/dist/resources/extensions/gsd/db-base-schema.js +28 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +30 -0
- package/dist/resources/extensions/gsd/db-schema-metadata.js +4 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +4 -4
- package/dist/resources/extensions/gsd/doctor-history.js +65 -0
- package/dist/resources/extensions/gsd/doctor-state-checks.js +509 -0
- package/dist/resources/extensions/gsd/doctor-workspace-checks.js +91 -0
- package/dist/resources/extensions/gsd/doctor.js +14 -653
- package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
- package/dist/resources/extensions/gsd/gsd-db.js +187 -45
- package/dist/resources/extensions/gsd/guided-flow.js +29 -10
- package/dist/resources/extensions/gsd/markdown-renderer.js +16 -2
- package/dist/resources/extensions/gsd/md-importer.js +109 -16
- package/dist/resources/extensions/gsd/migrate/command.js +19 -162
- package/dist/resources/extensions/gsd/migrate/execution.js +98 -0
- package/dist/resources/extensions/gsd/migrate/plan.js +49 -0
- package/dist/resources/extensions/gsd/migrate/planning-writer.js +20 -19
- package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
- package/dist/resources/extensions/gsd/migration-auto-check.js +4 -0
- package/dist/resources/extensions/gsd/parallel-eligibility.js +5 -4
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +28 -43
- package/dist/resources/extensions/gsd/paths.js +4 -1
- package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
- package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/dist/resources/extensions/gsd/safety/evidence-collector.js +26 -1
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +27 -13
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +13 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +54 -14
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +48 -5
- package/dist/resources/extensions/gsd/stop-notice.js +15 -1
- package/dist/resources/extensions/gsd/sync-lock.js +13 -7
- package/dist/resources/extensions/gsd/tools/complete-task.js +82 -1
- package/dist/resources/extensions/gsd/tools/plan-task.js +13 -15
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +18 -15
- package/dist/resources/extensions/gsd/tools/replan-task.js +128 -0
- package/dist/resources/extensions/gsd/tools/rework-brief.js +74 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +81 -0
- package/dist/resources/extensions/gsd/unit-registry.js +4 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +19 -3
- package/dist/resources/extensions/gsd/worktree-state-projection.js +6 -0
- package/dist/resources/extensions/mac-tools/index.js +31 -9
- 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 +9 -9
- 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/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- 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.js +2 -2
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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 +4 -4
- 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.js +1 -1
- 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.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.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.js +2 -2
- 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.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.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.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.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.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/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.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.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.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.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.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.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.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.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.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/mcp-connections/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/mcp-connections/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.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.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.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.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.js +2 -2
- 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.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.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.js +2 -2
- 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.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.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.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.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.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.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.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.js +2 -2
- 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.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.js +4 -4
- 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.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.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.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.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 +5 -5
- 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 +5 -5
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
- package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +3 -3
- 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/app/_not-found/page-a6fb1847f67f167c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
- package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/package.json +0 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +31 -3
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +12 -10
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/cloud-config.d.ts +1 -1
- package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
- package/packages/daemon/dist/cloud-config.js +30 -8
- package/packages/daemon/dist/cloud-config.js.map +1 -1
- package/packages/daemon/dist/cloud-config.test.js +69 -1
- package/packages/daemon/dist/cloud-config.test.js.map +1 -1
- package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
- package/packages/daemon/dist/local-tool-executor.js +2 -0
- package/packages/daemon/dist/local-tool-executor.js.map +1 -1
- package/packages/daemon/package.json +6 -6
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +18 -4
- package/packages/gsd-cloud/bin/gsd-cloud.js +6 -5
- package/packages/gsd-cloud/dist/cli.d.ts +5 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cli.js +160 -0
- package/packages/gsd-cloud/dist/cli.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.js +231 -0
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.js +37 -0
- package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
- package/packages/gsd-cloud/dist/config.d.ts +17 -0
- package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/config.js +146 -0
- package/packages/gsd-cloud/dist/config.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.js +128 -0
- package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
- package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.js +11 -0
- package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.js +29 -0
- package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
- package/packages/gsd-cloud/dist/index.d.ts +7 -0
- package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/index.js +8 -0
- package/packages/gsd-cloud/dist/index.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
- package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
- package/packages/gsd-cloud/dist/logger.d.ts +25 -0
- package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/logger.js +72 -0
- package/packages/gsd-cloud/dist/logger.js.map +1 -0
- package/packages/gsd-cloud/dist/types.d.ts +51 -0
- package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/types.js +9 -0
- package/packages/gsd-cloud/dist/types.js.map +1 -0
- package/packages/gsd-cloud/package.json +7 -5
- package/packages/mcp-server/README.md +8 -0
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +64 -2
- 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/dist/models.generated.d.ts +60 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +54 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +1 -0
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +19 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/package.json +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/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +16 -47
- package/src/resources/extensions/browser-tools/capture.ts +2 -86
- package/src/resources/extensions/browser-tools/screenshot-constraints.ts +94 -0
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +18 -1
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +108 -0
- package/src/resources/extensions/claude-code-cli/turn-assembler.ts +30 -2
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +86 -19
- package/src/resources/extensions/gsd/auto-post-unit.ts +4 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +38 -1
- package/src/resources/extensions/gsd/auto.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +91 -4
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +80 -24
- package/src/resources/extensions/gsd/command-feedback.ts +19 -12
- package/src/resources/extensions/gsd/compat/compat-marker.ts +21 -4
- package/src/resources/extensions/gsd/db/command-queue.ts +7 -1
- package/src/resources/extensions/gsd/db/engine.ts +53 -17
- package/src/resources/extensions/gsd/db/writers/cascades.ts +5 -1
- package/src/resources/extensions/gsd/db/writers/status.ts +25 -8
- package/src/resources/extensions/gsd/db-base-schema.ts +30 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +32 -0
- package/src/resources/extensions/gsd/db-schema-metadata.ts +4 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +4 -4
- package/src/resources/extensions/gsd/doctor-history.ts +81 -0
- package/src/resources/extensions/gsd/doctor-state-checks.ts +527 -0
- package/src/resources/extensions/gsd/doctor-workspace-checks.ts +97 -0
- package/src/resources/extensions/gsd/doctor.ts +14 -673
- package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
- package/src/resources/extensions/gsd/gsd-db.ts +255 -52
- package/src/resources/extensions/gsd/guided-flow.ts +39 -10
- package/src/resources/extensions/gsd/markdown-renderer.ts +23 -7
- package/src/resources/extensions/gsd/md-importer.ts +116 -13
- package/src/resources/extensions/gsd/migrate/command.ts +21 -227
- package/src/resources/extensions/gsd/migrate/execution.ts +136 -0
- package/src/resources/extensions/gsd/migrate/plan.ts +101 -0
- package/src/resources/extensions/gsd/migrate/planning-writer.ts +21 -23
- package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
- package/src/resources/extensions/gsd/migration-auto-check.ts +3 -0
- package/src/resources/extensions/gsd/parallel-eligibility.ts +5 -4
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +37 -40
- package/src/resources/extensions/gsd/paths.ts +4 -1
- package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
- package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- package/src/resources/extensions/gsd/safety/evidence-collector.ts +28 -1
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +30 -13
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +16 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +67 -20
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +47 -5
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +2 -2
- package/src/resources/extensions/gsd/stop-notice.ts +18 -1
- package/src/resources/extensions/gsd/sync-lock.ts +14 -6
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +96 -1
- package/src/resources/extensions/gsd/tests/command-feedback.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +104 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +286 -0
- package/src/resources/extensions/gsd/tests/db-authority-regression.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/doctor-history-public-api.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +81 -0
- package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/external-edit-scoped-import.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/import-slice-milestone-completion-preserve.test.ts +116 -0
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/migrate-plan.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/migrate-presentation.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/migrate-safety-audit.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/milestone-leases.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/parallel-eligibility-file-overlap.test.ts +146 -0
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/phase-anchor.test.ts +32 -4
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +26 -23
- package/src/resources/extensions/gsd/tests/planning-writer.test.ts +47 -1
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +18 -3
- package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/replan-task-handler.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/rework-brief.test.ts +197 -0
- package/src/resources/extensions/gsd/tests/skip-slice-cascades-tasks.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +177 -25
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +17 -0
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/workflow-migration-gates.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +120 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +14 -16
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +18 -17
- package/src/resources/extensions/gsd/tools/replan-task.ts +160 -0
- package/src/resources/extensions/gsd/tools/rework-brief.ts +91 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +92 -0
- package/src/resources/extensions/gsd/types.ts +11 -0
- package/src/resources/extensions/gsd/unit-registry.ts +4 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +20 -3
- package/src/resources/extensions/gsd/worktree-state-projection.ts +12 -0
- package/src/resources/extensions/mac-tools/index.ts +52 -9
- package/src/resources/extensions/mac-tools/tests/mac-screenshot-payload.test.cjs +70 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-49f565245e1e4afe.js +0 -1
- package/dist/web/standalone/.next/static/chunks/app/page-bc4c723c6a19c6f0.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ec3eaffc9785ba48.js +0 -1
- package/dist/web/standalone/.next/static/css/18c2fdf261bfc1b7.css +0 -1
- /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{enWQFRY-aLTUq3wmxG2Qz → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
|
@@ -1698,6 +1698,10 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
1698
1698
|
`Safety: task ${sTid} claimed passing verification that failed in recorded execution`,
|
|
1699
1699
|
"error",
|
|
1700
1700
|
);
|
|
1701
|
+
const gitActionResult = await runCloseoutGitAction(pctx, s.currentUnit);
|
|
1702
|
+
if (gitActionResult === "dispatched") {
|
|
1703
|
+
return "dispatched";
|
|
1704
|
+
}
|
|
1701
1705
|
await pauseAuto(ctx, pi);
|
|
1702
1706
|
return "dispatched";
|
|
1703
1707
|
}
|
|
@@ -28,7 +28,7 @@ import type { GSDPreferences } from "./preferences.js";
|
|
|
28
28
|
import { join, basename, relative, sep } from "node:path";
|
|
29
29
|
import { existsSync } from "node:fs";
|
|
30
30
|
import { computeBudgets, resolveExecutorContextWindow, truncateAtSectionBoundary, type MinimalModelRegistry } from "./context-budget.js";
|
|
31
|
-
import { getGateResults, getPendingGates, getPendingGatesForTurn } from "./gsd-db.js";
|
|
31
|
+
import { getBlockingReworkFindingsForTask, getGateResults, getPendingGates, getPendingGatesForTurn } from "./gsd-db.js";
|
|
32
32
|
import {
|
|
33
33
|
GATE_REGISTRY,
|
|
34
34
|
assertGateCoverage,
|
|
@@ -106,6 +106,34 @@ function resolveSummaryBudgetChars(): number {
|
|
|
106
106
|
return resolvePromptBudgets().summaryBudgetChars;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
|
|
110
|
+
function renderBlockingReworkFindingsBlock(mid: string, sid: string, tid: string): string {
|
|
111
|
+
const findings = getBlockingReworkFindingsForTask(mid, sid, tid)
|
|
112
|
+
.filter((finding) => finding.status === "pending");
|
|
113
|
+
if (findings.length === 0) return "";
|
|
114
|
+
|
|
115
|
+
const lines = [
|
|
116
|
+
"## Blocking Rework Findings (non-optional)",
|
|
117
|
+
"",
|
|
118
|
+
"This task has structured blocking rework findings. Address every finding before calling `gsd_task_complete`. Include `reworkResolution` entries with each `findingId`, `status: \"resolved\"`, and concrete evidence. If deferring a finding, use `status: \"deferred-with-override\"` with concrete evidence and `decisionRef`.",
|
|
119
|
+
"",
|
|
120
|
+
];
|
|
121
|
+
for (const finding of findings) {
|
|
122
|
+
lines.push(`### ${finding.finding_id} (${finding.severity})`);
|
|
123
|
+
lines.push(`- Status: ${finding.status}`);
|
|
124
|
+
lines.push(`- Finding: ${finding.description}`);
|
|
125
|
+
lines.push(`- Required fix: ${finding.required_fix}`);
|
|
126
|
+
if (finding.verification_commands.length > 0) {
|
|
127
|
+
lines.push("- Required verification:");
|
|
128
|
+
for (const command of finding.verification_commands) {
|
|
129
|
+
lines.push(` - \`${command}\``);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
lines.push("");
|
|
133
|
+
}
|
|
134
|
+
return lines.join("\n").trim();
|
|
135
|
+
}
|
|
136
|
+
|
|
109
137
|
function formatProjectClassificationForPlanning(classification: ProjectClassification): string {
|
|
110
138
|
const sampleFiles = classification.contentFiles.slice(0, 8);
|
|
111
139
|
const sample = sampleFiles.length > 0 ? sampleFiles.map((file) => `\`${file}\``).join(", ") : "(none)";
|
|
@@ -2745,6 +2773,15 @@ export async function buildExecuteTaskPrompt(
|
|
|
2745
2773
|
logWarning("prompt", `reopen reason injection failed: ${(reopenErr as Error).message}`);
|
|
2746
2774
|
}
|
|
2747
2775
|
|
|
2776
|
+
const reworkFindingsBlock = renderBlockingReworkFindingsBlock(mid, sid, tid);
|
|
2777
|
+
if (reworkFindingsBlock) {
|
|
2778
|
+
const block = reworkFindingsBlock + "\n\n---\n\n";
|
|
2779
|
+
phaseAnchorSection = phaseAnchorSection
|
|
2780
|
+
? `${block}${phaseAnchorSection}`
|
|
2781
|
+
: block;
|
|
2782
|
+
trackPromptContext(contextTelemetry, "rework-findings", "inline", reworkFindingsBlock);
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2748
2785
|
// ADR-011 Phase 2: inject any resolved-but-unapplied escalation override
|
|
2749
2786
|
// into this task's prompt. Claim is atomic via DB UPDATE WHERE IS NULL, so
|
|
2750
2787
|
// if a parallel build already injected it, we skip. Feature-gated by
|
|
@@ -19,7 +19,7 @@ import type {
|
|
|
19
19
|
SessionMessageEntry,
|
|
20
20
|
} from "@gsd/pi-coding-agent";
|
|
21
21
|
|
|
22
|
-
import { deriveState } from "./state.js";
|
|
22
|
+
import { deriveState, invalidateStateCache } from "./state.js";
|
|
23
23
|
import {
|
|
24
24
|
buildRequirementsBacklogSummaryLines,
|
|
25
25
|
countUnmappedActiveRequirements,
|
|
@@ -443,6 +443,9 @@ function captureMilestoneLockEnv(milestoneId: string | null): void {
|
|
|
443
443
|
} else {
|
|
444
444
|
delete process.env.GSD_MILESTONE_LOCK;
|
|
445
445
|
}
|
|
446
|
+
// The derive cache is keyed on basePath only; GSD_MILESTONE_LOCK changes
|
|
447
|
+
// what deriveState computes, so a lock flip must not serve a cached result.
|
|
448
|
+
invalidateStateCache();
|
|
446
449
|
}
|
|
447
450
|
|
|
448
451
|
function restoreMilestoneLockEnv(): void {
|
|
@@ -457,6 +460,7 @@ function restoreMilestoneLockEnv(): void {
|
|
|
457
460
|
s.previousMilestoneLockEnv = null;
|
|
458
461
|
s.hadMilestoneLockEnv = false;
|
|
459
462
|
s.milestoneLockEnvCaptured = false;
|
|
463
|
+
invalidateStateCache();
|
|
460
464
|
}
|
|
461
465
|
|
|
462
466
|
/**
|
|
@@ -771,12 +771,12 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
771
771
|
name: "gsd_plan_task",
|
|
772
772
|
label: "Plan Task",
|
|
773
773
|
description:
|
|
774
|
-
"Write task planning state to the GSD database, render
|
|
775
|
-
promptSnippet: "Plan a task via DB write +
|
|
774
|
+
"Write task planning state to the GSD database, render the slice PLAN from DB, and clear caches after a successful render.",
|
|
775
|
+
promptSnippet: "Plan a task via DB write + slice PLAN render + cache invalidation",
|
|
776
776
|
promptGuidelines: [
|
|
777
|
-
"Use gsd_plan_task for task planning instead of writing
|
|
777
|
+
"Use gsd_plan_task for task planning instead of writing task PLAN files directly.",
|
|
778
778
|
"Keep parameters flat and provide the full task planning payload.",
|
|
779
|
-
"The tool validates input, requires an existing parent slice, writes task planning data, renders the
|
|
779
|
+
"The tool validates input, requires an existing parent slice, writes task planning data, renders the slice PLAN file from DB, and clears both state and parse caches after success.",
|
|
780
780
|
"Use the canonical name gsd_plan_task; gsd_task_plan is only an alias.",
|
|
781
781
|
],
|
|
782
782
|
parameters: Type.Object({
|
|
@@ -860,6 +860,15 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
860
860
|
}),
|
|
861
861
|
{ description: "Array of verification evidence entries (structured objects only)" },
|
|
862
862
|
)),
|
|
863
|
+
reworkResolution: Type.Optional(Type.Array(
|
|
864
|
+
Type.Object({
|
|
865
|
+
findingId: Type.String({ description: "Rework finding ID being resolved (e.g. F1)" }),
|
|
866
|
+
status: StringEnum(["resolved", "deferred-with-override"], { description: "Resolution status for this finding" }),
|
|
867
|
+
evidence: Type.String({ description: "Concrete evidence that the required fix was completed" }),
|
|
868
|
+
decisionRef: Type.Optional(Type.String({ description: "Decision reference required for deferred-with-override findings" })),
|
|
869
|
+
}),
|
|
870
|
+
{ description: "Resolution evidence for structured rework findings linked to this task" },
|
|
871
|
+
)),
|
|
863
872
|
// Single-writer v3 audit trail (Stream 2): caller-provided actor identity + causation.
|
|
864
873
|
actorName: Type.Optional(Type.String({ description: "Caller-provided actor identity for the audit trail (e.g. 'executor-01', 'gsd-orchestrator')" })),
|
|
865
874
|
triggerReason: Type.Optional(Type.String({ description: "Caller-provided reason this action was triggered (e.g. 'task verified after retry')" })),
|
|
@@ -1180,6 +1189,84 @@ export function registerDbTools(pi: ExtensionAPI): void {
|
|
|
1180
1189
|
|
|
1181
1190
|
registerWorkflowTool(pi, replanSliceTool);
|
|
1182
1191
|
|
|
1192
|
+
// ─── gsd_replan_task ───────────────────────────────────────────────────
|
|
1193
|
+
|
|
1194
|
+
const replanTaskExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
1195
|
+
const { executeReplanTask } = await loadWorkflowExecutors();
|
|
1196
|
+
return executeReplanTask(params, resolveWorkflowToolBasePath(_ctx, params));
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
const replanTaskTool = {
|
|
1200
|
+
name: "gsd_replan_task",
|
|
1201
|
+
label: "Replan Task",
|
|
1202
|
+
description:
|
|
1203
|
+
"Update one pending task's planning contract after rework without touching sibling tasks. " +
|
|
1204
|
+
"Completed tasks are structurally protected. Re-renders the task/slice PLAN projection and records replan history.",
|
|
1205
|
+
promptSnippet: "Replan one pending GSD task after rework",
|
|
1206
|
+
promptGuidelines: [
|
|
1207
|
+
"Use gsd_replan_task when a reopened pending task needs its title, description, files, verify, inputs, or expectedOutput updated for rework.",
|
|
1208
|
+
"The task must already exist and be pending; completed tasks are rejected.",
|
|
1209
|
+
"Set reworkBriefRef when a structured rework brief triggered the task replan.",
|
|
1210
|
+
],
|
|
1211
|
+
parameters: Type.Object({
|
|
1212
|
+
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
1213
|
+
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
1214
|
+
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
1215
|
+
title: Type.String({ description: "Updated task title" }),
|
|
1216
|
+
description: Type.String({ description: "Updated task description incorporating rework scope" }),
|
|
1217
|
+
estimate: Type.String({ description: "Updated task estimate string" }),
|
|
1218
|
+
files: Type.Array(Type.String(), { description: "Updated files likely touched" }),
|
|
1219
|
+
verify: Type.String({ description: "Updated verification command or block" }),
|
|
1220
|
+
inputs: Type.Array(Type.String(), { description: "Updated input files or references" }),
|
|
1221
|
+
expectedOutput: Type.Array(Type.String(), { description: "Updated files this task creates or overwrites" }),
|
|
1222
|
+
reworkBriefRef: Type.Optional(Type.String({ description: "Rework brief ID/reference that triggered this task replan" })),
|
|
1223
|
+
actorName: Type.Optional(Type.String({ description: "Caller-provided actor identity for the audit trail" })),
|
|
1224
|
+
triggerReason: Type.Optional(Type.String({ description: "Caller-provided reason this action was triggered" })),
|
|
1225
|
+
}),
|
|
1226
|
+
execute: replanTaskExecute,
|
|
1227
|
+
};
|
|
1228
|
+
|
|
1229
|
+
registerWorkflowTool(pi, replanTaskTool);
|
|
1230
|
+
|
|
1231
|
+
// ─── gsd_rework_brief_save ─────────────────────────────────────────────
|
|
1232
|
+
|
|
1233
|
+
const reworkBriefSaveExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
1234
|
+
const { executeReworkBriefSave } = await loadWorkflowExecutors();
|
|
1235
|
+
return executeReworkBriefSave(params, resolveWorkflowToolBasePath(_ctx, params));
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
const reworkBriefSaveTool = {
|
|
1239
|
+
name: "gsd_rework_brief_save",
|
|
1240
|
+
label: "Save Rework Brief",
|
|
1241
|
+
description:
|
|
1242
|
+
"Persist a structured rework brief for a task. Blocking findings are enforced by gsd_task_complete until resolved with evidence.",
|
|
1243
|
+
promptSnippet: "Persist structured task rework findings",
|
|
1244
|
+
promptGuidelines: [
|
|
1245
|
+
"Use gsd_rework_brief_save when post-unit checks produce task rework findings.",
|
|
1246
|
+
"Use severity 'blocking' for findings that must be resolved before gsd_task_complete succeeds.",
|
|
1247
|
+
"Each finding needs a stable findingId, requiredFix, and verificationCommands.",
|
|
1248
|
+
],
|
|
1249
|
+
parameters: Type.Object({
|
|
1250
|
+
briefId: Type.Optional(Type.String({ description: "Stable brief ID; omitted defaults to RB-<milestone>-<slice>-<task>" })),
|
|
1251
|
+
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
1252
|
+
sliceId: Type.String({ description: "Slice ID (e.g. S01)" }),
|
|
1253
|
+
taskId: Type.String({ description: "Task ID (e.g. T01)" }),
|
|
1254
|
+
findings: Type.Array(Type.Object({
|
|
1255
|
+
findingId: Type.String({ description: "Stable finding ID (e.g. F1)" }),
|
|
1256
|
+
severity: StringEnum(["blocking", "advisory"], { description: "Whether this finding blocks task completion" }),
|
|
1257
|
+
description: Type.String({ description: "What was found" }),
|
|
1258
|
+
requiredFix: Type.String({ description: "What must change" }),
|
|
1259
|
+
verificationCommands: Type.Array(Type.String(), { description: "Commands that must pass after the fix" }),
|
|
1260
|
+
status: Type.Optional(StringEnum(["pending", "resolved", "deferred-with-override"], { description: "Finding status; defaults to pending" })),
|
|
1261
|
+
evidence: Type.Optional(Type.String({ description: "Resolution evidence when already resolved" })),
|
|
1262
|
+
decisionRef: Type.Optional(Type.String({ description: "Decision reference for deferred-with-override" })),
|
|
1263
|
+
}), { description: "Structured rework findings for this task" }),
|
|
1264
|
+
}),
|
|
1265
|
+
execute: reworkBriefSaveExecute,
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
registerWorkflowTool(pi, reworkBriefSaveTool);
|
|
1269
|
+
|
|
1183
1270
|
// ─── gsd_reassess_roadmap (gsd_roadmap_reassess alias) ─────────────────
|
|
1184
1271
|
|
|
1185
1272
|
const reassessRoadmapExecute = async (_toolCallId: string, params: any, _signal: AbortSignal | undefined, _onUpdate: unknown, _ctx: unknown) => {
|
|
@@ -10,6 +10,7 @@ import { loadJsonFileOrNull } from "../json-persistence.js";
|
|
|
10
10
|
import { getIsolationMode } from "../preferences.js";
|
|
11
11
|
import { compileSubagentPermissionContract, type ToolsPolicy } from "../unit-context-manifest.js";
|
|
12
12
|
import { logWarning } from "../workflow-logger.js";
|
|
13
|
+
import { acquireSyncLock, releaseSyncLock } from "../sync-lock.js";
|
|
13
14
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
14
15
|
import { worktreesDirs } from "../worktree-placement.js";
|
|
15
16
|
import { bashReferencesProjectRootOutsideWorktree } from "../worktree-shell-guard.js";
|
|
@@ -364,12 +365,63 @@ export function refreshWriteGateStateFromDisk(basePath: string): WriteGateSnapsh
|
|
|
364
365
|
return currentWriteGateSnapshot(basePath);
|
|
365
366
|
}
|
|
366
367
|
|
|
368
|
+
const WRITE_GATE_LOCK_NAME = "write-gate.lock";
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Test-only seam: fires once inside the held cross-process lock (after acquire,
|
|
372
|
+
* before the read-merge-write body) with the resolved lock root. Lets a
|
|
373
|
+
* regression test observe that a concurrent process is genuinely locked out of
|
|
374
|
+
* the critical section. Production leaves it null. Follows the repo's
|
|
375
|
+
* `_setGhAvailableForTest` naming convention.
|
|
376
|
+
*/
|
|
377
|
+
let interleaveHookForTest: ((lockRoot: string) => void) | null = null;
|
|
378
|
+
export function _setWriteGateInterleaveHookForTest(fn: ((lockRoot: string) => void) | null): void {
|
|
379
|
+
interleaveHookForTest = fn;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Serialize the read-merge-write critical section across the two processes
|
|
384
|
+
* that share the snapshot file (extension host + workflow MCP child). Atomic
|
|
385
|
+
* rename prevents torn files but not lost updates: without this lock the host
|
|
386
|
+
* can read the snapshot, the child can arm a gate and persist, then the host's
|
|
387
|
+
* later persist overwrites `pendingGateId`/`activeQueuePhase` (last-writer-wins
|
|
388
|
+
* fields) and silently drops the armed HARD-BLOCK gate.
|
|
389
|
+
*
|
|
390
|
+
* Fail-OPEN by contract: if a live peer holds the lock we proceed WITHOUT it —
|
|
391
|
+
* exactly the racy-but-functional behavior that shipped before this lock — and
|
|
392
|
+
* log once. The lock shrinks the race window to ~zero; it must never block,
|
|
393
|
+
* throw, or refuse a gate mutation. The lock is skipped entirely when snapshot
|
|
394
|
+
* persistence is off (no disk file, no cross-process seam).
|
|
395
|
+
*/
|
|
396
|
+
function withWriteGateLock<T>(basePath: string, fn: () => T): T {
|
|
397
|
+
if (!shouldPersistWriteGateSnapshot()) return fn();
|
|
398
|
+
const lockRoot = resolveWriteGateSnapshotRoot(basePath);
|
|
399
|
+
// Materialize `.gsd/` (including a dangling external-state symlink target)
|
|
400
|
+
// before locking. acquireSyncLock's own mkdir does NOT follow a symlink to
|
|
401
|
+
// create its target, so without this the O_EXCL open lands on a missing
|
|
402
|
+
// parent and the lock silently fails open — leaving the seam unserialized
|
|
403
|
+
// for exactly the external-state projects that need it. This is the same
|
|
404
|
+
// directory the persist path ensures anyway.
|
|
405
|
+
try { ensureWriteGateSnapshotDirectory(basePath); } catch { /* best-effort; acquire fails-open below */ }
|
|
406
|
+
const { acquired } = acquireSyncLock(lockRoot, 0, WRITE_GATE_LOCK_NAME);
|
|
407
|
+
if (!acquired) {
|
|
408
|
+
logWarning("intercept", "write-gate: proceeding without cross-process lock (held by live peer)", { lockRoot });
|
|
409
|
+
return fn();
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
interleaveHookForTest?.(lockRoot);
|
|
413
|
+
return fn();
|
|
414
|
+
} finally {
|
|
415
|
+
releaseSyncLock(lockRoot, WRITE_GATE_LOCK_NAME);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
367
419
|
/**
|
|
368
420
|
* Read-modify-write primitive for gate mutations. Reconciles the disk
|
|
369
421
|
* snapshot into memory (union merge), applies the mutation on top, then
|
|
370
|
-
* persists
|
|
371
|
-
*
|
|
372
|
-
*
|
|
422
|
+
* persists — all under the cross-process lock (withWriteGateLock). The whole
|
|
423
|
+
* sequence is synchronous, so the reconcile read doubles as the pre-persist
|
|
424
|
+
* merge of concurrent writes; there is no version field.
|
|
373
425
|
*
|
|
374
426
|
* The mutate callback sees the already-reconciled state, so policy checks
|
|
375
427
|
* (e.g. host setPending's verified-on-disk-wins guard) can live inside it
|
|
@@ -385,21 +437,23 @@ function mutateWriteGateState(
|
|
|
385
437
|
opts?: { writer?: WriteGateWriter; reconcile?: boolean },
|
|
386
438
|
): boolean {
|
|
387
439
|
const state = getWriteGateState(basePath);
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
440
|
+
return withWriteGateLock(basePath, () => {
|
|
441
|
+
if (shouldPersistWriteGateSnapshot() && (opts?.reconcile ?? true)) {
|
|
442
|
+
const disk = readDiskSnapshot(basePath);
|
|
443
|
+
if (disk) {
|
|
444
|
+
mergeSnapshotIntoState(state, disk);
|
|
445
|
+
} else {
|
|
446
|
+
// Missing OR unparseable on disk: treat as a full reset. Keeping
|
|
447
|
+
// stale in-memory state across a corrupt snapshot would persist it
|
|
448
|
+
// back on this very mutation and defeat the documented
|
|
449
|
+
// "delete the file to clear the HARD BLOCK gate" escape hatch.
|
|
450
|
+
replaceStateFromSnapshot(state, EMPTY_SNAPSHOT);
|
|
451
|
+
}
|
|
398
452
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
453
|
+
if (mutate(state) === false) return false;
|
|
454
|
+
persistWriteGateSnapshot(basePath, opts?.writer ?? defaultWriteGateWriter());
|
|
455
|
+
return true;
|
|
456
|
+
});
|
|
403
457
|
}
|
|
404
458
|
|
|
405
459
|
export function isDepthVerified(basePath: string = process.cwd()): boolean {
|
|
@@ -643,13 +697,15 @@ export const childWriteGateAdapter: WriteGateStateAdapter = {
|
|
|
643
697
|
|
|
644
698
|
function childMutate(basePath: string, mutate: (state: InMemoryWriteGateState) => void): void {
|
|
645
699
|
const state = getWriteGateState(basePath);
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
700
|
+
withWriteGateLock(basePath, () => {
|
|
701
|
+
if (shouldPersistWriteGateSnapshot()) {
|
|
702
|
+
// Always-fresh: disk is the only truth for the child; discard any
|
|
703
|
+
// cross-turn in-memory residue before mutating.
|
|
704
|
+
replaceStateFromSnapshot(state, readDiskSnapshot(basePath) ?? EMPTY_SNAPSHOT);
|
|
705
|
+
}
|
|
706
|
+
mutate(state);
|
|
707
|
+
persistWriteGateSnapshot(basePath, "child");
|
|
708
|
+
});
|
|
653
709
|
}
|
|
654
710
|
|
|
655
711
|
/**
|
|
@@ -96,22 +96,29 @@ export function notifyDiscussNeedsInteractiveMenu(
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Hub picker for /gsd queue (reorder vs add) is unavailable.
|
|
101
|
+
*
|
|
102
|
+
* Unlike the other picker-guidance notices, /gsd queue does NOT dead-end here:
|
|
103
|
+
* the caller falls through to the add-work flow, which runs headlessly. So this
|
|
104
|
+
* notice must avoid the "did not start:" picker-failure phrasing — the headless
|
|
105
|
+
* host classifies that as a blocked dead-end (see stop-notice.ts / #1294) and
|
|
106
|
+
* would exit 10 before the add-work run starts.
|
|
107
|
+
*/
|
|
100
108
|
export function notifyQueueHubNeedsInteractiveMenu(
|
|
101
109
|
ctx: ExtensionCommandContext,
|
|
102
110
|
reason: string,
|
|
103
111
|
): void {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
});
|
|
112
|
+
ctx.ui.notify(
|
|
113
|
+
[
|
|
114
|
+
`/gsd queue reorder menu needs an interactive session (${reason}).`,
|
|
115
|
+
"Continuing headless with the add-work flow.",
|
|
116
|
+
"",
|
|
117
|
+
" • /gsd queue — run from the GSD TUI to reorder pending milestones",
|
|
118
|
+
" • /gsd status — see milestone order and phase",
|
|
119
|
+
].join("\n"),
|
|
120
|
+
"warning",
|
|
121
|
+
);
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
/** /gsd, /gsd new-milestone, /gsd new-project wizard menus. */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
-
import { dirname, join } from "node:path";
|
|
10
|
+
import { dirname, join, isAbsolute, normalize } from "node:path";
|
|
11
11
|
|
|
12
12
|
/** Current marker schema version. Bump on breaking format changes + migrate. */
|
|
13
13
|
export const COMPAT_MARKER_SCHEMA = 2;
|
|
@@ -34,8 +34,10 @@ export interface PlanningMarker {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Per-file projection entry. `sha` is a normalized-content SHA-256; `entities`
|
|
37
|
-
* is the list of DB entity ids (milestone/slice/task) that the file projects
|
|
38
|
-
*
|
|
37
|
+
* is the list of DB entity ids (milestone/slice/task) that the file projects.
|
|
38
|
+
* External-edit repair derives milestone ids from this list so markdown status
|
|
39
|
+
* authority is limited to the drifted projection's milestone scope while the
|
|
40
|
+
* importer still walks the whole tree.
|
|
39
41
|
*/
|
|
40
42
|
export interface ProjectionEntry {
|
|
41
43
|
sha: string;
|
|
@@ -220,9 +222,24 @@ function isValidProjectionEntry(x: unknown): x is ProjectionEntry {
|
|
|
220
222
|
return true;
|
|
221
223
|
}
|
|
222
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Projection-map keys are repo-relative paths under .gsd/ or .planning/.
|
|
227
|
+
* The marker is repo-controlled content, so a key must never escape its
|
|
228
|
+
* root: reject absolute paths, drive letters, backslashes, and any
|
|
229
|
+
* normalized form that starts with "..". Mirrors the write-side guard in
|
|
230
|
+
* db-writer.ts.
|
|
231
|
+
*/
|
|
232
|
+
function isSafeProjectionKey(key: string): boolean {
|
|
233
|
+
if (key.length === 0 || key.includes("\\") || key.includes("\0")) return false;
|
|
234
|
+
if (isAbsolute(key) || /^[A-Za-z]:/.test(key)) return false;
|
|
235
|
+
const norm = normalize(key);
|
|
236
|
+
return norm !== ".." && !norm.startsWith("../") && !isAbsolute(norm);
|
|
237
|
+
}
|
|
238
|
+
|
|
223
239
|
function isValidProjectionMap(x: unknown): boolean {
|
|
224
240
|
if (typeof x !== "object" || x === null) return false;
|
|
225
|
-
for (const v of Object.
|
|
241
|
+
for (const [k, v] of Object.entries(x as Record<string, unknown>)) {
|
|
242
|
+
if (!isSafeProjectionKey(k)) return false;
|
|
226
243
|
if (!isValidProjectionEntry(v)) return false;
|
|
227
244
|
}
|
|
228
245
|
return true;
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import {
|
|
17
17
|
_getAdapter,
|
|
18
|
+
immediateTransaction,
|
|
18
19
|
isDbAvailable,
|
|
19
20
|
transaction,
|
|
20
21
|
} from "../gsd-db.js";
|
|
@@ -75,7 +76,12 @@ export function claimNextCommand(workerId: string): CommandQueueRow | null {
|
|
|
75
76
|
const now = new Date().toISOString();
|
|
76
77
|
const db = _getAdapter()!;
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
// BEGIN IMMEDIATE: this is a read-then-write claim. Under WAL, a deferred
|
|
80
|
+
// transaction that reads first and then upgrades to a writer can fail with
|
|
81
|
+
// SQLITE_BUSY_SNAPSHOT (not retried by busy_timeout) when two workers race;
|
|
82
|
+
// taking the write lock up front serializes claimants so the loser waits
|
|
83
|
+
// and then sees the row already claimed (changes !== 1 → null).
|
|
84
|
+
return immediateTransaction((): CommandQueueRow | null => {
|
|
79
85
|
// Find the oldest unclaimed command targeted at this worker OR
|
|
80
86
|
// broadcast. The partial index covers both via NULL-in-B-tree.
|
|
81
87
|
const row = db.prepare(
|
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
applyMigrationV27ArtifactHash,
|
|
47
47
|
applyMigrationV28MemoryLastHitAt,
|
|
48
48
|
applyMigrationV29RepositoryTargets,
|
|
49
|
+
applyMigrationV30ReworkBriefs,
|
|
49
50
|
} from "../db-migration-steps.js";
|
|
50
51
|
import {
|
|
51
52
|
isMemoriesFtsAvailableSchema,
|
|
@@ -93,7 +94,7 @@ const providerLoader = createSqliteProviderLoader({
|
|
|
93
94
|
nodeVersion: process.versions.node,
|
|
94
95
|
writeStderr: (message: string) => process.stderr.write(message),
|
|
95
96
|
});
|
|
96
|
-
export const SCHEMA_VERSION =
|
|
97
|
+
export const SCHEMA_VERSION = 30;
|
|
97
98
|
function initSchema(db: DbAdapter, fileBacked: boolean, dbPath: string | null): void {
|
|
98
99
|
const conservativeFilePragmas = fileBacked && _isLikelyWslDrvFsPathForTest(dbPath);
|
|
99
100
|
if (fileBacked) db.exec(conservativeFilePragmas ? "PRAGMA journal_mode=DELETE" : "PRAGMA journal_mode=WAL");
|
|
@@ -114,21 +115,39 @@ function initSchema(db: DbAdapter, fileBacked: boolean, dbPath: string | null):
|
|
|
114
115
|
|
|
115
116
|
const existing = db.prepare("SELECT count(*) as cnt FROM schema_version").get();
|
|
116
117
|
if (existing && (existing["cnt"] as number) === 0) {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
// An empty schema_version table usually means a fresh install, but it can
|
|
119
|
+
// also be a legacy/truncated DB that already holds user data. Stamping
|
|
120
|
+
// that DB SCHEMA_VERSION without running migrations would mis-mark it as
|
|
121
|
+
// fully migrated and break at first query. Probe before stamping.
|
|
122
|
+
const hasData = ["milestones", "decisions", "memories"].some((t) => {
|
|
123
|
+
try {
|
|
124
|
+
const r = db.prepare(`SELECT count(*) as cnt FROM ${t}`).get();
|
|
125
|
+
return ((r?.["cnt"] as number) ?? 0) > 0;
|
|
126
|
+
} catch { /* table absent on a truly fresh DB — treat as no data */ return false; }
|
|
127
|
+
});
|
|
128
|
+
if (hasData) {
|
|
129
|
+
// Legacy DB with data but no version row: record the baseline so
|
|
130
|
+
// migrateSchema runs the full chain instead of stamping the current version.
|
|
131
|
+
recordSchemaVersion(db, 1);
|
|
132
|
+
} else {
|
|
133
|
+
createCoordinationTablesV24(db);
|
|
134
|
+
createRuntimeKvTableV25(db);
|
|
135
|
+
|
|
136
|
+
// Fresh install — all tables are created above with the full current schema,
|
|
137
|
+
// so it is safe to create all migration-specific indexes here. For existing
|
|
138
|
+
// databases these indexes are created inside the individual migration guards
|
|
139
|
+
// in migrateSchema() after the corresponding columns have been added.
|
|
140
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_escalation_pending ON tasks(milestone_id, slice_id, escalation_pending)");
|
|
141
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
|
|
142
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
|
|
143
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
|
|
144
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
|
|
145
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
|
|
146
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_rework_briefs_task ON rework_briefs(milestone_id, slice_id, task_id)");
|
|
147
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_rework_findings_status ON rework_brief_findings(brief_id, severity, status)");
|
|
148
|
+
|
|
149
|
+
recordSchemaVersion(db, SCHEMA_VERSION);
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
db.exec("COMMIT");
|
|
@@ -183,9 +202,19 @@ function copyQualityGateRowsToRepairedTable(db: DbAdapter): void {
|
|
|
183
202
|
`);
|
|
184
203
|
}
|
|
185
204
|
|
|
205
|
+
let _migrationFaultForTest = false;
|
|
206
|
+
/** Test-only: force migrateSchema to throw after applying its steps but before COMMIT. */
|
|
207
|
+
export function _setMigrationFaultForTest(v: boolean): void { _migrationFaultForTest = v; }
|
|
208
|
+
|
|
186
209
|
function migrateSchema(db: DbAdapter, dbPath: string | null): void {
|
|
187
210
|
const currentVersion = getCurrentSchemaVersion(db);
|
|
188
|
-
if (currentVersion
|
|
211
|
+
if (currentVersion > SCHEMA_VERSION) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
`gsd.db schema is v${currentVersion}, newer than the v${SCHEMA_VERSION} this gsd-pi supports. ` +
|
|
214
|
+
`Update gsd-pi (npm i -g @opengsd/gsd-pi) before opening this project.`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (currentVersion === SCHEMA_VERSION) return;
|
|
189
218
|
|
|
190
219
|
backupDatabaseBeforeMigration(db, dbPath, currentVersion, {
|
|
191
220
|
existsSync,
|
|
@@ -351,6 +380,13 @@ function migrateSchema(db: DbAdapter, dbPath: string | null): void {
|
|
|
351
380
|
recordSchemaVersion(db, 29);
|
|
352
381
|
}
|
|
353
382
|
|
|
383
|
+
if (currentVersion < 30) {
|
|
384
|
+
applyMigrationV30ReworkBriefs(db);
|
|
385
|
+
recordSchemaVersion(db, 30);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (_migrationFaultForTest) throw new Error("migration fault injected for test");
|
|
389
|
+
|
|
354
390
|
db.exec("COMMIT");
|
|
355
391
|
} catch (err) {
|
|
356
392
|
db.exec("ROLLBACK");
|
|
@@ -211,7 +211,11 @@ export function skipSliceCascade(milestoneId: string, sliceId: string): SkipSlic
|
|
|
211
211
|
transaction(() => {
|
|
212
212
|
const slice = getSlice(milestoneId, sliceId);
|
|
213
213
|
if (!slice) { outcome = { ok: false, reason: "slice-not-found" }; return; }
|
|
214
|
-
|
|
214
|
+
// Reject any closed slice except "skipped" (which falls through to the
|
|
215
|
+
// wasAlreadySkipped no-op). isClosedStatus covers the "closed"/"done"
|
|
216
|
+
// aliases too — hand-picking literals here nulls a completed slice's
|
|
217
|
+
// completed_at on re-skip.
|
|
218
|
+
if (isClosedStatus(slice.status) && slice.status !== "skipped") {
|
|
215
219
|
outcome = { ok: false, reason: "slice-already-complete" };
|
|
216
220
|
return;
|
|
217
221
|
}
|