@opengsd/gsd-pi 1.8.1 → 1.9.0-dev.5c1a3ff2
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 -8
- 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 +18 -49
- 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/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +16 -10
- 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 +125 -18
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +80 -4
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +31 -5
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +88 -50
- 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/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- 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 +26 -4
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +3 -6
- package/dist/resources/extensions/gsd/flat-phase-migration.js +156 -21
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +187 -45
- package/dist/resources/extensions/gsd/guided-flow.js +38 -13
- package/dist/resources/extensions/gsd/markdown-renderer.js +17 -13
- package/dist/resources/extensions/gsd/md-importer.js +107 -20
- 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 +12 -17
- package/dist/resources/extensions/gsd/migrate/presentation.js +64 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
- package/dist/resources/extensions/gsd/model-router.js +11 -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 +55 -11
- package/dist/resources/extensions/gsd/phase-anchor.js +7 -2
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
- package/dist/resources/extensions/gsd/post-execution-checks.js +4 -4
- package/dist/resources/extensions/gsd/preferences-types.js +5 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
- package/dist/resources/extensions/gsd/preferences.js +17 -0
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- 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/safety/evidence-collector.js +26 -1
- package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +30 -5
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- 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/stop-notice.js +15 -1
- package/dist/resources/extensions/gsd/sync-lock.js +13 -7
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +94 -6
- 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/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/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-context-composer.js +28 -5
- 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/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- 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 +8 -8
- 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 +8 -8
- package/dist/web/standalone/.next/server/chunks/2842.js +4 -4
- package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +3 -3
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/app/_not-found/page-a6fb1847f67f167c.js +1 -0
- package/dist/web/standalone/.next/static/chunks/app/{layout-b35cbfff38aaf4cf.js → layout-4ae2d68984392bbf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-72a856634ad14c10.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{main-app-590a74400e35f685.js → main-app-90d1d8d5e5d2dc6b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-1115d46ac61b9823.js +1 -0
- package/dist/web/standalone/.next/static/css/3b1ceb7abfb9a230.css +1 -0
- package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/package.json +0 -1
- package/dist/web/standalone/server.js +1 -1
- package/dist/web-mode.js +31 -3
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +12 -10
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/dist/cloud-config.d.ts +1 -1
- package/packages/daemon/dist/cloud-config.d.ts.map +1 -1
- package/packages/daemon/dist/cloud-config.js +5 -1
- package/packages/daemon/dist/cloud-config.js.map +1 -1
- package/packages/daemon/dist/cloud-config.test.js +51 -1
- package/packages/daemon/dist/cloud-config.test.js.map +1 -1
- package/packages/daemon/dist/local-tool-executor.d.ts.map +1 -1
- package/packages/daemon/dist/local-tool-executor.js +2 -0
- package/packages/daemon/dist/local-tool-executor.js.map +1 -1
- package/packages/daemon/package.json +6 -6
- package/packages/gsd-agent-core/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/package.json +7 -7
- package/packages/gsd-cloud/dist/cli.d.ts +5 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cli.js +160 -0
- package/packages/gsd-cloud/dist/cli.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts +19 -0
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.js +231 -0
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-config.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js +118 -0
- package/packages/gsd-cloud/dist/cloud-config.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js +37 -0
- package/packages/gsd-cloud/dist/cloud-gateway-lookup.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +35 -0
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js +258 -0
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js +88 -0
- package/packages/gsd-cloud/dist/cloud-runtime.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts +3 -0
- package/packages/gsd-cloud/dist/cloud-token.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/cloud-token.js +37 -0
- package/packages/gsd-cloud/dist/cloud-token.js.map +1 -0
- package/packages/gsd-cloud/dist/config.d.ts +17 -0
- package/packages/gsd-cloud/dist/config.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/config.js +146 -0
- package/packages/gsd-cloud/dist/config.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts +24 -0
- package/packages/gsd-cloud/dist/device-flow.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.js +128 -0
- package/packages/gsd-cloud/dist/device-flow.js.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/device-flow.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/device-flow.test.js +155 -0
- package/packages/gsd-cloud/dist/device-flow.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/claude-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts +6 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js +15 -0
- package/packages/gsd-cloud/dist/executors/codex-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts +28 -0
- package/packages/gsd-cloud/dist/executors/executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/executor.js +11 -0
- package/packages/gsd-cloud/dist/executors/executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts +34 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js +179 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js +44 -0
- package/packages/gsd-cloud/dist/executors/gsd-pi-executor.test.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts +17 -0
- package/packages/gsd-cloud/dist/executors/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/index.js +29 -0
- package/packages/gsd-cloud/dist/executors/index.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts +36 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js +176 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.js.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js +34 -0
- package/packages/gsd-cloud/dist/executors/mcp-stdio-client.test.js.map +1 -0
- package/packages/gsd-cloud/dist/index.d.ts +7 -0
- package/packages/gsd-cloud/dist/index.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/index.js +8 -0
- package/packages/gsd-cloud/dist/index.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts +16 -0
- package/packages/gsd-cloud/dist/inject-gateway.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.js +29 -0
- package/packages/gsd-cloud/dist/inject-gateway.js.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js +41 -0
- package/packages/gsd-cloud/dist/inject-gateway.test.js.map +1 -0
- package/packages/gsd-cloud/dist/logger.d.ts +25 -0
- package/packages/gsd-cloud/dist/logger.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/logger.js +72 -0
- package/packages/gsd-cloud/dist/logger.js.map +1 -0
- package/packages/gsd-cloud/dist/types.d.ts +51 -0
- package/packages/gsd-cloud/dist/types.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/types.js +9 -0
- package/packages/gsd-cloud/dist/types.js.map +1 -0
- package/packages/gsd-cloud/package.json +3 -3
- package/packages/mcp-server/README.md +15 -2
- 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 +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/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/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +119 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +107 -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 +25 -1
- package/packages/pi-ai/dist/providers/anthropic.js.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-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.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-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
- 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/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 +18 -49
- 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/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +16 -9
- 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 +142 -16
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +5 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +92 -4
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +39 -10
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +87 -53
- 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/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- 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 +26 -4
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +3 -5
- package/src/resources/extensions/gsd/flat-phase-migration.ts +160 -19
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +255 -52
- package/src/resources/extensions/gsd/guided-flow.ts +48 -12
- package/src/resources/extensions/gsd/markdown-renderer.ts +25 -21
- package/src/resources/extensions/gsd/md-importer.ts +114 -16
- 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 +12 -20
- package/src/resources/extensions/gsd/migrate/presentation.ts +83 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
- package/src/resources/extensions/gsd/model-router.ts +12 -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 +62 -11
- package/src/resources/extensions/gsd/phase-anchor.ts +8 -2
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
- package/src/resources/extensions/gsd/post-execution-checks.ts +4 -4
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
- package/src/resources/extensions/gsd/preferences.ts +25 -0
- package/src/resources/extensions/gsd/prompts/refine-slice.md +2 -2
- 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/safety/evidence-collector.ts +28 -1
- package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +31 -5
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- 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/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/templates/PREFERENCES.md +5 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- 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 +362 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +29 -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/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/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/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/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/milestone-leases.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- 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/parallel-skill-prompt-integration.test.ts +7 -5
- 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 +29 -0
- package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- 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/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/skip-slice-cascades-tasks.test.ts +21 -0
- 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/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +73 -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/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
- package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +52 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +140 -5
- 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/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/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-context-composer.ts +34 -8
- 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/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- 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/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{UaXRrOYxBpG9QBINKhZkg → 6YWV7VAPg-jqjfPswrKZb}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A project advertised to the cloud gateway. Matches the shape the daemon's
|
|
3
|
+
* LocalToolExecutor.advertisedProjects() produced and that the gateway's
|
|
4
|
+
* `hello` message expects.
|
|
5
|
+
*/
|
|
6
|
+
export interface AdvertisedProject {
|
|
7
|
+
alias: string;
|
|
8
|
+
path: string;
|
|
9
|
+
repoIdentity: string;
|
|
10
|
+
remoteLabel?: string;
|
|
11
|
+
markers: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The behaviour CloudRuntime requires from a local execution backend.
|
|
15
|
+
*
|
|
16
|
+
* - `execute` runs a single GSD workflow tool call and returns its result
|
|
17
|
+
* (typically MCP `{ content: [...] }`), which CloudRuntime relays back to the
|
|
18
|
+
* gateway verbatim as a `tool_result`.
|
|
19
|
+
* - `advertisedProjects` lists the projects this runtime is willing to act on;
|
|
20
|
+
* CloudRuntime sends them in the `hello` message on every (re)connect.
|
|
21
|
+
*/
|
|
22
|
+
export interface Executor {
|
|
23
|
+
execute(toolName: string, rawArgs: Record<string, unknown>, projectAlias?: string): Promise<unknown>;
|
|
24
|
+
advertisedProjects(): Promise<AdvertisedProject[]>;
|
|
25
|
+
/** Optional teardown hook (e.g. kill a spawned child process). */
|
|
26
|
+
close?(): Promise<void> | void;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/executors/executor.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrG,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAEnD,kEAAkE;IAClE,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAChC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Project/App: Open GSD
|
|
2
|
+
// File Purpose: The Executor seam — the contract CloudRuntime drives to run GSD
|
|
3
|
+
// work locally, decoupled from any particular backend engine.
|
|
4
|
+
//
|
|
5
|
+
// The daemon shipped one concrete implementation (LocalToolExecutor, which linked
|
|
6
|
+
// @opengsd/mcp-server directly). This package instead depends only on this
|
|
7
|
+
// INTERFACE, so the standalone agent stays free of the internal `@gsd/*` scope.
|
|
8
|
+
// Concrete adapters (gsd-pi shell-out, and later codex / claude -p) live beside
|
|
9
|
+
// this file and are chosen by selectExecutor().
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/executors/executor.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,gFAAgF;AAChF,4EAA4E;AAC5E,EAAE;AACF,kFAAkF;AAClF,2EAA2E;AAC3E,gFAAgF;AAChF,gFAAgF;AAChF,gDAAgD","sourcesContent":["// Project/App: Open GSD\n// File Purpose: The Executor seam — the contract CloudRuntime drives to run GSD\n// work locally, decoupled from any particular backend engine.\n//\n// The daemon shipped one concrete implementation (LocalToolExecutor, which linked\n// @opengsd/mcp-server directly). This package instead depends only on this\n// INTERFACE, so the standalone agent stays free of the internal `@gsd/*` scope.\n// Concrete adapters (gsd-pi shell-out, and later codex / claude -p) live beside\n// this file and are chosen by selectExecutor().\n\n/**\n * A project advertised to the cloud gateway. Matches the shape the daemon's\n * LocalToolExecutor.advertisedProjects() produced and that the gateway's\n * `hello` message expects.\n */\nexport interface AdvertisedProject {\n alias: string;\n path: string;\n repoIdentity: string;\n remoteLabel?: string;\n markers: string[];\n}\n\n/**\n * The behaviour CloudRuntime requires from a local execution backend.\n *\n * - `execute` runs a single GSD workflow tool call and returns its result\n * (typically MCP `{ content: [...] }`), which CloudRuntime relays back to the\n * gateway verbatim as a `tool_result`.\n * - `advertisedProjects` lists the projects this runtime is willing to act on;\n * CloudRuntime sends them in the `hello` message on every (re)connect.\n */\nexport interface Executor {\n execute(toolName: string, rawArgs: Record<string, unknown>, projectAlias?: string): Promise<unknown>;\n advertisedProjects(): Promise<AdvertisedProject[]>;\n\n /** Optional teardown hook (e.g. kill a spawned child process). */\n close?(): Promise<void> | void;\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Logger } from "../logger.js";
|
|
2
|
+
import type { AdvertisedProject, Executor } from "./executor.js";
|
|
3
|
+
export interface GsdPiExecutorOptions {
|
|
4
|
+
/** Path to the `gsd` binary. Defaults to GSD_CLI_PATH env, else `gsd` on PATH. */
|
|
5
|
+
gsdBinary?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Explicit list of project directories to advertise. Defaults to
|
|
8
|
+
* GSD_CLOUD_PROJECTS (path-delimiter separated), else [cwd].
|
|
9
|
+
*/
|
|
10
|
+
projectDirs?: string[];
|
|
11
|
+
}
|
|
12
|
+
export declare class GsdPiExecutor implements Executor {
|
|
13
|
+
private readonly logger;
|
|
14
|
+
private readonly gsdBinary;
|
|
15
|
+
private readonly projectDirs;
|
|
16
|
+
/** Lazily-created MCP clients, keyed by resolved absolute project path. */
|
|
17
|
+
private readonly projects;
|
|
18
|
+
/** In-flight project client creation, keyed by resolved absolute project path. */
|
|
19
|
+
private readonly projectInit;
|
|
20
|
+
constructor(logger: Logger, opts?: GsdPiExecutorOptions);
|
|
21
|
+
/**
|
|
22
|
+
* Advertised aliases are directory basenames, so two projects that share a
|
|
23
|
+
* folder name collide. Warn up front — such an alias can only be routed by an
|
|
24
|
+
* absolute `projectDir` (see resolveProjectPath).
|
|
25
|
+
*/
|
|
26
|
+
private warnDuplicateAliases;
|
|
27
|
+
execute(toolName: string, rawArgs: Record<string, unknown>, projectAlias?: string): Promise<unknown>;
|
|
28
|
+
advertisedProjects(): Promise<AdvertisedProject[]>;
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
private resolveProject;
|
|
31
|
+
private createProjectEntry;
|
|
32
|
+
private resolveProjectPath;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=gsd-pi-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsd-pi-executor.d.ts","sourceRoot":"","sources":["../../src/executors/gsd-pi-executor.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGjE,MAAM,WAAW,oBAAoB;IACnC,kFAAkF;IAClF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAQD,qBAAa,aAAc,YAAW,QAAQ;IAQhC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAW;IACvC,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAC5D,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA4C;gBAE3C,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,oBAAyB;IAQ5E;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAgBtB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUpG,kBAAkB,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;IAalD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKd,cAAc;YAcd,kBAAkB;IAiBhC,OAAO,CAAC,kBAAkB;CA0B3B"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Project/App: Open GSD
|
|
2
|
+
// File Purpose: Executor adapter that drives the installed `gsd` CLI headlessly.
|
|
3
|
+
//
|
|
4
|
+
// MECHANISM
|
|
5
|
+
// ---------
|
|
6
|
+
// The `gsd` CLI exposes every registered workflow tool over the Model Context
|
|
7
|
+
// Protocol when started with `gsd --mode mcp` (see src/cli.ts in gsd-pi: mode
|
|
8
|
+
// 'mcp' flips the active tool set to the full registry and serves MCP over
|
|
9
|
+
// stdin/stdout). This adapter spawns ONE long-lived `gsd --mode mcp` child per
|
|
10
|
+
// project and issues `tools/call` requests for each `execute()` — the same
|
|
11
|
+
// gsd_* tool names the cloud gateway forwards (gsd_execute, gsd_status,
|
|
12
|
+
// gsd_graph, gsd_cancel, gsd_query, …). No GSD package is linked; the only
|
|
13
|
+
// contract is the MCP wire protocol.
|
|
14
|
+
//
|
|
15
|
+
// DOCUMENTED GAPS (see report):
|
|
16
|
+
// 1. Project discovery. The daemon's LocalToolExecutor scanned filesystem roots
|
|
17
|
+
// via a dedicated ProjectScanner. This standalone package has no scanner, so
|
|
18
|
+
// it advertises an EXPLICIT project list from `GSD_CLOUD_PROJECTS` (a
|
|
19
|
+
// path-list separated by the OS path delimiter) or, if unset, the current
|
|
20
|
+
// working directory. Each advertised project's `repoIdentity` is computed
|
|
21
|
+
// exactly as the daemon did (sha256 of the git origin remote, else
|
|
22
|
+
// basename:path), so gateway-side identity matching is preserved.
|
|
23
|
+
// 2. One MCP server per project. `gsd --mode mcp` is project-scoped (it resolves
|
|
24
|
+
// the GSD root from its cwd). A `tool_call` carrying a `projectAlias` is
|
|
25
|
+
// routed to that project's dedicated child; the `projectDir` arg the daemon
|
|
26
|
+
// injected is not needed because cwd already scopes the server. Tool args are
|
|
27
|
+
// forwarded verbatim otherwise.
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
29
|
+
import { execFileSync } from "node:child_process";
|
|
30
|
+
import { existsSync } from "node:fs";
|
|
31
|
+
import { basename, delimiter, resolve } from "node:path";
|
|
32
|
+
import { McpStdioClient } from "./mcp-stdio-client.js";
|
|
33
|
+
export class GsdPiExecutor {
|
|
34
|
+
logger;
|
|
35
|
+
gsdBinary;
|
|
36
|
+
projectDirs;
|
|
37
|
+
/** Lazily-created MCP clients, keyed by resolved absolute project path. */
|
|
38
|
+
projects = new Map();
|
|
39
|
+
/** In-flight project client creation, keyed by resolved absolute project path. */
|
|
40
|
+
projectInit = new Map();
|
|
41
|
+
constructor(logger, opts = {}) {
|
|
42
|
+
this.logger = logger;
|
|
43
|
+
this.gsdBinary = opts.gsdBinary
|
|
44
|
+
?? process.env["GSD_CLI_PATH"]
|
|
45
|
+
?? "gsd";
|
|
46
|
+
this.projectDirs = (opts.projectDirs ?? defaultProjectDirs()).map((p) => resolve(p));
|
|
47
|
+
this.warnDuplicateAliases();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Advertised aliases are directory basenames, so two projects that share a
|
|
51
|
+
* folder name collide. Warn up front — such an alias can only be routed by an
|
|
52
|
+
* absolute `projectDir` (see resolveProjectPath).
|
|
53
|
+
*/
|
|
54
|
+
warnDuplicateAliases() {
|
|
55
|
+
const counts = new Map();
|
|
56
|
+
for (const p of this.projectDirs) {
|
|
57
|
+
const alias = basename(p);
|
|
58
|
+
counts.set(alias, (counts.get(alias) ?? 0) + 1);
|
|
59
|
+
}
|
|
60
|
+
for (const [alias, count] of counts) {
|
|
61
|
+
if (count > 1) {
|
|
62
|
+
this.logger.warn("duplicate project alias advertised; route by absolute projectDir", {
|
|
63
|
+
alias,
|
|
64
|
+
count,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async execute(toolName, rawArgs, projectAlias) {
|
|
70
|
+
const routingKey = projectAlias
|
|
71
|
+
?? (typeof rawArgs.projectDir === "string" ? rawArgs.projectDir : undefined)
|
|
72
|
+
?? (typeof rawArgs.projectAlias === "string" ? rawArgs.projectAlias : undefined);
|
|
73
|
+
const entry = await this.resolveProject(routingKey);
|
|
74
|
+
const { projectAlias: _pa, ...args } = rawArgs;
|
|
75
|
+
void _pa;
|
|
76
|
+
return entry.client.callTool(toolName, { ...args, projectDir: entry.path });
|
|
77
|
+
}
|
|
78
|
+
async advertisedProjects() {
|
|
79
|
+
return this.projectDirs.map((path) => {
|
|
80
|
+
const remoteLabel = gitRemote(path);
|
|
81
|
+
return {
|
|
82
|
+
alias: basename(path),
|
|
83
|
+
path,
|
|
84
|
+
repoIdentity: identityFor(path, remoteLabel),
|
|
85
|
+
...(remoteLabel ? { remoteLabel } : {}),
|
|
86
|
+
markers: detectMarkers(path),
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async close() {
|
|
91
|
+
for (const entry of this.projects.values())
|
|
92
|
+
entry.client.close();
|
|
93
|
+
this.projects.clear();
|
|
94
|
+
}
|
|
95
|
+
async resolveProject(aliasOrPath) {
|
|
96
|
+
const path = this.resolveProjectPath(aliasOrPath);
|
|
97
|
+
const existing = this.projects.get(path);
|
|
98
|
+
if (existing)
|
|
99
|
+
return existing;
|
|
100
|
+
let init = this.projectInit.get(path);
|
|
101
|
+
if (!init) {
|
|
102
|
+
init = this.createProjectEntry(path);
|
|
103
|
+
this.projectInit.set(path, init);
|
|
104
|
+
void init.finally(() => this.projectInit.delete(path));
|
|
105
|
+
}
|
|
106
|
+
return init;
|
|
107
|
+
}
|
|
108
|
+
async createProjectEntry(path) {
|
|
109
|
+
const existing = this.projects.get(path);
|
|
110
|
+
if (existing)
|
|
111
|
+
return existing;
|
|
112
|
+
// `gsd --mode mcp` resolves its GSD root from cwd, so spawn the child in the
|
|
113
|
+
// project directory. GSD_PROJECT_ROOT is also set as a belt-and-suspenders
|
|
114
|
+
// hint for gsd's root resolution.
|
|
115
|
+
const client = new McpStdioClient(this.gsdBinary, ["--mode", "mcp"], this.logger, { env: { ...process.env, GSD_PROJECT_ROOT: path }, cwd: path });
|
|
116
|
+
const entry = { alias: basename(path), path, client };
|
|
117
|
+
this.projects.set(path, entry);
|
|
118
|
+
return entry;
|
|
119
|
+
}
|
|
120
|
+
resolveProjectPath(aliasOrPath) {
|
|
121
|
+
if (!aliasOrPath) {
|
|
122
|
+
if (this.projectDirs.length === 0) {
|
|
123
|
+
throw new Error("No project advertised by the standalone GSD runtime");
|
|
124
|
+
}
|
|
125
|
+
if (this.projectDirs.length > 1) {
|
|
126
|
+
throw new Error("Project routing is ambiguous: multiple projects are advertised — projectDir or projectAlias is required");
|
|
127
|
+
}
|
|
128
|
+
return this.projectDirs[0];
|
|
129
|
+
}
|
|
130
|
+
const resolved = resolve(aliasOrPath);
|
|
131
|
+
// Prefer an exact absolute-path match — always unambiguous.
|
|
132
|
+
const exact = this.projectDirs.find((p) => p === resolved);
|
|
133
|
+
if (exact)
|
|
134
|
+
return exact;
|
|
135
|
+
// Otherwise match by advertised alias (basename). If more than one advertised
|
|
136
|
+
// directory shares that basename the alias is ambiguous, so fail loudly rather
|
|
137
|
+
// than silently routing work to whichever entry happens to come first.
|
|
138
|
+
const byBasename = this.projectDirs.filter((p) => basename(p) === aliasOrPath);
|
|
139
|
+
if (byBasename.length > 1) {
|
|
140
|
+
throw new Error(`Project alias is ambiguous: ${aliasOrPath}`);
|
|
141
|
+
}
|
|
142
|
+
if (byBasename.length === 1)
|
|
143
|
+
return byBasename[0];
|
|
144
|
+
throw new Error(`Project is not advertised by the standalone GSD runtime: ${aliasOrPath}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function defaultProjectDirs() {
|
|
148
|
+
const env = process.env["GSD_CLOUD_PROJECTS"];
|
|
149
|
+
if (env && env.trim()) {
|
|
150
|
+
return env.split(delimiter).map((p) => p.trim()).filter(Boolean);
|
|
151
|
+
}
|
|
152
|
+
return [process.cwd()];
|
|
153
|
+
}
|
|
154
|
+
function detectMarkers(path) {
|
|
155
|
+
const markers = [];
|
|
156
|
+
if (existsSync(resolve(path, ".git")))
|
|
157
|
+
markers.push("git");
|
|
158
|
+
if (existsSync(resolve(path, "package.json")))
|
|
159
|
+
markers.push("node");
|
|
160
|
+
if (existsSync(resolve(path, ".gsd")))
|
|
161
|
+
markers.push("gsd");
|
|
162
|
+
return markers;
|
|
163
|
+
}
|
|
164
|
+
function gitRemote(projectPath) {
|
|
165
|
+
try {
|
|
166
|
+
return execFileSync("git", ["remote", "get-url", "origin"], {
|
|
167
|
+
cwd: projectPath,
|
|
168
|
+
encoding: "utf8",
|
|
169
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
170
|
+
}).trim() || undefined;
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function identityFor(projectPath, remote) {
|
|
177
|
+
return createHash("sha256").update(remote || `${basename(projectPath)}:${projectPath}`).digest("hex").slice(0, 12);
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=gsd-pi-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsd-pi-executor.js","sourceRoot":"","sources":["../../src/executors/gsd-pi-executor.ts"],"names":[],"mappings":"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","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Executor adapter that drives the installed `gsd` CLI headlessly.\n//\n// MECHANISM\n// ---------\n// The `gsd` CLI exposes every registered workflow tool over the Model Context\n// Protocol when started with `gsd --mode mcp` (see src/cli.ts in gsd-pi: mode\n// 'mcp' flips the active tool set to the full registry and serves MCP over\n// stdin/stdout). This adapter spawns ONE long-lived `gsd --mode mcp` child per\n// project and issues `tools/call` requests for each `execute()` — the same\n// gsd_* tool names the cloud gateway forwards (gsd_execute, gsd_status,\n// gsd_graph, gsd_cancel, gsd_query, …). No GSD package is linked; the only\n// contract is the MCP wire protocol.\n//\n// DOCUMENTED GAPS (see report):\n// 1. Project discovery. The daemon's LocalToolExecutor scanned filesystem roots\n// via a dedicated ProjectScanner. This standalone package has no scanner, so\n// it advertises an EXPLICIT project list from `GSD_CLOUD_PROJECTS` (a\n// path-list separated by the OS path delimiter) or, if unset, the current\n// working directory. Each advertised project's `repoIdentity` is computed\n// exactly as the daemon did (sha256 of the git origin remote, else\n// basename:path), so gateway-side identity matching is preserved.\n// 2. One MCP server per project. `gsd --mode mcp` is project-scoped (it resolves\n// the GSD root from its cwd). A `tool_call` carrying a `projectAlias` is\n// routed to that project's dedicated child; the `projectDir` arg the daemon\n// injected is not needed because cwd already scopes the server. Tool args are\n// forwarded verbatim otherwise.\n\nimport { createHash } from \"node:crypto\";\nimport { execFileSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { basename, delimiter, resolve } from \"node:path\";\nimport type { Logger } from \"../logger.js\";\nimport type { AdvertisedProject, Executor } from \"./executor.js\";\nimport { McpStdioClient } from \"./mcp-stdio-client.js\";\n\nexport interface GsdPiExecutorOptions {\n /** Path to the `gsd` binary. Defaults to GSD_CLI_PATH env, else `gsd` on PATH. */\n gsdBinary?: string;\n /**\n * Explicit list of project directories to advertise. Defaults to\n * GSD_CLOUD_PROJECTS (path-delimiter separated), else [cwd].\n */\n projectDirs?: string[];\n}\n\ninterface ProjectEntry {\n alias: string;\n path: string;\n client: McpStdioClient;\n}\n\nexport class GsdPiExecutor implements Executor {\n private readonly gsdBinary: string;\n private readonly projectDirs: string[];\n /** Lazily-created MCP clients, keyed by resolved absolute project path. */\n private readonly projects = new Map<string, ProjectEntry>();\n /** In-flight project client creation, keyed by resolved absolute project path. */\n private readonly projectInit = new Map<string, Promise<ProjectEntry>>();\n\n constructor(private readonly logger: Logger, opts: GsdPiExecutorOptions = {}) {\n this.gsdBinary = opts.gsdBinary\n ?? process.env[\"GSD_CLI_PATH\"]\n ?? \"gsd\";\n this.projectDirs = (opts.projectDirs ?? defaultProjectDirs()).map((p) => resolve(p));\n this.warnDuplicateAliases();\n }\n\n /**\n * Advertised aliases are directory basenames, so two projects that share a\n * folder name collide. Warn up front — such an alias can only be routed by an\n * absolute `projectDir` (see resolveProjectPath).\n */\n private warnDuplicateAliases(): void {\n const counts = new Map<string, number>();\n for (const p of this.projectDirs) {\n const alias = basename(p);\n counts.set(alias, (counts.get(alias) ?? 0) + 1);\n }\n for (const [alias, count] of counts) {\n if (count > 1) {\n this.logger.warn(\"duplicate project alias advertised; route by absolute projectDir\", {\n alias,\n count,\n });\n }\n }\n }\n\n async execute(toolName: string, rawArgs: Record<string, unknown>, projectAlias?: string): Promise<unknown> {\n const routingKey = projectAlias\n ?? (typeof rawArgs.projectDir === \"string\" ? rawArgs.projectDir : undefined)\n ?? (typeof rawArgs.projectAlias === \"string\" ? rawArgs.projectAlias : undefined);\n const entry = await this.resolveProject(routingKey);\n const { projectAlias: _pa, ...args } = rawArgs;\n void _pa;\n return entry.client.callTool(toolName, { ...args, projectDir: entry.path });\n }\n\n async advertisedProjects(): Promise<AdvertisedProject[]> {\n return this.projectDirs.map((path) => {\n const remoteLabel = gitRemote(path);\n return {\n alias: basename(path),\n path,\n repoIdentity: identityFor(path, remoteLabel),\n ...(remoteLabel ? { remoteLabel } : {}),\n markers: detectMarkers(path),\n };\n });\n }\n\n async close(): Promise<void> {\n for (const entry of this.projects.values()) entry.client.close();\n this.projects.clear();\n }\n\n private async resolveProject(aliasOrPath?: string): Promise<ProjectEntry> {\n const path = this.resolveProjectPath(aliasOrPath);\n const existing = this.projects.get(path);\n if (existing) return existing;\n\n let init = this.projectInit.get(path);\n if (!init) {\n init = this.createProjectEntry(path);\n this.projectInit.set(path, init);\n void init.finally(() => this.projectInit.delete(path));\n }\n return init;\n }\n\n private async createProjectEntry(path: string): Promise<ProjectEntry> {\n const existing = this.projects.get(path);\n if (existing) return existing;\n // `gsd --mode mcp` resolves its GSD root from cwd, so spawn the child in the\n // project directory. GSD_PROJECT_ROOT is also set as a belt-and-suspenders\n // hint for gsd's root resolution.\n const client = new McpStdioClient(\n this.gsdBinary,\n [\"--mode\", \"mcp\"],\n this.logger,\n { env: { ...process.env, GSD_PROJECT_ROOT: path }, cwd: path },\n );\n const entry: ProjectEntry = { alias: basename(path), path, client };\n this.projects.set(path, entry);\n return entry;\n }\n\n private resolveProjectPath(aliasOrPath?: string): string {\n if (!aliasOrPath) {\n if (this.projectDirs.length === 0) {\n throw new Error(\"No project advertised by the standalone GSD runtime\");\n }\n if (this.projectDirs.length > 1) {\n throw new Error(\n \"Project routing is ambiguous: multiple projects are advertised — projectDir or projectAlias is required\",\n );\n }\n return this.projectDirs[0]!;\n }\n const resolved = resolve(aliasOrPath);\n // Prefer an exact absolute-path match — always unambiguous.\n const exact = this.projectDirs.find((p) => p === resolved);\n if (exact) return exact;\n // Otherwise match by advertised alias (basename). If more than one advertised\n // directory shares that basename the alias is ambiguous, so fail loudly rather\n // than silently routing work to whichever entry happens to come first.\n const byBasename = this.projectDirs.filter((p) => basename(p) === aliasOrPath);\n if (byBasename.length > 1) {\n throw new Error(`Project alias is ambiguous: ${aliasOrPath}`);\n }\n if (byBasename.length === 1) return byBasename[0]!;\n throw new Error(`Project is not advertised by the standalone GSD runtime: ${aliasOrPath}`);\n }\n}\n\nfunction defaultProjectDirs(): string[] {\n const env = process.env[\"GSD_CLOUD_PROJECTS\"];\n if (env && env.trim()) {\n return env.split(delimiter).map((p) => p.trim()).filter(Boolean);\n }\n return [process.cwd()];\n}\n\nfunction detectMarkers(path: string): string[] {\n const markers: string[] = [];\n if (existsSync(resolve(path, \".git\"))) markers.push(\"git\");\n if (existsSync(resolve(path, \"package.json\"))) markers.push(\"node\");\n if (existsSync(resolve(path, \".gsd\"))) markers.push(\"gsd\");\n return markers;\n}\n\nfunction gitRemote(projectPath: string): string | undefined {\n try {\n return execFileSync(\"git\", [\"remote\", \"get-url\", \"origin\"], {\n cwd: projectPath,\n encoding: \"utf8\",\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n }).trim() || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction identityFor(projectPath: string, remote?: string): string {\n return createHash(\"sha256\").update(remote || `${basename(projectPath)}:${projectPath}`).digest(\"hex\").slice(0, 12);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsd-pi-executor.test.d.ts","sourceRoot":"","sources":["../../src/executors/gsd-pi-executor.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Project/App: Open GSD
|
|
2
|
+
// File Purpose: Regression tests for GsdPiExecutor project routing — a bare alias
|
|
3
|
+
// (directory basename) shared by two advertised projects must fail loudly instead
|
|
4
|
+
// of silently routing cloud work to whichever entry comes first.
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { GsdPiExecutor } from "./gsd-pi-executor.js";
|
|
8
|
+
const warnings = [];
|
|
9
|
+
const logger = {
|
|
10
|
+
info: () => undefined,
|
|
11
|
+
warn: (msg, meta) => warnings.push({ msg, meta }),
|
|
12
|
+
error: () => undefined,
|
|
13
|
+
debug: () => undefined,
|
|
14
|
+
};
|
|
15
|
+
test("ambiguous alias across colliding basenames rejects instead of mis-routing", async () => {
|
|
16
|
+
const exec = new GsdPiExecutor(logger, {
|
|
17
|
+
projectDirs: ["/tmp/team-a/web", "/tmp/team-b/web"],
|
|
18
|
+
});
|
|
19
|
+
await assert.rejects(exec.execute("gsd_status", {}, "web"), /ambiguous/i);
|
|
20
|
+
});
|
|
21
|
+
test("constructing with colliding aliases warns once", () => {
|
|
22
|
+
warnings.length = 0;
|
|
23
|
+
// eslint-disable-next-line no-new
|
|
24
|
+
new GsdPiExecutor(logger, { projectDirs: ["/tmp/team-a/web", "/tmp/team-b/web"] });
|
|
25
|
+
const dupWarn = warnings.filter((w) => /duplicate project alias/i.test(w.msg));
|
|
26
|
+
assert.equal(dupWarn.length, 1);
|
|
27
|
+
});
|
|
28
|
+
test("missing alias with several projects rejects instead of using the first", async () => {
|
|
29
|
+
const exec = new GsdPiExecutor(logger, {
|
|
30
|
+
projectDirs: ["/tmp/alpha", "/tmp/beta"],
|
|
31
|
+
});
|
|
32
|
+
await assert.rejects(exec.execute("gsd_status", {}), /ambiguous/i);
|
|
33
|
+
});
|
|
34
|
+
test("an alias that is not advertised rejects", async () => {
|
|
35
|
+
const exec = new GsdPiExecutor(logger, { projectDirs: ["/tmp/solo/app"] });
|
|
36
|
+
await assert.rejects(exec.execute("gsd_status", {}, "nope"), /not advertised/i);
|
|
37
|
+
});
|
|
38
|
+
test("advertised alias is the directory basename", async () => {
|
|
39
|
+
const exec = new GsdPiExecutor(logger, { projectDirs: ["/tmp/solo/app"] });
|
|
40
|
+
const projects = await exec.advertisedProjects();
|
|
41
|
+
assert.equal(projects.length, 1);
|
|
42
|
+
assert.equal(projects[0]?.alias, "app");
|
|
43
|
+
});
|
|
44
|
+
//# sourceMappingURL=gsd-pi-executor.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gsd-pi-executor.test.js","sourceRoot":"","sources":["../../src/executors/gsd-pi-executor.test.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,kFAAkF;AAClF,kFAAkF;AAClF,iEAAiE;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,QAAQ,GAA0C,EAAE,CAAC;AAC3D,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS;IACrB,IAAI,EAAE,CAAC,GAAW,EAAE,IAAc,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IACnE,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;IACtB,KAAK,EAAE,GAAG,EAAE,CAAC,SAAS;CACvB,CAAC;AAEF,IAAI,CAAC,2EAA2E,EAAE,KAAK,IAAI,EAAE;IAC3F,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,MAAe,EAAE;QAC9C,WAAW,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;KACpD,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,YAAY,CAAC,CAAC;AAC5E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IACpB,kCAAkC;IAClC,IAAI,aAAa,CAAC,MAAe,EAAE,EAAE,WAAW,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAC5F,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/E,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAClC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wEAAwE,EAAE,KAAK,IAAI,EAAE;IACxF,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,MAAe,EAAE;QAC9C,WAAW,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC;KACzC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC;AACrE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;IACzD,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,MAAe,EAAE,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACpF,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAClF,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;IAC5D,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,MAAe,EAAE,EAAE,WAAW,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IACpF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;IACjD,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACjC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAC1C,CAAC,CAAC,CAAC","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Regression tests for GsdPiExecutor project routing — a bare alias\n// (directory basename) shared by two advertised projects must fail loudly instead\n// of silently routing cloud work to whichever entry comes first.\nimport { test } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { GsdPiExecutor } from \"./gsd-pi-executor.js\";\n\nconst warnings: Array<{ msg: string; meta: unknown }> = [];\nconst logger = {\n info: () => undefined,\n warn: (msg: string, meta?: unknown) => warnings.push({ msg, meta }),\n error: () => undefined,\n debug: () => undefined,\n};\n\ntest(\"ambiguous alias across colliding basenames rejects instead of mis-routing\", async () => {\n const exec = new GsdPiExecutor(logger as never, {\n projectDirs: [\"/tmp/team-a/web\", \"/tmp/team-b/web\"],\n });\n await assert.rejects(exec.execute(\"gsd_status\", {}, \"web\"), /ambiguous/i);\n});\n\ntest(\"constructing with colliding aliases warns once\", () => {\n warnings.length = 0;\n // eslint-disable-next-line no-new\n new GsdPiExecutor(logger as never, { projectDirs: [\"/tmp/team-a/web\", \"/tmp/team-b/web\"] });\n const dupWarn = warnings.filter((w) => /duplicate project alias/i.test(w.msg));\n assert.equal(dupWarn.length, 1);\n});\n\ntest(\"missing alias with several projects rejects instead of using the first\", async () => {\n const exec = new GsdPiExecutor(logger as never, {\n projectDirs: [\"/tmp/alpha\", \"/tmp/beta\"],\n });\n await assert.rejects(exec.execute(\"gsd_status\", {}), /ambiguous/i);\n});\n\ntest(\"an alias that is not advertised rejects\", async () => {\n const exec = new GsdPiExecutor(logger as never, { projectDirs: [\"/tmp/solo/app\"] });\n await assert.rejects(exec.execute(\"gsd_status\", {}, \"nope\"), /not advertised/i);\n});\n\ntest(\"advertised alias is the directory basename\", async () => {\n const exec = new GsdPiExecutor(logger as never, { projectDirs: [\"/tmp/solo/app\"] });\n const projects = await exec.advertisedProjects();\n assert.equal(projects.length, 1);\n assert.equal(projects[0]?.alias, \"app\");\n});\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Logger } from "../logger.js";
|
|
2
|
+
import type { Executor } from "./executor.js";
|
|
3
|
+
import { type GsdPiExecutorOptions } from "./gsd-pi-executor.js";
|
|
4
|
+
export type ExecutorKind = "gsd-pi" | "codex" | "claude";
|
|
5
|
+
export interface SelectExecutorOptions extends GsdPiExecutorOptions {
|
|
6
|
+
kind?: ExecutorKind;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the execution backend. Defaults to the gsd-pi shell-out adapter, which
|
|
10
|
+
* drives the installed `gsd` CLI over MCP. Selection can also be overridden with
|
|
11
|
+
* the GSD_CLOUD_EXECUTOR env var.
|
|
12
|
+
*/
|
|
13
|
+
export declare function selectExecutor(logger: Logger, opts?: SelectExecutorOptions): Executor;
|
|
14
|
+
export type { Executor, AdvertisedProject } from "./executor.js";
|
|
15
|
+
export { GsdPiExecutor } from "./gsd-pi-executor.js";
|
|
16
|
+
export type { GsdPiExecutorOptions } from "./gsd-pi-executor.js";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/executors/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAIhF,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEzD,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,QAAQ,CAYzF;AAED,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Project/App: Open GSD
|
|
2
|
+
// File Purpose: Executor selection seam — pick a backend adapter by name.
|
|
3
|
+
//
|
|
4
|
+
// The gsd-pi shell-out adapter is the only implemented backend today. `codex`
|
|
5
|
+
// and `claude` are stubbed so the seam is visible; selecting them throws until
|
|
6
|
+
// their behaviour is designed.
|
|
7
|
+
import { GsdPiExecutor } from "./gsd-pi-executor.js";
|
|
8
|
+
import { CodexExecutor } from "./codex-executor.js";
|
|
9
|
+
import { ClaudeExecutor } from "./claude-executor.js";
|
|
10
|
+
/**
|
|
11
|
+
* Resolve the execution backend. Defaults to the gsd-pi shell-out adapter, which
|
|
12
|
+
* drives the installed `gsd` CLI over MCP. Selection can also be overridden with
|
|
13
|
+
* the GSD_CLOUD_EXECUTOR env var.
|
|
14
|
+
*/
|
|
15
|
+
export function selectExecutor(logger, opts = {}) {
|
|
16
|
+
const kind = opts.kind ?? process.env["GSD_CLOUD_EXECUTOR"] ?? "gsd-pi";
|
|
17
|
+
switch (kind) {
|
|
18
|
+
case "gsd-pi":
|
|
19
|
+
return new GsdPiExecutor(logger, opts);
|
|
20
|
+
case "codex":
|
|
21
|
+
return new CodexExecutor();
|
|
22
|
+
case "claude":
|
|
23
|
+
return new ClaudeExecutor();
|
|
24
|
+
default:
|
|
25
|
+
throw new Error(`Unknown executor kind: ${String(kind)}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export { GsdPiExecutor } from "./gsd-pi-executor.js";
|
|
29
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/executors/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,0EAA0E;AAC1E,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,+BAA+B;AAI/B,OAAO,EAAE,aAAa,EAA6B,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAQtD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,OAA8B,EAAE;IAC7E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAK,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAA8B,IAAI,QAAQ,CAAC;IACtG,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACzC,KAAK,OAAO;YACV,OAAO,IAAI,aAAa,EAAE,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,EAAE,CAAC;QAC9B;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;AAGD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Executor selection seam — pick a backend adapter by name.\n//\n// The gsd-pi shell-out adapter is the only implemented backend today. `codex`\n// and `claude` are stubbed so the seam is visible; selecting them throws until\n// their behaviour is designed.\n\nimport type { Logger } from \"../logger.js\";\nimport type { Executor } from \"./executor.js\";\nimport { GsdPiExecutor, type GsdPiExecutorOptions } from \"./gsd-pi-executor.js\";\nimport { CodexExecutor } from \"./codex-executor.js\";\nimport { ClaudeExecutor } from \"./claude-executor.js\";\n\nexport type ExecutorKind = \"gsd-pi\" | \"codex\" | \"claude\";\n\nexport interface SelectExecutorOptions extends GsdPiExecutorOptions {\n kind?: ExecutorKind;\n}\n\n/**\n * Resolve the execution backend. Defaults to the gsd-pi shell-out adapter, which\n * drives the installed `gsd` CLI over MCP. Selection can also be overridden with\n * the GSD_CLOUD_EXECUTOR env var.\n */\nexport function selectExecutor(logger: Logger, opts: SelectExecutorOptions = {}): Executor {\n const kind = opts.kind ?? (process.env[\"GSD_CLOUD_EXECUTOR\"] as ExecutorKind | undefined) ?? \"gsd-pi\";\n switch (kind) {\n case \"gsd-pi\":\n return new GsdPiExecutor(logger, opts);\n case \"codex\":\n return new CodexExecutor();\n case \"claude\":\n return new ClaudeExecutor();\n default:\n throw new Error(`Unknown executor kind: ${String(kind)}`);\n }\n}\n\nexport type { Executor, AdvertisedProject } from \"./executor.js\";\nexport { GsdPiExecutor } from \"./gsd-pi-executor.js\";\nexport type { GsdPiExecutorOptions } from \"./gsd-pi-executor.js\";\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Logger } from "../logger.js";
|
|
2
|
+
/**
|
|
3
|
+
* Long-lived MCP client bound to a single spawned server process.
|
|
4
|
+
* Lazily starts and initializes the server on first use; subsequent calls reuse
|
|
5
|
+
* the same connection.
|
|
6
|
+
*/
|
|
7
|
+
export declare class McpStdioClient {
|
|
8
|
+
private readonly command;
|
|
9
|
+
private readonly args;
|
|
10
|
+
private readonly logger;
|
|
11
|
+
private readonly options;
|
|
12
|
+
private child;
|
|
13
|
+
private rl;
|
|
14
|
+
private nextId;
|
|
15
|
+
private readonly pending;
|
|
16
|
+
private initPromise;
|
|
17
|
+
private closed;
|
|
18
|
+
constructor(command: string, args: string[], logger: Logger, options?: {
|
|
19
|
+
env?: NodeJS.ProcessEnv;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
});
|
|
22
|
+
/** Ensure the server is spawned and `initialize` has completed. Idempotent. */
|
|
23
|
+
ensureReady(): Promise<void>;
|
|
24
|
+
private awaitReadyProcess;
|
|
25
|
+
/** Invoke an MCP tool and return its raw result object. */
|
|
26
|
+
callTool(name: string, args: Record<string, unknown>): Promise<unknown>;
|
|
27
|
+
close(): void;
|
|
28
|
+
private startAndInitialize;
|
|
29
|
+
private request;
|
|
30
|
+
private notify;
|
|
31
|
+
private handleLine;
|
|
32
|
+
private failAll;
|
|
33
|
+
private isProcessAlive;
|
|
34
|
+
private resetConnection;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=mcp-stdio-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-stdio-client.d.ts","sourceRoot":"","sources":["../../src/executors/mcp-stdio-client.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAmB3C;;;;GAIG;AACH,qBAAa,cAAc;IASvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAX1B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,EAAE,CAAwB;IAClC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuC;IAC/D,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,MAAM,CAAS;gBAGJ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAO;IAG1E,+EAA+E;IACzE,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC,OAAO,CAAC,iBAAiB;IAwBzB,2DAA2D;IACrD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAK7E,KAAK,IAAI,IAAI;YAKC,kBAAkB;IAwChC,OAAO,CAAC,OAAO;IA0Bf,OAAO,CAAC,MAAM;IAMd,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,eAAe;CAUxB"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// Project/App: Open GSD
|
|
2
|
+
// File Purpose: Minimal MCP JSON-RPC 2.0 client over a child process's stdio.
|
|
3
|
+
//
|
|
4
|
+
// Zero external deps — just enough of the Model Context Protocol to `initialize`
|
|
5
|
+
// a server and issue `tools/call` requests. Used by the gsd-pi shell-out adapter
|
|
6
|
+
// to drive `gsd --mode mcp` without linking any GSD package.
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import { createInterface } from "node:readline";
|
|
9
|
+
const PROTOCOL_VERSION = "2024-11-05";
|
|
10
|
+
const INIT_TIMEOUT_MS = 60_000;
|
|
11
|
+
const CALL_TIMEOUT_MS = 30 * 60_000; // GSD tool calls (e.g. gsd_execute) can be long-running.
|
|
12
|
+
/**
|
|
13
|
+
* Long-lived MCP client bound to a single spawned server process.
|
|
14
|
+
* Lazily starts and initializes the server on first use; subsequent calls reuse
|
|
15
|
+
* the same connection.
|
|
16
|
+
*/
|
|
17
|
+
export class McpStdioClient {
|
|
18
|
+
command;
|
|
19
|
+
args;
|
|
20
|
+
logger;
|
|
21
|
+
options;
|
|
22
|
+
child;
|
|
23
|
+
rl;
|
|
24
|
+
nextId = 1;
|
|
25
|
+
pending = new Map();
|
|
26
|
+
initPromise;
|
|
27
|
+
closed = false;
|
|
28
|
+
constructor(command, args, logger, options = {}) {
|
|
29
|
+
this.command = command;
|
|
30
|
+
this.args = args;
|
|
31
|
+
this.logger = logger;
|
|
32
|
+
this.options = options;
|
|
33
|
+
}
|
|
34
|
+
/** Ensure the server is spawned and `initialize` has completed. Idempotent. */
|
|
35
|
+
async ensureReady() {
|
|
36
|
+
await this.awaitReadyProcess();
|
|
37
|
+
}
|
|
38
|
+
awaitReadyProcess() {
|
|
39
|
+
if (this.closed) {
|
|
40
|
+
return Promise.reject(new Error("MCP client closed"));
|
|
41
|
+
}
|
|
42
|
+
if (!this.initPromise) {
|
|
43
|
+
this.initPromise = this.startAndInitialize().catch((err) => {
|
|
44
|
+
this.resetConnection();
|
|
45
|
+
throw err;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return this.initPromise.then(async () => {
|
|
49
|
+
if (this.closed)
|
|
50
|
+
throw new Error("MCP client closed");
|
|
51
|
+
if (this.isProcessAlive())
|
|
52
|
+
return;
|
|
53
|
+
this.resetConnection();
|
|
54
|
+
throw new Error("gsd MCP process is not running after initialize");
|
|
55
|
+
}, (err) => {
|
|
56
|
+
if (this.closed)
|
|
57
|
+
throw new Error("MCP client closed");
|
|
58
|
+
throw err;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/** Invoke an MCP tool and return its raw result object. */
|
|
62
|
+
async callTool(name, args) {
|
|
63
|
+
await this.ensureReady();
|
|
64
|
+
return this.request("tools/call", { name, arguments: args }, CALL_TIMEOUT_MS);
|
|
65
|
+
}
|
|
66
|
+
close() {
|
|
67
|
+
this.closed = true;
|
|
68
|
+
this.resetConnection(new Error("MCP client closed"));
|
|
69
|
+
}
|
|
70
|
+
async startAndInitialize() {
|
|
71
|
+
const child = spawn(this.command, this.args, {
|
|
72
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
73
|
+
env: this.options.env ?? process.env,
|
|
74
|
+
...(this.options.cwd ? { cwd: this.options.cwd } : {}),
|
|
75
|
+
});
|
|
76
|
+
this.child = child;
|
|
77
|
+
child.on("error", (err) => {
|
|
78
|
+
this.logger.error("gsd MCP process error", { error: err.message });
|
|
79
|
+
this.resetConnection(new Error(`gsd MCP process error: ${err.message}`));
|
|
80
|
+
});
|
|
81
|
+
child.on("exit", (code, signal) => {
|
|
82
|
+
this.logger.warn("gsd MCP process exited", { code, signal });
|
|
83
|
+
this.resetConnection(new Error(`gsd MCP process exited (code=${code ?? "null"}, signal=${signal ?? "null"})`));
|
|
84
|
+
});
|
|
85
|
+
// MCP servers commonly log human-readable startup noise on stderr; forward at debug.
|
|
86
|
+
child.stderr.on("data", (chunk) => {
|
|
87
|
+
this.logger.debug("gsd MCP stderr", { text: chunk.toString("utf8").trimEnd() });
|
|
88
|
+
});
|
|
89
|
+
this.rl = createInterface({ input: child.stdout });
|
|
90
|
+
this.rl.on("line", (line) => this.handleLine(line));
|
|
91
|
+
await this.request("initialize", {
|
|
92
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
93
|
+
capabilities: {},
|
|
94
|
+
clientInfo: { name: "@opengsd/gsd-cloud", version: "1.7.1" },
|
|
95
|
+
}, INIT_TIMEOUT_MS);
|
|
96
|
+
// Per MCP spec, the client sends an `initialized` notification (no id, no response).
|
|
97
|
+
this.notify("notifications/initialized");
|
|
98
|
+
}
|
|
99
|
+
request(method, params, timeoutMs) {
|
|
100
|
+
const child = this.child;
|
|
101
|
+
if (!child || !child.stdin.writable) {
|
|
102
|
+
return Promise.reject(new Error("gsd MCP process is not running"));
|
|
103
|
+
}
|
|
104
|
+
const id = this.nextId++;
|
|
105
|
+
const payload = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
|
|
106
|
+
return new Promise((resolve, reject) => {
|
|
107
|
+
const timer = setTimeout(() => {
|
|
108
|
+
this.pending.delete(id);
|
|
109
|
+
reject(new Error(`gsd MCP request '${method}' timed out after ${timeoutMs}ms`));
|
|
110
|
+
this.resetConnection();
|
|
111
|
+
}, timeoutMs);
|
|
112
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
113
|
+
child.stdin.write(payload, (err) => {
|
|
114
|
+
if (err) {
|
|
115
|
+
clearTimeout(timer);
|
|
116
|
+
this.pending.delete(id);
|
|
117
|
+
reject(new Error(`Failed to write MCP request: ${err.message}`));
|
|
118
|
+
this.resetConnection();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
notify(method) {
|
|
124
|
+
const child = this.child;
|
|
125
|
+
if (!child || !child.stdin.writable)
|
|
126
|
+
return;
|
|
127
|
+
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", method }) + "\n");
|
|
128
|
+
}
|
|
129
|
+
handleLine(line) {
|
|
130
|
+
const trimmed = line.trim();
|
|
131
|
+
if (!trimmed)
|
|
132
|
+
return;
|
|
133
|
+
let message;
|
|
134
|
+
try {
|
|
135
|
+
message = JSON.parse(trimmed);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// Non-JSON line (stray log). Ignore.
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (message.id === undefined || message.id === null)
|
|
142
|
+
return; // notification/request from server — ignored.
|
|
143
|
+
const pending = this.pending.get(message.id);
|
|
144
|
+
if (!pending)
|
|
145
|
+
return;
|
|
146
|
+
this.pending.delete(message.id);
|
|
147
|
+
clearTimeout(pending.timer);
|
|
148
|
+
if (message.error) {
|
|
149
|
+
pending.reject(new Error(message.error.message || `MCP error ${message.error.code}`));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
pending.resolve(message.result);
|
|
153
|
+
}
|
|
154
|
+
failAll(err) {
|
|
155
|
+
for (const [, p] of this.pending) {
|
|
156
|
+
clearTimeout(p.timer);
|
|
157
|
+
p.reject(err);
|
|
158
|
+
}
|
|
159
|
+
this.pending.clear();
|
|
160
|
+
}
|
|
161
|
+
isProcessAlive() {
|
|
162
|
+
const child = this.child;
|
|
163
|
+
return child !== undefined && child.exitCode === null && child.signalCode === null;
|
|
164
|
+
}
|
|
165
|
+
resetConnection(reason = new Error("MCP connection reset")) {
|
|
166
|
+
this.failAll(reason);
|
|
167
|
+
this.rl?.close();
|
|
168
|
+
this.rl = undefined;
|
|
169
|
+
if (this.child && this.child.exitCode === null && this.child.signalCode === null) {
|
|
170
|
+
this.child.kill();
|
|
171
|
+
}
|
|
172
|
+
this.child = undefined;
|
|
173
|
+
this.initPromise = undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=mcp-stdio-client.js.map
|