@opengsd/gsd-pi 1.10.0 → 1.11.0
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto-model-selection.js +1 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto-verification.js +25 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -3
- package/dist/resources/extensions/gsd/db/engine.js +8 -2
- package/dist/resources/extensions/gsd/db-canonical-foundation-schema.js +120 -0
- package/dist/resources/extensions/gsd/db-migration-steps.js +4 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +16 -4
- package/dist/resources/extensions/gsd/model-cost-table.js +6 -3
- package/dist/resources/extensions/gsd/model-router.js +10 -5
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +12 -4
- package/dist/resources/extensions/gsd/preferences-models.js +50 -10
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +41 -6
- package/dist/resources/extensions/gsd/preferences.js +7 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +5 -1
- package/dist/resources/extensions/gsd/verification-evidence.js +5 -3
- package/dist/resources/extensions/ollama/ollama-chat-provider.js +2 -2
- 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 +7 -7
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- 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/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- 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 +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
- package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- 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/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +7 -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/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 +12 -2
- package/packages/gsd-cloud/dist/background-cli.test.js +157 -80
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -1
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +36 -12
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +6 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +106 -24
- 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 +5 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.js +429 -61
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.test.js +493 -47
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -1
- 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/package.json +4 -4
- package/packages/native/package.json +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 +113 -2
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +84 -9
- 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/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.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/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 +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 +3 -3
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.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/extensions/gsd/auto-model-selection.ts +1 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto-verification.ts +46 -12
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +4 -3
- package/src/resources/extensions/gsd/db/engine.ts +9 -1
- package/src/resources/extensions/gsd/db-canonical-foundation-schema.ts +129 -0
- package/src/resources/extensions/gsd/db-migration-steps.ts +5 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +12 -3
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +15 -4
- package/src/resources/extensions/gsd/model-cost-table.ts +14 -3
- package/src/resources/extensions/gsd/model-router.ts +10 -5
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +18 -4
- package/src/resources/extensions/gsd/preferences-models.ts +54 -10
- package/src/resources/extensions/gsd/preferences-types.ts +10 -2
- package/src/resources/extensions/gsd/preferences-validation.ts +49 -6
- package/src/resources/extensions/gsd/preferences.ts +13 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +3 -0
- package/src/resources/extensions/gsd/tests/db-canonical-foundation.test.ts +459 -0
- package/src/resources/extensions/gsd/tests/db-engine-migrate-guards.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +22 -7
- 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/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 +71 -4
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +3 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
- 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/write-gate-planning-unit.test.ts +40 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +5 -1
- package/src/resources/extensions/gsd/verification-evidence.ts +5 -2
- 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/subagent/index.ts +1 -1
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{EAhnhYMt5UVOiG9-iPDjc → 8ub6oiEp2YnlOHQU20LJr}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Standalone gsd-cloud CLI — login / status / connect / disconnect.\n//\n// Wires device-flow + CloudRuntime + a selected Executor adapter DIRECTLY. It has\n// no dependency on any Daemon or Orchestrator class; the only cloud behaviour is\n// the WS relay client driving the local GSD runtime through the Executor seam.\n\nimport { parseArgs } from \"node:util\";\nimport { realpathSync } from \"node:fs\";\nimport { delimiter, resolve } from \"node:path\";\nimport { resolveConfigPath, loadConfig } from \"./config.js\";\nimport { Logger } from \"./logger.js\";\nimport {\n clearCloudConfig,\n exchangePairingCode,\n redactedCloudStatus,\n saveCloudConfig,\n} from \"./cloud-config.js\";\nimport { runDeviceFlow } from \"./device-flow.js\";\nimport { CloudRuntime } from \"./cloud-runtime.js\";\nimport { selectExecutor } from \"./executors/index.js\";\nimport {\n backgroundRuntimeStatus,\n clearRuntimeState,\n startBackgroundRuntime,\n stopBackgroundRuntime,\n writeRuntimeState,\n} from \"./runtime-process.js\";\nimport type { DaemonConfig } from \"./types.js\";\n\nexport async function handleCloudCommand(argv: string[], opts: {\n binaryName: string;\n}): Promise<void> {\n if (argv[0] === \"--help\" || argv[0] === \"-h\") {\n process.stdout.write(formatUsage(opts.binaryName));\n process.exit(0);\n }\n\n const command = argv[0];\n const { values } = parseArgs({\n args: argv.slice(1),\n options: {\n config: { type: \"string\", short: \"c\" },\n gateway: { type: \"string\" },\n code: { type: \"string\" },\n \"runtime-name\": { type: \"string\" },\n verbose: { type: \"boolean\", short: \"v\", default: false },\n foreground: { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n });\n\n if (values.help || !command) {\n process.stdout.write(formatUsage(opts.binaryName));\n process.exit(0);\n }\n\n const configPath = resolveConfigPath(values.config);\n\n if (command === \"status\") {\n const config = loadConfig(configPath);\n process.stdout.write(`${JSON.stringify({\n ...redactedCloudStatus(config),\n projects: config.projects.scan_roots,\n background: backgroundRuntimeStatus(configPath),\n }, null, 2)}\\n`);\n return;\n }\n\n if (command === \"disconnect\") {\n await stopBackgroundRuntime(configPath);\n clearCloudConfig(configPath);\n process.stdout.write(`${opts.binaryName}: background runtime stopped and cloud credentials removed.\\n`);\n return;\n }\n\n if (command === \"login\") {\n if (!values.gateway) {\n throw new Error(\"login requires --gateway\");\n }\n const runtimeName = values[\"runtime-name\"];\n const { deviceToken, runtimeId, gatewayUrl } = await runDeviceFlow({\n gatewayUrl: values.gateway,\n configPath,\n runtimeName,\n binaryName: opts.binaryName,\n });\n const projectDirs = selectedProjectDirs([]);\n const config = saveCloudConfig(configPath, {\n gateway_url: gatewayUrl,\n device_token: deviceToken,\n runtime_id: runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n }, projectDirs);\n process.stdout.write(`${opts.binaryName}: cloud runtime ${runtimeId} paired — connecting...\\n`);\n if (values.foreground) {\n await stopBackgroundRuntime(configPath);\n await runCloudRuntime(config, opts.binaryName, values.verbose, projectDirs, {\n registerConfigPath: configPath,\n });\n return;\n }\n await startAndReportBackgroundRuntime(configPath, projectDirs, opts.binaryName, values.verbose);\n return;\n }\n\n if (command === \"pair\") {\n if (!values.gateway || !values.code) {\n throw new Error(\"pair requires --gateway and --code\");\n }\n const runtimeName = values[\"runtime-name\"];\n const result = await exchangePairingCode({\n gatewayUrl: values.gateway,\n code: values.code,\n runtimeName,\n });\n saveCloudConfig(configPath, {\n gateway_url: values.gateway,\n device_token: result.deviceToken,\n runtime_id: result.runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n });\n process.stdout.write(`${opts.binaryName}: paired cloud runtime ${result.runtimeId}.\\n`);\n return;\n }\n\n if (command === \"connect\") {\n let config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `login` first\");\n }\n const projectDirs = selectedProjectDirs(config.projects.scan_roots);\n config = saveCloudConfig(configPath, config.cloud, projectDirs);\n if (values.foreground) {\n await stopBackgroundRuntime(configPath);\n await runCloudRuntime(config, opts.binaryName, values.verbose, projectDirs, {\n registerConfigPath: configPath,\n });\n return;\n }\n await startAndReportBackgroundRuntime(configPath, projectDirs, opts.binaryName, values.verbose);\n return;\n }\n\n if (command === \"_run\") {\n const config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `login` first\");\n }\n const projectDirs = selectedProjectDirs(config.projects.scan_roots);\n await runCloudRuntime(config, opts.binaryName, values.verbose, projectDirs, {\n onConnected: () => {\n process.send?.({ type: \"ready\" });\n },\n });\n return;\n }\n\n throw new Error(`Unknown cloud runtime command: ${command}`);\n}\n\n/**\n * Start the WS relay and block until the process is signalled. This is the whole\n * \"daemon\" for the standalone agent: one CloudRuntime + one Executor, no Discord,\n * no scanner, no session-manager class.\n */\nasync function runCloudRuntime(\n config: DaemonConfig,\n binaryName: string,\n verbose: boolean,\n projectDirs: string[],\n opts: { onConnected?: () => void; registerConfigPath?: string } = {},\n): Promise<void> {\n if (!config.cloud) throw new Error(\"cloud runtime is not configured\");\n if (config.cloud.enabled === false) {\n throw new Error(\"cloud runtime is disabled in config; set cloud.enabled to true to connect\");\n }\n const logger = new Logger({\n filePath: config.log.file,\n level: config.log.level,\n verbose,\n });\n const executor = selectExecutor(logger, { projectDirs });\n const runtime = new CloudRuntime(config.cloud, executor, logger);\n // A foreground session owns the runtime itself, so it records its own PID in\n // the shared state file. That lets a later `connect`/`disconnect` find and\n // stop it, just like a detached background runtime. Background `_run` children\n // do not register here; their launcher records the child PID instead.\n if (opts.registerConfigPath) {\n writeRuntimeState(opts.registerConfigPath, process.pid, projectDirs);\n }\n try {\n await runtime.start();\n } catch (error) {\n if (opts.registerConfigPath) clearRuntimeState(opts.registerConfigPath);\n throw error;\n }\n opts.onConnected?.();\n process.stdout.write(`${binaryName}: connected to ${config.cloud.gateway_url}. Press Ctrl+C to stop.\\n`);\n\n await new Promise<void>((resolve) => {\n const shutdown = () => {\n if (opts.registerConfigPath) clearRuntimeState(opts.registerConfigPath);\n runtime.stop();\n void Promise.resolve(executor.close?.()).finally(() => {\n void logger.close().finally(() => resolve());\n });\n };\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n });\n}\n\nasync function startAndReportBackgroundRuntime(\n configPath: string,\n projectDirs: string[],\n binaryName: string,\n verbose = false,\n): Promise<void> {\n const binaryPath = process.argv[1];\n if (!binaryPath) throw new Error(\"could not resolve the gsd-cloud executable path\");\n const status = await startBackgroundRuntime({ binaryPath, configPath, projectDirs, verbose });\n process.stdout.write(`${binaryName}: connected in the background (PID ${status.pid}).\\n`);\n for (const project of projectDirs) process.stdout.write(`${binaryName}: project ${project}\\n`);\n process.stdout.write(`${binaryName}: logs ${status.log_file}\\n`);\n}\n\nfunction selectedProjectDirs(savedProjectDirs: string[]): string[] {\n const configured = process.env[\"GSD_CLOUD_PROJECTS\"];\n if (configured?.trim()) {\n const configuredPaths = uniqueResolvedPaths(configured.split(delimiter));\n if (configuredPaths.length > 0) return configuredPaths;\n }\n if (savedProjectDirs.length > 0) {\n const savedPaths = uniqueResolvedPaths(savedProjectDirs);\n if (savedPaths.length > 0) return savedPaths;\n }\n return [canonicalizePath(process.cwd())];\n}\n\nfunction uniqueResolvedPaths(paths: string[]): string[] {\n const resolved = paths\n .map((path) => path.trim())\n .filter(Boolean)\n .map((path) => canonicalizePath(path));\n return [...new Set(resolved)];\n}\n\n/**\n * Resolve a project path to its canonical, symlink-free absolute form. The\n * executor advertises project paths via `resolve()` alone, so canonicalizing\n * here keeps the saved `scan_roots` and the advertised hello paths identical to\n * the real directory (e.g. when the cwd or GSD_CLOUD_PROJECTS points through a\n * symlink). Falls back to the plain resolved path when the target does not yet\n * exist on disk.\n */\nfunction canonicalizePath(path: string): string {\n const resolved = resolve(path);\n try {\n return realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\nexport function formatUsage(binaryName: string): string {\n return `Usage: ${binaryName} login [--gateway <url>] [--runtime-name <name>] [--config <path>] [--foreground]\n ${binaryName} status [--config <path>]\n ${binaryName} pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n ${binaryName} connect [--config <path>] [--verbose] [--foreground]\n ${binaryName} disconnect [--config <path>]\n\nCommands:\n login (Recommended) Browser-based pairing — opens an approval URL, then\n connects the current project in the background. Defaults to the\n public GSD Cloud gateway.\n status Show current cloud runtime configuration and connection status.\n pair Exchange a pairing code for a device token (headless/CI environments).\n connect Start a background connection using saved credentials and projects.\n disconnect Stop the background runtime and remove local cloud credentials.\n\nOptions:\n --config <path> Path to YAML config file (default: ~/.gsd/daemon.yaml)\n --gateway <url> Cloud gateway URL (login defaults to https://cloud.opengsd.net)\n --code <code> Pairing code from the gateway (pair only)\n --runtime-name <name> Friendly name for this local GSD runtime\n --verbose Print log entries to stderr in addition to the log file\n --foreground Keep login/connect attached to this terminal (debugging)\n --help Show this help message and exit\n\nEnvironment:\n GSD_CLOUD_PROJECTS Path-delimiter separated project dirs to advertise\n (default: current working directory)\n GSD_CLI_PATH Path to the gsd binary (default: gsd on PATH)\n GSD_CLOUD_EXECUTOR Backend adapter: gsd-pi (default), codex, claude\n`;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["// Project/App: Open GSD\n// File Purpose: Standalone gsd-cloud CLI — login / status / connect / disconnect.\n//\n// Wires device-flow + CloudRuntime + a selected Executor adapter DIRECTLY. It has\n// no dependency on any Daemon or Orchestrator class; the only cloud behaviour is\n// the WS relay client driving the local GSD runtime through the Executor seam.\n\nimport { parseArgs } from \"node:util\";\nimport { realpathSync } from \"node:fs\";\nimport { delimiter, resolve } from \"node:path\";\nimport { resolveConfigPath, loadConfig } from \"./config.js\";\nimport { Logger } from \"./logger.js\";\nimport {\n clearCloudConfig,\n exchangePairingCode,\n redactedCloudStatus,\n saveCloudConfig,\n} from \"./cloud-config.js\";\nimport { runDeviceFlow } from \"./device-flow.js\";\nimport { CloudRuntime } from \"./cloud-runtime.js\";\nimport { selectExecutor } from \"./executors/index.js\";\nimport {\n acquireRuntimeStartLock,\n backgroundRuntimeStatus,\n clearRuntimeState,\n startBackgroundRuntime,\n stopBackgroundRuntime,\n writeRuntimeState,\n} from \"./runtime-process.js\";\nimport { clearRuntimeTelemetry, readRuntimeTelemetry, RuntimeTelemetryStore } from \"./runtime-telemetry.js\";\nimport type { DaemonConfig } from \"./types.js\";\n\nexport async function handleCloudCommand(argv: string[], opts: {\n binaryName: string;\n}): Promise<void> {\n if (argv[0] === \"--help\" || argv[0] === \"-h\") {\n process.stdout.write(formatUsage(opts.binaryName));\n process.exit(0);\n }\n\n const command = argv[0];\n const { values } = parseArgs({\n args: argv.slice(1),\n options: {\n config: { type: \"string\", short: \"c\" },\n gateway: { type: \"string\" },\n code: { type: \"string\" },\n \"runtime-name\": { type: \"string\" },\n verbose: { type: \"boolean\", short: \"v\", default: false },\n foreground: { type: \"boolean\", default: false },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n strict: true,\n });\n\n if (values.help || !command) {\n process.stdout.write(formatUsage(opts.binaryName));\n process.exit(0);\n }\n\n const configPath = resolveConfigPath(values.config);\n\n if (command === \"status\") {\n const config = loadConfig(configPath);\n process.stdout.write(`${JSON.stringify({\n ...redactedCloudStatus(config),\n projects: config.projects.scan_roots,\n background: backgroundRuntimeStatus(configPath),\n telemetry: readRuntimeTelemetry(configPath),\n }, null, 2)}\\n`);\n return;\n }\n\n if (command === \"disconnect\") {\n await stopBackgroundRuntime(configPath);\n clearCloudConfig(configPath);\n clearRuntimeTelemetry(configPath);\n process.stdout.write(`${opts.binaryName}: background runtime stopped and cloud credentials removed.\\n`);\n return;\n }\n\n if (command === \"stop\") {\n const stopped = await stopBackgroundRuntime(configPath);\n process.stdout.write(stopped\n ? `${opts.binaryName}: background runtime stopped.\\n`\n : `${opts.binaryName}: background runtime is not running.\\n`);\n return;\n }\n\n if (command === \"login\") {\n if (!values.gateway) {\n throw new Error(\"login requires --gateway\");\n }\n const runtimeName = values[\"runtime-name\"];\n const { deviceToken, runtimeId, gatewayUrl } = await runDeviceFlow({\n gatewayUrl: values.gateway,\n configPath,\n runtimeName,\n binaryName: opts.binaryName,\n });\n const projectDirs = selectedProjectDirs([]);\n const config = saveCloudConfig(configPath, {\n gateway_url: gatewayUrl,\n device_token: deviceToken,\n runtime_id: runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n }, projectDirs);\n process.stdout.write(`${opts.binaryName}: cloud runtime ${runtimeId} paired — connecting...\\n`);\n if (values.foreground) {\n await runForegroundCloudRuntime(config, configPath, opts.binaryName, values.verbose, projectDirs);\n return;\n }\n await startAndReportBackgroundRuntime(configPath, projectDirs, opts.binaryName, values.verbose);\n return;\n }\n\n if (command === \"pair\") {\n if (!values.gateway || !values.code) {\n throw new Error(\"pair requires --gateway and --code\");\n }\n const runtimeName = values[\"runtime-name\"];\n const result = await exchangePairingCode({\n gatewayUrl: values.gateway,\n code: values.code,\n runtimeName,\n });\n saveCloudConfig(configPath, {\n gateway_url: values.gateway,\n device_token: result.deviceToken,\n runtime_id: result.runtimeId,\n ...(runtimeName ? { runtime_name: runtimeName } : {}),\n enabled: true,\n });\n process.stdout.write(`${opts.binaryName}: paired cloud runtime ${result.runtimeId}.\\n`);\n return;\n }\n\n if (command === \"connect\") {\n let config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `login` first\");\n }\n const projectDirs = selectedProjectDirs(config.projects.scan_roots);\n config = saveCloudConfig(configPath, config.cloud, projectDirs);\n if (values.foreground) {\n await runForegroundCloudRuntime(config, configPath, opts.binaryName, values.verbose, projectDirs);\n return;\n }\n await startAndReportBackgroundRuntime(configPath, projectDirs, opts.binaryName, values.verbose);\n return;\n }\n\n if (command === \"_run\") {\n const config = loadConfig(configPath);\n if (!config.cloud?.device_token || !config.cloud.runtime_id) {\n throw new Error(\"cloud runtime is not paired; run `login` first\");\n }\n const projectDirs = selectedProjectDirs(config.projects.scan_roots);\n await runCloudRuntime(config, configPath, opts.binaryName, values.verbose, projectDirs, {\n onConnected: () => {\n process.send?.({ type: \"ready\" });\n },\n });\n return;\n }\n\n throw new Error(`Unknown cloud runtime command: ${command}`);\n}\n\nasync function runForegroundCloudRuntime(\n config: DaemonConfig,\n configPath: string,\n binaryName: string,\n verbose: boolean,\n projectDirs: string[],\n): Promise<void> {\n const releaseStartLock = await acquireRuntimeStartLock(configPath);\n try {\n await stopBackgroundRuntime(configPath);\n await runCloudRuntime(config, configPath, binaryName, verbose, projectDirs, {\n registerConfigPath: configPath,\n onConnected: releaseStartLock,\n });\n } finally {\n releaseStartLock();\n }\n}\n\n/**\n * Start the WS relay and block until the process is signalled. This is the whole\n * \"daemon\" for the standalone agent: one CloudRuntime + one Executor, no Discord,\n * no scanner, no session-manager class.\n */\nasync function runCloudRuntime(\n config: DaemonConfig,\n configPath: string,\n binaryName: string,\n verbose: boolean,\n projectDirs: string[],\n opts: { onConnected?: () => void; registerConfigPath?: string } = {},\n): Promise<void> {\n if (!config.cloud) throw new Error(\"cloud runtime is not configured\");\n if (config.cloud.enabled === false) {\n throw new Error(\"cloud runtime is disabled in config; set cloud.enabled to true to connect\");\n }\n const logger = new Logger({\n filePath: config.log.file,\n level: config.log.level,\n verbose,\n });\n const executor = selectExecutor(logger, { projectDirs });\n const telemetry = new RuntimeTelemetryStore(configPath, {\n gatewayUrl: config.cloud.gateway_url,\n runtimeId: config.cloud.runtime_id,\n runtimeName: config.cloud.runtime_name,\n });\n const runtime = new CloudRuntime(config.cloud, executor, logger, telemetry);\n // A foreground session owns the runtime itself, so it records its own PID in\n // the shared state file. That lets a later `connect`/`disconnect` find and\n // stop it, just like a detached background runtime. Background `_run` children\n // do not register here; their launcher records the child PID instead.\n if (opts.registerConfigPath) {\n writeRuntimeState(opts.registerConfigPath, process.pid, projectDirs);\n }\n try {\n await runtime.start();\n } catch (error) {\n if (opts.registerConfigPath) clearRuntimeState(opts.registerConfigPath);\n throw error;\n }\n opts.onConnected?.();\n process.stdout.write(`${binaryName}: connected to ${config.cloud.gateway_url}. Press Ctrl+C to stop.\\n`);\n\n await new Promise<void>((resolve) => {\n const shutdown = () => {\n if (opts.registerConfigPath) clearRuntimeState(opts.registerConfigPath);\n runtime.stop();\n void Promise.resolve(executor.close?.()).finally(() => {\n void logger.close().finally(() => resolve());\n });\n };\n process.once(\"SIGINT\", shutdown);\n process.once(\"SIGTERM\", shutdown);\n });\n}\n\nasync function startAndReportBackgroundRuntime(\n configPath: string,\n projectDirs: string[],\n binaryName: string,\n verbose = false,\n): Promise<void> {\n const binaryPath = process.argv[1];\n if (!binaryPath) throw new Error(\"could not resolve the gsd-cloud executable path\");\n const status = await startBackgroundRuntime({ binaryPath, configPath, projectDirs, verbose });\n process.stdout.write(`${binaryName}: connected in the background (PID ${status.pid}).\\n`);\n for (const project of projectDirs) process.stdout.write(`${binaryName}: project ${project}\\n`);\n process.stdout.write(`${binaryName}: logs ${status.log_file}\\n`);\n}\n\nfunction selectedProjectDirs(savedProjectDirs: string[]): string[] {\n const configured = process.env[\"GSD_CLOUD_PROJECTS\"];\n if (configured?.trim()) {\n const configuredPaths = uniqueResolvedPaths(configured.split(delimiter));\n if (configuredPaths.length > 0) return configuredPaths;\n }\n if (savedProjectDirs.length > 0) {\n const savedPaths = uniqueResolvedPaths(savedProjectDirs);\n if (savedPaths.length > 0) return savedPaths;\n }\n return [canonicalizePath(process.cwd())];\n}\n\nfunction uniqueResolvedPaths(paths: string[]): string[] {\n const resolved = paths\n .map((path) => path.trim())\n .filter(Boolean)\n .map((path) => canonicalizePath(path));\n return [...new Set(resolved)];\n}\n\n/**\n * Resolve a project path to its canonical, symlink-free absolute form. The\n * executor advertises project paths via `resolve()` alone, so canonicalizing\n * here keeps the saved `scan_roots` and the advertised hello paths identical to\n * the real directory (e.g. when the cwd or GSD_CLOUD_PROJECTS points through a\n * symlink). Falls back to the plain resolved path when the target does not yet\n * exist on disk.\n */\nfunction canonicalizePath(path: string): string {\n const resolved = resolve(path);\n try {\n return realpathSync(resolved);\n } catch {\n return resolved;\n }\n}\n\nexport function formatUsage(binaryName: string): string {\n return `Usage: ${binaryName} login [--gateway <url>] [--runtime-name <name>] [--config <path>] [--foreground]\n ${binaryName} status [--config <path>]\n ${binaryName} pair --gateway <url> --code <code> [--runtime-name <name>] [--config <path>]\n ${binaryName} connect [--config <path>] [--verbose] [--foreground]\n ${binaryName} stop [--config <path>]\n ${binaryName} disconnect [--config <path>]\n\nCommands:\n login (Recommended) Browser-based pairing — opens an approval URL, then\n connects the current project in the background. Defaults to the\n public GSD Cloud gateway.\n status Show current cloud runtime configuration and connection status.\n pair Exchange a pairing code for a device token (headless/CI environments).\n connect Start a background connection using saved credentials and projects.\n stop Stop the background runtime without removing saved credentials.\n disconnect Stop the background runtime and remove local cloud credentials.\n\nOptions:\n --config <path> Path to YAML config file (default: ~/.gsd/daemon.yaml)\n --gateway <url> Cloud gateway URL (login defaults to https://cloud.opengsd.net)\n --code <code> Pairing code from the gateway (pair only)\n --runtime-name <name> Friendly name for this local GSD runtime\n --verbose Print log entries to stderr in addition to the log file\n --foreground Keep login/connect attached to this terminal (debugging)\n --help Show this help message and exit\n\nEnvironment:\n GSD_CLOUD_PROJECTS Path-delimiter separated project dirs to advertise\n (default: current working directory)\n GSD_CLI_PATH Path to the gsd binary (default: gsd on PATH)\n GSD_CLOUD_EXECUTOR Backend adapter: gsd-pi (default), codex, claude\n`;\n}\n"]}
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import type { Logger } from "./logger.js";
|
|
2
2
|
import type { DaemonConfig } from "./types.js";
|
|
3
3
|
import type { Executor } from "./executors/executor.js";
|
|
4
|
+
import { type RuntimeTelemetryReporter } from "./runtime-telemetry.js";
|
|
4
5
|
export declare const CLOUD_RUNTIME_INITIAL_CONNECT_WINDOW_MS: number;
|
|
5
6
|
export declare class CloudRuntime {
|
|
6
7
|
private readonly cloud;
|
|
7
8
|
private readonly executor;
|
|
8
9
|
private readonly logger;
|
|
10
|
+
private readonly telemetry;
|
|
9
11
|
private static readonly MAX_OUTBOX;
|
|
10
12
|
private socket;
|
|
11
13
|
private heartbeat;
|
|
12
14
|
private reconnect;
|
|
13
15
|
private readonly inFlight;
|
|
14
16
|
private outbox;
|
|
17
|
+
private advertisedProjects;
|
|
15
18
|
private stopped;
|
|
16
19
|
private firstConnectDeferred;
|
|
17
20
|
private initialConnectAttempts;
|
|
18
|
-
constructor(cloud: NonNullable<DaemonConfig["cloud"]>, executor: Executor, logger: Logger);
|
|
21
|
+
constructor(cloud: NonNullable<DaemonConfig["cloud"]>, executor: Executor, logger: Logger, telemetry?: RuntimeTelemetryReporter);
|
|
19
22
|
start(): Promise<void>;
|
|
20
23
|
stop(): void;
|
|
21
24
|
private connect;
|
|
@@ -25,6 +28,8 @@ export declare class CloudRuntime {
|
|
|
25
28
|
private handleSocketError;
|
|
26
29
|
private advertiseProjects;
|
|
27
30
|
private handleMessage;
|
|
31
|
+
private resolveRoutingKey;
|
|
32
|
+
private resolveProject;
|
|
28
33
|
private cancelInFlight;
|
|
29
34
|
private resolveFirstConnect;
|
|
30
35
|
private rejectFirstConnect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-runtime.d.ts","sourceRoot":"","sources":["../src/cloud-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"cloud-runtime.d.ts","sourceRoot":"","sources":["../src/cloud-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAqB,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE3E,OAAO,EAEL,KAAK,wBAAwB,EAC9B,MAAM,wBAAwB,CAAC;AAMhC,eAAO,MAAM,uCAAuC,QAEG,CAAC;AAoBxD,qBAAa,YAAY;IAkBrB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IApB5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAO;IAMzC,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAA6C;IAC9D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;IAC/D,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,kBAAkB,CAA2B;IACrD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,oBAAoB,CAAyC;IACrE,OAAO,CAAC,sBAAsB,CAAK;gBAGhB,KAAK,EAAE,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,EACzC,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,wBAA+C;IAG7E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBtB,IAAI,IAAI,IAAI;IAeZ,OAAO,CAAC,OAAO;IAsDf,OAAO,CAAC,gBAAgB;YAuBV,mBAAmB;IAMjC,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,iBAAiB;YAMX,iBAAiB;YAYjB,aAAa;IAgE3B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,cAAc;YAWR,cAAc;IA4B5B,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,IAAI;CAeb"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import WebSocket from "ws";
|
|
2
2
|
import { createGatewayLookup, parseCloudGatewayUrl, validateGatewayNetworkTarget } from "./cloud-config.js";
|
|
3
|
+
import { noopRuntimeTelemetry, } from "./runtime-telemetry.js";
|
|
3
4
|
const INITIAL_CONNECT_ATTEMPTS = 5;
|
|
4
5
|
const INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS = 30_000;
|
|
5
6
|
const RECONNECT_DELAY_MS = 5_000;
|
|
@@ -9,6 +10,7 @@ export class CloudRuntime {
|
|
|
9
10
|
cloud;
|
|
10
11
|
executor;
|
|
11
12
|
logger;
|
|
13
|
+
telemetry;
|
|
12
14
|
static MAX_OUTBOX = 200;
|
|
13
15
|
// How many times to retry the initial connect before rejecting start(). A
|
|
14
16
|
// transient handshake failure (gateway briefly unreachable, DNS hiccup) should
|
|
@@ -20,23 +22,39 @@ export class CloudRuntime {
|
|
|
20
22
|
reconnect;
|
|
21
23
|
inFlight = new Map();
|
|
22
24
|
outbox = [];
|
|
25
|
+
advertisedProjects = [];
|
|
23
26
|
stopped = false;
|
|
24
27
|
firstConnectDeferred;
|
|
25
28
|
initialConnectAttempts = 0;
|
|
26
|
-
constructor(cloud, executor, logger) {
|
|
29
|
+
constructor(cloud, executor, logger, telemetry = noopRuntimeTelemetry) {
|
|
27
30
|
this.cloud = cloud;
|
|
28
31
|
this.executor = executor;
|
|
29
32
|
this.logger = logger;
|
|
33
|
+
this.telemetry = telemetry;
|
|
30
34
|
}
|
|
31
35
|
start() {
|
|
32
36
|
this.stopped = false;
|
|
33
37
|
this.initialConnectAttempts = 0;
|
|
34
|
-
|
|
35
|
-
this.
|
|
36
|
-
|
|
38
|
+
const firstConnect = Promise.withResolvers();
|
|
39
|
+
this.firstConnectDeferred = firstConnect;
|
|
40
|
+
const result = firstConnect.promise.catch(async (error) => {
|
|
41
|
+
this.telemetry.failed?.();
|
|
42
|
+
await this.telemetry.flush?.();
|
|
43
|
+
throw error;
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
this.connect();
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
50
|
+
this.telemetry.socketError(message);
|
|
51
|
+
this.rejectFirstConnect(error instanceof Error ? error : new Error(message));
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
37
54
|
}
|
|
38
55
|
stop() {
|
|
39
56
|
this.stopped = true;
|
|
57
|
+
this.telemetry.stopped();
|
|
40
58
|
this.rejectFirstConnect(new Error("cloud runtime stopped"));
|
|
41
59
|
if (this.reconnect)
|
|
42
60
|
clearTimeout(this.reconnect);
|
|
@@ -54,9 +72,12 @@ export class CloudRuntime {
|
|
|
54
72
|
if (this.reconnect)
|
|
55
73
|
clearTimeout(this.reconnect);
|
|
56
74
|
this.reconnect = undefined;
|
|
75
|
+
this.telemetry.connecting();
|
|
57
76
|
if (!this.cloud.device_token || !this.cloud.runtime_id) {
|
|
77
|
+
const message = "cloud runtime missing device token or runtime id";
|
|
58
78
|
this.logger.warn("cloud runtime skipped — missing device token or runtime id");
|
|
59
|
-
this.
|
|
79
|
+
this.telemetry.socketError(message);
|
|
80
|
+
this.rejectFirstConnect(new Error(message));
|
|
60
81
|
return;
|
|
61
82
|
}
|
|
62
83
|
const gatewayUrl = parseCloudGatewayUrl(this.cloud.gateway_url);
|
|
@@ -66,6 +87,7 @@ export class CloudRuntime {
|
|
|
66
87
|
catch (err) {
|
|
67
88
|
const message = err instanceof Error ? err.message : String(err);
|
|
68
89
|
this.logger.warn("cloud runtime skipped unsafe gateway URL", { error: message });
|
|
90
|
+
this.telemetry.socketError(message);
|
|
69
91
|
this.rejectFirstConnect(new Error(`cloud runtime unsafe gateway URL: ${message}`));
|
|
70
92
|
return;
|
|
71
93
|
}
|
|
@@ -103,6 +125,7 @@ export class CloudRuntime {
|
|
|
103
125
|
handleSocketOpen(socket) {
|
|
104
126
|
if (socket !== this.socket)
|
|
105
127
|
return;
|
|
128
|
+
this.telemetry.connected();
|
|
106
129
|
this.resolveFirstConnect();
|
|
107
130
|
this.logger.info("cloud runtime connected", { gateway_url: this.cloud.gateway_url, runtime_id: this.cloud.runtime_id });
|
|
108
131
|
// Re-advertise projects (async: the hello is sent on a later microtask), then
|
|
@@ -112,11 +135,13 @@ export class CloudRuntime {
|
|
|
112
135
|
void this.advertiseProjects();
|
|
113
136
|
const pending = this.outbox;
|
|
114
137
|
this.outbox = [];
|
|
115
|
-
for (const
|
|
116
|
-
if (this.socket?.readyState === WebSocket.OPEN)
|
|
117
|
-
this.socket.send(text);
|
|
138
|
+
for (const frame of pending) {
|
|
139
|
+
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
140
|
+
this.socket.send(frame.text);
|
|
141
|
+
this.telemetry.sent(frame.text, frame.projectPath);
|
|
142
|
+
}
|
|
118
143
|
else
|
|
119
|
-
this.outbox.push(
|
|
144
|
+
this.outbox.push(frame);
|
|
120
145
|
}
|
|
121
146
|
if (this.heartbeat)
|
|
122
147
|
clearInterval(this.heartbeat);
|
|
@@ -125,6 +150,7 @@ export class CloudRuntime {
|
|
|
125
150
|
async handleSocketMessage(socket, text) {
|
|
126
151
|
if (socket !== this.socket)
|
|
127
152
|
return;
|
|
153
|
+
this.telemetry.received(text);
|
|
128
154
|
await this.handleMessage(text);
|
|
129
155
|
}
|
|
130
156
|
handleSocketClose(socket) {
|
|
@@ -136,6 +162,7 @@ export class CloudRuntime {
|
|
|
136
162
|
this.socket = undefined;
|
|
137
163
|
if (this.stopped)
|
|
138
164
|
return;
|
|
165
|
+
this.telemetry.disconnected();
|
|
139
166
|
if (this.firstConnectDeferred) {
|
|
140
167
|
// Still trying to establish the first connection: retry transient
|
|
141
168
|
// handshake failures (like the daemon's reconnect loop) and only reject
|
|
@@ -143,7 +170,9 @@ export class CloudRuntime {
|
|
|
143
170
|
// not kill the runtime while a persistent outage still surfaces an error.
|
|
144
171
|
this.initialConnectAttempts += 1;
|
|
145
172
|
if (this.initialConnectAttempts >= INITIAL_CONNECT_ATTEMPTS) {
|
|
146
|
-
|
|
173
|
+
const error = new Error(`cloud runtime connection failed after ${this.initialConnectAttempts} attempt(s)`);
|
|
174
|
+
this.telemetry.socketError(error.message);
|
|
175
|
+
this.rejectFirstConnect(error);
|
|
147
176
|
return;
|
|
148
177
|
}
|
|
149
178
|
this.logger.warn("cloud runtime initial connect failed; retrying", {
|
|
@@ -162,9 +191,12 @@ export class CloudRuntime {
|
|
|
162
191
|
if (socket !== this.socket)
|
|
163
192
|
return;
|
|
164
193
|
this.logger.warn("cloud runtime socket error", { error: err.message });
|
|
194
|
+
this.telemetry.socketError(err.message);
|
|
165
195
|
}
|
|
166
196
|
async advertiseProjects() {
|
|
167
197
|
const projects = await this.executor.advertisedProjects();
|
|
198
|
+
this.advertisedProjects = projects;
|
|
199
|
+
this.telemetry.projectsAdvertised(projects);
|
|
168
200
|
this.send({
|
|
169
201
|
type: "hello",
|
|
170
202
|
runtimeId: this.cloud.runtime_id,
|
|
@@ -186,25 +218,75 @@ export class CloudRuntime {
|
|
|
186
218
|
}
|
|
187
219
|
if (message.type !== "tool_call" || !message.requestId || !message.toolName)
|
|
188
220
|
return;
|
|
189
|
-
this.
|
|
221
|
+
const routingKey = this.resolveRoutingKey(message);
|
|
222
|
+
const project = this.resolveProject(routingKey);
|
|
223
|
+
const projectAlias = project?.alias;
|
|
224
|
+
const projectPath = project?.path;
|
|
225
|
+
const startedAt = Date.now();
|
|
226
|
+
const receivedBytes = Buffer.byteLength(text);
|
|
227
|
+
this.inFlight.set(message.requestId, {
|
|
228
|
+
message,
|
|
229
|
+
...(routingKey !== undefined ? { routingKey } : {}),
|
|
230
|
+
});
|
|
231
|
+
this.telemetry.requestStarted({
|
|
232
|
+
requestId: message.requestId,
|
|
233
|
+
...(projectAlias ? { projectAlias } : {}),
|
|
234
|
+
...(projectPath ? { projectPath } : {}),
|
|
235
|
+
toolName: message.toolName,
|
|
236
|
+
receivedBytes,
|
|
237
|
+
});
|
|
238
|
+
let outcome = "success";
|
|
239
|
+
let errorMessage;
|
|
190
240
|
try {
|
|
191
|
-
const result = await this.executor.execute(message.toolName, message.args ?? {},
|
|
192
|
-
if (!this.inFlight.has(message.requestId))
|
|
241
|
+
const result = await this.executor.execute(message.toolName, message.args ?? {}, routingKey);
|
|
242
|
+
if (!this.inFlight.has(message.requestId)) {
|
|
243
|
+
outcome = "cancelled";
|
|
193
244
|
return;
|
|
194
|
-
|
|
245
|
+
}
|
|
246
|
+
this.send({ type: "tool_result", requestId: message.requestId, result }, projectPath);
|
|
195
247
|
}
|
|
196
248
|
catch (err) {
|
|
197
|
-
if (!this.inFlight.has(message.requestId))
|
|
249
|
+
if (!this.inFlight.has(message.requestId)) {
|
|
250
|
+
outcome = "cancelled";
|
|
198
251
|
return;
|
|
252
|
+
}
|
|
253
|
+
outcome = "error";
|
|
254
|
+
errorMessage = err instanceof Error ? err.message : String(err);
|
|
199
255
|
this.send({
|
|
200
256
|
type: "tool_result",
|
|
201
257
|
requestId: message.requestId,
|
|
202
|
-
error:
|
|
203
|
-
});
|
|
258
|
+
error: errorMessage,
|
|
259
|
+
}, projectPath);
|
|
204
260
|
}
|
|
205
261
|
finally {
|
|
206
262
|
this.inFlight.delete(message.requestId);
|
|
263
|
+
this.telemetry.requestFinished({
|
|
264
|
+
requestId: message.requestId,
|
|
265
|
+
...(projectAlias ? { projectAlias } : {}),
|
|
266
|
+
...(projectPath ? { projectPath } : {}),
|
|
267
|
+
toolName: message.toolName,
|
|
268
|
+
durationMs: Date.now() - startedAt,
|
|
269
|
+
outcome,
|
|
270
|
+
...(errorMessage ? { error: errorMessage } : {}),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
resolveRoutingKey(message) {
|
|
275
|
+
return message.projectAlias
|
|
276
|
+
?? (typeof message.args?.projectDir === "string" ? message.args.projectDir : undefined)
|
|
277
|
+
?? (typeof message.args?.projectAlias === "string" ? message.args.projectAlias : undefined);
|
|
278
|
+
}
|
|
279
|
+
resolveProject(routingKey) {
|
|
280
|
+
if (routingKey !== undefined) {
|
|
281
|
+
const exact = this.advertisedProjects.find((project) => project.path === routingKey);
|
|
282
|
+
if (exact)
|
|
283
|
+
return exact;
|
|
284
|
+
const matches = this.advertisedProjects.filter((project) => project.alias === routingKey);
|
|
285
|
+
return matches.length === 1 ? matches[0] : undefined;
|
|
207
286
|
}
|
|
287
|
+
if (this.advertisedProjects.length === 1)
|
|
288
|
+
return this.advertisedProjects[0];
|
|
289
|
+
return undefined;
|
|
208
290
|
}
|
|
209
291
|
async cancelInFlight(requestId) {
|
|
210
292
|
const pending = this.inFlight.get(requestId);
|
|
@@ -212,13 +294,12 @@ export class CloudRuntime {
|
|
|
212
294
|
return;
|
|
213
295
|
this.inFlight.delete(requestId);
|
|
214
296
|
try {
|
|
215
|
-
if (typeof pending.args?.sessionId === "string") {
|
|
216
|
-
await this.executor.execute("gsd_cancel", { sessionId: pending.args.sessionId }, pending.
|
|
297
|
+
if (typeof pending.message.args?.sessionId === "string") {
|
|
298
|
+
await this.executor.execute("gsd_cancel", { sessionId: pending.message.args.sessionId }, pending.routingKey);
|
|
217
299
|
return;
|
|
218
300
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
await this.executor.execute("gsd_cancel", { projectDir });
|
|
301
|
+
if (pending.routingKey !== undefined) {
|
|
302
|
+
await this.executor.execute("gsd_cancel", { projectDir: pending.routingKey }, pending.routingKey);
|
|
222
303
|
}
|
|
223
304
|
}
|
|
224
305
|
catch (err) {
|
|
@@ -242,16 +323,17 @@ export class CloudRuntime {
|
|
|
242
323
|
this.firstConnectDeferred = undefined;
|
|
243
324
|
deferred.reject(err);
|
|
244
325
|
}
|
|
245
|
-
send(message) {
|
|
326
|
+
send(message, projectPath) {
|
|
246
327
|
const text = JSON.stringify(message);
|
|
247
328
|
if (this.socket?.readyState === WebSocket.OPEN) {
|
|
248
329
|
this.socket.send(text);
|
|
330
|
+
this.telemetry.sent(text, projectPath);
|
|
249
331
|
return;
|
|
250
332
|
}
|
|
251
333
|
// Buffer while disconnected; flushed on reconnect in handleSocketOpen. Bounded
|
|
252
334
|
// so a long outage cannot grow memory without limit — a stale heartbeat is
|
|
253
335
|
// worth less than a fresh tool_result, so drop oldest first.
|
|
254
|
-
this.outbox.push(text);
|
|
336
|
+
this.outbox.push({ text, ...(projectPath ? { projectPath } : {}) });
|
|
255
337
|
if (this.outbox.length > CloudRuntime.MAX_OUTBOX) {
|
|
256
338
|
this.outbox.shift();
|
|
257
339
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-runtime.js","sourceRoot":"","sources":["../src/cloud-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,IAAI,CAAC;AAI3B,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAE5G,MAAM,wBAAwB,GAAG,CAAC,CAAC;AACnC,MAAM,oCAAoC,GAAG,MAAM,CAAC;AACpD,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC,MAAM,CAAC,MAAM,uCAAuC,GAClD,wBAAwB,GAAG,oCAAoC;MAC7D,CAAC,wBAAwB,GAAG,CAAC,CAAC,GAAG,kBAAkB,CAAC;AAUxD,MAAM,OAAO,YAAY;IAiBJ;IACA;IACA;IAlBX,MAAM,CAAU,UAAU,GAAG,GAAG,CAAC;IACzC,0EAA0E;IAC1E,+EAA+E;IAC/E,yEAAyE;IACzE,gFAAgF;IAChF,mEAAmE;IAC3D,MAAM,CAAwB;IAC9B,SAAS,CAA6C;IACtD,SAAS,CAA4C;IAC5C,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IACtD,MAAM,GAAa,EAAE,CAAC;IACtB,OAAO,GAAG,KAAK,CAAC;IAChB,oBAAoB,CAAyC;IAC7D,sBAAsB,GAAG,CAAC,CAAC;IAEnC,YACmB,KAAyC,EACzC,QAAkB,EAClB,MAAc;QAFd,UAAK,GAAL,KAAK,CAAoC;QACzC,aAAQ,GAAR,QAAQ,CAAU;QAClB,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,sBAAsB,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,oBAAoB,GAAG,OAAO,CAAC,aAAa,EAAQ,CAAC;QAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC;IAC3C,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAC5D,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,IAAI,CAAC,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,MAAM,EAAE,KAAK,EAAE,CAAC;IAClB,CAAC;IAEO,OAAO;QACb,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YACvD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;YAC/E,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;YACvF,OAAO;QACT,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,4BAA4B,CAAC,UAAU,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YACjF,IAAI,CAAC,kBAAkB,CAAC,IAAI,KAAK,CAAC,qCAAqC,OAAO,EAAE,CAAC,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;QACpD,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE;YAC/D,MAAM,EAAE,mBAAmB,CAAC,UAAU,CAAC;YACvC,gBAAgB,EAAE,oCAAoC;SACvD,CAAC,CAAC;QACH,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,cAAc,EAAE,CAAC;YACnB,yEAAyE;YACzE,oEAAoE;YACpE,oDAAoD;YACpD,cAAc,CAAC,kBAAkB,EAAE,CAAC;YACpC,IAAI,cAAc,CAAC,UAAU,KAAK,SAAS,CAAC,OAAO,IAAI,cAAc,CAAC,UAAU,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;gBACtG,cAAc,CAAC,KAAK,EAAE,CAAC;YACzB,CAAC;QACH,CAAC;QAED,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YAC5B,KAAK,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,gBAAgB,CAAC,MAAiB;QACxC,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QACnC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QACxH,8EAA8E;QAC9E,wEAAwE;QACxE,4EAA4E;QAC5E,mBAAmB;QACnB,KAAK,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;gBAClE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,CAAC;QACD,IAAI,IAAI,CAAC,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/F,CAAC;IAEO,KAAK,CAAC,mBAAmB,CAAC,MAAiB,EAAE,IAAY;QAC/D,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QACnC,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAEO,iBAAiB,CAAC,MAAiB;QACzC,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QACnC,IAAI,IAAI,CAAC,SAAS;YAAE,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC9B,kEAAkE;YAClE,wEAAwE;YACxE,wEAAwE;YACxE,0EAA0E;YAC1E,IAAI,CAAC,sBAAsB,IAAI,CAAC,CAAC;YACjC,IAAI,IAAI,CAAC,sBAAsB,IAAI,wBAAwB,EAAE,CAAC;gBAC5D,IAAI,CAAC,kBAAkB,CACrB,IAAI,KAAK,CACP,yCAAyC,IAAI,CAAC,sBAAsB,aAAa,CAClF,CACF,CAAC;gBACF,OAAO;YACT,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gDAAgD,EAAE;gBACjE,OAAO,EAAE,IAAI,CAAC,sBAAsB;gBACpC,GAAG,EAAE,wBAAwB;aAC9B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QAC/D,CAAC;QACD,IAAI,IAAI,CAAC,SAAS;YAAE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,IAAI,CAAC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;IACxE,CAAC;IAEO,iBAAiB,CAAC,MAAiB,EAAE,GAAU;QACrD,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM;YAAE,OAAO;QACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IAEO,KAAK,CAAC,iBAAiB;QAC7B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QAC1D,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU;YAChC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY;YACpC,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,IAAY;QACtC,IAAI,OAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACnD,KAAK,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC5C,OAAO;QACT,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,QAAQ;YAAE,OAAO;QACpF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,EAAE,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;YACvG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;gBAAE,OAAO;YAClD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC;gBAAE,OAAO;YAClD,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAC1C,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,SAAiB;QAC5C,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAChC,IAAI,CAAC;YACH,IAAI,OAAO,OAAO,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ,EAAE,CAAC;gBAChD,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;gBACvG,OAAO;YACT,CAAC;YACD,MAAM,UAAU,GAAG,OAAO,OAAO,CAAC,IAAI,EAAE,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;YACjH,IAAI,UAAU,EAAE,CAAC;gBACf,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE;gBAC9C,SAAS;gBACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;aACxD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,mBAAmB;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC;QAC3C,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC;QACtC,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;IAEO,kBAAkB,CAAC,GAAU;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,oBAAoB,CAAC;QAC3C,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,IAAI,CAAC,oBAAoB,GAAG,SAAS,CAAC;QACtC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IAEO,IAAI,CAAC,OAAgB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,MAAM,EAAE,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,+EAA+E;QAC/E,2EAA2E;QAC3E,6DAA6D;QAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC;YACjD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;IACH,CAAC","sourcesContent":["import WebSocket from \"ws\";\nimport type { Logger } from \"./logger.js\";\nimport type { DaemonConfig } from \"./types.js\";\nimport type { Executor } from \"./executors/executor.js\";\nimport { createGatewayLookup, parseCloudGatewayUrl, validateGatewayNetworkTarget } from \"./cloud-config.js\";\n\nconst INITIAL_CONNECT_ATTEMPTS = 5;\nconst INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS = 30_000;\nconst RECONNECT_DELAY_MS = 5_000;\n\nexport const CLOUD_RUNTIME_INITIAL_CONNECT_WINDOW_MS =\n INITIAL_CONNECT_ATTEMPTS * INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS\n + (INITIAL_CONNECT_ATTEMPTS - 1) * RECONNECT_DELAY_MS;\n\ninterface GatewayMessage {\n type: string;\n requestId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n projectAlias?: string;\n}\n\nexport class CloudRuntime {\n private static readonly MAX_OUTBOX = 200;\n // How many times to retry the initial connect before rejecting start(). A\n // transient handshake failure (gateway briefly unreachable, DNS hiccup) should\n // retry like the daemon's reconnect loop rather than kill the runtime; a\n // persistent failure (gateway down, session rejected) must eventually reject so\n // the CLI reports an error instead of hanging or exiting silently.\n private socket: WebSocket | undefined;\n private heartbeat: ReturnType<typeof setInterval> | undefined;\n private reconnect: ReturnType<typeof setTimeout> | undefined;\n private readonly inFlight = new Map<string, GatewayMessage>();\n private outbox: string[] = [];\n private stopped = false;\n private firstConnectDeferred: PromiseWithResolvers<void> | undefined;\n private initialConnectAttempts = 0;\n\n constructor(\n private readonly cloud: NonNullable<DaemonConfig[\"cloud\"]>,\n private readonly executor: Executor,\n private readonly logger: Logger,\n ) {}\n\n start(): Promise<void> {\n this.stopped = false;\n this.initialConnectAttempts = 0;\n this.firstConnectDeferred = Promise.withResolvers<void>();\n this.connect();\n return this.firstConnectDeferred.promise;\n }\n\n stop(): void {\n this.stopped = true;\n this.rejectFirstConnect(new Error(\"cloud runtime stopped\"));\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = undefined;\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = undefined;\n this.inFlight.clear();\n this.outbox = [];\n const socket = this.socket;\n this.socket = undefined;\n socket?.close();\n }\n\n private connect(): void {\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = undefined;\n if (!this.cloud.device_token || !this.cloud.runtime_id) {\n this.logger.warn(\"cloud runtime skipped — missing device token or runtime id\");\n this.rejectFirstConnect(new Error(\"cloud runtime missing device token or runtime id\"));\n return;\n }\n const gatewayUrl = parseCloudGatewayUrl(this.cloud.gateway_url);\n try {\n validateGatewayNetworkTarget(gatewayUrl);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.warn(\"cloud runtime skipped unsafe gateway URL\", { error: message });\n this.rejectFirstConnect(new Error(`cloud runtime unsafe gateway URL: ${message}`));\n return;\n }\n const url = new URL(\"/runtime/connect\", gatewayUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const socket = new WebSocket(url, {\n headers: { Authorization: `Bearer ${this.cloud.device_token}` },\n lookup: createGatewayLookup(gatewayUrl),\n handshakeTimeout: INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS,\n });\n const previousSocket = this.socket;\n this.socket = socket;\n if (previousSocket) {\n // Detach the old socket's handlers before closing so its listeners don't\n // linger on a socket we've already replaced (handlers also guard on\n // identity, but this releases them eagerly for GC).\n previousSocket.removeAllListeners();\n if (previousSocket.readyState !== WebSocket.CLOSING && previousSocket.readyState !== WebSocket.CLOSED) {\n previousSocket.close();\n }\n }\n\n socket.on(\"open\", () => {\n this.handleSocketOpen(socket);\n });\n socket.on(\"message\", (data) => {\n void this.handleSocketMessage(socket, data.toString(\"utf8\"));\n });\n socket.on(\"close\", () => {\n this.handleSocketClose(socket);\n });\n socket.on(\"error\", (err) => {\n this.handleSocketError(socket, err);\n });\n }\n\n private handleSocketOpen(socket: WebSocket): void {\n if (socket !== this.socket) return;\n this.resolveFirstConnect();\n this.logger.info(\"cloud runtime connected\", { gateway_url: this.cloud.gateway_url, runtime_id: this.cloud.runtime_id });\n // Re-advertise projects (async: the hello is sent on a later microtask), then\n // drain any messages buffered while disconnected. tool_results route by\n // requestId on the authenticated connection, so drain order vs the hello is\n // not significant.\n void this.advertiseProjects();\n const pending = this.outbox;\n this.outbox = [];\n for (const text of pending) {\n if (this.socket?.readyState === WebSocket.OPEN) this.socket.send(text);\n else this.outbox.push(text);\n }\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = setInterval(() => this.send({ type: \"heartbeat\", at: Date.now() }), 30_000);\n }\n\n private async handleSocketMessage(socket: WebSocket, text: string): Promise<void> {\n if (socket !== this.socket) return;\n await this.handleMessage(text);\n }\n\n private handleSocketClose(socket: WebSocket): void {\n if (socket !== this.socket) return;\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = undefined;\n this.socket = undefined;\n if (this.stopped) return;\n if (this.firstConnectDeferred) {\n // Still trying to establish the first connection: retry transient\n // handshake failures (like the daemon's reconnect loop) and only reject\n // start() once the bounded attempts are exhausted, so a brief blip does\n // not kill the runtime while a persistent outage still surfaces an error.\n this.initialConnectAttempts += 1;\n if (this.initialConnectAttempts >= INITIAL_CONNECT_ATTEMPTS) {\n this.rejectFirstConnect(\n new Error(\n `cloud runtime connection failed after ${this.initialConnectAttempts} attempt(s)`,\n ),\n );\n return;\n }\n this.logger.warn(\"cloud runtime initial connect failed; retrying\", {\n attempt: this.initialConnectAttempts,\n max: INITIAL_CONNECT_ATTEMPTS,\n });\n } else {\n this.logger.warn(\"cloud runtime disconnected; reconnecting\");\n }\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = setTimeout(() => this.connect(), RECONNECT_DELAY_MS);\n }\n\n private handleSocketError(socket: WebSocket, err: Error): void {\n if (socket !== this.socket) return;\n this.logger.warn(\"cloud runtime socket error\", { error: err.message });\n }\n\n private async advertiseProjects(): Promise<void> {\n const projects = await this.executor.advertisedProjects();\n this.send({\n type: \"hello\",\n runtimeId: this.cloud.runtime_id,\n runtimeName: this.cloud.runtime_name,\n projects,\n });\n }\n\n private async handleMessage(text: string): Promise<void> {\n let message: GatewayMessage;\n try {\n message = JSON.parse(text) as GatewayMessage;\n } catch {\n return;\n }\n if (message.type === \"cancel\" && message.requestId) {\n void this.cancelInFlight(message.requestId);\n return;\n }\n if (message.type !== \"tool_call\" || !message.requestId || !message.toolName) return;\n this.inFlight.set(message.requestId, message);\n try {\n const result = await this.executor.execute(message.toolName, message.args ?? {}, message.projectAlias);\n if (!this.inFlight.has(message.requestId)) return;\n this.send({ type: \"tool_result\", requestId: message.requestId, result });\n } catch (err) {\n if (!this.inFlight.has(message.requestId)) return;\n this.send({\n type: \"tool_result\",\n requestId: message.requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n } finally {\n this.inFlight.delete(message.requestId);\n }\n }\n\n private async cancelInFlight(requestId: string): Promise<void> {\n const pending = this.inFlight.get(requestId);\n if (!pending) return;\n this.inFlight.delete(requestId);\n try {\n if (typeof pending.args?.sessionId === \"string\") {\n await this.executor.execute(\"gsd_cancel\", { sessionId: pending.args.sessionId }, pending.projectAlias);\n return;\n }\n const projectDir = typeof pending.args?.projectDir === \"string\" ? pending.args.projectDir : pending.projectAlias;\n if (projectDir) {\n await this.executor.execute(\"gsd_cancel\", { projectDir });\n }\n } catch (err) {\n this.logger.warn(\"cloud runtime cancel failed\", {\n requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n private resolveFirstConnect(): void {\n const deferred = this.firstConnectDeferred;\n if (!deferred) return;\n this.firstConnectDeferred = undefined;\n deferred.resolve();\n }\n\n private rejectFirstConnect(err: Error): void {\n const deferred = this.firstConnectDeferred;\n if (!deferred) return;\n this.firstConnectDeferred = undefined;\n deferred.reject(err);\n }\n\n private send(message: unknown): void {\n const text = JSON.stringify(message);\n if (this.socket?.readyState === WebSocket.OPEN) {\n this.socket.send(text);\n return;\n }\n // Buffer while disconnected; flushed on reconnect in handleSocketOpen. Bounded\n // so a long outage cannot grow memory without limit — a stale heartbeat is\n // worth less than a fresh tool_result, so drop oldest first.\n this.outbox.push(text);\n if (this.outbox.length > CloudRuntime.MAX_OUTBOX) {\n this.outbox.shift();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"cloud-runtime.js","sourceRoot":"","sources":["../src/cloud-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import WebSocket from \"ws\";\nimport type { Logger } from \"./logger.js\";\nimport type { DaemonConfig } from \"./types.js\";\nimport type { AdvertisedProject, Executor } from \"./executors/executor.js\";\nimport { createGatewayLookup, parseCloudGatewayUrl, validateGatewayNetworkTarget } from \"./cloud-config.js\";\nimport {\n noopRuntimeTelemetry,\n type RuntimeTelemetryReporter,\n} from \"./runtime-telemetry.js\";\n\nconst INITIAL_CONNECT_ATTEMPTS = 5;\nconst INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS = 30_000;\nconst RECONNECT_DELAY_MS = 5_000;\n\nexport const CLOUD_RUNTIME_INITIAL_CONNECT_WINDOW_MS =\n INITIAL_CONNECT_ATTEMPTS * INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS\n + (INITIAL_CONNECT_ATTEMPTS - 1) * RECONNECT_DELAY_MS;\n\ninterface GatewayMessage {\n type: string;\n requestId?: string;\n toolName?: string;\n args?: Record<string, unknown>;\n projectAlias?: string;\n}\n\ninterface QueuedFrame {\n text: string;\n projectPath?: string;\n}\n\ninterface InFlightRequest {\n message: GatewayMessage;\n routingKey?: string;\n}\n\nexport class CloudRuntime {\n private static readonly MAX_OUTBOX = 200;\n // How many times to retry the initial connect before rejecting start(). A\n // transient handshake failure (gateway briefly unreachable, DNS hiccup) should\n // retry like the daemon's reconnect loop rather than kill the runtime; a\n // persistent failure (gateway down, session rejected) must eventually reject so\n // the CLI reports an error instead of hanging or exiting silently.\n private socket: WebSocket | undefined;\n private heartbeat: ReturnType<typeof setInterval> | undefined;\n private reconnect: ReturnType<typeof setTimeout> | undefined;\n private readonly inFlight = new Map<string, InFlightRequest>();\n private outbox: QueuedFrame[] = [];\n private advertisedProjects: AdvertisedProject[] = [];\n private stopped = false;\n private firstConnectDeferred: PromiseWithResolvers<void> | undefined;\n private initialConnectAttempts = 0;\n\n constructor(\n private readonly cloud: NonNullable<DaemonConfig[\"cloud\"]>,\n private readonly executor: Executor,\n private readonly logger: Logger,\n private readonly telemetry: RuntimeTelemetryReporter = noopRuntimeTelemetry,\n ) {}\n\n start(): Promise<void> {\n this.stopped = false;\n this.initialConnectAttempts = 0;\n const firstConnect = Promise.withResolvers<void>();\n this.firstConnectDeferred = firstConnect;\n const result = firstConnect.promise.catch(async (error: unknown) => {\n this.telemetry.failed?.();\n await this.telemetry.flush?.();\n throw error;\n });\n try {\n this.connect();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n this.telemetry.socketError(message);\n this.rejectFirstConnect(error instanceof Error ? error : new Error(message));\n }\n return result;\n }\n\n stop(): void {\n this.stopped = true;\n this.telemetry.stopped();\n this.rejectFirstConnect(new Error(\"cloud runtime stopped\"));\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = undefined;\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = undefined;\n this.inFlight.clear();\n this.outbox = [];\n const socket = this.socket;\n this.socket = undefined;\n socket?.close();\n }\n\n private connect(): void {\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = undefined;\n this.telemetry.connecting();\n if (!this.cloud.device_token || !this.cloud.runtime_id) {\n const message = \"cloud runtime missing device token or runtime id\";\n this.logger.warn(\"cloud runtime skipped — missing device token or runtime id\");\n this.telemetry.socketError(message);\n this.rejectFirstConnect(new Error(message));\n return;\n }\n const gatewayUrl = parseCloudGatewayUrl(this.cloud.gateway_url);\n try {\n validateGatewayNetworkTarget(gatewayUrl);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.logger.warn(\"cloud runtime skipped unsafe gateway URL\", { error: message });\n this.telemetry.socketError(message);\n this.rejectFirstConnect(new Error(`cloud runtime unsafe gateway URL: ${message}`));\n return;\n }\n const url = new URL(\"/runtime/connect\", gatewayUrl);\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const socket = new WebSocket(url, {\n headers: { Authorization: `Bearer ${this.cloud.device_token}` },\n lookup: createGatewayLookup(gatewayUrl),\n handshakeTimeout: INITIAL_CONNECT_HANDSHAKE_TIMEOUT_MS,\n });\n const previousSocket = this.socket;\n this.socket = socket;\n if (previousSocket) {\n // Detach the old socket's handlers before closing so its listeners don't\n // linger on a socket we've already replaced (handlers also guard on\n // identity, but this releases them eagerly for GC).\n previousSocket.removeAllListeners();\n if (previousSocket.readyState !== WebSocket.CLOSING && previousSocket.readyState !== WebSocket.CLOSED) {\n previousSocket.close();\n }\n }\n\n socket.on(\"open\", () => {\n this.handleSocketOpen(socket);\n });\n socket.on(\"message\", (data) => {\n void this.handleSocketMessage(socket, data.toString(\"utf8\"));\n });\n socket.on(\"close\", () => {\n this.handleSocketClose(socket);\n });\n socket.on(\"error\", (err) => {\n this.handleSocketError(socket, err);\n });\n }\n\n private handleSocketOpen(socket: WebSocket): void {\n if (socket !== this.socket) return;\n this.telemetry.connected();\n this.resolveFirstConnect();\n this.logger.info(\"cloud runtime connected\", { gateway_url: this.cloud.gateway_url, runtime_id: this.cloud.runtime_id });\n // Re-advertise projects (async: the hello is sent on a later microtask), then\n // drain any messages buffered while disconnected. tool_results route by\n // requestId on the authenticated connection, so drain order vs the hello is\n // not significant.\n void this.advertiseProjects();\n const pending = this.outbox;\n this.outbox = [];\n for (const frame of pending) {\n if (this.socket?.readyState === WebSocket.OPEN) {\n this.socket.send(frame.text);\n this.telemetry.sent(frame.text, frame.projectPath);\n }\n else this.outbox.push(frame);\n }\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = setInterval(() => this.send({ type: \"heartbeat\", at: Date.now() }), 30_000);\n }\n\n private async handleSocketMessage(socket: WebSocket, text: string): Promise<void> {\n if (socket !== this.socket) return;\n this.telemetry.received(text);\n await this.handleMessage(text);\n }\n\n private handleSocketClose(socket: WebSocket): void {\n if (socket !== this.socket) return;\n if (this.heartbeat) clearInterval(this.heartbeat);\n this.heartbeat = undefined;\n this.socket = undefined;\n if (this.stopped) return;\n this.telemetry.disconnected();\n if (this.firstConnectDeferred) {\n // Still trying to establish the first connection: retry transient\n // handshake failures (like the daemon's reconnect loop) and only reject\n // start() once the bounded attempts are exhausted, so a brief blip does\n // not kill the runtime while a persistent outage still surfaces an error.\n this.initialConnectAttempts += 1;\n if (this.initialConnectAttempts >= INITIAL_CONNECT_ATTEMPTS) {\n const error = new Error(\n `cloud runtime connection failed after ${this.initialConnectAttempts} attempt(s)`,\n );\n this.telemetry.socketError(error.message);\n this.rejectFirstConnect(error);\n return;\n }\n this.logger.warn(\"cloud runtime initial connect failed; retrying\", {\n attempt: this.initialConnectAttempts,\n max: INITIAL_CONNECT_ATTEMPTS,\n });\n } else {\n this.logger.warn(\"cloud runtime disconnected; reconnecting\");\n }\n if (this.reconnect) clearTimeout(this.reconnect);\n this.reconnect = setTimeout(() => this.connect(), RECONNECT_DELAY_MS);\n }\n\n private handleSocketError(socket: WebSocket, err: Error): void {\n if (socket !== this.socket) return;\n this.logger.warn(\"cloud runtime socket error\", { error: err.message });\n this.telemetry.socketError(err.message);\n }\n\n private async advertiseProjects(): Promise<void> {\n const projects = await this.executor.advertisedProjects();\n this.advertisedProjects = projects;\n this.telemetry.projectsAdvertised(projects);\n this.send({\n type: \"hello\",\n runtimeId: this.cloud.runtime_id,\n runtimeName: this.cloud.runtime_name,\n projects,\n });\n }\n\n private async handleMessage(text: string): Promise<void> {\n let message: GatewayMessage;\n try {\n message = JSON.parse(text) as GatewayMessage;\n } catch {\n return;\n }\n if (message.type === \"cancel\" && message.requestId) {\n void this.cancelInFlight(message.requestId);\n return;\n }\n if (message.type !== \"tool_call\" || !message.requestId || !message.toolName) return;\n const routingKey = this.resolveRoutingKey(message);\n const project = this.resolveProject(routingKey);\n const projectAlias = project?.alias;\n const projectPath = project?.path;\n const startedAt = Date.now();\n const receivedBytes = Buffer.byteLength(text);\n this.inFlight.set(message.requestId, {\n message,\n ...(routingKey !== undefined ? { routingKey } : {}),\n });\n this.telemetry.requestStarted({\n requestId: message.requestId,\n ...(projectAlias ? { projectAlias } : {}),\n ...(projectPath ? { projectPath } : {}),\n toolName: message.toolName,\n receivedBytes,\n });\n let outcome: \"success\" | \"error\" | \"cancelled\" = \"success\";\n let errorMessage: string | undefined;\n try {\n const result = await this.executor.execute(message.toolName, message.args ?? {}, routingKey);\n if (!this.inFlight.has(message.requestId)) {\n outcome = \"cancelled\";\n return;\n }\n this.send({ type: \"tool_result\", requestId: message.requestId, result }, projectPath);\n } catch (err) {\n if (!this.inFlight.has(message.requestId)) {\n outcome = \"cancelled\";\n return;\n }\n outcome = \"error\";\n errorMessage = err instanceof Error ? err.message : String(err);\n this.send({\n type: \"tool_result\",\n requestId: message.requestId,\n error: errorMessage,\n }, projectPath);\n } finally {\n this.inFlight.delete(message.requestId);\n this.telemetry.requestFinished({\n requestId: message.requestId,\n ...(projectAlias ? { projectAlias } : {}),\n ...(projectPath ? { projectPath } : {}),\n toolName: message.toolName,\n durationMs: Date.now() - startedAt,\n outcome,\n ...(errorMessage ? { error: errorMessage } : {}),\n });\n }\n }\n\n private resolveRoutingKey(message: GatewayMessage): string | undefined {\n return message.projectAlias\n ?? (typeof message.args?.projectDir === \"string\" ? message.args.projectDir : undefined)\n ?? (typeof message.args?.projectAlias === \"string\" ? message.args.projectAlias : undefined);\n }\n\n private resolveProject(routingKey?: string): AdvertisedProject | undefined {\n if (routingKey !== undefined) {\n const exact = this.advertisedProjects.find((project) => project.path === routingKey);\n if (exact) return exact;\n const matches = this.advertisedProjects.filter((project) => project.alias === routingKey);\n return matches.length === 1 ? matches[0] : undefined;\n }\n if (this.advertisedProjects.length === 1) return this.advertisedProjects[0];\n return undefined;\n }\n\n private async cancelInFlight(requestId: string): Promise<void> {\n const pending = this.inFlight.get(requestId);\n if (!pending) return;\n this.inFlight.delete(requestId);\n try {\n if (typeof pending.message.args?.sessionId === \"string\") {\n await this.executor.execute(\n \"gsd_cancel\",\n { sessionId: pending.message.args.sessionId },\n pending.routingKey,\n );\n return;\n }\n if (pending.routingKey !== undefined) {\n await this.executor.execute(\n \"gsd_cancel\",\n { projectDir: pending.routingKey },\n pending.routingKey,\n );\n }\n } catch (err) {\n this.logger.warn(\"cloud runtime cancel failed\", {\n requestId,\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n private resolveFirstConnect(): void {\n const deferred = this.firstConnectDeferred;\n if (!deferred) return;\n this.firstConnectDeferred = undefined;\n deferred.resolve();\n }\n\n private rejectFirstConnect(err: Error): void {\n const deferred = this.firstConnectDeferred;\n if (!deferred) return;\n this.firstConnectDeferred = undefined;\n deferred.reject(err);\n }\n\n private send(message: unknown, projectPath?: string): void {\n const text = JSON.stringify(message);\n if (this.socket?.readyState === WebSocket.OPEN) {\n this.socket.send(text);\n this.telemetry.sent(text, projectPath);\n return;\n }\n // Buffer while disconnected; flushed on reconnect in handleSocketOpen. Bounded\n // so a long outage cannot grow memory without limit — a stale heartbeat is\n // worth less than a fresh tool_result, so drop oldest first.\n this.outbox.push({ text, ...(projectPath ? { projectPath } : {}) });\n if (this.outbox.length > CloudRuntime.MAX_OUTBOX) {\n this.outbox.shift();\n }\n }\n}\n"]}
|