@opengsd/gsd-pi 1.8.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 -3
- 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 +5 -5
- 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 +5 -5
- 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 +5 -1
- package/packages/daemon/dist/cloud-config.js.map +1 -1
- package/packages/daemon/dist/cloud-config.test.js +51 -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/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 +3 -3
- 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/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{seHIUVbR1mm7LfG83nWJO → TezjdjSHBVRRr54XjAvte}/_ssgManifest.js +0 -0
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// instruction. Markdown hierarchy import is reserved for operator-controlled
|
|
6
6
|
// migration/recovery commands, not automatic runtime reconciliation.
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
8
|
-
import { getMilestone, isDbAvailable } from "../../gsd-db.js";
|
|
9
|
-
import { findMilestoneIds } from "../../milestone-ids.js";
|
|
8
|
+
import { getAllMilestones, getMilestone, isDbAvailable } from "../../gsd-db.js";
|
|
9
|
+
import { findMilestoneIds, parseMilestoneId } from "../../milestone-ids.js";
|
|
10
10
|
import { resolveMilestoneFile, resolveMilestonePath } from "../../paths.js";
|
|
11
11
|
function milestoneHasContent(basePath, milestoneId) {
|
|
12
12
|
const roadmap = resolveMilestoneFile(basePath, milestoneId, "ROADMAP");
|
|
@@ -16,6 +16,26 @@ function milestoneHasContent(basePath, milestoneId) {
|
|
|
16
16
|
(context !== null && existsSync(context)) ||
|
|
17
17
|
(summary !== null && existsSync(summary)));
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* A directory extracted to a bare `M{NNN}` id is not unregistered when the
|
|
21
|
+
* milestone is actually registered under a `unique_milestone_ids` suffixed id
|
|
22
|
+
* (`M{NNN}-<suffix>`) for the same sequence number. The flat-phase extractor in
|
|
23
|
+
* `milestone-ids` cannot recover the suffix from a descriptive slug (e.g.
|
|
24
|
+
* `07-v40fmq-m007-...-footer-system`), so it falls through to the bare `M007`.
|
|
25
|
+
* Probing the DB for a suffixed row on that sequence resolves the directory to
|
|
26
|
+
* its registered identity instead of firing a false-positive drift (issue
|
|
27
|
+
* #1281).
|
|
28
|
+
*/
|
|
29
|
+
function hasRegisteredSuffixedVariant(milestoneId) {
|
|
30
|
+
const { suffix, num } = parseMilestoneId(milestoneId);
|
|
31
|
+
// Only bare, well-formed `M{NNN}` ids can be ambiguous with a suffixed row.
|
|
32
|
+
if (suffix || num === 0)
|
|
33
|
+
return false;
|
|
34
|
+
return getAllMilestones().some((m) => {
|
|
35
|
+
const parsed = parseMilestoneId(m.id);
|
|
36
|
+
return parsed.num === num && parsed.suffix !== undefined;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
19
39
|
export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
20
40
|
if (!isDbAvailable())
|
|
21
41
|
return [];
|
|
@@ -23,6 +43,8 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
|
23
43
|
for (const milestoneId of findMilestoneIds(ctx.basePath)) {
|
|
24
44
|
if (getMilestone(milestoneId))
|
|
25
45
|
continue;
|
|
46
|
+
if (hasRegisteredSuffixedVariant(milestoneId))
|
|
47
|
+
continue;
|
|
26
48
|
if (!milestoneHasContent(ctx.basePath, milestoneId))
|
|
27
49
|
continue;
|
|
28
50
|
drifts.push({ kind: "unregistered-milestone", milestoneId });
|
|
@@ -30,29 +52,47 @@ export function detectUnregisteredMilestoneDrift(_state, ctx) {
|
|
|
30
52
|
return drifts;
|
|
31
53
|
}
|
|
32
54
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* directory — not a full DB reimport. `/gsd recover --confirm` is a destructive
|
|
41
|
-
* clear-and-reimport of the entire DB and is offered only as a last resort, so
|
|
42
|
-
* users do not reach for it expecting a targeted repair (see issue #826).
|
|
55
|
+
* The recovery hint deliberately leads with the *targeted*, non-destructive
|
|
56
|
+
* options. The common cause of this drift is a directory left under an old ID
|
|
57
|
+
* after a `unique_milestone_ids` rename, where the right fix is to rename (move)
|
|
58
|
+
* the directory — not a full DB reimport. `/gsd recover --confirm` is a
|
|
59
|
+
* destructive clear-and-reimport of the entire DB and is offered only as a last
|
|
60
|
+
* resort, so users do not reach for it expecting a targeted repair (see issue
|
|
61
|
+
* #826).
|
|
43
62
|
*/
|
|
44
|
-
|
|
63
|
+
function unregisteredMilestoneGuidance(record, ctx) {
|
|
45
64
|
const dir = resolveMilestonePath(ctx.basePath, record.milestoneId);
|
|
46
65
|
const dirHint = dir ?? `the .gsd directory for ${record.milestoneId}`;
|
|
47
|
-
|
|
66
|
+
return (`Milestone ${record.milestoneId} exists only as markdown projection ` +
|
|
48
67
|
"(on-disk ROADMAP/CONTEXT/SUMMARY with no authoritative DB row). " +
|
|
49
68
|
"Runtime reconciliation will not import markdown into the DB. Choose one:\n" +
|
|
50
69
|
` • Rename: if this directory is the same milestone under an old ID (e.g. a unique_milestone_ids rename), move \`${dirHint}\` to the current ID's directory and re-run.\n` +
|
|
51
70
|
` • Discard: if this milestone is no longer relevant, delete \`${dirHint}\` and re-run.\n` +
|
|
52
71
|
" • Last resort: `/gsd recover --confirm` performs a destructive full DB clear-and-reimport — it does NOT do a targeted import and can replace or duplicate existing DB milestones.");
|
|
53
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Terminal blocker for an unregistered milestone. The project-root DB is
|
|
75
|
+
* authoritative at runtime; markdown-only milestones must be reconciled through
|
|
76
|
+
* an explicit, operator-controlled action so operators opt into changing
|
|
77
|
+
* canonical state. Exposing this as a `blocker` (matching the `artifact-db`
|
|
78
|
+
* convention) surfaces the drift as a pause-with-hint that gates dispatch,
|
|
79
|
+
* instead of a guaranteed repair throw that escalates auto-mode health to red
|
|
80
|
+
* (see issue #1281).
|
|
81
|
+
*/
|
|
82
|
+
export function describeUnregisteredMilestoneBlocker(record, ctx) {
|
|
83
|
+
return unregisteredMilestoneGuidance(record, ctx);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Repair intentionally fails closed. Retained as a defensive fallback for the
|
|
87
|
+
* reconciliation engine; in practice `blocker` short-circuits this drift into a
|
|
88
|
+
* non-fatal pause before repair is ever attempted.
|
|
89
|
+
*/
|
|
90
|
+
export function repairUnregisteredMilestone(record, ctx) {
|
|
91
|
+
throw new Error(unregisteredMilestoneGuidance(record, ctx));
|
|
92
|
+
}
|
|
54
93
|
export const unregisteredMilestoneHandler = {
|
|
55
94
|
kind: "unregistered-milestone",
|
|
56
95
|
detect: detectUnregisteredMilestoneDrift,
|
|
96
|
+
blocker: describeUnregisteredMilestoneBlocker,
|
|
57
97
|
repair: repairUnregisteredMilestone,
|
|
58
98
|
};
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
// 2. Flag-OFF downgrade: when progressive_planning is off, dispatch routes
|
|
8
8
|
// sketch slices to plan-slice, which writes PLAN.md but leaves
|
|
9
9
|
// is_sketch=1 — the next reconciliation pass clears it.
|
|
10
|
-
import { existsSync } from "node:fs";
|
|
10
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
11
11
|
import { getSketchedSliceIds, isDbAvailable, setSliceSketchFlag, } from "../../gsd-db.js";
|
|
12
|
+
import { parsePlan } from "../../parsers-legacy.js";
|
|
12
13
|
import { resolveSliceFile } from "../../paths.js";
|
|
13
14
|
export function detectStaleSketchFlags(state, ctx) {
|
|
14
15
|
if (!isDbAvailable())
|
|
@@ -18,12 +19,54 @@ export function detectStaleSketchFlags(state, ctx) {
|
|
|
18
19
|
return [];
|
|
19
20
|
const sliceIds = getSketchedSliceIds(mid);
|
|
20
21
|
return sliceIds
|
|
21
|
-
.filter((sid) =>
|
|
22
|
-
const planPath = resolveSliceFile(ctx.basePath, mid, sid, "PLAN");
|
|
23
|
-
return planPath !== null && existsSync(planPath);
|
|
24
|
-
})
|
|
22
|
+
.filter((sid) => sketchIsPlanned(ctx.basePath, mid, sid))
|
|
25
23
|
.map((sid) => ({ kind: "stale-sketch-flag", mid, sid }));
|
|
26
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* True when a task title is a synthetic placeholder emitted by a projection
|
|
27
|
+
* round-trip rather than a real, refined task. `migrate/transformer.buildTaskTitle`
|
|
28
|
+
* produces two shapes when a plan was never decomposed:
|
|
29
|
+
* - `Plan NN` (fallback when phase/plan frontmatter is absent)
|
|
30
|
+
* - `${phase} ${plan}` (e.g. `00 01`, `00 03b`, `29-auth-system 01`)
|
|
31
|
+
* Neither carries genuine planning intent, so both must be treated as stubs.
|
|
32
|
+
*/
|
|
33
|
+
function isPlaceholderTaskTitle(title) {
|
|
34
|
+
const t = title.trim();
|
|
35
|
+
if (/^Plan\s+\d+[a-z]*$/i.test(t))
|
|
36
|
+
return true;
|
|
37
|
+
// buildTaskTitle returns `${phase} ${plan}` when frontmatter has both fields.
|
|
38
|
+
// Phase slugs are digit-led (e.g. `00`, `29-auth-system`); require that so
|
|
39
|
+
// legitimate titles like `Step 1` are not misclassified as stubs.
|
|
40
|
+
return /^\d[\w-]*\s+\d+[a-z]*$/i.test(t);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* A sketch slice counts as "planned" (so its is_sketch flag may be cleared)
|
|
44
|
+
* only when it has a *real* plan on disk — not merely any PLAN file.
|
|
45
|
+
*
|
|
46
|
+
* File existence alone (#1287) is too weak: a stub/placeholder PLAN, a
|
|
47
|
+
* crash-leftover, or a projection round-trip that emits synthetic placeholder
|
|
48
|
+
* task titles (migrate/transformer.buildTaskTitle) all satisfy existsSync yet
|
|
49
|
+
* were never actually refined. Clearing the flag for one strips the `refining`
|
|
50
|
+
* guard in phase derivation and lets a phantom task drive dispatch.
|
|
51
|
+
*
|
|
52
|
+
* A legitimate plan-slice always decomposes into >= 1 genuine task, so require
|
|
53
|
+
* at least one non-placeholder task. This is strictly stricter than the old
|
|
54
|
+
* existence check — the documented crash-recovery scenarios (a real plan-slice
|
|
55
|
+
* that wrote its tasks) still clear, a bare stub no longer does.
|
|
56
|
+
*/
|
|
57
|
+
function sketchIsPlanned(basePath, mid, sid) {
|
|
58
|
+
const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
|
|
59
|
+
if (planPath === null || !existsSync(planPath))
|
|
60
|
+
return false;
|
|
61
|
+
try {
|
|
62
|
+
const plan = parsePlan(readFileSync(planPath, "utf-8"));
|
|
63
|
+
return plan.tasks.some((t) => !isPlaceholderTaskTitle(t.title));
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// A PLAN we cannot parse is not a trustworthy "planning done" signal.
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
27
70
|
export function repairStaleSketchFlag(record) {
|
|
28
71
|
setSliceSketchFlag(record.mid, record.sid, false);
|
|
29
72
|
}
|
|
@@ -50,8 +50,22 @@ export function isTerminalNotice(message) {
|
|
|
50
50
|
export function isNonBlockingPauseNotice(message) {
|
|
51
51
|
return message.includes("idempotent advance: unit already active");
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* A picker / next-action menu that could not render in a non-interactive
|
|
55
|
+
* (headless / RPC) session. Both wordings originate from the menu-unavailable
|
|
56
|
+
* helpers (`notifyCommandMenuUnavailable` and `notifyPickerCommandNeedsInteractiveMenu`
|
|
57
|
+
* in next-action-ui.ts / command-feedback.ts). Headless `auto`/`next` cannot
|
|
58
|
+
* answer such a menu, so the run has dead-ended and needs operator intervention.
|
|
59
|
+
* Classify it as blocked so the headless host exits 10 instead of idling
|
|
60
|
+
* forever waiting for a completion signal that never comes. (#1294)
|
|
61
|
+
*/
|
|
62
|
+
export function isInteractiveMenuUnavailableNotice(message) {
|
|
63
|
+
return (message.includes("menu could not be shown in this session") ||
|
|
64
|
+
message.includes("did not start:"));
|
|
65
|
+
}
|
|
53
66
|
export function isBlockedNoticeMessage(message) {
|
|
54
67
|
return (message.includes("blocked:") ||
|
|
55
68
|
(isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
|
|
56
|
-
isManualResolutionNotice(message)
|
|
69
|
+
isManualResolutionNotice(message) ||
|
|
70
|
+
isInteractiveMenuUnavailableNotice(message));
|
|
57
71
|
}
|
|
@@ -6,8 +6,9 @@ import { closeSync, existsSync, mkdirSync, openSync, readFileSync, statSync, unl
|
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
const STALE_THRESHOLD_MS = 60_000; // 60 seconds
|
|
8
8
|
const DEFAULT_TIMEOUT_MS = 0; // fail fast; sync waits block the JS event loop
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const DEFAULT_LOCK_NAME = "sync.lock";
|
|
10
|
+
function lockFilePath(basePath, lockName = DEFAULT_LOCK_NAME) {
|
|
11
|
+
return join(basePath, ".gsd", lockName);
|
|
11
12
|
}
|
|
12
13
|
/** True if the given PID is alive in the current process namespace. */
|
|
13
14
|
function isPidAlive(pid) {
|
|
@@ -71,8 +72,8 @@ function tryCreateLockFile(lp, payload) {
|
|
|
71
72
|
* I/O, and UI work on Node's single JS thread. The timeout argument remains
|
|
72
73
|
* accepted for compatibility but is intentionally not used for sync waiting.
|
|
73
74
|
*/
|
|
74
|
-
export function acquireSyncLock(basePath, _timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
75
|
-
const lp = lockFilePath(basePath);
|
|
75
|
+
export function acquireSyncLock(basePath, _timeoutMs = DEFAULT_TIMEOUT_MS, lockName = DEFAULT_LOCK_NAME) {
|
|
76
|
+
const lp = lockFilePath(basePath, lockName);
|
|
76
77
|
const lockData = JSON.stringify({ pid: process.pid, acquired_at: new Date().toISOString() }, null, 2);
|
|
77
78
|
while (true) {
|
|
78
79
|
// First try the fast path: atomic create. No check-then-write race.
|
|
@@ -82,7 +83,12 @@ export function acquireSyncLock(basePath, _timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
85
|
catch {
|
|
85
|
-
|
|
86
|
+
// tryCreateLockFile only throws for non-EEXIST errors — a persistently
|
|
87
|
+
// uncreatable lock path (dangling-symlink parent, ENOTDIR, read-only FS).
|
|
88
|
+
// Retrying would spin the loop forever with no progress condition,
|
|
89
|
+
// blocking the JS event loop. Fail open like a contended lock so callers
|
|
90
|
+
// proceed (racy but functional) instead of hanging.
|
|
91
|
+
return { acquired: false };
|
|
86
92
|
}
|
|
87
93
|
// File exists. Decide whether to steal (stale + owner dead) or skip.
|
|
88
94
|
let canSteal = false;
|
|
@@ -125,8 +131,8 @@ export function acquireSyncLock(basePath, _timeoutMs = DEFAULT_TIMEOUT_MS) {
|
|
|
125
131
|
/**
|
|
126
132
|
* Release the advisory sync lock. No-op if lock file does not exist.
|
|
127
133
|
*/
|
|
128
|
-
export function releaseSyncLock(basePath) {
|
|
129
|
-
const lp = lockFilePath(basePath);
|
|
134
|
+
export function releaseSyncLock(basePath, lockName = DEFAULT_LOCK_NAME) {
|
|
135
|
+
const lp = lockFilePath(basePath, lockName);
|
|
130
136
|
try {
|
|
131
137
|
if (existsSync(lp)) {
|
|
132
138
|
unlinkSync(lp);
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import { existsSync, unlinkSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { isClosedStatus } from "../status-guards.js";
|
|
15
|
-
import { transaction, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, getMilestone, getSlice, getTask, updateTaskStatus, deleteVerificationEvidence, saveGateResult, getPendingGatesForTurn, } from "../gsd-db.js";
|
|
15
|
+
import { transaction, insertMilestone, insertSlice, insertTask, insertVerificationEvidence, getMilestone, getSlice, getTask, updateTaskStatus, deleteVerificationEvidence, saveGateResult, getPendingGatesForTurn, getUnresolvedBlockingReworkFindingsForTask, getBlockingReworkFindingsForTask, applyReworkResolutions, } from "../gsd-db.js";
|
|
16
16
|
import { getWorkflowDatabasePath, ensureWorkflowDbAtPath } from "../db-workspace.js";
|
|
17
17
|
import { getGatesForTurn } from "../gate-registry.js";
|
|
18
18
|
import { gsdProjectionRoot, clearPathCache, resolveMilestonePath, resolveSlicePath } from "../paths.js";
|
|
@@ -107,6 +107,44 @@ export function normalizeListParam(value) {
|
|
|
107
107
|
* Build a TaskRow-shaped object from CompleteTaskParams so the unified
|
|
108
108
|
* renderSummaryContent() can be used at completion time (#2720).
|
|
109
109
|
*/
|
|
110
|
+
function normalizeReworkResolution(params) {
|
|
111
|
+
return (params.reworkResolution ?? []).map((resolution) => ({
|
|
112
|
+
milestoneId: params.milestoneId,
|
|
113
|
+
sliceId: params.sliceId,
|
|
114
|
+
taskId: params.taskId,
|
|
115
|
+
findingId: resolution.findingId,
|
|
116
|
+
status: resolution.status,
|
|
117
|
+
evidence: resolution.evidence,
|
|
118
|
+
decisionRef: resolution.decisionRef,
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
function unresolvedReworkError(missingFindingIds) {
|
|
122
|
+
const plural = missingFindingIds.length === 1 ? "finding" : "findings";
|
|
123
|
+
return `unresolved blocking rework ${plural}: ${missingFindingIds.join(", ")} — provide reworkResolution entries with status resolved and evidence, or status deferred-with-override with evidence and decisionRef, before completing the task`;
|
|
124
|
+
}
|
|
125
|
+
function satisfiesBlockingReworkFinding(resolution) {
|
|
126
|
+
if (resolution.evidence.trim().length === 0)
|
|
127
|
+
return false;
|
|
128
|
+
if (resolution.status === "resolved")
|
|
129
|
+
return true;
|
|
130
|
+
return (resolution.decisionRef ?? "").trim().length > 0;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Restore rework findings to their pre-completion state.
|
|
134
|
+
*
|
|
135
|
+
* The completion transaction flips blocking findings to resolved/
|
|
136
|
+
* deferred-with-override via applyReworkResolutions. When a later projection
|
|
137
|
+
* or escalation write fails and we compensate by reverting the task to
|
|
138
|
+
* `pending`, we must also revert those findings. Otherwise a retry sees no
|
|
139
|
+
* unresolved blocking findings (getUnresolvedBlockingReworkFindingsForTask
|
|
140
|
+
* only returns `pending` rows) and completes the task with the blocking gate
|
|
141
|
+
* silently skipped.
|
|
142
|
+
*/
|
|
143
|
+
function revertAppliedReworkResolutions(snapshot) {
|
|
144
|
+
if (snapshot.length === 0)
|
|
145
|
+
return;
|
|
146
|
+
applyReworkResolutions(snapshot);
|
|
147
|
+
}
|
|
110
148
|
function paramsToTaskRow(params, completedAt) {
|
|
111
149
|
return {
|
|
112
150
|
milestone_id: params.milestoneId,
|
|
@@ -182,6 +220,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
182
220
|
let guardError = null;
|
|
183
221
|
let summaryMd = "";
|
|
184
222
|
let repairTaskSummaryRow = null;
|
|
223
|
+
let appliedReworkSnapshot = [];
|
|
185
224
|
const rollbackDbPath = getWorkflowDatabasePath();
|
|
186
225
|
// ── ADR-011 Phase 2: validate escalation payload BEFORE any side effects ─
|
|
187
226
|
// Building the artifact runs the full shape validation (2-4 options, unique
|
|
@@ -192,6 +231,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
192
231
|
// no escalation recorded, and the loop would silently advance past it.
|
|
193
232
|
// The filesystem write happens later (after side effects) because that's
|
|
194
233
|
// the cheapest ordering and validation is where 99% of failures live.
|
|
234
|
+
const reworkResolutions = normalizeReworkResolution(params);
|
|
195
235
|
let validatedEscalationArtifact = null;
|
|
196
236
|
let escalationWriteEnabled = false;
|
|
197
237
|
if (params.escalation) {
|
|
@@ -231,6 +271,17 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
231
271
|
return;
|
|
232
272
|
}
|
|
233
273
|
const existingTask = getTask(params.milestoneId, params.sliceId, params.taskId);
|
|
274
|
+
const unresolvedRework = getUnresolvedBlockingReworkFindingsForTask(params.milestoneId, params.sliceId, params.taskId);
|
|
275
|
+
const resolvedFindingIds = new Set(reworkResolutions
|
|
276
|
+
.filter(satisfiesBlockingReworkFinding)
|
|
277
|
+
.map((resolution) => resolution.findingId));
|
|
278
|
+
const missingFindingIds = unresolvedRework
|
|
279
|
+
.filter((finding) => !resolvedFindingIds.has(finding.finding_id))
|
|
280
|
+
.map((finding) => finding.finding_id);
|
|
281
|
+
if (missingFindingIds.length > 0) {
|
|
282
|
+
guardError = unresolvedReworkError(missingFindingIds);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
234
285
|
if (existingTask && isClosedStatus(existingTask.status)) {
|
|
235
286
|
// Stale-turn path: a timed-out turn that was superseded by recovery
|
|
236
287
|
// can still reach this code when its LLM call eventually returns and
|
|
@@ -278,6 +329,33 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
278
329
|
keyDecisions: params.keyDecisions ?? [],
|
|
279
330
|
fullSummaryMd: summaryMd,
|
|
280
331
|
});
|
|
332
|
+
// Only persist resolutions that actually satisfy the evidence
|
|
333
|
+
// requirement. The guard above admits a finding as long as ONE satisfying
|
|
334
|
+
// entry exists, but applyReworkResolutions writes by findingId and lets the
|
|
335
|
+
// last entry win. Persisting every entry would let a later non-satisfying
|
|
336
|
+
// duplicate (empty evidence, or deferred-with-override without decisionRef)
|
|
337
|
+
// overwrite a valid resolution and leave the finding non-pending without
|
|
338
|
+
// acceptable evidence. Filtering with the same predicate the guard uses
|
|
339
|
+
// keeps the applied set and the gate consistent.
|
|
340
|
+
const resolutionsToApply = reworkResolutions.filter(satisfiesBlockingReworkFinding);
|
|
341
|
+
if (resolutionsToApply.length > 0) {
|
|
342
|
+
// Snapshot the pre-resolution state of the findings we're about to
|
|
343
|
+
// change so a compensating rollback can restore them exactly (see
|
|
344
|
+
// revertAppliedReworkResolutions).
|
|
345
|
+
const resolvedFindingIdsForSnapshot = new Set(resolutionsToApply.map((r) => r.findingId));
|
|
346
|
+
appliedReworkSnapshot = getBlockingReworkFindingsForTask(params.milestoneId, params.sliceId, params.taskId)
|
|
347
|
+
.filter((finding) => resolvedFindingIdsForSnapshot.has(finding.finding_id))
|
|
348
|
+
.map((finding) => ({
|
|
349
|
+
milestoneId: params.milestoneId,
|
|
350
|
+
sliceId: params.sliceId,
|
|
351
|
+
taskId: params.taskId,
|
|
352
|
+
findingId: finding.finding_id,
|
|
353
|
+
status: finding.status,
|
|
354
|
+
evidence: finding.evidence,
|
|
355
|
+
decisionRef: finding.decision_ref,
|
|
356
|
+
}));
|
|
357
|
+
applyReworkResolutions(resolutionsToApply);
|
|
358
|
+
}
|
|
281
359
|
for (const evidence of (params.verificationEvidence ?? [])) {
|
|
282
360
|
insertVerificationEvidence({
|
|
283
361
|
taskId: params.taskId,
|
|
@@ -340,6 +418,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
340
418
|
ensureWorkflowDbAtPath(rollbackDbPath);
|
|
341
419
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
342
420
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, "pending");
|
|
421
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
343
422
|
invalidateStateCache();
|
|
344
423
|
rollbackSucceeded = true;
|
|
345
424
|
}
|
|
@@ -430,6 +509,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
430
509
|
try {
|
|
431
510
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
432
511
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
512
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
433
513
|
invalidateStateCache();
|
|
434
514
|
logWarning("tool", `complete-task rolled back DB completion for ${params.milestoneId}/${params.sliceId}/${params.taskId} after escalation write failure; SUMMARY.md left on disk for retry.`);
|
|
435
515
|
}
|
|
@@ -447,6 +527,7 @@ export async function handleCompleteTask(params, basePath) {
|
|
|
447
527
|
try {
|
|
448
528
|
deleteVerificationEvidence(params.milestoneId, params.sliceId, params.taskId);
|
|
449
529
|
updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, 'pending');
|
|
530
|
+
revertAppliedReworkResolutions(appliedReworkSnapshot);
|
|
450
531
|
invalidateStateCache();
|
|
451
532
|
logWarning("tool", `complete-task rolled back DB completion for ${params.milestoneId}/${params.sliceId}/${params.taskId} because hard-blocker escalation handling is disabled; SUMMARY.md left on disk for retry.`);
|
|
452
533
|
}
|
|
@@ -5,7 +5,7 @@ import { getGateIdsForTurn } from "../gate-registry.js";
|
|
|
5
5
|
import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning, insertGateRow, setSliceSketchFlag } from "../gsd-db.js";
|
|
6
6
|
import { invalidateStateCache } from "../state.js";
|
|
7
7
|
import { renderTaskPlanFromDb, renderPlanFromDb } from "../markdown-renderer.js";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveMilestonePath, resolveSlicePath } from "../paths.js";
|
|
9
9
|
import { flushWorkflowProjections } from "../projection-flush.js";
|
|
10
10
|
import { writeManifest } from "../workflow-manifest.js";
|
|
11
11
|
import { appendEvent } from "../workflow-events.js";
|
|
@@ -193,21 +193,19 @@ export async function handlePlanTask(rawParams, basePath) {
|
|
|
193
193
|
return { error: guardError };
|
|
194
194
|
}
|
|
195
195
|
try {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Guard: resolveTasksDir is null in flat-phase (no tasks/ subdir exists).
|
|
196
|
+
const milestonePath = resolveMilestonePath(basePath, params.milestoneId);
|
|
197
|
+
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
198
|
+
const isLegacySliceLayout = Boolean(milestonePath && slicePath && slicePath !== milestonePath);
|
|
199
|
+
let renderedPath;
|
|
201
200
|
let slicePlanSynced = false;
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
206
|
-
slicePlanSynced = true;
|
|
207
|
-
}
|
|
201
|
+
if (isLegacySliceLayout) {
|
|
202
|
+
const renderResult = await renderTaskPlanFromDb(basePath, params.milestoneId, params.sliceId, params.taskId);
|
|
203
|
+
renderedPath = renderResult.taskPlanPath;
|
|
208
204
|
}
|
|
209
|
-
|
|
210
|
-
|
|
205
|
+
else {
|
|
206
|
+
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
207
|
+
renderedPath = renderResult.planPath;
|
|
208
|
+
slicePlanSynced = true;
|
|
211
209
|
}
|
|
212
210
|
if (slicePlanSynced) {
|
|
213
211
|
setSliceSketchFlag(params.milestoneId, params.sliceId, false);
|
|
@@ -234,7 +232,7 @@ export async function handlePlanTask(rawParams, basePath) {
|
|
|
234
232
|
milestoneId: params.milestoneId,
|
|
235
233
|
sliceId: params.sliceId,
|
|
236
234
|
taskId: params.taskId,
|
|
237
|
-
taskPlanPath:
|
|
235
|
+
taskPlanPath: renderedPath,
|
|
238
236
|
};
|
|
239
237
|
}
|
|
240
238
|
catch (err) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, unlinkSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import {
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
import { gsdProjectionRoot, gsdRoot, resolveMilestoneFile, resolveMilestonePath, targetMilestoneFile } from "../paths.js";
|
|
4
4
|
import { clearParseCache } from "../files.js";
|
|
5
5
|
import { isClosedStatus } from "../status-guards.js";
|
|
6
6
|
import { isNonEmptyString } from "../validation.js";
|
|
@@ -11,6 +11,14 @@ import { flushWorkflowProjections } from "../projection-flush.js";
|
|
|
11
11
|
import { writeManifest } from "../workflow-manifest.js";
|
|
12
12
|
import { appendEvent } from "../workflow-events.js";
|
|
13
13
|
import { logWarning } from "../workflow-logger.js";
|
|
14
|
+
function assessmentDbPathForRenderedFile(basePath, absPath) {
|
|
15
|
+
const projectionRoot = gsdProjectionRoot(basePath);
|
|
16
|
+
const projectionRel = relative(projectionRoot, absPath);
|
|
17
|
+
const root = projectionRel && !projectionRel.startsWith("..") && !projectionRel.startsWith("/")
|
|
18
|
+
? projectionRoot
|
|
19
|
+
: gsdRoot(basePath);
|
|
20
|
+
return `.gsd/${relative(root, absPath).replace(/\\/g, "/")}`;
|
|
21
|
+
}
|
|
14
22
|
function validateParams(params) {
|
|
15
23
|
if (!isNonEmptyString(params?.milestoneId))
|
|
16
24
|
throw new Error("milestoneId is required");
|
|
@@ -74,10 +82,6 @@ export async function handleReassessRoadmap(rawParams, basePath) {
|
|
|
74
82
|
catch (err) {
|
|
75
83
|
return { error: `validation failed: ${err.message}` };
|
|
76
84
|
}
|
|
77
|
-
// ── Compute assessment artifact path ──────────────────────────────
|
|
78
|
-
// Assessment lives in the completed slice's directory.
|
|
79
|
-
// Use relSliceFile so the path is layout-aware (flat-phase or legacy).
|
|
80
|
-
const assessmentRelPath = relSliceFile(basePath, params.milestoneId, params.completedSliceId, "ASSESSMENT");
|
|
81
85
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
82
86
|
// Guards must be inside the transaction so the state they check cannot
|
|
83
87
|
// change between the read and the write (#2723).
|
|
@@ -152,15 +156,6 @@ export async function handleReassessRoadmap(rawParams, basePath) {
|
|
|
152
156
|
}
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
|
-
// Record assessment
|
|
156
|
-
insertAssessment({
|
|
157
|
-
path: assessmentRelPath,
|
|
158
|
-
milestoneId: params.milestoneId,
|
|
159
|
-
sliceId: params.completedSliceId,
|
|
160
|
-
status: params.verdict,
|
|
161
|
-
scope: "roadmap",
|
|
162
|
-
fullContent: params.assessment,
|
|
163
|
-
});
|
|
164
159
|
// Apply slice modifications
|
|
165
160
|
for (const mod of params.sliceChanges.modified) {
|
|
166
161
|
updateSliceFields(params.milestoneId, mod.sliceId, {
|
|
@@ -220,6 +215,14 @@ export async function handleReassessRoadmap(rawParams, basePath) {
|
|
|
220
215
|
assessment: params.assessment,
|
|
221
216
|
completedSliceId: params.completedSliceId,
|
|
222
217
|
});
|
|
218
|
+
insertAssessment({
|
|
219
|
+
path: assessmentDbPathForRenderedFile(basePath, assessmentResult.assessmentPath),
|
|
220
|
+
milestoneId: params.milestoneId,
|
|
221
|
+
sliceId: params.completedSliceId,
|
|
222
|
+
status: params.verdict,
|
|
223
|
+
scope: "roadmap",
|
|
224
|
+
fullContent: params.assessment,
|
|
225
|
+
});
|
|
223
226
|
// ── Remove stale VALIDATION file from disk (#2957) ────────────
|
|
224
227
|
const hasStructuralChanges = params.sliceChanges.added.length > 0 ||
|
|
225
228
|
params.sliceChanges.modified.length > 0 ||
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { clearParseCache } from "../files.js";
|
|
2
|
+
import { getSlice, getTask, insertReplanHistory, transaction, upsertTaskPlanning, } from "../gsd-db.js";
|
|
3
|
+
import { invalidateStateCache } from "../state.js";
|
|
4
|
+
import { isClosedStatus } from "../status-guards.js";
|
|
5
|
+
import { isNonEmptyString, validateStringArray } from "../validation.js";
|
|
6
|
+
import { renderPlanFromDb, renderTaskPlanFromDb } from "../markdown-renderer.js";
|
|
7
|
+
import { resolveMilestonePath, resolveSlicePath } from "../paths.js";
|
|
8
|
+
import { flushWorkflowProjections } from "../projection-flush.js";
|
|
9
|
+
import { writeManifest } from "../workflow-manifest.js";
|
|
10
|
+
import { appendEvent } from "../workflow-events.js";
|
|
11
|
+
import { logWarning } from "../workflow-logger.js";
|
|
12
|
+
function validateParams(params) {
|
|
13
|
+
if (!isNonEmptyString(params?.milestoneId))
|
|
14
|
+
throw new Error("milestoneId is required");
|
|
15
|
+
if (!isNonEmptyString(params?.sliceId))
|
|
16
|
+
throw new Error("sliceId is required");
|
|
17
|
+
if (!isNonEmptyString(params?.taskId))
|
|
18
|
+
throw new Error("taskId is required");
|
|
19
|
+
if (!isNonEmptyString(params?.title))
|
|
20
|
+
throw new Error("title is required");
|
|
21
|
+
if (!isNonEmptyString(params?.description))
|
|
22
|
+
throw new Error("description is required");
|
|
23
|
+
if (!isNonEmptyString(params?.estimate))
|
|
24
|
+
throw new Error("estimate is required");
|
|
25
|
+
if (!isNonEmptyString(params?.verify))
|
|
26
|
+
throw new Error("verify is required");
|
|
27
|
+
return {
|
|
28
|
+
...params,
|
|
29
|
+
files: validateStringArray(params.files, "files"),
|
|
30
|
+
inputs: validateStringArray(params.inputs, "inputs"),
|
|
31
|
+
expectedOutput: validateStringArray(params.expectedOutput, "expectedOutput"),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function replanSummary(params) {
|
|
35
|
+
const ref = params.reworkBriefRef?.trim();
|
|
36
|
+
return ref
|
|
37
|
+
? `Task ${params.taskId} replanned from rework brief ${ref}`
|
|
38
|
+
: `Task ${params.taskId} replanned`;
|
|
39
|
+
}
|
|
40
|
+
export async function handleReplanTask(rawParams, basePath) {
|
|
41
|
+
let params;
|
|
42
|
+
try {
|
|
43
|
+
params = validateParams(rawParams);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
return { error: `validation failed: ${err.message}` };
|
|
47
|
+
}
|
|
48
|
+
let guardError = null;
|
|
49
|
+
try {
|
|
50
|
+
transaction(() => {
|
|
51
|
+
const parentSlice = getSlice(params.milestoneId, params.sliceId);
|
|
52
|
+
if (!parentSlice) {
|
|
53
|
+
guardError = `missing parent slice: ${params.milestoneId}/${params.sliceId}`;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (isClosedStatus(parentSlice.status)) {
|
|
57
|
+
guardError = `cannot replan a task in a closed slice: ${params.sliceId} (status: ${parentSlice.status})`;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const task = getTask(params.milestoneId, params.sliceId, params.taskId);
|
|
61
|
+
if (!task) {
|
|
62
|
+
guardError = `task not found: ${params.milestoneId}/${params.sliceId}/${params.taskId}`;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (isClosedStatus(task.status)) {
|
|
66
|
+
guardError = `cannot replan completed task ${params.taskId} — use gsd_task_reopen first`;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
upsertTaskPlanning(params.milestoneId, params.sliceId, params.taskId, {
|
|
70
|
+
title: params.title,
|
|
71
|
+
description: params.description,
|
|
72
|
+
estimate: params.estimate,
|
|
73
|
+
files: params.files,
|
|
74
|
+
verify: params.verify,
|
|
75
|
+
inputs: params.inputs,
|
|
76
|
+
expectedOutput: params.expectedOutput,
|
|
77
|
+
fullPlanMd: params.fullPlanMd,
|
|
78
|
+
});
|
|
79
|
+
insertReplanHistory({
|
|
80
|
+
milestoneId: params.milestoneId,
|
|
81
|
+
sliceId: params.sliceId,
|
|
82
|
+
taskId: params.taskId,
|
|
83
|
+
summary: replanSummary(params),
|
|
84
|
+
previousArtifactPath: params.reworkBriefRef ?? null,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return { error: `db write failed: ${err.message}` };
|
|
90
|
+
}
|
|
91
|
+
if (guardError)
|
|
92
|
+
return { error: guardError };
|
|
93
|
+
try {
|
|
94
|
+
const milestonePath = resolveMilestonePath(basePath, params.milestoneId);
|
|
95
|
+
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
96
|
+
const isLegacySliceLayout = Boolean(milestonePath && slicePath && slicePath !== milestonePath);
|
|
97
|
+
const renderResult = isLegacySliceLayout
|
|
98
|
+
? await renderTaskPlanFromDb(basePath, params.milestoneId, params.sliceId, params.taskId)
|
|
99
|
+
: await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
100
|
+
const taskPlanPath = "taskPlanPath" in renderResult ? renderResult.taskPlanPath : renderResult.planPath;
|
|
101
|
+
invalidateStateCache();
|
|
102
|
+
clearParseCache();
|
|
103
|
+
try {
|
|
104
|
+
await flushWorkflowProjections(basePath, { milestoneId: params.milestoneId });
|
|
105
|
+
writeManifest(basePath);
|
|
106
|
+
appendEvent(basePath, {
|
|
107
|
+
cmd: "replan-task",
|
|
108
|
+
params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
|
|
109
|
+
ts: new Date().toISOString(),
|
|
110
|
+
actor: "agent",
|
|
111
|
+
actor_name: params.actorName,
|
|
112
|
+
trigger_reason: params.triggerReason,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (hookErr) {
|
|
116
|
+
logWarning("tool", `replan-task post-mutation hook warning: ${hookErr.message}`);
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
milestoneId: params.milestoneId,
|
|
120
|
+
sliceId: params.sliceId,
|
|
121
|
+
taskId: params.taskId,
|
|
122
|
+
taskPlanPath,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
return { error: `render failed: ${err.message}` };
|
|
127
|
+
}
|
|
128
|
+
}
|