@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
|
@@ -6,58 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Frame, Page } from "playwright";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
// can still be loaded on platforms where sharp is unavailable (e.g. bunx on
|
|
12
|
-
// Raspberry Pi). constrainScreenshot falls back to returning the raw buffer
|
|
13
|
-
// when sharp is not installed, which means screenshots won't be resized but
|
|
14
|
-
// the tool remains functional.
|
|
15
|
-
let _sharp: typeof import("sharp") | null | undefined;
|
|
16
|
-
async function getSharp(): Promise<typeof import("sharp") | null> {
|
|
17
|
-
if (_sharp !== undefined) return _sharp;
|
|
18
|
-
try {
|
|
19
|
-
_sharp = (await import("sharp")).default;
|
|
20
|
-
} catch {
|
|
21
|
-
_sharp = null;
|
|
22
|
-
}
|
|
23
|
-
return _sharp;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Test-only seam: override the cached sharp module. Pass `null` to simulate
|
|
28
|
-
* an environment where the sharp native dep is unavailable; pass `undefined`
|
|
29
|
-
* to clear the cache and let the next getSharp() call re-import. See
|
|
30
|
-
* tests/capture-sharp-optional.test.cjs.
|
|
31
|
-
*/
|
|
32
|
-
export function __setSharpForTesting(
|
|
33
|
-
value: typeof import("sharp") | null | undefined,
|
|
34
|
-
): void {
|
|
35
|
-
_sharp = value;
|
|
36
|
-
}
|
|
9
|
+
import { constrainScreenshot } from "./screenshot-constraints.js";
|
|
10
|
+
export { constrainScreenshot, __setSharpForTesting } from "./screenshot-constraints.js";
|
|
37
11
|
import type { CompactPageState, CompactSelectorState } from "./state.js";
|
|
38
12
|
import { formatCompactStateSummary } from "./utils.js";
|
|
39
13
|
|
|
40
|
-
// Anthropic vision: 1568px is the recommended optimal width. Height is capped
|
|
41
|
-
// generously at 8000px so tall full-page screenshots remain readable rather
|
|
42
|
-
// than being squished into a square constraint.
|
|
43
|
-
//
|
|
44
14
|
// Override via environment variables:
|
|
45
|
-
// SCREENSHOT_MAX_WIDTH=0 → uncap width (use raw resolution)
|
|
46
|
-
// SCREENSHOT_MAX_HEIGHT=0 → uncap height
|
|
47
15
|
// SCREENSHOT_FORMAT=png → lossless PNG for all viewport/fullpage screenshots
|
|
48
16
|
// SCREENSHOT_QUALITY=100 → max JPEG quality (1-100, default 80)
|
|
49
|
-
const MAX_SCREENSHOT_WIDTH = parseScreenshotDimension(process.env.SCREENSHOT_MAX_WIDTH, 1568);
|
|
50
|
-
const MAX_SCREENSHOT_HEIGHT = parseScreenshotDimension(process.env.SCREENSHOT_MAX_HEIGHT, 8000);
|
|
51
|
-
|
|
52
|
-
/** Parse a dimension env var: positive int = that value, 0 = Infinity (uncapped), absent/invalid = default. */
|
|
53
|
-
function parseScreenshotDimension(value: string | undefined, fallback: number): number {
|
|
54
|
-
if (value === undefined || value === "") return fallback;
|
|
55
|
-
const n = parseInt(value, 10);
|
|
56
|
-
if (isNaN(n) || n < 0) return fallback;
|
|
57
|
-
if (n === 0) return Infinity;
|
|
58
|
-
return n;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
17
|
/** Return the user-configured screenshot format override, or null for default behavior. */
|
|
62
18
|
export function getScreenshotFormatOverride(): "png" | "jpeg" | null {
|
|
63
19
|
const fmt = process.env.SCREENSHOT_FORMAT?.toLowerCase();
|
|
@@ -176,46 +132,6 @@ export async function postActionSummary(p: Page, target?: Page | Frame): Promise
|
|
|
176
132
|
}
|
|
177
133
|
}
|
|
178
134
|
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
// Screenshot helpers
|
|
181
|
-
// ---------------------------------------------------------------------------
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Constrain screenshot dimensions for the Anthropic vision API.
|
|
185
|
-
* Width is capped at 1568px (optimal) and height at 8000px, each
|
|
186
|
-
* independently, using `fit: "inside"` so aspect ratio is preserved.
|
|
187
|
-
* Small images are never upscaled.
|
|
188
|
-
*
|
|
189
|
-
* `page` parameter is retained for ToolDeps signature stability (D008)
|
|
190
|
-
* but is no longer used — all processing is server-side via sharp.
|
|
191
|
-
*/
|
|
192
|
-
export async function constrainScreenshot(
|
|
193
|
-
_page: Page,
|
|
194
|
-
buffer: Buffer,
|
|
195
|
-
mimeType: string,
|
|
196
|
-
quality: number,
|
|
197
|
-
): Promise<Buffer> {
|
|
198
|
-
const sharp = await getSharp();
|
|
199
|
-
if (!sharp) return buffer;
|
|
200
|
-
|
|
201
|
-
const meta = await sharp(buffer).metadata();
|
|
202
|
-
const width = meta.width;
|
|
203
|
-
const height = meta.height;
|
|
204
|
-
|
|
205
|
-
if (width === undefined || height === undefined) return buffer;
|
|
206
|
-
if (width <= MAX_SCREENSHOT_WIDTH && height <= MAX_SCREENSHOT_HEIGHT) return buffer;
|
|
207
|
-
|
|
208
|
-
const resizer = sharp(buffer).resize(MAX_SCREENSHOT_WIDTH, MAX_SCREENSHOT_HEIGHT, {
|
|
209
|
-
fit: "inside",
|
|
210
|
-
withoutEnlargement: true,
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
if (mimeType === "image/png") {
|
|
214
|
-
return Buffer.from(await resizer.png().toBuffer());
|
|
215
|
-
}
|
|
216
|
-
return Buffer.from(await resizer.jpeg({ quality }).toBuffer());
|
|
217
|
-
}
|
|
218
|
-
|
|
219
135
|
/** Capture a JPEG screenshot for error debugging. Returns base64 or null. */
|
|
220
136
|
export async function captureErrorScreenshot(p: Page | null): Promise<{ data: string; mimeType: string } | null> {
|
|
221
137
|
if (!p) return null;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
|
|
3
|
+
// sharp is an optional native dependency. Load it lazily so that screenshot
|
|
4
|
+
// emitters still work on platforms where sharp is unavailable (e.g. bunx on
|
|
5
|
+
// Raspberry Pi). constrainScreenshot falls back to returning the raw buffer
|
|
6
|
+
// when sharp is not installed.
|
|
7
|
+
let _sharp: typeof import("sharp") | null | undefined;
|
|
8
|
+
async function getSharp(): Promise<typeof import("sharp") | null> {
|
|
9
|
+
if (_sharp !== undefined) return _sharp;
|
|
10
|
+
try {
|
|
11
|
+
_sharp = (await import("sharp")).default;
|
|
12
|
+
} catch {
|
|
13
|
+
_sharp = null;
|
|
14
|
+
}
|
|
15
|
+
return _sharp;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Test-only seam: override the cached sharp module. Pass `null` to simulate
|
|
20
|
+
* an environment where the sharp native dep is unavailable; pass `undefined`
|
|
21
|
+
* to clear the cache and let the next getSharp() call re-import. See
|
|
22
|
+
* tests/capture-sharp-optional.test.cjs.
|
|
23
|
+
*/
|
|
24
|
+
export function __setSharpForTesting(
|
|
25
|
+
value: typeof import("sharp") | null | undefined,
|
|
26
|
+
): void {
|
|
27
|
+
_sharp = value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Anthropic vision: 1568px is the recommended optimal width. Height is capped
|
|
31
|
+
// generously at 8000px so tall full-page screenshots remain readable rather
|
|
32
|
+
// than being squished into a square constraint.
|
|
33
|
+
//
|
|
34
|
+
// Override via environment variables:
|
|
35
|
+
// SCREENSHOT_MAX_WIDTH=0 -> uncap width (use raw resolution)
|
|
36
|
+
// SCREENSHOT_MAX_HEIGHT=0 -> uncap height
|
|
37
|
+
export const MAX_SCREENSHOT_WIDTH = parseScreenshotDimension(process.env.SCREENSHOT_MAX_WIDTH, 1568);
|
|
38
|
+
export const MAX_SCREENSHOT_HEIGHT = parseScreenshotDimension(process.env.SCREENSHOT_MAX_HEIGHT, 8000);
|
|
39
|
+
|
|
40
|
+
/** Parse a dimension env var: positive int = that value, 0 = Infinity (uncapped), absent/invalid = default. */
|
|
41
|
+
function parseScreenshotDimension(value: string | undefined, fallback: number): number {
|
|
42
|
+
if (value === undefined || value === "") return fallback;
|
|
43
|
+
const n = parseInt(value, 10);
|
|
44
|
+
if (isNaN(n) || n < 0) return fallback;
|
|
45
|
+
if (n === 0) return Infinity;
|
|
46
|
+
return n;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export async function getScreenshotBufferDimensions(
|
|
50
|
+
buffer: Buffer,
|
|
51
|
+
): Promise<{ width: number; height: number } | null> {
|
|
52
|
+
const sharp = await getSharp();
|
|
53
|
+
if (!sharp) return null;
|
|
54
|
+
|
|
55
|
+
const meta = await sharp(buffer).metadata();
|
|
56
|
+
if (meta.width === undefined || meta.height === undefined) return null;
|
|
57
|
+
return { width: meta.width, height: meta.height };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Constrain screenshot dimensions for the Anthropic vision API.
|
|
62
|
+
* Width is capped at 1568px (optimal) and height at 8000px, each
|
|
63
|
+
* independently, using `fit: "inside"` so aspect ratio is preserved.
|
|
64
|
+
* Small images are never upscaled.
|
|
65
|
+
*
|
|
66
|
+
* `page` parameter is retained for ToolDeps signature stability (D008)
|
|
67
|
+
* but is no longer used — all processing is server-side via sharp.
|
|
68
|
+
*/
|
|
69
|
+
export async function constrainScreenshot(
|
|
70
|
+
_page: Page | null,
|
|
71
|
+
buffer: Buffer,
|
|
72
|
+
mimeType: string,
|
|
73
|
+
quality: number,
|
|
74
|
+
): Promise<Buffer> {
|
|
75
|
+
const sharp = await getSharp();
|
|
76
|
+
if (!sharp) return buffer;
|
|
77
|
+
|
|
78
|
+
const dimensions = await getScreenshotBufferDimensions(buffer);
|
|
79
|
+
const width = dimensions?.width;
|
|
80
|
+
const height = dimensions?.height;
|
|
81
|
+
|
|
82
|
+
if (width === undefined || height === undefined) return buffer;
|
|
83
|
+
if (width <= MAX_SCREENSHOT_WIDTH && height <= MAX_SCREENSHOT_HEIGHT) return buffer;
|
|
84
|
+
|
|
85
|
+
const resizer = sharp(buffer).resize(MAX_SCREENSHOT_WIDTH, MAX_SCREENSHOT_HEIGHT, {
|
|
86
|
+
fit: "inside",
|
|
87
|
+
withoutEnlargement: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
if (mimeType === "image/png") {
|
|
91
|
+
return Buffer.from(await resizer.png().toBuffer());
|
|
92
|
+
}
|
|
93
|
+
return Buffer.from(await resizer.jpeg({ quality }).toBuffer());
|
|
94
|
+
}
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
import type { ExtensionUIContext } from "@gsd/pi-coding-agent";
|
|
23
23
|
import { EventStream } from "@gsd/pi-ai";
|
|
24
24
|
import { execSync } from "node:child_process";
|
|
25
|
+
import { createHash } from "node:crypto";
|
|
25
26
|
import { existsSync, readFileSync } from "node:fs";
|
|
26
27
|
import { homedir } from "node:os";
|
|
27
28
|
import { createRequire } from "node:module";
|
|
@@ -583,6 +584,7 @@ function inferMimeTypeFromDataUri(value: string): string | null {
|
|
|
583
584
|
/** Collect all base64 image blocks from user messages in the context for inclusion in the SDK prompt. */
|
|
584
585
|
export function extractImageBlocksFromContext(context: Context): SDKInputImageBlock[] {
|
|
585
586
|
const imageBlocks: SDKInputImageBlock[] = [];
|
|
587
|
+
const seenImageKeys = new Set<string>();
|
|
586
588
|
|
|
587
589
|
for (const msg of context.messages) {
|
|
588
590
|
if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
|
|
@@ -597,12 +599,17 @@ export function extractImageBlocksFromContext(context: Context): SDKInputImageBl
|
|
|
597
599
|
: inferMimeTypeFromDataUri(block.data);
|
|
598
600
|
if (!mimeType) continue;
|
|
599
601
|
|
|
602
|
+
const data = stripDataUriPrefix(block.data);
|
|
603
|
+
const imageKey = `${mimeType}\0${createHash("sha1").update(data).digest("hex")}`;
|
|
604
|
+
if (seenImageKeys.has(imageKey)) continue;
|
|
605
|
+
seenImageKeys.add(imageKey);
|
|
606
|
+
|
|
600
607
|
imageBlocks.push({
|
|
601
608
|
type: "image",
|
|
602
609
|
source: {
|
|
603
610
|
type: "base64",
|
|
604
611
|
media_type: mimeType,
|
|
605
|
-
data
|
|
612
|
+
data,
|
|
606
613
|
},
|
|
607
614
|
});
|
|
608
615
|
}
|
|
@@ -2252,6 +2259,7 @@ export function streamViaClaudeCode(
|
|
|
2252
2259
|
interface SdkAttemptMessageState {
|
|
2253
2260
|
builder: PartialMessageBuilder | null;
|
|
2254
2261
|
intermediateToolBlocks: AssistantMessage["content"];
|
|
2262
|
+
intermediateTextBlocks: AssistantMessage["content"];
|
|
2255
2263
|
toolResultsById: Map<string, ExternalToolResultPayload>;
|
|
2256
2264
|
toolCompletionTargetsById: Map<string, { partial: AssistantMessage; contentIndex: number }>;
|
|
2257
2265
|
emittedExternalToolResultIds: Set<string>;
|
|
@@ -2261,6 +2269,7 @@ function createSdkAttemptMessageState(): SdkAttemptMessageState {
|
|
|
2261
2269
|
return {
|
|
2262
2270
|
builder: null,
|
|
2263
2271
|
intermediateToolBlocks: [],
|
|
2272
|
+
intermediateTextBlocks: [],
|
|
2264
2273
|
toolResultsById: new Map<string, ExternalToolResultPayload>(),
|
|
2265
2274
|
toolCompletionTargetsById: new Map<string, { partial: AssistantMessage; contentIndex: number }>(),
|
|
2266
2275
|
emittedExternalToolResultIds: new Set<string>(),
|
|
@@ -2402,6 +2411,7 @@ async function pumpSdkMessages(
|
|
|
2402
2411
|
let {
|
|
2403
2412
|
builder,
|
|
2404
2413
|
intermediateToolBlocks,
|
|
2414
|
+
intermediateTextBlocks,
|
|
2405
2415
|
toolResultsById,
|
|
2406
2416
|
toolCompletionTargetsById,
|
|
2407
2417
|
emittedExternalToolResultIds,
|
|
@@ -2542,8 +2552,14 @@ async function pumpSdkMessages(
|
|
|
2542
2552
|
for (const [contentIndex, block] of builder.message.content.entries()) {
|
|
2543
2553
|
if (block.type === "text" && block.text) {
|
|
2544
2554
|
lastTextContent = block.text;
|
|
2555
|
+
// Accumulate completed prose in order — a multi-question
|
|
2556
|
+
// turn commits [prose][elicitation] segments across several
|
|
2557
|
+
// synthetic-user boundaries, and overwriting a single
|
|
2558
|
+
// scalar would drop every explanation but the last.
|
|
2559
|
+
intermediateTextBlocks.push({ type: "text", text: block.text });
|
|
2545
2560
|
} else if (block.type === "thinking" && block.thinking) {
|
|
2546
2561
|
lastThinkingContent = block.thinking;
|
|
2562
|
+
intermediateTextBlocks.push({ type: "thinking", thinking: block.thinking });
|
|
2547
2563
|
} else if (block.type === "toolCall" || block.type === "serverToolUse") {
|
|
2548
2564
|
// Collect tool blocks for externalToolExecution rendering
|
|
2549
2565
|
intermediateToolBlocks.push(block);
|
|
@@ -2641,6 +2657,7 @@ async function pumpSdkMessages(
|
|
|
2641
2657
|
const result = msg as SDKResultMessage;
|
|
2642
2658
|
const finalContent = buildFinalAssistantContent({
|
|
2643
2659
|
intermediateToolBlocks,
|
|
2660
|
+
intermediateTextBlocks,
|
|
2644
2661
|
pendingContent: builder?.message.content,
|
|
2645
2662
|
toolResultsById,
|
|
2646
2663
|
lastThinkingContent,
|
|
@@ -363,6 +363,53 @@ describe("stream-adapter — image prompt forwarding (#4183)", () => {
|
|
|
363
363
|
]);
|
|
364
364
|
});
|
|
365
365
|
|
|
366
|
+
test("extractImageBlocksFromContext deduplicates byte-identical image parts", () => {
|
|
367
|
+
const context: Context = {
|
|
368
|
+
messages: [
|
|
369
|
+
{
|
|
370
|
+
role: "user",
|
|
371
|
+
content: [
|
|
372
|
+
{
|
|
373
|
+
type: "image",
|
|
374
|
+
data: "data:image/png;base64,abc123",
|
|
375
|
+
mimeType: "image/png",
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
type: "image",
|
|
379
|
+
data: "abc123",
|
|
380
|
+
mimeType: "image/png",
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
type: "image",
|
|
384
|
+
data: "def456",
|
|
385
|
+
mimeType: "image/png",
|
|
386
|
+
},
|
|
387
|
+
],
|
|
388
|
+
} as Message,
|
|
389
|
+
],
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const imageBlocks = extractImageBlocksFromContext(context);
|
|
393
|
+
assert.deepEqual(imageBlocks, [
|
|
394
|
+
{
|
|
395
|
+
type: "image",
|
|
396
|
+
source: {
|
|
397
|
+
type: "base64",
|
|
398
|
+
media_type: "image/png",
|
|
399
|
+
data: "abc123",
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
type: "image",
|
|
404
|
+
source: {
|
|
405
|
+
type: "base64",
|
|
406
|
+
media_type: "image/png",
|
|
407
|
+
data: "def456",
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
]);
|
|
411
|
+
});
|
|
412
|
+
|
|
366
413
|
test("buildSdkQueryPrompt returns plain string when no images exist in context", () => {
|
|
367
414
|
const context: Context = {
|
|
368
415
|
messages: [{ role: "user", content: "hello" } as Message],
|
|
@@ -1365,6 +1412,67 @@ describe("stream-adapter — Claude Code external tool results", () => {
|
|
|
1365
1412
|
});
|
|
1366
1413
|
assert.deepEqual(finalContent[1], { type: "text", text: "Read complete." });
|
|
1367
1414
|
});
|
|
1415
|
+
|
|
1416
|
+
test("buildFinalAssistantContent keeps every prose segment across successive elicitation boundaries (#1284)", () => {
|
|
1417
|
+
// A multi-question /gsd discuss turn: [prose A][Q1][prose B][Q2][prose C].
|
|
1418
|
+
// Prose A and B are committed at synthetic-user boundaries (intermediate),
|
|
1419
|
+
// prose C is still in the builder (pending) when `result` arrives.
|
|
1420
|
+
const finalContent = buildFinalAssistantContent({
|
|
1421
|
+
intermediateToolBlocks: [
|
|
1422
|
+
{ type: "toolCall", id: "q1", name: "ask_user_questions", arguments: {} } as any,
|
|
1423
|
+
{ type: "toolCall", id: "q2", name: "ask_user_questions", arguments: {} } as any,
|
|
1424
|
+
],
|
|
1425
|
+
intermediateTextBlocks: [
|
|
1426
|
+
{ type: "text", text: "prose A" },
|
|
1427
|
+
{ type: "text", text: "prose B" },
|
|
1428
|
+
],
|
|
1429
|
+
pendingContent: [{ type: "text", text: "prose C" }],
|
|
1430
|
+
toolResultsById: new Map(),
|
|
1431
|
+
});
|
|
1432
|
+
|
|
1433
|
+
const textBlocks = finalContent.filter((b) => b.type === "text").map((b) => (b as any).text);
|
|
1434
|
+
assert.deepEqual(textBlocks, ["prose A", "prose B", "prose C"]);
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
test("buildFinalAssistantContent does not duplicate the last prose when the turn ends on an elicitation (#1284)", () => {
|
|
1438
|
+
// [prose A][Q1][prose B][Q2] — builder was reset at the final boundary, so
|
|
1439
|
+
// pendingContent is empty and lastTextContent still holds "prose B".
|
|
1440
|
+
const finalContent = buildFinalAssistantContent({
|
|
1441
|
+
intermediateToolBlocks: [
|
|
1442
|
+
{ type: "toolCall", id: "q1", name: "ask_user_questions", arguments: {} } as any,
|
|
1443
|
+
{ type: "toolCall", id: "q2", name: "ask_user_questions", arguments: {} } as any,
|
|
1444
|
+
],
|
|
1445
|
+
intermediateTextBlocks: [
|
|
1446
|
+
{ type: "text", text: "prose A" },
|
|
1447
|
+
{ type: "text", text: "prose B" },
|
|
1448
|
+
],
|
|
1449
|
+
toolResultsById: new Map(),
|
|
1450
|
+
lastTextContent: "prose B",
|
|
1451
|
+
});
|
|
1452
|
+
|
|
1453
|
+
const textBlocks = finalContent.filter((b) => b.type === "text").map((b) => (b as any).text);
|
|
1454
|
+
assert.deepEqual(textBlocks, ["prose A", "prose B"]);
|
|
1455
|
+
});
|
|
1456
|
+
|
|
1457
|
+
test("buildFinalAssistantContent emits scalar fallback prose/thinking not captured in the accumulator", () => {
|
|
1458
|
+
// A non-streaming `assistant` SDK message sets lastText/lastThinkingContent
|
|
1459
|
+
// only (never pushed to intermediateTextBlocks). With pendingContent empty
|
|
1460
|
+
// and intermediate blocks present, the fallback must still be emitted.
|
|
1461
|
+
const finalContent = buildFinalAssistantContent({
|
|
1462
|
+
intermediateToolBlocks: [
|
|
1463
|
+
{ type: "toolCall", id: "q1", name: "ask_user_questions", arguments: {} } as any,
|
|
1464
|
+
],
|
|
1465
|
+
intermediateTextBlocks: [{ type: "text", text: "prose A" }],
|
|
1466
|
+
toolResultsById: new Map(),
|
|
1467
|
+
lastThinkingContent: "final thinking",
|
|
1468
|
+
lastTextContent: "final prose",
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
const textBlocks = finalContent.filter((b) => b.type === "text").map((b) => (b as any).text);
|
|
1472
|
+
const thinkingBlocks = finalContent.filter((b) => b.type === "thinking").map((b) => (b as any).thinking);
|
|
1473
|
+
assert.deepEqual(textBlocks, ["prose A", "final prose"]);
|
|
1474
|
+
assert.deepEqual(thinkingBlocks, ["final thinking"]);
|
|
1475
|
+
});
|
|
1368
1476
|
});
|
|
1369
1477
|
|
|
1370
1478
|
describe("claude-code-cli — Claude Fable 5 Opus-tier support", () => {
|
|
@@ -244,6 +244,7 @@ export function shouldSuppressDuplicateToolUnavailableBlock(
|
|
|
244
244
|
*/
|
|
245
245
|
export function buildFinalAssistantContent(params: {
|
|
246
246
|
intermediateToolBlocks: AssistantMessage["content"];
|
|
247
|
+
intermediateTextBlocks?: AssistantMessage["content"];
|
|
247
248
|
pendingContent?: AssistantMessage["content"];
|
|
248
249
|
toolResultsById: ReadonlyMap<string, ExternalToolResultPayload>;
|
|
249
250
|
lastThinkingContent?: string;
|
|
@@ -259,6 +260,15 @@ export function buildFinalAssistantContent(params: {
|
|
|
259
260
|
const finalContent: AssistantMessage["content"] = mergedToolBlocks.filter(
|
|
260
261
|
(block) => !shouldSuppressDuplicateToolUnavailableBlock(block, mergedToolBlocks),
|
|
261
262
|
);
|
|
263
|
+
// Emit prose/thinking captured at earlier turn-boundaries (each successive
|
|
264
|
+
// `ask_user_questions` elicitation completes a turn) before the final
|
|
265
|
+
// segment. Capturing these in an ordered accumulator — symmetric with
|
|
266
|
+
// `intermediateToolBlocks` — is what keeps intermediate explanations from
|
|
267
|
+
// being collapsed to a single overwritten scalar and silently dropped.
|
|
268
|
+
const intermediateTextBlocks = params.intermediateTextBlocks ?? [];
|
|
269
|
+
for (const block of intermediateTextBlocks) {
|
|
270
|
+
finalContent.push(block);
|
|
271
|
+
}
|
|
262
272
|
if (params.pendingContent && params.pendingContent.length > 0) {
|
|
263
273
|
for (const block of params.pendingContent) {
|
|
264
274
|
if (block.type === "text" || block.type === "thinking") {
|
|
@@ -266,11 +276,29 @@ export function buildFinalAssistantContent(params: {
|
|
|
266
276
|
}
|
|
267
277
|
}
|
|
268
278
|
} else {
|
|
279
|
+
// No builder content survived to this turn boundary, so fall back to the
|
|
280
|
+
// last scalar thinking/text captured off the stream. When the turn ends
|
|
281
|
+
// on an elicitation these scalars just mirror the final intermediate
|
|
282
|
+
// block (they are overwritten at each synthetic-user boundary), so only
|
|
283
|
+
// emit them when they carry content not already accumulated — otherwise
|
|
284
|
+
// a non-streaming `assistant` message's prose/thinking is silently lost.
|
|
285
|
+
const lastBlockOfType = (type: "text" | "thinking") => {
|
|
286
|
+
for (let i = intermediateTextBlocks.length - 1; i >= 0; i--) {
|
|
287
|
+
if (intermediateTextBlocks[i].type === type) return intermediateTextBlocks[i];
|
|
288
|
+
}
|
|
289
|
+
return undefined;
|
|
290
|
+
};
|
|
269
291
|
if (params.lastThinkingContent) {
|
|
270
|
-
|
|
292
|
+
const lastThinking = lastBlockOfType("thinking") as { thinking?: string } | undefined;
|
|
293
|
+
if (lastThinking?.thinking !== params.lastThinkingContent) {
|
|
294
|
+
finalContent.push({ type: "thinking", thinking: params.lastThinkingContent });
|
|
295
|
+
}
|
|
271
296
|
}
|
|
272
297
|
if (params.lastTextContent) {
|
|
273
|
-
|
|
298
|
+
const lastText = lastBlockOfType("text") as { text?: string } | undefined;
|
|
299
|
+
if (lastText?.text !== params.lastTextContent) {
|
|
300
|
+
finalContent.push({ type: "text", text: params.lastTextContent });
|
|
301
|
+
}
|
|
274
302
|
}
|
|
275
303
|
}
|
|
276
304
|
|
|
@@ -297,9 +297,9 @@ export function diagnoseExpectedArtifact(
|
|
|
297
297
|
}
|
|
298
298
|
return `${relSliceFile(base, mid, sid!, "RESEARCH")} (slice research)`;
|
|
299
299
|
case "plan-slice":
|
|
300
|
-
return `${relSliceFile(base, mid, sid!, "PLAN")}
|
|
300
|
+
return `${relSliceFile(base, mid, sid!, "PLAN")} with embedded task plans`;
|
|
301
301
|
case "refine-slice":
|
|
302
|
-
return `${relSliceFile(base, mid, sid!, "PLAN")}
|
|
302
|
+
return `${relSliceFile(base, mid, sid!, "PLAN")} with embedded refined task plans`;
|
|
303
303
|
case "execute-task": {
|
|
304
304
|
return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid!, "PLAN")} + summary written`;
|
|
305
305
|
}
|
|
@@ -393,7 +393,8 @@ function resolveArtifactBasePath(
|
|
|
393
393
|
): string {
|
|
394
394
|
if (
|
|
395
395
|
session?.basePath &&
|
|
396
|
-
session.currentMilestoneId
|
|
396
|
+
session.currentMilestoneId &&
|
|
397
|
+
milestoneIdsDispatchCompatible(session.currentMilestoneId, mid) &&
|
|
397
398
|
existsSync(session.basePath)
|
|
398
399
|
) {
|
|
399
400
|
return session.basePath;
|
|
@@ -422,6 +423,28 @@ function normalizeMilestoneScope(value: string | null | undefined): string | nul
|
|
|
422
423
|
return trimmed;
|
|
423
424
|
}
|
|
424
425
|
|
|
426
|
+
function dispatchMilestoneIdentity(value: string | null | undefined): { baseId: string; hasSuffix: boolean } | null {
|
|
427
|
+
const normalized = normalizeMilestoneScope(value);
|
|
428
|
+
const match = normalized?.match(/^(M\d{3})(?:-[a-z0-9]{6})?$/);
|
|
429
|
+
if (!match) return null;
|
|
430
|
+
return { baseId: match[1]!, hasSuffix: normalized !== match[1] };
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function isBareSuffixedMilestoneAlias(left: string, right: string): boolean {
|
|
434
|
+
const leftId = dispatchMilestoneIdentity(left);
|
|
435
|
+
const rightId = dispatchMilestoneIdentity(right);
|
|
436
|
+
return Boolean(
|
|
437
|
+
leftId &&
|
|
438
|
+
rightId &&
|
|
439
|
+
leftId.baseId === rightId.baseId &&
|
|
440
|
+
leftId.hasSuffix !== rightId.hasSuffix,
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function milestoneIdsDispatchCompatible(left: string, right: string): boolean {
|
|
445
|
+
return left === right || isBareSuffixedMilestoneAlias(left, right);
|
|
446
|
+
}
|
|
447
|
+
|
|
425
448
|
function resolveDispatchMilestoneScope(
|
|
426
449
|
ctx: DispatchContext,
|
|
427
450
|
): { id: string; source: string } | null {
|
|
@@ -439,6 +462,37 @@ function resolveDispatchMilestoneScope(
|
|
|
439
462
|
return null;
|
|
440
463
|
}
|
|
441
464
|
|
|
465
|
+
function resolveEffectiveDispatchMilestoneId(
|
|
466
|
+
ctx: DispatchContext,
|
|
467
|
+
scopedMilestone: { id: string; source: string } | null,
|
|
468
|
+
): string {
|
|
469
|
+
if (scopedMilestone && isBareSuffixedMilestoneAlias(ctx.mid, scopedMilestone.id)) {
|
|
470
|
+
return dispatchMilestoneIdentity(scopedMilestone.id)?.hasSuffix ? scopedMilestone.id : ctx.mid;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const activeMid = ctx.state.activeMilestone?.id;
|
|
474
|
+
if (activeMid && isBareSuffixedMilestoneAlias(ctx.mid, activeMid)) {
|
|
475
|
+
return dispatchMilestoneIdentity(activeMid)?.hasSuffix ? activeMid : ctx.mid;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return ctx.mid;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function withEffectiveDispatchMilestone(ctx: DispatchContext, effectiveMid: string): DispatchContext {
|
|
482
|
+
if (effectiveMid === ctx.mid) return ctx;
|
|
483
|
+
const activeMilestone = ctx.state.activeMilestone;
|
|
484
|
+
const state = activeMilestone && milestoneIdsDispatchCompatible(activeMilestone.id, effectiveMid)
|
|
485
|
+
? {
|
|
486
|
+
...ctx.state,
|
|
487
|
+
activeMilestone: {
|
|
488
|
+
...activeMilestone,
|
|
489
|
+
id: effectiveMid,
|
|
490
|
+
},
|
|
491
|
+
}
|
|
492
|
+
: ctx.state;
|
|
493
|
+
return { ...ctx, mid: effectiveMid, state };
|
|
494
|
+
}
|
|
495
|
+
|
|
442
496
|
function hasMilestonePassedDiscuss(basePath: string, mid: string): boolean {
|
|
443
497
|
if (isDbAvailable()) {
|
|
444
498
|
try {
|
|
@@ -732,14 +786,21 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
732
786
|
// Fire BEFORE the execution-entry phase rules so we redispatch to
|
|
733
787
|
// `discuss-milestone` instead of hitting the plan-v2 gate.
|
|
734
788
|
name: "execution-entry phase (no context) → discuss-milestone",
|
|
735
|
-
match: async ({ state, mid, midTitle, basePath, prefs, structuredQuestionsAvailable }) => {
|
|
789
|
+
match: async ({ state, mid, midTitle, basePath, session, prefs, structuredQuestionsAvailable }) => {
|
|
736
790
|
if (!EXECUTION_ENTRY_PHASES.has(state.phase)) return null;
|
|
737
791
|
if (!MILESTONE_ID_RE.test(mid)) return null;
|
|
738
792
|
if (isRegistryMilestoneComplete(state, mid)) return null;
|
|
739
|
-
|
|
793
|
+
// Resolve discuss/context artifacts against the active session worktree,
|
|
794
|
+
// mirroring the executing rules below. For a suffixed-worktree milestone
|
|
795
|
+
// the CONTEXT and slice plans live under the worktree, not the project
|
|
796
|
+
// root; checking the raw project-root basePath misreads the milestone as
|
|
797
|
+
// "never discussed" and re-dispatches discuss-milestone after task
|
|
798
|
+
// closeout instead of continuing execution (#1317).
|
|
799
|
+
const artifactBasePath = resolveArtifactBasePath(basePath, mid, session);
|
|
800
|
+
if (hasMilestonePassedDiscuss(artifactBasePath, mid)) return null;
|
|
740
801
|
// Align with the plan-v2 gate's lookup semantics: whitespace-only counts
|
|
741
802
|
// as missing, and an auto worktree may fall back to GSD_PROJECT_ROOT.
|
|
742
|
-
if (hasFinalizedMilestoneContext(
|
|
803
|
+
if (hasFinalizedMilestoneContext(artifactBasePath, mid)) return null;
|
|
743
804
|
// H6 fix (#4973): non-deep auto-mode has no human to answer the
|
|
744
805
|
// depth-verification question, so pre-marking avoids a write-gate
|
|
745
806
|
// deadlock. Deep planning is still user-driven even inside auto-mode,
|
|
@@ -1095,10 +1156,13 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1095
1156
|
},
|
|
1096
1157
|
{
|
|
1097
1158
|
name: "pre-planning (no context) → discuss-milestone",
|
|
1098
|
-
match: async ({ state, mid, midTitle, basePath, prefs, structuredQuestionsAvailable }) => {
|
|
1159
|
+
match: async ({ state, mid, midTitle, basePath, prefs, session, structuredQuestionsAvailable }) => {
|
|
1099
1160
|
if (state.phase !== "pre-planning") return null;
|
|
1100
1161
|
if (isRegistryMilestoneComplete(state, mid)) return null;
|
|
1101
|
-
const
|
|
1162
|
+
const contextBasePath = resolveWorktreeProjectRoot(basePath, session?.originalBasePath);
|
|
1163
|
+
const contextFile =
|
|
1164
|
+
resolveMilestoneFile(basePath, mid, "CONTEXT") ??
|
|
1165
|
+
(contextBasePath !== basePath ? resolveMilestoneFile(contextBasePath, mid, "CONTEXT") : null);
|
|
1102
1166
|
const hasContext = !!(contextFile && (await loadFile(contextFile)));
|
|
1103
1167
|
if (hasContext) return null; // fall through to next rule
|
|
1104
1168
|
if (prefs?.planning_depth === "deep") return null;
|
|
@@ -1908,36 +1972,39 @@ function applyLanguageDirectiveToDispatch(
|
|
|
1908
1972
|
export async function resolveDispatch(
|
|
1909
1973
|
ctx: DispatchContext,
|
|
1910
1974
|
): Promise<DispatchAction> {
|
|
1911
|
-
|
|
1912
|
-
|
|
1975
|
+
const scopedMilestone = resolveDispatchMilestoneScope(ctx);
|
|
1976
|
+
const effectiveMid = resolveEffectiveDispatchMilestoneId(ctx, scopedMilestone);
|
|
1977
|
+
const dispatchCtx = withEffectiveDispatchMilestone(ctx, effectiveMid);
|
|
1978
|
+
|
|
1979
|
+
if (dispatchCtx.mid && isDbAvailable()) {
|
|
1980
|
+
const milestone = getMilestone(dispatchCtx.mid);
|
|
1913
1981
|
if (milestone && isClosedStatus(milestone.status)) {
|
|
1914
1982
|
return {
|
|
1915
1983
|
action: "stop",
|
|
1916
1984
|
reason:
|
|
1917
|
-
`Milestone ${
|
|
1985
|
+
`Milestone ${dispatchCtx.mid} is closed (status: ${milestone.status}); auto-mode will not reopen or recover it implicitly. ` +
|
|
1918
1986
|
"Use an explicit reopen command before planning or executing more work for this milestone.",
|
|
1919
1987
|
level: "warning",
|
|
1920
1988
|
};
|
|
1921
1989
|
}
|
|
1922
1990
|
}
|
|
1923
1991
|
|
|
1924
|
-
const activeMid =
|
|
1925
|
-
if (activeMid &&
|
|
1992
|
+
const activeMid = dispatchCtx.state.activeMilestone?.id;
|
|
1993
|
+
if (activeMid && !milestoneIdsDispatchCompatible(dispatchCtx.mid, activeMid)) {
|
|
1926
1994
|
return {
|
|
1927
1995
|
action: "stop",
|
|
1928
1996
|
reason:
|
|
1929
|
-
`Dispatch milestone mismatch: context mid "${
|
|
1997
|
+
`Dispatch milestone mismatch: context mid "${dispatchCtx.mid}" does not match active milestone "${activeMid}". ` +
|
|
1930
1998
|
"This usually means a project-level deep setup pseudo-id leaked into milestone dispatch; rerun /gsd auto after setup state is reconciled.",
|
|
1931
1999
|
level: "warning",
|
|
1932
2000
|
};
|
|
1933
2001
|
}
|
|
1934
2002
|
|
|
1935
|
-
|
|
1936
|
-
if (scopedMilestone && ctx.mid !== scopedMilestone.id) {
|
|
2003
|
+
if (scopedMilestone && !milestoneIdsDispatchCompatible(dispatchCtx.mid, scopedMilestone.id)) {
|
|
1937
2004
|
return {
|
|
1938
2005
|
action: "stop",
|
|
1939
2006
|
reason:
|
|
1940
|
-
`Dispatch milestone mismatch: context mid "${
|
|
2007
|
+
`Dispatch milestone mismatch: context mid "${dispatchCtx.mid}" does not match ${scopedMilestone.source} "${scopedMilestone.id}". ` +
|
|
1941
2008
|
"The active worktree/session and derived project state disagree; recover, park, or discard the stranded milestone before continuing.",
|
|
1942
2009
|
level: "warning",
|
|
1943
2010
|
};
|
|
@@ -1946,10 +2013,10 @@ export async function resolveDispatch(
|
|
|
1946
2013
|
// Delegate to registry when available
|
|
1947
2014
|
try {
|
|
1948
2015
|
const registry = getRegistry();
|
|
1949
|
-
const action = annotateBackgroundable(await registry.evaluateDispatch(
|
|
2016
|
+
const action = annotateBackgroundable(await registry.evaluateDispatch(dispatchCtx));
|
|
1950
2017
|
if (
|
|
1951
2018
|
action.action === "dispatch" &&
|
|
1952
|
-
|
|
2019
|
+
dispatchCtx.session?.exhaustedVerificationUnits?.has(`${action.unitType}:${action.unitId}`)
|
|
1953
2020
|
) {
|
|
1954
2021
|
return {
|
|
1955
2022
|
action: "stop",
|
|
@@ -1964,13 +2031,13 @@ export async function resolveDispatch(
|
|
|
1964
2031
|
}
|
|
1965
2032
|
|
|
1966
2033
|
for (const rule of DISPATCH_RULES) {
|
|
1967
|
-
const result = await rule.match(
|
|
2034
|
+
const result = await rule.match(dispatchCtx);
|
|
1968
2035
|
if (result) {
|
|
1969
2036
|
if (result.action !== "skip") result.matchedRule = rule.name;
|
|
1970
2037
|
const action = annotateBackgroundable(result);
|
|
1971
2038
|
if (
|
|
1972
2039
|
action.action === "dispatch" &&
|
|
1973
|
-
|
|
2040
|
+
dispatchCtx.session?.exhaustedVerificationUnits?.has(`${action.unitType}:${action.unitId}`)
|
|
1974
2041
|
) {
|
|
1975
2042
|
return {
|
|
1976
2043
|
action: "stop",
|