@opengsd/gsd-pi 1.9.0 → 1.10.0-dev.a5e42e99
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 +10 -9
- package/dist/headless.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto/loop.js +24 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
- package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
- package/dist/resources/extensions/gsd/auto-start.js +30 -10
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +7 -26
- package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
- package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
- package/dist/resources/extensions/gsd/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- package/dist/resources/extensions/gsd/db/engine.js +5 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +33 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +40 -12
- package/dist/resources/extensions/gsd/error-classifier.js +12 -2
- package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
- package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +75 -31
- package/dist/resources/extensions/gsd/guided-flow.js +11 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
- package/dist/resources/extensions/gsd/md-importer.js +5 -6
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -1
- package/dist/resources/extensions/gsd/model-router.js +16 -0
- package/dist/resources/extensions/gsd/paths.js +66 -15
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +33 -0
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +6 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +86 -4
- package/dist/resources/extensions/gsd/preferences.js +24 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
- package/dist/resources/extensions/gsd/stop-notice.js +9 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
- package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
- package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- package/dist/resources/extensions/shared/interview-ui.js +43 -6
- package/dist/resources/extensions/subagent/index.js +1 -1
- package/dist/startup-model-validation.d.ts +1 -1
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- 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/1991.js +2 -2
- package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- 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/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/server.js +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +8 -6
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/rpc.d.ts +1 -1
- package/packages/contracts/dist/rpc.d.ts.map +1 -1
- package/packages/contracts/dist/rpc.js +1 -1
- package/packages/contracts/dist/rpc.js.map +1 -1
- package/packages/contracts/dist/rpc.test.js +1 -1
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +1 -0
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/cli/args.js +2 -2
- package/packages/gsd-agent-modes/dist/cli/args.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +21 -5
- package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/background-cli.test.js +325 -0
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +146 -16
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.js +7 -1
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +7 -4
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +115 -31
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +224 -59
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts +3 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js +36 -0
- package/packages/gsd-cloud/dist/runtime-artifacts.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts +32 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.js +640 -0
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js +543 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts +117 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js +291 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js +434 -0
- package/packages/gsd-cloud/dist/runtime-telemetry.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/README.md +7 -2
- package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli-runner.js +119 -33
- package/packages/mcp-server/dist/cli-runner.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- 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/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +2 -2
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +187 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +145 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.js +18 -6
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/providers/amazon-bedrock.js +3 -2
- package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +6 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
- package/packages/pi-ai/dist/providers/google.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
- package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js +1 -1
- package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +9 -1
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +2 -2
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +14 -4
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +54 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/theme/theme.js +1 -0
- package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/theme.d.ts +1 -1
- package/pkg/dist/theme/theme.d.ts.map +1 -1
- package/pkg/dist/theme/theme.js +1 -0
- package/pkg/dist/theme/theme.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto/loop.ts +48 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
- package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
- package/src/resources/extensions/gsd/auto-start.ts +32 -9
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +20 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +10 -31
- package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
- package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
- package/src/resources/extensions/gsd/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- package/src/resources/extensions/gsd/db/engine.ts +5 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +33 -2
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +45 -11
- package/src/resources/extensions/gsd/error-classifier.ts +13 -2
- package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
- package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +85 -33
- package/src/resources/extensions/gsd/guided-flow.ts +11 -4
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
- package/src/resources/extensions/gsd/md-importer.ts +5 -5
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -1
- package/src/resources/extensions/gsd/model-router.ts +17 -0
- package/src/resources/extensions/gsd/paths.ts +73 -15
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +45 -0
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +26 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +108 -3
- package/src/resources/extensions/gsd/preferences.ts +38 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
- package/src/resources/extensions/gsd/stop-notice.ts +11 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +8 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
- package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/model-isolation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/preferences.test.ts +151 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-faults.test.ts +238 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-fixture.ts +141 -0
- package/src/resources/extensions/gsd/tests/workflow-authority-projection-conflict.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/workflow-fault-harness.ts +72 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +74 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
- package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
- package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
- package/src/resources/extensions/ollama/ollama-chat-provider.ts +2 -2
- package/src/resources/extensions/ollama/tests/ollama-chat-provider-think.test.ts +4 -0
- package/src/resources/extensions/shared/interview-ui.ts +47 -8
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
- package/src/resources/extensions/subagent/index.ts +1 -1
- 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/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → xwUaOqui04jIIFVsIBLiL}/_ssgManifest.js +0 -0
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
// (drift to import). gsd-core is oblivious to this file and ignores it.
|
|
7
7
|
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
|
-
import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
-
import { dirname, join, isAbsolute, normalize } from "node:path";
|
|
9
|
+
import { existsSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync, mkdirSync } from "node:fs";
|
|
10
|
+
import { dirname, join, isAbsolute, normalize, relative, resolve } from "node:path";
|
|
11
11
|
|
|
12
12
|
/** Current marker schema version. Bump on breaking format changes + migrate. */
|
|
13
13
|
export const COMPAT_MARKER_SCHEMA = 2;
|
|
@@ -54,6 +54,13 @@ export interface CompatMarker {
|
|
|
54
54
|
piVersion: string;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
export interface ReadCompatMarkerOptions {
|
|
58
|
+
/** Rewrite invalid-but-derivable marker keys back to safe root-relative keys. */
|
|
59
|
+
healInvalidKeys?: boolean;
|
|
60
|
+
/** Quarantine malformed/unsafe markers. Disable only for read-only previews. */
|
|
61
|
+
quarantineInvalid?: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
/** Marker returned when no marker exists yet (fresh project, first gsd-pi run). */
|
|
58
65
|
export const EMPTY_MARKER: CompatMarker = {
|
|
59
66
|
schema: COMPAT_MARKER_SCHEMA,
|
|
@@ -81,6 +88,37 @@ export function computeProjectionSha(content: string): string {
|
|
|
81
88
|
return createHash("sha256").update(normalizeForHash(content)).digest("hex").slice(0, 16);
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
function normalizeRealPath(p: string): string {
|
|
92
|
+
try {
|
|
93
|
+
return realpathSync.native(p);
|
|
94
|
+
} catch {
|
|
95
|
+
return resolve(p);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function rootRelativeKey(rootPath: string, absPath: string): string | null {
|
|
100
|
+
const root = normalizeRealPath(rootPath);
|
|
101
|
+
const abs = normalizeRealPath(absPath);
|
|
102
|
+
const rel = relative(root, abs);
|
|
103
|
+
if (!rel || rel === ".." || rel.startsWith(`..${sepForRelative(rel)}`) || isAbsolute(rel)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
return rel.replace(/\\/g, "/");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function sepForRelative(rel: string): string {
|
|
110
|
+
return rel.includes("\\") ? "\\" : "/";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function deriveCompatProjectionKey(absPath: string, roots: readonly string[]): string {
|
|
114
|
+
for (const root of roots) {
|
|
115
|
+
const key = rootRelativeKey(root, absPath);
|
|
116
|
+
if (key) return key;
|
|
117
|
+
}
|
|
118
|
+
const fallbackRoot = roots[roots.length - 1] ?? dirname(absPath);
|
|
119
|
+
return relative(fallbackRoot, absPath).replace(/\\/g, "/");
|
|
120
|
+
}
|
|
121
|
+
|
|
84
122
|
/**
|
|
85
123
|
* Read & validate the marker. A missing marker → EMPTY_MARKER (treat every
|
|
86
124
|
* projection as external on next reconcile). A malformed marker is quarantined
|
|
@@ -88,7 +126,12 @@ export function computeProjectionSha(content: string): string {
|
|
|
88
126
|
* EMPTY_MARKER. A schema-mismatch returns EMPTY_MARKER (forward-compat: refuse
|
|
89
127
|
* to act on a future format we don't understand).
|
|
90
128
|
*/
|
|
91
|
-
export function readCompatMarker(
|
|
129
|
+
export function readCompatMarker(
|
|
130
|
+
basePath: string,
|
|
131
|
+
options: ReadCompatMarkerOptions = {},
|
|
132
|
+
): CompatMarker {
|
|
133
|
+
const healInvalidKeys = options.healInvalidKeys ?? true;
|
|
134
|
+
const quarantineInvalid = options.quarantineInvalid ?? true;
|
|
92
135
|
const path = compatMarkerPath(basePath);
|
|
93
136
|
if (!existsSync(path)) return emptyMarker();
|
|
94
137
|
|
|
@@ -103,12 +146,16 @@ export function readCompatMarker(basePath: string): CompatMarker {
|
|
|
103
146
|
try {
|
|
104
147
|
parsed = JSON.parse(raw);
|
|
105
148
|
} catch {
|
|
106
|
-
quarantine(basePath, raw);
|
|
149
|
+
if (quarantineInvalid) quarantine(basePath, raw);
|
|
107
150
|
return emptyMarker();
|
|
108
151
|
}
|
|
109
152
|
|
|
153
|
+
if (healInvalidKeys && healMarkerProjectionKeys(basePath, parsed) && isValidMarker(parsed)) {
|
|
154
|
+
writeCompatMarker(basePath, parsed);
|
|
155
|
+
}
|
|
156
|
+
|
|
110
157
|
if (!isValidMarker(parsed)) {
|
|
111
|
-
quarantine(basePath, raw);
|
|
158
|
+
if (quarantineInvalid) quarantine(basePath, raw);
|
|
112
159
|
return emptyMarker();
|
|
113
160
|
}
|
|
114
161
|
// Promote older markers by defaulting absent fields. Schema 1 → 2 only adds
|
|
@@ -245,6 +292,53 @@ function isValidProjectionMap(x: unknown): boolean {
|
|
|
245
292
|
return true;
|
|
246
293
|
}
|
|
247
294
|
|
|
295
|
+
function healMarkerProjectionKeys(basePath: string, marker: unknown): marker is CompatMarker {
|
|
296
|
+
if (typeof marker !== "object" || marker === null) return false;
|
|
297
|
+
const m = marker as Record<string, unknown>;
|
|
298
|
+
let changed = false;
|
|
299
|
+
|
|
300
|
+
if (typeof m.projections === "object" && m.projections !== null) {
|
|
301
|
+
changed = healProjectionMapKeys(basePath, ".gsd", m.projections as Record<string, ProjectionEntry>) || changed;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const planning = m.planning;
|
|
305
|
+
if (typeof planning === "object" && planning !== null) {
|
|
306
|
+
const p = planning as Record<string, unknown>;
|
|
307
|
+
if (typeof p.projections === "object" && p.projections !== null) {
|
|
308
|
+
changed = healProjectionMapKeys(basePath, ".planning", p.projections as Record<string, ProjectionEntry>) || changed;
|
|
309
|
+
}
|
|
310
|
+
if (typeof p.passthrough === "object" && p.passthrough !== null) {
|
|
311
|
+
changed = healProjectionMapKeys(basePath, ".planning", p.passthrough as Record<string, ProjectionEntry>) || changed;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return changed;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function healProjectionMapKeys(
|
|
319
|
+
basePath: string,
|
|
320
|
+
rootName: ".gsd" | ".planning",
|
|
321
|
+
map: Record<string, ProjectionEntry>,
|
|
322
|
+
): boolean {
|
|
323
|
+
let changed = false;
|
|
324
|
+
const root = join(basePath, rootName);
|
|
325
|
+
|
|
326
|
+
for (const key of Object.keys(map)) {
|
|
327
|
+
if (isSafeProjectionKey(key)) continue;
|
|
328
|
+
if (key.includes("\0") || isAbsolute(key) || /^[A-Za-z]:/.test(key)) continue;
|
|
329
|
+
const healedKey = rootRelativeKey(root, resolve(root, key));
|
|
330
|
+
if (!healedKey || !isSafeProjectionKey(healedKey)) continue;
|
|
331
|
+
|
|
332
|
+
if (!map[healedKey]) {
|
|
333
|
+
map[healedKey] = map[key]!;
|
|
334
|
+
}
|
|
335
|
+
delete map[key];
|
|
336
|
+
changed = true;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return changed;
|
|
340
|
+
}
|
|
341
|
+
|
|
248
342
|
function isValidPlanningMarker(x: unknown): x is PlanningMarker {
|
|
249
343
|
if (typeof x !== "object" || x === null) return false;
|
|
250
344
|
const p = x as Record<string, unknown>;
|
|
@@ -31,36 +31,37 @@ export const CACHE_MAX = 50;
|
|
|
31
31
|
* By scoping tools to this allowlist during discuss dispatches, the grammar
|
|
32
32
|
* sent to the provider stays well under provider limits.
|
|
33
33
|
*
|
|
34
|
-
* Included tools and why
|
|
34
|
+
* Included tools and why (canonical names only — aliases are no longer
|
|
35
|
+
* advertised to models by default, see plan 035):
|
|
35
36
|
* - gsd_summary_save: writes CONTEXT.md artifacts (all discuss prompts)
|
|
36
|
-
* - gsd_save_summary: alias for above
|
|
37
37
|
* - gsd_decision_save: records decisions (discuss.md output phase)
|
|
38
|
-
* - gsd_save_decision: alias for above
|
|
39
38
|
* - gsd_plan_milestone: writes roadmap (discuss.md single/multi milestone)
|
|
40
|
-
* - gsd_milestone_plan: alias for above
|
|
41
39
|
* - gsd_milestone_generate_id: generates milestone IDs (discuss.md multi-milestone)
|
|
42
|
-
* - gsd_generate_milestone_id: alias for above
|
|
43
40
|
* - gsd_requirement_save: creates requirements during discuss
|
|
44
|
-
* - gsd_save_requirement: alias for above
|
|
45
41
|
* - gsd_requirement_update: updates requirements during discuss
|
|
46
|
-
* - gsd_update_requirement: alias for above
|
|
47
42
|
*/
|
|
48
43
|
export const DISCUSS_TOOLS_ALLOWLIST: readonly string[] = [
|
|
49
44
|
// Context / summary writing
|
|
50
45
|
"gsd_summary_save",
|
|
51
|
-
"gsd_save_summary",
|
|
52
46
|
// Decision recording
|
|
53
47
|
"gsd_decision_save",
|
|
54
|
-
"gsd_save_decision",
|
|
55
48
|
// Milestone planning (needed for discuss.md output phase)
|
|
56
49
|
"gsd_plan_milestone",
|
|
57
|
-
"gsd_milestone_plan",
|
|
58
50
|
// Milestone ID generation (multi-milestone flow)
|
|
59
51
|
"gsd_milestone_generate_id",
|
|
60
|
-
"gsd_generate_milestone_id",
|
|
61
52
|
// Requirement updates
|
|
62
53
|
"gsd_requirement_save",
|
|
63
|
-
"gsd_save_requirement",
|
|
64
54
|
"gsd_requirement_update",
|
|
65
|
-
"gsd_update_requirement",
|
|
66
55
|
];
|
|
56
|
+
|
|
57
|
+
// ─── Context Injection ────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Leading marker stamped on every buildContextMessage() output
|
|
61
|
+
* (bootstrap/system-context.ts). Single source of truth for the producer and
|
|
62
|
+
* the consumer: the provider payload policy (filterSupersededContextInjections
|
|
63
|
+
* in context-masker.ts) matches this prefix to find and dedupe injected
|
|
64
|
+
* memory/guided/forensics messages after convertToLlm strips their customType.
|
|
65
|
+
* Both sides import it from here — do not inline the literal in either module.
|
|
66
|
+
*/
|
|
67
|
+
export const GSD_CONTEXT_MESSAGE_SENTINEL = "[GSD Context Injection]";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { GSD_CONTEXT_MESSAGE_SENTINEL } from "./constants.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Observation masking for GSD auto-mode sessions.
|
|
3
5
|
*
|
|
@@ -75,6 +77,26 @@ function findTurnBoundary(messages: MaskableMessage[], keepRecentTurns: number):
|
|
|
75
77
|
return 0;
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
function countRealUserTurns(messages: MaskableMessage[]): number {
|
|
81
|
+
let count = 0;
|
|
82
|
+
for (const m of messages) {
|
|
83
|
+
if (m.role === "user" && !isBashResultUserMessage(m)) count++;
|
|
84
|
+
}
|
|
85
|
+
return count;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Quantizes how many recent turns stay unmasked so the boundary only moves
|
|
90
|
+
* forward once per full block of `keepRecentTurns` new turns, instead of
|
|
91
|
+
* every turn. Keeps the masked prefix byte-stable within a block, which is
|
|
92
|
+
* what lets the LLM provider's prompt cache survive across turns.
|
|
93
|
+
*/
|
|
94
|
+
function quantizedKeepTurns(totalTurns: number, keepRecentTurns: number): number {
|
|
95
|
+
if (keepRecentTurns <= 0 || totalTurns < 2 * keepRecentTurns) return totalTurns;
|
|
96
|
+
const maskedTurns = Math.floor((totalTurns - keepRecentTurns) / keepRecentTurns) * keepRecentTurns;
|
|
97
|
+
return totalTurns - maskedTurns;
|
|
98
|
+
}
|
|
99
|
+
|
|
78
100
|
/**
|
|
79
101
|
* Detect user messages that originated from bashExecution.
|
|
80
102
|
* After convertToLlm, these are {role: "user", content: [{type:"text", text:"Ran `cmd`\n..."}]}.
|
|
@@ -95,7 +117,8 @@ function isMaskableMessage(m: MaskableMessage): boolean {
|
|
|
95
117
|
|
|
96
118
|
export function createObservationMask(keepRecentTurns: number = 8) {
|
|
97
119
|
return (messages: MaskableMessage[]): MaskableMessage[] => {
|
|
98
|
-
const
|
|
120
|
+
const totalTurns = countRealUserTurns(messages);
|
|
121
|
+
const boundary = findTurnBoundary(messages, quantizedKeepTurns(totalTurns, keepRecentTurns));
|
|
99
122
|
if (boundary === 0) return messages;
|
|
100
123
|
|
|
101
124
|
return messages.map((m, i) => {
|
|
@@ -126,6 +149,14 @@ function findResponsesTurnBoundary(items: ResponsesInputItem[], keepRecentTurns:
|
|
|
126
149
|
return 0;
|
|
127
150
|
}
|
|
128
151
|
|
|
152
|
+
function countResponsesRealUserTurns(items: ResponsesInputItem[]): number {
|
|
153
|
+
let count = 0;
|
|
154
|
+
for (const item of items) {
|
|
155
|
+
if (item.role === "user" && !isResponsesBashResultUserItem(item)) count++;
|
|
156
|
+
}
|
|
157
|
+
return count;
|
|
158
|
+
}
|
|
159
|
+
|
|
129
160
|
/**
|
|
130
161
|
* Observation masking for OpenAI/Codex Responses API payloads.
|
|
131
162
|
*
|
|
@@ -135,7 +166,8 @@ function findResponsesTurnBoundary(items: ResponsesInputItem[], keepRecentTurns:
|
|
|
135
166
|
*/
|
|
136
167
|
export function createResponsesInputObservationMask(keepRecentTurns: number = 8) {
|
|
137
168
|
return (items: ResponsesInputItem[]): ResponsesInputItem[] => {
|
|
138
|
-
const
|
|
169
|
+
const totalTurns = countResponsesRealUserTurns(items);
|
|
170
|
+
const boundary = findResponsesTurnBoundary(items, quantizedKeepTurns(totalTurns, keepRecentTurns));
|
|
139
171
|
if (boundary === 0) return items;
|
|
140
172
|
|
|
141
173
|
return items.map((item, i) => {
|
|
@@ -219,3 +251,67 @@ export function truncateResponsesInputResultItems(items: ResponsesInputItem[], m
|
|
|
219
251
|
return item;
|
|
220
252
|
});
|
|
221
253
|
}
|
|
254
|
+
|
|
255
|
+
// GSD injects at most one context message per turn (memory/guided/forensics —
|
|
256
|
+
// see buildContextMessage in bootstrap/system-context.ts), marked with
|
|
257
|
+
// GSD_CONTEXT_MESSAGE_SENTINEL. convertToLlm strips the distinguishing
|
|
258
|
+
// customType before the payload reaches this hook, so detection is by content
|
|
259
|
+
// prefix instead. Pre-sentinel session history lacks the sentinel, so we also
|
|
260
|
+
// match the stable *bracketed* GSD block labels those injections begin with,
|
|
261
|
+
// letting resumed sessions dedupe older memory/guided blocks.
|
|
262
|
+
//
|
|
263
|
+
// Only GSD-specific bracketed markers belong here — never generic prose. A
|
|
264
|
+
// message is dropped from the payload when it matches, so a natural-language
|
|
265
|
+
// prefix (e.g. the forensics prompt "Debug GSD itself.") could silently delete
|
|
266
|
+
// a real user message that happens to start the same way. Legacy forensics
|
|
267
|
+
// injections without memory are therefore left un-deduped by design; those
|
|
268
|
+
// with memory still match via the "[GSD Context Metadata]" wrapper.
|
|
269
|
+
const LEGACY_GSD_CONTEXT_INJECTION_PREFIXES = [
|
|
270
|
+
"[GSD Context Metadata]",
|
|
271
|
+
"[MEMORY — Critical and prompt-relevant memories from the GSD memory store]",
|
|
272
|
+
"[GSD Guided Execute Context]",
|
|
273
|
+
] as const;
|
|
274
|
+
|
|
275
|
+
function isGsdContextInjectionText(text: string | undefined): boolean {
|
|
276
|
+
if (typeof text !== "string") return false;
|
|
277
|
+
if (text.startsWith(GSD_CONTEXT_MESSAGE_SENTINEL)) return true;
|
|
278
|
+
return LEGACY_GSD_CONTEXT_INJECTION_PREFIXES.some((prefix) => text.startsWith(prefix));
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function isGsdContextInjectionMessage(m: MaskableMessage): boolean {
|
|
282
|
+
if (m.role !== "user") return false;
|
|
283
|
+
return isGsdContextInjectionText(firstTextFromContent(m.content));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Removes every GSD context-injection user message except the latest one.
|
|
288
|
+
* Each turn re-injects a near-identical memory/guided/forensics block; left
|
|
289
|
+
* in place they duplicate verbatim across an N-turn session. Removal (not
|
|
290
|
+
* masking) — an empty placeholder still costs tokens and shifts message
|
|
291
|
+
* positions, breaking cache byte-stability. Pure function: stored history is
|
|
292
|
+
* never mutated, only the outgoing payload array.
|
|
293
|
+
*/
|
|
294
|
+
export function filterSupersededContextInjections(messages: MaskableMessage[]): MaskableMessage[] {
|
|
295
|
+
let lastIndex = -1;
|
|
296
|
+
for (let i = 0; i < messages.length; i++) {
|
|
297
|
+
if (isGsdContextInjectionMessage(messages[i])) lastIndex = i;
|
|
298
|
+
}
|
|
299
|
+
if (lastIndex === -1) return messages;
|
|
300
|
+
return messages.filter((m, i) => i === lastIndex || !isGsdContextInjectionMessage(m));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function isResponsesGsdContextInjectionItem(item: ResponsesInputItem): boolean {
|
|
304
|
+
if (item.role !== "user") return false;
|
|
305
|
+
return isGsdContextInjectionText(firstTextFromContent(item.content));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
export function filterSupersededResponsesContextInjections(
|
|
309
|
+
items: ResponsesInputItem[],
|
|
310
|
+
): ResponsesInputItem[] {
|
|
311
|
+
let lastIndex = -1;
|
|
312
|
+
for (let i = 0; i < items.length; i++) {
|
|
313
|
+
if (isResponsesGsdContextInjectionItem(items[i])) lastIndex = i;
|
|
314
|
+
}
|
|
315
|
+
if (lastIndex === -1) return items;
|
|
316
|
+
return items.filter((item, i) => i === lastIndex || !isResponsesGsdContextInjectionItem(item));
|
|
317
|
+
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// writer layer.
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
|
|
13
|
-
import { dirname, join } from "node:path";
|
|
13
|
+
import { dirname, join, resolve } from "node:path";
|
|
14
14
|
import { GSDError, GSD_STALE_STATE } from "../errors.js";
|
|
15
15
|
import type { GsdWorkspace, MilestoneScope } from "../workspace.js";
|
|
16
16
|
import { logError, logWarning } from "../workflow-logger.js";
|
|
@@ -71,7 +71,10 @@ let _gsdRequire: ReturnType<typeof createRequire> | null | undefined;
|
|
|
71
71
|
function getGsdRequire(): ReturnType<typeof createRequire> | null {
|
|
72
72
|
if (_gsdRequire !== undefined) return _gsdRequire;
|
|
73
73
|
try {
|
|
74
|
-
|
|
74
|
+
// Next.js may emit this module into a CommonJS chunk. Avoid ESM-only module
|
|
75
|
+
// metadata syntax here; it is a hard parse error there.
|
|
76
|
+
const packageRoot = process.env.GSD_WEB_PACKAGE_ROOT || process.env.GSD_PKG_ROOT || process.cwd();
|
|
77
|
+
_gsdRequire = createRequire(resolve(packageRoot, "package.json"));
|
|
75
78
|
} catch {
|
|
76
79
|
_gsdRequire = null;
|
|
77
80
|
}
|
|
@@ -124,11 +124,11 @@ Diagnostics record the file path, scope (global/project), severity (error/warnin
|
|
|
124
124
|
- `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.
|
|
125
125
|
- `uat` — used for UAT runs. Falls back to `completion` if unset.
|
|
126
126
|
|
|
127
|
-
- `thinking`: per-phase reasoning effort (ADR-026), separate from `models`. Same phase keys as `models`. Values: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. Thinking travels with the model — model choice and reasoning effort are independent controls, so you can run one model across phases at different reasoning levels.
|
|
127
|
+
- `thinking`: per-phase reasoning effort (ADR-026), separate from `models`. Same phase keys as `models`. Values: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Thinking travels with the model — model choice and reasoning effort are independent controls, so you can run one model across phases at different reasoning levels.
|
|
128
128
|
- Two equivalent ways to set it: inline as `models.<phase>.thinking`, or as a separate `thinking:` block keyed by phase. For the same phase, the inline value wins over the block; project preferences win over global; a phase that's unset inherits via the same sibling chain as `models` (e.g. `discuss → planning`).
|
|
129
129
|
- If no thinking is configured for a phase, the session level (set via `/model`) is used, exactly as before — this is fully backward-compatible.
|
|
130
130
|
- `execute-task` (code-writing) has a measured reasoning floor of `medium`: at lower levels models stop planning edits and thrash on file re-reads. The floor applies to the session/default path. An **explicit** `execution` thinking level bypasses the floor and is honored verbatim (with a one-time advisory) — set `execution: low` deliberately if you want it.
|
|
131
|
-
- Levels a model can't support are clamped to the nearest supported level at dispatch and never sent to the provider, so a model/level mismatch never fails a unit mid-run. `xhigh` support
|
|
131
|
+
- Levels a model can't support are clamped to the nearest supported level at dispatch and never sent to the provider, so a model/level mismatch never fails a unit mid-run. `xhigh` and `max` support are model-dependent; current examples include `gpt-5.6-sol`, `gpt-5.6-terra`, and `gpt-5.6-luna`, which advertise both.
|
|
132
132
|
|
|
133
133
|
- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.
|
|
134
134
|
|
|
@@ -357,6 +357,37 @@ In `"parent"` mode, slice/task `targetRepositories` default to the declared chil
|
|
|
357
357
|
- `"replace"` requires `prompt`.
|
|
358
358
|
- `"skip"` is valid with no additional fields.
|
|
359
359
|
|
|
360
|
+
- `planning_subagent_registry`: object — optional classification for custom planning agents. Each key is an agent id and must set:
|
|
361
|
+
- `read_only_specialist`: boolean — set to `true` to classify the custom agent as safe for planning dispatch.
|
|
362
|
+
|
|
363
|
+
- `planning_subagents`: object — project-local widening for read-only planning subagent dispatch. Supported unit keys are `plan-milestone` and `plan-slice`; each has:
|
|
364
|
+
- `allowed`: string[] — additional planning-safe agents for that unit.
|
|
365
|
+
|
|
366
|
+
Agents must be built-in read-only planning specialists (`mnemo`, `scout`, `planner`, `reviewer`, `security`, or `tester`) or registered in `planning_subagent_registry` with `read_only_specialist: true`. The write gate still blocks source writes outside `.gsd/**`, unrestricted bash, stale subagent calls without agent identities, agents outside the read-only registry, and agents not listed for the active unit.
|
|
367
|
+
|
|
368
|
+
Example:
|
|
369
|
+
|
|
370
|
+
```yaml
|
|
371
|
+
planning_subagent_registry:
|
|
372
|
+
my-custom-planner:
|
|
373
|
+
read_only_specialist: true
|
|
374
|
+
|
|
375
|
+
planning_subagents:
|
|
376
|
+
plan-milestone:
|
|
377
|
+
allowed:
|
|
378
|
+
- scout
|
|
379
|
+
- planner
|
|
380
|
+
- my-custom-planner
|
|
381
|
+
- security
|
|
382
|
+
plan-slice:
|
|
383
|
+
allowed:
|
|
384
|
+
- scout
|
|
385
|
+
- planner
|
|
386
|
+
- my-custom-planner
|
|
387
|
+
- reviewer
|
|
388
|
+
- security
|
|
389
|
+
```
|
|
390
|
+
|
|
360
391
|
**Known unit types for `before`/`after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`.
|
|
361
392
|
|
|
362
393
|
- `experimental`: opt-in experimental features. All features here are **off by default** — you must explicitly set each one to `true` to enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:
|
|
@@ -15,13 +15,13 @@ import {
|
|
|
15
15
|
import { MEMORIES_FTS_REBUILT_KEY } from "./db-memory-fts-schema.js";
|
|
16
16
|
import { isAfter, latestExplicitReopenAt } from "./milestone-reopen-events.js";
|
|
17
17
|
import {
|
|
18
|
-
buildTaskFileName,
|
|
19
18
|
gsdProjectionRoot,
|
|
20
19
|
gsdRoot,
|
|
21
20
|
resolveGsdPathContract,
|
|
22
21
|
resolveMilestoneFile,
|
|
23
22
|
resolveMilestonePath,
|
|
24
23
|
resolveSliceFile,
|
|
24
|
+
resolveTaskFile,
|
|
25
25
|
} from "./paths.js";
|
|
26
26
|
import { deriveState } from "./state.js";
|
|
27
27
|
import { isClosedStatus } from "./status-guards.js";
|
|
@@ -32,6 +32,7 @@ import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
|
32
32
|
import { parsePlan } from "./parsers-legacy.js";
|
|
33
33
|
import { parseSummary } from "./files.js";
|
|
34
34
|
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
35
|
+
import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
|
|
35
36
|
|
|
36
37
|
const USER_AUTHORED_ARTIFACT_TYPES = new Set(["CONTEXT", "RESEARCH"]);
|
|
37
38
|
|
|
@@ -95,9 +96,29 @@ function reportCheckboxDbStatusDivergence(
|
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
98
|
|
|
99
|
+
function bareDuplicateMilestoneId(milestoneId: string): string | null {
|
|
100
|
+
const match = milestoneId.match(/^(M\d{3})-[a-z0-9]{6}$/i);
|
|
101
|
+
return match?.[1]?.toUpperCase() ?? null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function checkboxDbStatusMilestoneIds(basePath: string, milestoneIds: string[]): string[] {
|
|
105
|
+
if (!hasFlatPhaseLayout(basePath)) return milestoneIds;
|
|
106
|
+
|
|
107
|
+
// Flat-phase directories are keyed by phase number. A restored
|
|
108
|
+
// M003-xxxxxx row alongside M003 is a stale duplicate for the same
|
|
109
|
+
// phases/03-* projection, so checking both can compare DB status against two
|
|
110
|
+
// competing PLAN files and report a persistent false divergence.
|
|
111
|
+
const allIds = new Set(milestoneIds.map((id) => id.toUpperCase()));
|
|
112
|
+
return milestoneIds.filter((milestoneId) => {
|
|
113
|
+
const bareId = bareDuplicateMilestoneId(milestoneId);
|
|
114
|
+
return !bareId || !allIds.has(bareId);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
98
118
|
function checkProjectionCheckboxDbStatus(basePath: string, milestoneIds: string[], issues: DoctorIssue[]): void {
|
|
99
119
|
for (const milestoneId of milestoneIds) {
|
|
100
|
-
const
|
|
120
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, milestoneId);
|
|
121
|
+
const roadmapPath = resolveMilestoneFile(artifactBasePath, milestoneId, "ROADMAP");
|
|
101
122
|
const slices = getMilestoneSlices(milestoneId);
|
|
102
123
|
|
|
103
124
|
if (roadmapPath && existsSync(roadmapPath)) {
|
|
@@ -123,7 +144,7 @@ function checkProjectionCheckboxDbStatus(basePath: string, milestoneIds: string[
|
|
|
123
144
|
}
|
|
124
145
|
|
|
125
146
|
for (const slice of slices) {
|
|
126
|
-
const planPath = resolveSliceFile(
|
|
147
|
+
const planPath = resolveSliceFile(artifactBasePath, milestoneId, slice.id, "PLAN");
|
|
127
148
|
if (!planPath || !existsSync(planPath)) continue;
|
|
128
149
|
try {
|
|
129
150
|
const plan = readFileSync(planPath, "utf-8");
|
|
@@ -173,7 +194,7 @@ function artifactExistsOnDisk(basePath: string, artifactPath: string, row?: Arti
|
|
|
173
194
|
return resolveArtifactDiskPath(basePath, artifactPath, row) !== null;
|
|
174
195
|
}
|
|
175
196
|
|
|
176
|
-
function resolveLiteralArtifactDiskPath(basePath: string, artifactPath: string): string | null {
|
|
197
|
+
function resolveLiteralArtifactDiskPath(basePath: string, artifactPath: string, row?: ArtifactRow): string | null {
|
|
177
198
|
const relativeArtifactPath = artifactPathRelativeToGsd(artifactPath);
|
|
178
199
|
if (isAbsolute(relativeArtifactPath)) {
|
|
179
200
|
return existsSync(relativeArtifactPath) ? relativeArtifactPath : null;
|
|
@@ -182,6 +203,15 @@ function resolveLiteralArtifactDiskPath(basePath: string, artifactPath: string):
|
|
|
182
203
|
const candidate = join(root, relativeArtifactPath);
|
|
183
204
|
if (isPathInside(root, candidate) && existsSync(candidate)) return candidate;
|
|
184
205
|
}
|
|
206
|
+
if (row?.milestone_id) {
|
|
207
|
+
const artifactBasePath = resolveCanonicalMilestoneRoot(basePath, row.milestone_id);
|
|
208
|
+
if (artifactBasePath !== basePath) {
|
|
209
|
+
for (const root of [gsdProjectionRoot(artifactBasePath), gsdRoot(artifactBasePath)]) {
|
|
210
|
+
const candidate = join(root, relativeArtifactPath);
|
|
211
|
+
if (isPathInside(root, candidate) && existsSync(candidate)) return candidate;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
185
215
|
return null;
|
|
186
216
|
}
|
|
187
217
|
|
|
@@ -208,10 +238,8 @@ function resolveFlatPhaseArtifactDiskPath(basePath: string, row: ArtifactRow): s
|
|
|
208
238
|
if (!artifactType) return null;
|
|
209
239
|
|
|
210
240
|
if (row.slice_id && row.task_id) {
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
const candidate = join(phaseDir, buildTaskFileName(row.task_id, artifactType));
|
|
214
|
-
return existsSync(candidate) ? candidate : null;
|
|
241
|
+
const candidate = resolveTaskFile(basePath, row.milestone_id, row.slice_id, row.task_id, artifactType);
|
|
242
|
+
return candidate && isFlatPhaseDiskPath(basePath, candidate) ? candidate : null;
|
|
215
243
|
}
|
|
216
244
|
|
|
217
245
|
const candidate = row.slice_id
|
|
@@ -226,7 +254,7 @@ function resolveArtifactDiskPath(basePath: string, artifactPath: string, row?: A
|
|
|
226
254
|
const flatPath = resolveFlatPhaseArtifactDiskPath(basePath, row);
|
|
227
255
|
if (flatPath) return flatPath;
|
|
228
256
|
}
|
|
229
|
-
return resolveLiteralArtifactDiskPath(basePath, artifactPath);
|
|
257
|
+
return resolveLiteralArtifactDiskPath(basePath, artifactPath, row);
|
|
230
258
|
}
|
|
231
259
|
|
|
232
260
|
function taskExistsInPlan(basePath: string, milestoneId: string, sliceId: string, taskId: string): boolean {
|
|
@@ -436,7 +464,9 @@ function staleMilestonesArtifactRowFixable(basePath: string, row: ArtifactRow, a
|
|
|
436
464
|
|
|
437
465
|
function stalePhasesArtifactRowFixable(basePath: string, row: ArtifactRow, artifactRows: ArtifactRow[]): boolean {
|
|
438
466
|
const issuePath = artifactPathRelativeToGsd(row.path);
|
|
439
|
-
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) &&
|
|
467
|
+
return issuePath.startsWith(`${LAYOUT_SEGMENTS.level1}/`) &&
|
|
468
|
+
(hasPresentFlatPhaseReplacement(basePath, row, artifactRows) ||
|
|
469
|
+
hasPresentMilestonesReplacement(basePath, row, artifactRows));
|
|
440
470
|
}
|
|
441
471
|
|
|
442
472
|
function staleArtifactRowFixable(basePath: string, row: ArtifactRow, artifactRows: ArtifactRow[]): boolean {
|
|
@@ -809,7 +839,11 @@ export async function checkEngineHealth(
|
|
|
809
839
|
// block doctor.
|
|
810
840
|
try {
|
|
811
841
|
if (isDbAvailable()) {
|
|
812
|
-
checkProjectionCheckboxDbStatus(
|
|
842
|
+
checkProjectionCheckboxDbStatus(
|
|
843
|
+
basePath,
|
|
844
|
+
checkboxDbStatusMilestoneIds(basePath, getAllMilestones().map((milestone) => milestone.id)),
|
|
845
|
+
issues,
|
|
846
|
+
);
|
|
813
847
|
}
|
|
814
848
|
} catch {
|
|
815
849
|
// Non-fatal: checkbox-vs-DB divergence check must never block doctor
|
|
@@ -65,8 +65,12 @@ const NETWORK_RE = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|web
|
|
|
65
65
|
// transient errors so auto-mode can retry with reduced budget or fall back to a larger-context model.
|
|
66
66
|
// See: https://github.com/open-gsd/gsd-pi/issues/4528
|
|
67
67
|
const SERVER_RE = /internal(?: server)?[ _-]?error|server[ _-]?error|500|502|503|overloaded|server_error|api_error|service.?unavailable|context (?:window|length) exceed|context window exceed/i;
|
|
68
|
+
// Provider adapters throw this when an upstream stop reason reaches Pi before
|
|
69
|
+
// the adapter knows how to map it. Keep the match scoped so plain "unknown"
|
|
70
|
+
// runtime errors still pause for inspection instead of being retried forever.
|
|
71
|
+
const PROVIDER_STOP_REASON_RE = /unhandled stop reason:\s*(?:abort|unknown)\b/i;
|
|
68
72
|
// ECONNRESET/ECONNREFUSED are in NETWORK_RE (same-model retry first).
|
|
69
|
-
const CONNECTION_RE = /terminated|connection.?(?:refused|error)|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
|
|
73
|
+
const CONNECTION_RE = /terminated|\babort\b|connection.?(?:refused|error)|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
|
|
70
74
|
// Catch-all for V8 JSON.parse errors: all modern variants end with "in JSON at position \d+".
|
|
71
75
|
// This eliminates the need to enumerate every error message variant individually.
|
|
72
76
|
const STREAM_RE = /in JSON at position \d+|Unexpected end of JSON|SyntaxError.*JSON/i;
|
|
@@ -103,7 +107,7 @@ const UNSUPPORTED_MODEL_SCOPE_RE = /\b(?:account|plan|tier|subscription)\b/i;
|
|
|
103
107
|
* 3. Network (ECONNRESET, ETIMEDOUT, socket hang up, fetch failed, dns)
|
|
104
108
|
* 4. Stream truncation (malformed JSON from mid-stream cut)
|
|
105
109
|
* 5. Server (500/502/503, overloaded, server_error)
|
|
106
|
-
* 6. Connection (terminated, ECONNREFUSED, EPIPE, other side closed)
|
|
110
|
+
* 6. Connection (terminated, abort/unknown stop reason, ECONNREFUSED, EPIPE, other side closed)
|
|
107
111
|
* 7. Model error (400 invalid argument / payload rejected for this model)
|
|
108
112
|
* 8. Unknown
|
|
109
113
|
*/
|
|
@@ -163,6 +167,13 @@ export function classifyError(errorMsg: string, retryAfterMs?: number): ErrorCla
|
|
|
163
167
|
return { kind: "rate-limit", retryAfterMs: delayMs };
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
// Provider stop-reason adapter gaps are usually request/stream failures from
|
|
171
|
+
// the current model. Treat the scoped adapter message as fallback-eligible,
|
|
172
|
+
// but keep generic unknown errors on the indefinite pause path.
|
|
173
|
+
if (PROVIDER_STOP_REASON_RE.test(errorMsg)) {
|
|
174
|
+
return { kind: "connection", retryAfterMs: retryAfterMs ?? 15_000 };
|
|
175
|
+
}
|
|
176
|
+
|
|
166
177
|
// 3. Network errors — same-model retry candidate
|
|
167
178
|
if (NETWORK_RE.test(errorMsg)) {
|
|
168
179
|
// Exclude if also matches permanent signals (already handled above for
|
|
@@ -155,6 +155,19 @@ function isInsideFlatProjectionBackup(backupDir: string, src: string): boolean {
|
|
|
155
155
|
return src === phaseBackupDir || src.startsWith(`${phaseBackupDir}/`) || src.startsWith(`${phaseBackupDir}\\`);
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function removeFlatProjectionBackup(backupDir: string): void {
|
|
159
|
+
const phaseBackupDir = join(backupDir, "__phases");
|
|
160
|
+
if (!existsSync(phaseBackupDir)) return;
|
|
161
|
+
try {
|
|
162
|
+
removePathWithRetries(phaseBackupDir);
|
|
163
|
+
} catch (err) {
|
|
164
|
+
logWarning(
|
|
165
|
+
"migration",
|
|
166
|
+
`flat-phase migration succeeded but could not remove temporary ${LAYOUT_SEGMENTS.level1}/ backup: ${(err as Error).message}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
158
171
|
function restoreFlatProjectionFromBackup(basePath: string, backupDir: string): void {
|
|
159
172
|
const phaseBackupDir = join(backupDir, "__phases");
|
|
160
173
|
if (!existsSync(phaseBackupDir)) return;
|
|
@@ -494,4 +507,5 @@ export async function migrateToFlatPhase(basePath: string): Promise<void> {
|
|
|
494
507
|
`flat-phase migration succeeded but could not remove ${LEGACY_MIGRATING_SEGMENT}: ${(err as Error).message}`,
|
|
495
508
|
);
|
|
496
509
|
}
|
|
510
|
+
removeFlatProjectionBackup(backupDir);
|
|
497
511
|
}
|
|
@@ -385,10 +385,16 @@ const runtimeFilesCleanedUpRepos = new Set<string>();
|
|
|
385
385
|
// ─── Integration Branch Metadata ───────────────────────────────────────────
|
|
386
386
|
|
|
387
387
|
/**
|
|
388
|
-
* Path to the milestone metadata file
|
|
389
|
-
* Format: .gsd
|
|
388
|
+
* Path to the milestone integration-branch metadata file.
|
|
389
|
+
* Format: .gsd/<MID>-META.json (deliberately OUTSIDE milestones/<MID>/ so it
|
|
390
|
+
* cannot poison isLegacyMilestonesLayout — see ADR-045).
|
|
390
391
|
*/
|
|
391
|
-
function milestoneMetaPath(basePath: string, milestoneId: string): string {
|
|
392
|
+
export function milestoneMetaPath(basePath: string, milestoneId: string): string {
|
|
393
|
+
return join(gsdRoot(basePath), `${milestoneId}-META.json`);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Legacy location (pre-ADR-045). Read-only fallback for existing on-disk trees. */
|
|
397
|
+
function legacyMilestoneMetaPath(basePath: string, milestoneId: string): string {
|
|
392
398
|
return join(gsdRoot(basePath), "milestones", milestoneId, `${milestoneId}-META.json`);
|
|
393
399
|
}
|
|
394
400
|
|
|
@@ -398,8 +404,12 @@ function milestoneMetaPath(basePath: string, milestoneId: string): string {
|
|
|
398
404
|
*/
|
|
399
405
|
export function readIntegrationBranch(basePath: string, milestoneId: string): string | null {
|
|
400
406
|
try {
|
|
401
|
-
|
|
402
|
-
if (!existsSync(metaFile))
|
|
407
|
+
let metaFile = milestoneMetaPath(basePath, milestoneId);
|
|
408
|
+
if (!existsSync(metaFile)) {
|
|
409
|
+
const legacy = legacyMilestoneMetaPath(basePath, milestoneId);
|
|
410
|
+
if (!existsSync(legacy)) return null;
|
|
411
|
+
metaFile = legacy;
|
|
412
|
+
}
|
|
403
413
|
const data = JSON.parse(readFileSync(metaFile, "utf-8"));
|
|
404
414
|
const branch = data?.integrationBranch;
|
|
405
415
|
if (typeof branch === "string" && branch.trim() !== "" && VALID_BRANCH_NAME.test(branch)) {
|
|
@@ -451,7 +461,10 @@ export function writeIntegrationBranch(
|
|
|
451
461
|
if (existingBranch === branch) return;
|
|
452
462
|
|
|
453
463
|
const metaFile = milestoneMetaPath(basePath, milestoneId);
|
|
454
|
-
|
|
464
|
+
// Ensure the flat .gsd/ root exists (never milestones/<MID>/ — that would
|
|
465
|
+
// poison layout detection, ADR-045). In production .gsd/ already exists; this
|
|
466
|
+
// guards fresh trees so the write below can't ENOENT.
|
|
467
|
+
mkdirSync(gsdRoot(basePath), { recursive: true });
|
|
455
468
|
|
|
456
469
|
// Merge with existing metadata if present
|
|
457
470
|
let existing: Record<string, unknown> = {};
|