@clinebot/core 0.0.35 → 0.0.37
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 +1 -2
- package/dist/ClineCore.d.ts +362 -39
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts.map +1 -1
- package/dist/account/index.d.ts +1 -1
- package/dist/account/index.d.ts.map +1 -1
- package/dist/account/rpc.d.ts +6 -6
- package/dist/account/rpc.d.ts.map +1 -1
- package/dist/cron/cron-event-ingress.d.ts +38 -0
- package/dist/cron/cron-event-ingress.d.ts.map +1 -0
- package/dist/cron/cron-materializer.d.ts +36 -0
- package/dist/cron/cron-materializer.d.ts.map +1 -0
- package/dist/cron/cron-reconciler.d.ts +62 -0
- package/dist/cron/cron-reconciler.d.ts.map +1 -0
- package/dist/cron/cron-report-writer.d.ts +41 -0
- package/dist/cron/cron-report-writer.d.ts.map +1 -0
- package/dist/cron/cron-runner.d.ts +43 -0
- package/dist/cron/cron-runner.d.ts.map +1 -0
- package/dist/cron/cron-schema.d.ts +3 -0
- package/dist/cron/cron-schema.d.ts.map +1 -0
- package/dist/cron/cron-service.d.ts +57 -0
- package/dist/cron/cron-service.d.ts.map +1 -0
- package/dist/cron/cron-spec-parser.d.ts +27 -0
- package/dist/cron/cron-spec-parser.d.ts.map +1 -0
- package/dist/cron/cron-watcher.d.ts +23 -0
- package/dist/cron/cron-watcher.d.ts.map +1 -0
- package/dist/cron/resource-limiter.d.ts +9 -0
- package/dist/cron/resource-limiter.d.ts.map +1 -0
- package/dist/cron/schedule-command-service.d.ts +10 -0
- package/dist/cron/schedule-command-service.d.ts.map +1 -0
- package/dist/cron/schedule-service.d.ts +100 -0
- package/dist/cron/schedule-service.d.ts.map +1 -0
- package/dist/cron/scheduler.d.ts +68 -0
- package/dist/cron/scheduler.d.ts.map +1 -0
- package/dist/cron/sqlite-cron-store.d.ts +230 -0
- package/dist/cron/sqlite-cron-store.d.ts.map +1 -0
- package/dist/cron/sqlite-schedule-store.d.ts +52 -0
- package/dist/cron/sqlite-schedule-store.d.ts.map +1 -0
- package/dist/extensions/config/agent-config-loader.d.ts +4 -3
- package/dist/extensions/config/agent-config-loader.d.ts.map +1 -1
- package/dist/extensions/config/runtime-commands.d.ts +1 -0
- package/dist/extensions/config/runtime-commands.d.ts.map +1 -1
- package/dist/extensions/config/user-instruction-config-loader.d.ts +1 -0
- package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -1
- package/dist/extensions/context/agentic-compaction.d.ts +2 -2
- package/dist/extensions/context/agentic-compaction.d.ts.map +1 -1
- package/dist/extensions/context/compaction-shared.d.ts +5 -4
- package/dist/extensions/context/compaction-shared.d.ts.map +1 -1
- package/dist/extensions/context/compaction.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts +15 -2
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts +13 -7
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts +21 -2
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-targeting.d.ts +7 -0
- package/dist/extensions/plugin/plugin-targeting.d.ts.map +1 -0
- package/dist/extensions/plugin-sandbox-bootstrap.js +237 -276
- package/dist/extensions/tools/constants.d.ts +1 -0
- package/dist/extensions/tools/constants.d.ts.map +1 -1
- package/dist/extensions/tools/definitions.d.ts +3 -4
- package/dist/extensions/tools/definitions.d.ts.map +1 -1
- package/dist/extensions/tools/executors/apply-patch.d.ts +3 -1
- package/dist/extensions/tools/executors/apply-patch.d.ts.map +1 -1
- package/dist/extensions/tools/executors/editor.d.ts.map +1 -1
- package/dist/extensions/tools/executors/search.d.ts +1 -1
- package/dist/extensions/tools/executors/search.d.ts.map +1 -1
- package/dist/extensions/tools/helpers.d.ts +1 -0
- package/dist/extensions/tools/helpers.d.ts.map +1 -1
- package/dist/extensions/tools/index.d.ts +3 -2
- package/dist/extensions/tools/index.d.ts.map +1 -1
- package/dist/extensions/tools/presets.d.ts +27 -44
- package/dist/extensions/tools/presets.d.ts.map +1 -1
- package/dist/extensions/tools/runtime.d.ts +25 -0
- package/dist/extensions/tools/runtime.d.ts.map +1 -0
- package/dist/extensions/tools/schemas.d.ts +25 -3
- package/dist/extensions/tools/schemas.d.ts.map +1 -1
- package/dist/extensions/tools/team/delegated-agent.d.ts +2 -2
- package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/multi-agent.d.ts +7 -3
- package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -1
- package/dist/extensions/tools/team/team-tools.d.ts +1 -0
- package/dist/extensions/tools/team/team-tools.d.ts.map +1 -1
- package/dist/extensions/tools/types.d.ts +0 -5
- package/dist/extensions/tools/types.d.ts.map +1 -1
- package/dist/hooks/hook-bridge.d.ts +118 -0
- package/dist/hooks/hook-bridge.d.ts.map +1 -0
- package/dist/hooks/hook-file-hooks.d.ts +6 -2
- package/dist/hooks/hook-file-hooks.d.ts.map +1 -1
- package/dist/hooks/hook-registry.d.ts +16 -0
- package/dist/hooks/hook-registry.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +0 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/subprocess.d.ts +8 -1
- package/dist/hooks/subprocess.d.ts.map +1 -1
- package/dist/hub/browser-websocket.d.ts +18 -0
- package/dist/hub/browser-websocket.d.ts.map +1 -0
- package/dist/hub/client.d.ts +51 -0
- package/dist/hub/client.d.ts.map +1 -0
- package/dist/hub/connect.d.ts +15 -0
- package/dist/hub/connect.d.ts.map +1 -0
- package/dist/hub/daemon-entry.d.ts +2 -0
- package/dist/hub/daemon-entry.d.ts.map +1 -0
- package/dist/hub/daemon-entry.js +1305 -0
- package/dist/hub/daemon.d.ts +5 -0
- package/dist/hub/daemon.d.ts.map +1 -0
- package/dist/hub/defaults.d.ts +17 -0
- package/dist/hub/defaults.d.ts.map +1 -0
- package/dist/hub/discovery.d.ts +29 -0
- package/dist/hub/discovery.d.ts.map +1 -0
- package/dist/hub/index.d.ts +15 -0
- package/dist/hub/index.d.ts.map +1 -0
- package/dist/hub/index.js +1294 -0
- package/dist/hub/native-transport.d.ts +17 -0
- package/dist/hub/native-transport.d.ts.map +1 -0
- package/dist/hub/runtime-handlers.d.ts +11 -0
- package/dist/hub/runtime-handlers.d.ts.map +1 -0
- package/dist/hub/server.d.ts +104 -0
- package/dist/hub/server.d.ts.map +1 -0
- package/dist/hub/session-client.d.ts +90 -0
- package/dist/hub/session-client.d.ts.map +1 -0
- package/dist/hub/start-shared-server.d.ts +19 -0
- package/dist/hub/start-shared-server.d.ts.map +1 -0
- package/dist/hub/transport.d.ts +8 -0
- package/dist/hub/transport.d.ts.map +1 -0
- package/dist/hub/ui-client.d.ts +45 -0
- package/dist/hub/ui-client.d.ts.map +1 -0
- package/dist/hub/workspace.d.ts +4 -0
- package/dist/hub/workspace.d.ts.map +1 -0
- package/dist/index.d.ts +29 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +782 -471
- package/dist/llms/cline-recommended-models.d.ts +20 -0
- package/dist/llms/cline-recommended-models.d.ts.map +1 -0
- package/dist/llms/configured-provider-registry.d.ts +28 -0
- package/dist/llms/configured-provider-registry.d.ts.map +1 -0
- package/dist/llms/handler-factory.d.ts +16 -0
- package/dist/llms/handler-factory.d.ts.map +1 -0
- package/dist/llms/provider-defaults.d.ts +27 -0
- package/dist/llms/provider-defaults.d.ts.map +1 -0
- package/dist/llms/provider-settings.d.ts +245 -0
- package/dist/llms/provider-settings.d.ts.map +1 -0
- package/dist/llms/runtime-config.d.ts +4 -0
- package/dist/llms/runtime-config.d.ts.map +1 -0
- package/dist/llms/runtime-registry.d.ts +20 -0
- package/dist/llms/runtime-registry.d.ts.map +1 -0
- package/dist/llms/runtime-types.d.ts +85 -0
- package/dist/llms/runtime-types.d.ts.map +1 -0
- package/dist/runtime/agent-config-adapter.d.ts +148 -0
- package/dist/runtime/agent-config-adapter.d.ts.map +1 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts +96 -0
- package/dist/runtime/agent-runtime-config-builder.d.ts.map +1 -0
- package/dist/runtime/history.d.ts +6 -0
- package/dist/runtime/history.d.ts.map +1 -1
- package/dist/runtime/host.d.ts +1 -2
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/loop-detection.d.ts +59 -0
- package/dist/runtime/loop-detection.d.ts.map +1 -0
- package/dist/runtime/mistake-tracker.d.ts +69 -0
- package/dist/runtime/mistake-tracker.d.ts.map +1 -0
- package/dist/runtime/rules.d.ts +1 -0
- package/dist/runtime/rules.d.ts.map +1 -1
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/runtime/runtime-event-adapter.d.ts +102 -0
- package/dist/runtime/runtime-event-adapter.d.ts.map +1 -0
- package/dist/runtime/runtime-host.d.ts +49 -26
- package/dist/runtime/runtime-host.d.ts.map +1 -1
- package/dist/runtime/runtime-oauth-token-manager.d.ts.map +1 -1
- package/dist/runtime/session-runtime-orchestrator.d.ts +261 -0
- package/dist/runtime/session-runtime-orchestrator.d.ts.map +1 -0
- package/dist/runtime/session-runtime.d.ts +16 -21
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/user-input-builder.d.ts +24 -0
- package/dist/runtime/user-input-builder.d.ts.map +1 -0
- package/dist/services/global-settings.d.ts +12 -0
- package/dist/services/global-settings.d.ts.map +1 -0
- package/dist/services/index.js +28 -0
- package/dist/services/local-runtime-bootstrap.d.ts +9 -3
- package/dist/services/local-runtime-bootstrap.d.ts.map +1 -1
- package/dist/services/plugin-tools.d.ts +16 -0
- package/dist/services/plugin-tools.d.ts.map +1 -0
- package/dist/services/providers/local-provider-registry.d.ts +199 -23
- package/dist/services/providers/local-provider-registry.d.ts.map +1 -1
- package/dist/services/providers/local-provider-service.d.ts +15 -13
- package/dist/services/providers/local-provider-service.d.ts.map +1 -1
- package/dist/services/session-data.d.ts +1 -1
- package/dist/services/session-data.d.ts.map +1 -1
- package/dist/services/session-telemetry.d.ts +7 -2
- package/dist/services/session-telemetry.d.ts.map +1 -1
- package/dist/services/storage/file-team-store.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-legacy-migration.d.ts +1 -1
- package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -1
- package/dist/services/storage/provider-settings-manager.d.ts +1 -0
- package/dist/services/storage/provider-settings-manager.d.ts.map +1 -1
- package/dist/services/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/services/workspace-manifest.d.ts +11 -0
- package/dist/services/workspace-manifest.d.ts.map +1 -1
- package/dist/session/conversation-store.d.ts +30 -0
- package/dist/session/conversation-store.d.ts.map +1 -0
- package/dist/session/message-builder.d.ts +65 -0
- package/dist/session/message-builder.d.ts.map +1 -0
- package/dist/session/persistence-service.d.ts +11 -23
- package/dist/session/persistence-service.d.ts.map +1 -1
- package/dist/session/session-manifest-store.d.ts +22 -0
- package/dist/session/session-manifest-store.d.ts.map +1 -0
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/session/session-row.d.ts +93 -0
- package/dist/session/session-row.d.ts.map +1 -0
- package/dist/session/session-service.d.ts +2 -102
- package/dist/session/session-service.d.ts.map +1 -1
- package/dist/session/subagent-session-manager.d.ts +36 -0
- package/dist/session/subagent-session-manager.d.ts.map +1 -0
- package/dist/session/team-persistence-store.d.ts +24 -0
- package/dist/session/team-persistence-store.d.ts.map +1 -0
- package/dist/transports/hub.d.ts +58 -0
- package/dist/transports/hub.d.ts.map +1 -0
- package/dist/transports/local.d.ts +23 -9
- package/dist/transports/local.d.ts.map +1 -1
- package/dist/transports/remote.d.ts +10 -0
- package/dist/transports/remote.d.ts.map +1 -0
- package/dist/transports/runtime-host-support.d.ts +3 -2
- package/dist/transports/runtime-host-support.d.ts.map +1 -1
- package/dist/types/chat-schema.d.ts +15 -17
- package/dist/types/chat-schema.d.ts.map +1 -1
- package/dist/types/config.d.ts +17 -7
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +7 -6
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/provider-settings.d.ts +4 -5
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/session.d.ts +7 -3
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types.d.ts +11 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +20 -6
- package/src/ClineCore.ts +757 -44
- package/src/account/cline-account-service.ts +44 -6
- package/src/account/index.ts +3 -3
- package/src/account/rpc.ts +12 -12
- package/src/cron/cron-event-ingress.ts +357 -0
- package/src/cron/cron-materializer.ts +97 -0
- package/src/cron/cron-reconciler.ts +241 -0
- package/src/cron/cron-report-writer.ts +153 -0
- package/src/cron/cron-runner.ts +495 -0
- package/src/cron/cron-schema.ts +127 -0
- package/src/cron/cron-service.ts +163 -0
- package/src/cron/cron-spec-parser.ts +489 -0
- package/src/cron/cron-watcher.ts +102 -0
- package/src/cron/index.ts +15 -0
- package/src/cron/resource-limiter.ts +46 -0
- package/src/cron/schedule-command-service.ts +193 -0
- package/src/cron/schedule-service.ts +703 -0
- package/src/cron/scheduler.ts +772 -0
- package/src/cron/sqlite-cron-store.ts +1286 -0
- package/src/cron/sqlite-schedule-store.ts +708 -0
- package/src/extensions/config/agent-config-loader.ts +17 -7
- package/src/extensions/config/runtime-commands.ts +6 -0
- package/src/extensions/config/user-instruction-config-loader.ts +1 -0
- package/src/extensions/context/agentic-compaction.ts +3 -3
- package/src/extensions/context/basic-compaction.ts +2 -2
- package/src/extensions/context/compaction-shared.ts +5 -4
- package/src/extensions/context/compaction.ts +3 -3
- package/src/extensions/plugin/plugin-config-loader.ts +37 -2
- package/src/extensions/plugin/plugin-loader.ts +69 -9
- package/src/extensions/plugin/plugin-module-import.ts +0 -2
- package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +243 -39
- package/src/extensions/plugin/plugin-sandbox.ts +173 -29
- package/src/extensions/plugin/plugin-targeting.ts +32 -0
- package/src/extensions/tools/constants.ts +2 -0
- package/src/extensions/tools/definitions.ts +61 -71
- package/src/extensions/tools/executors/apply-patch.ts +69 -80
- package/src/extensions/tools/executors/editor.ts +4 -3
- package/src/extensions/tools/executors/search.ts +195 -3
- package/src/extensions/tools/helpers.ts +24 -0
- package/src/extensions/tools/index.ts +11 -2
- package/src/extensions/tools/presets.ts +32 -47
- package/src/extensions/tools/runtime.ts +261 -0
- package/src/extensions/tools/schemas.ts +17 -20
- package/src/extensions/tools/team/delegated-agent.ts +8 -3
- package/src/extensions/tools/team/multi-agent.ts +135 -19
- package/src/extensions/tools/team/team-tools.ts +172 -91
- package/src/extensions/tools/types.ts +0 -6
- package/src/hooks/hook-bridge.ts +489 -0
- package/src/hooks/hook-file-hooks.ts +66 -5
- package/src/hooks/hook-registry.ts +257 -0
- package/src/hooks/index.ts +0 -7
- package/src/hooks/subprocess-runner.ts +1 -1
- package/src/hooks/subprocess.ts +9 -0
- package/src/hub/browser-websocket.ts +159 -0
- package/src/hub/client.ts +633 -0
- package/src/hub/connect.ts +156 -0
- package/src/hub/daemon-entry.ts +122 -0
- package/src/hub/daemon.ts +284 -0
- package/src/hub/defaults.ts +70 -0
- package/src/hub/discovery.ts +247 -0
- package/src/hub/index.ts +14 -0
- package/src/hub/native-transport.ts +31 -0
- package/src/hub/runtime-handlers.ts +141 -0
- package/src/hub/server.ts +2317 -0
- package/src/hub/session-client.ts +502 -0
- package/src/hub/start-shared-server.ts +61 -0
- package/src/hub/transport.ts +14 -0
- package/src/hub/ui-client.ts +126 -0
- package/src/hub/workspace.ts +19 -0
- package/src/index.ts +169 -68
- package/src/llms/cline-recommended-models.ts +167 -0
- package/src/llms/configured-provider-registry.ts +193 -0
- package/src/llms/handler-factory.ts +56 -0
- package/src/llms/provider-defaults.ts +653 -0
- package/src/llms/provider-settings.ts +310 -0
- package/src/llms/runtime-config.ts +43 -0
- package/src/llms/runtime-registry.ts +172 -0
- package/src/llms/runtime-types.ts +121 -0
- package/src/runtime/agent-config-adapter.ts +636 -0
- package/src/runtime/agent-runtime-config-builder.ts +205 -0
- package/src/runtime/error-feedback.ts +142 -0
- package/src/runtime/history.ts +137 -0
- package/src/runtime/host.ts +127 -267
- package/src/runtime/index.ts +1 -0
- package/src/runtime/loop-detection.ts +162 -0
- package/src/runtime/mistake-tracker.ts +221 -0
- package/src/runtime/rules.ts +12 -0
- package/src/runtime/runtime-builder.ts +85 -13
- package/src/runtime/runtime-event-adapter.ts +412 -0
- package/src/runtime/runtime-host.ts +134 -62
- package/src/runtime/runtime-oauth-token-manager.ts +11 -15
- package/src/runtime/session-runtime-orchestrator.ts +1253 -0
- package/src/runtime/session-runtime.ts +16 -26
- package/src/runtime/user-input-builder.ts +167 -0
- package/src/services/global-settings.ts +122 -0
- package/src/services/local-runtime-bootstrap.ts +175 -31
- package/src/services/plugin-tools.ts +86 -0
- package/src/services/providers/local-provider-registry.ts +277 -61
- package/src/services/providers/local-provider-service.ts +109 -44
- package/src/services/session-data.ts +18 -10
- package/src/services/session-telemetry.ts +6 -15
- package/src/services/storage/file-team-store.ts +1 -5
- package/src/services/storage/provider-settings-legacy-migration.ts +14 -51
- package/src/services/storage/provider-settings-manager.ts +17 -2
- package/src/services/storage/sqlite-team-store.ts +1 -5
- package/src/services/workspace-manifest.ts +18 -0
- package/src/session/conversation-store.ts +77 -0
- package/src/session/file-session-service.ts +1 -1
- package/src/session/index.ts +6 -27
- package/src/session/message-builder.ts +941 -0
- package/src/session/persistence-service.ts +119 -504
- package/src/session/session-manifest-store.ts +158 -0
- package/src/session/session-row.ts +199 -0
- package/src/session/session-service.ts +17 -376
- package/src/session/session-team-coordination.ts +1 -1
- package/src/session/subagent-session-manager.ts +397 -0
- package/src/session/team-persistence-store.ts +176 -0
- package/src/transports/hub.ts +1081 -0
- package/src/transports/local.ts +419 -93
- package/src/transports/remote.ts +27 -0
- package/src/transports/runtime-host-support.ts +63 -9
- package/src/types/chat-schema.ts +4 -5
- package/src/types/config.ts +17 -7
- package/src/types/events.ts +8 -6
- package/src/types/index.ts +3 -0
- package/src/types/provider-settings.ts +18 -7
- package/src/types/session.ts +7 -6
- package/src/types.ts +42 -2
- package/dist/hooks/persistent.d.ts +0 -64
- package/dist/hooks/persistent.d.ts.map +0 -1
- package/dist/runtime/rpc-runtime-ensure.d.ts +0 -65
- package/dist/runtime/rpc-runtime-ensure.d.ts.map +0 -1
- package/dist/runtime/rpc-spawn-lease.d.ts +0 -8
- package/dist/runtime/rpc-spawn-lease.d.ts.map +0 -1
- package/dist/services/telemetry/index.js +0 -15
- package/dist/session/rpc-session-service.d.ts +0 -16
- package/dist/session/rpc-session-service.d.ts.map +0 -1
- package/dist/session/sqlite-rpc-session-backend.d.ts +0 -31
- package/dist/session/sqlite-rpc-session-backend.d.ts.map +0 -1
- package/dist/transports/rpc.d.ts +0 -51
- package/dist/transports/rpc.d.ts.map +0 -1
- package/src/ClineCore.test.ts +0 -226
- package/src/account/cline-account-service.test.ts +0 -185
- package/src/account/featurebase-token.test.ts +0 -175
- package/src/account/rpc.test.ts +0 -63
- package/src/auth/bounded-ttl-cache.test.ts +0 -38
- package/src/auth/client.test.ts +0 -69
- package/src/auth/cline.test.ts +0 -267
- package/src/auth/codex.test.ts +0 -170
- package/src/auth/oca.test.ts +0 -340
- package/src/auth/server.test.ts +0 -287
- package/src/auth/utils.test.ts +0 -128
- package/src/extensions/config/agent-config-loader.test.ts +0 -236
- package/src/extensions/config/hooks-config-loader.test.ts +0 -20
- package/src/extensions/config/runtime-commands.test.ts +0 -115
- package/src/extensions/config/unified-config-file-watcher.test.ts +0 -196
- package/src/extensions/config/user-instruction-config-loader.test.ts +0 -246
- package/src/extensions/context/compaction.test.ts +0 -483
- package/src/extensions/mcp/config-loader.test.ts +0 -238
- package/src/extensions/mcp/manager.test.ts +0 -105
- package/src/extensions/plugin/plugin-config-loader.test.ts +0 -184
- package/src/extensions/plugin/plugin-loader.test.ts +0 -292
- package/src/extensions/plugin/plugin-sandbox.test.ts +0 -423
- package/src/extensions/tools/definitions.test.ts +0 -780
- package/src/extensions/tools/executors/bash.test.ts +0 -87
- package/src/extensions/tools/executors/editor.test.ts +0 -35
- package/src/extensions/tools/executors/file-read.test.ts +0 -125
- package/src/extensions/tools/model-tool-routing.test.ts +0 -86
- package/src/extensions/tools/presets.test.ts +0 -70
- package/src/extensions/tools/team/multi-agent.lifecycle.test.ts +0 -455
- package/src/extensions/tools/team/spawn-agent-tool.test.ts +0 -381
- package/src/extensions/tools/team/team-tools.test.ts +0 -918
- package/src/hooks/checkpoint-hooks.test.ts +0 -168
- package/src/hooks/hook-file-hooks.test.ts +0 -311
- package/src/hooks/persistent.ts +0 -661
- package/src/runtime/history.test.ts +0 -114
- package/src/runtime/host.test.ts +0 -230
- package/src/runtime/rpc-runtime-ensure.test.ts +0 -123
- package/src/runtime/rpc-runtime-ensure.ts +0 -659
- package/src/runtime/rpc-spawn-lease.test.ts +0 -81
- package/src/runtime/rpc-spawn-lease.ts +0 -156
- package/src/runtime/runtime-builder.team-persistence.test.ts +0 -245
- package/src/runtime/runtime-builder.test.ts +0 -615
- package/src/runtime/runtime-oauth-token-manager.test.ts +0 -137
- package/src/runtime/runtime-parity.test.ts +0 -143
- package/src/services/providers/local-provider-service.test.ts +0 -1062
- package/src/services/session-data.test.ts +0 -160
- package/src/services/storage/provider-settings-legacy-migration.test.ts +0 -424
- package/src/services/storage/provider-settings-manager.test.ts +0 -191
- package/src/services/telemetry/OpenTelemetryAdapter.test.ts +0 -157
- package/src/services/telemetry/OpenTelemetryProvider.test.ts +0 -326
- package/src/services/telemetry/TelemetryLoggerSink.test.ts +0 -42
- package/src/services/telemetry/TelemetryService.test.ts +0 -134
- package/src/services/telemetry/distinct-id.test.ts +0 -57
- package/src/services/workspace/file-indexer.d.ts +0 -11
- package/src/services/workspace/file-indexer.test.ts +0 -156
- package/src/services/workspace/mention-enricher.test.ts +0 -106
- package/src/session/persistence-service.test.ts +0 -300
- package/src/session/rpc-session-service.ts +0 -114
- package/src/session/session-service.team-persistence.test.ts +0 -48
- package/src/session/sqlite-rpc-session-backend.ts +0 -301
- package/src/transports/local.e2e.test.ts +0 -380
- package/src/transports/local.test.ts +0 -2559
- package/src/transports/rpc.test.ts +0 -82
- package/src/transports/rpc.ts +0 -665
|
@@ -1,659 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import { createServer } from "node:net";
|
|
4
|
-
import { dirname, join, resolve } from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
getRpcServerHealth,
|
|
7
|
-
RPC_BUILD_VERSION,
|
|
8
|
-
RPC_PROTOCOL_VERSION,
|
|
9
|
-
RpcSessionClient,
|
|
10
|
-
requestRpcServerShutdown,
|
|
11
|
-
} from "@clinebot/rpc";
|
|
12
|
-
import { resolveClineDataDir } from "@clinebot/shared/storage";
|
|
13
|
-
import { CORE_BUILD_VERSION } from "../version";
|
|
14
|
-
|
|
15
|
-
const RPC_STARTUP_LOCK_MAX_AGE_MS = 30_000;
|
|
16
|
-
const RPC_STARTUP_LOCK_WAIT_MS = 15_000;
|
|
17
|
-
const RPC_STARTUP_LOCK_POLL_MS = 100;
|
|
18
|
-
export const RPC_STARTUP_LOCK_BYPASS_ENV = "CLINE_RPC_STARTUP_LOCK_HELD";
|
|
19
|
-
export const RPC_OWNER_ID_ENV = "CLINE_RPC_OWNER_ID";
|
|
20
|
-
export const RPC_BUILD_ID_ENV = "CLINE_RPC_BUILD_ID";
|
|
21
|
-
export const RPC_DISCOVERY_PATH_ENV = "CLINE_RPC_DISCOVERY_PATH";
|
|
22
|
-
|
|
23
|
-
type RpcStartupLockRecord = {
|
|
24
|
-
pid: number;
|
|
25
|
-
address: string;
|
|
26
|
-
acquiredAt: string;
|
|
27
|
-
updatedAt: string;
|
|
28
|
-
status: "starting" | "running";
|
|
29
|
-
resolvedAddress?: string;
|
|
30
|
-
serverId?: string;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export type RpcDiscoveryRecord = {
|
|
34
|
-
ownerId: string;
|
|
35
|
-
buildId: string;
|
|
36
|
-
entryPath?: string;
|
|
37
|
-
address: string;
|
|
38
|
-
pid?: number;
|
|
39
|
-
serverId?: string;
|
|
40
|
-
startedAt?: string;
|
|
41
|
-
protocolVersion: string;
|
|
42
|
-
updatedAt: string;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type RpcOwnerContext = {
|
|
46
|
-
ownerId: string;
|
|
47
|
-
buildId: string;
|
|
48
|
-
entryPath?: string;
|
|
49
|
-
discoveryPath: string;
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export type ResolveRpcRuntimeResult = {
|
|
53
|
-
address: string;
|
|
54
|
-
action: "reuse" | "new-port" | "started";
|
|
55
|
-
owner: RpcOwnerContext;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
export type EnsureRpcRuntimeOptions = {
|
|
59
|
-
owner?: RpcOwnerContext;
|
|
60
|
-
resolveOwner?: () => RpcOwnerContext;
|
|
61
|
-
spawnIfNeeded: (
|
|
62
|
-
address: string,
|
|
63
|
-
owner: RpcOwnerContext,
|
|
64
|
-
) => void | Promise<void>;
|
|
65
|
-
readinessCheck?: (address: string) => Promise<boolean>;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
export type ResolveRpcOwnerContextOptions = {
|
|
69
|
-
discoveryPath?: string;
|
|
70
|
-
hostBuildKey?: string;
|
|
71
|
-
identityPath?: string;
|
|
72
|
-
ownerBasis?: string;
|
|
73
|
-
ownerId?: string;
|
|
74
|
-
ownerPrefix?: string;
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
|
|
78
|
-
|
|
79
|
-
function sanitizeKey(value: string): string {
|
|
80
|
-
return value.replace(/[^a-zA-Z0-9_.-]+/g, "_");
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function hashValue(value: string): string {
|
|
84
|
-
return createHash("sha256").update(value).digest("hex").slice(0, 12);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function errorCode(error: unknown): string {
|
|
88
|
-
return error && typeof error === "object" && "code" in error
|
|
89
|
-
? String((error as { code?: unknown }).code)
|
|
90
|
-
: "";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function parseRpcAddress(address: string): { host: string; port: number } {
|
|
94
|
-
const trimmed = address.trim();
|
|
95
|
-
const idx = trimmed.lastIndexOf(":");
|
|
96
|
-
if (idx <= 0 || idx >= trimmed.length - 1) {
|
|
97
|
-
throw new Error(`invalid rpc address: ${address}`);
|
|
98
|
-
}
|
|
99
|
-
const host = trimmed.slice(0, idx);
|
|
100
|
-
const port = Number.parseInt(trimmed.slice(idx + 1), 10);
|
|
101
|
-
if (!Number.isInteger(port) || port <= 0 || port > 65535) {
|
|
102
|
-
throw new Error(`invalid rpc port in address: ${address}`);
|
|
103
|
-
}
|
|
104
|
-
return { host, port };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function defaultIdentityPath(): string | undefined {
|
|
108
|
-
const entryArg = process.argv[1]?.trim();
|
|
109
|
-
if (!entryArg) return undefined;
|
|
110
|
-
return resolve(process.cwd(), entryArg);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function resolveRpcRuntimeBuildKey(hostBuildKey?: string): string {
|
|
114
|
-
const base = `core=${CORE_BUILD_VERSION}:rpc=${RPC_BUILD_VERSION}`;
|
|
115
|
-
return hostBuildKey?.trim() ? `${base}:host=${hostBuildKey.trim()}` : base;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function resolveRpcOwnerContext(
|
|
119
|
-
options: ResolveRpcOwnerContextOptions = {},
|
|
120
|
-
): RpcOwnerContext {
|
|
121
|
-
const entryPath = options.identityPath?.trim() || defaultIdentityPath();
|
|
122
|
-
const defaultOwnerBasis =
|
|
123
|
-
options.ownerBasis?.trim() ||
|
|
124
|
-
(entryPath ? `${entryPath}` : `pid:${process.pid}:cwd:${process.cwd()}`);
|
|
125
|
-
const ownerPrefix = options.ownerPrefix?.trim() || "rpc";
|
|
126
|
-
const ownerId =
|
|
127
|
-
options.ownerId?.trim() ||
|
|
128
|
-
process.env[RPC_OWNER_ID_ENV]?.trim() ||
|
|
129
|
-
`${ownerPrefix}-${hashValue(defaultOwnerBasis)}`;
|
|
130
|
-
const defaultBuildBasis = `${defaultOwnerBasis}:${resolveRpcRuntimeBuildKey(options.hostBuildKey)}`;
|
|
131
|
-
const buildId =
|
|
132
|
-
process.env[RPC_BUILD_ID_ENV]?.trim() ||
|
|
133
|
-
`build-${hashValue(defaultBuildBasis)}`;
|
|
134
|
-
const discoveryPath =
|
|
135
|
-
options.discoveryPath?.trim() ||
|
|
136
|
-
process.env[RPC_DISCOVERY_PATH_ENV]?.trim() ||
|
|
137
|
-
join(
|
|
138
|
-
resolveClineDataDir(),
|
|
139
|
-
"rpc",
|
|
140
|
-
"owners",
|
|
141
|
-
`${sanitizeKey(ownerId)}.json`,
|
|
142
|
-
);
|
|
143
|
-
return { ownerId, buildId, entryPath, discoveryPath };
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function readRpcDiscovery(
|
|
147
|
-
owner: RpcOwnerContext,
|
|
148
|
-
): Promise<RpcDiscoveryRecord | undefined> {
|
|
149
|
-
try {
|
|
150
|
-
const parsed = JSON.parse(
|
|
151
|
-
await readFile(owner.discoveryPath, "utf8"),
|
|
152
|
-
) as Partial<RpcDiscoveryRecord>;
|
|
153
|
-
if (
|
|
154
|
-
typeof parsed.ownerId !== "string" ||
|
|
155
|
-
typeof parsed.buildId !== "string" ||
|
|
156
|
-
typeof parsed.address !== "string" ||
|
|
157
|
-
typeof parsed.protocolVersion !== "string"
|
|
158
|
-
) {
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
return {
|
|
162
|
-
ownerId: parsed.ownerId,
|
|
163
|
-
buildId: parsed.buildId,
|
|
164
|
-
address: parsed.address,
|
|
165
|
-
protocolVersion: parsed.protocolVersion,
|
|
166
|
-
updatedAt:
|
|
167
|
-
typeof parsed.updatedAt === "string"
|
|
168
|
-
? parsed.updatedAt
|
|
169
|
-
: new Date().toISOString(),
|
|
170
|
-
entryPath:
|
|
171
|
-
typeof parsed.entryPath === "string" ? parsed.entryPath : undefined,
|
|
172
|
-
pid: typeof parsed.pid === "number" ? parsed.pid : undefined,
|
|
173
|
-
serverId:
|
|
174
|
-
typeof parsed.serverId === "string" ? parsed.serverId : undefined,
|
|
175
|
-
startedAt:
|
|
176
|
-
typeof parsed.startedAt === "string" ? parsed.startedAt : undefined,
|
|
177
|
-
};
|
|
178
|
-
} catch {
|
|
179
|
-
return undefined;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export async function recordRpcDiscovery(
|
|
184
|
-
owner: RpcOwnerContext,
|
|
185
|
-
record: Omit<RpcDiscoveryRecord, "ownerId" | "buildId" | "updatedAt">,
|
|
186
|
-
): Promise<void> {
|
|
187
|
-
await mkdir(dirname(owner.discoveryPath), { recursive: true });
|
|
188
|
-
await writeFile(
|
|
189
|
-
owner.discoveryPath,
|
|
190
|
-
JSON.stringify(
|
|
191
|
-
{
|
|
192
|
-
ownerId: owner.ownerId,
|
|
193
|
-
buildId: owner.buildId,
|
|
194
|
-
updatedAt: new Date().toISOString(),
|
|
195
|
-
...record,
|
|
196
|
-
} satisfies RpcDiscoveryRecord,
|
|
197
|
-
null,
|
|
198
|
-
2,
|
|
199
|
-
),
|
|
200
|
-
"utf8",
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async function clearRpcDiscovery(owner: RpcOwnerContext): Promise<void> {
|
|
205
|
-
await rm(owner.discoveryPath, { force: true }).catch(() => undefined);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export async function clearRpcDiscoveryIfAddressMatches(
|
|
209
|
-
owner: RpcOwnerContext,
|
|
210
|
-
address: string,
|
|
211
|
-
): Promise<void> {
|
|
212
|
-
const current = await readRpcDiscovery(owner);
|
|
213
|
-
if (current?.address === address) await clearRpcDiscovery(owner);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function isHealthCompatible(
|
|
217
|
-
health: Awaited<ReturnType<typeof getRpcServerHealth>> | undefined,
|
|
218
|
-
): boolean {
|
|
219
|
-
const serverVersion = health?.rpcVersion?.trim() || "";
|
|
220
|
-
return !!serverVersion && serverVersion === RPC_PROTOCOL_VERSION;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
function isUnimplementedError(error: unknown): boolean {
|
|
224
|
-
if (Number(errorCode(error)) === 12) return true;
|
|
225
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
226
|
-
return message.toUpperCase().includes("UNIMPLEMENTED");
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function isAuthenticationError(error: unknown): boolean {
|
|
230
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
231
|
-
return /missing authentication header|401\b|unauthenticated|unauthorized/i.test(
|
|
232
|
-
message,
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function isProbeBlocked(error: unknown): boolean {
|
|
237
|
-
return isUnimplementedError(error) || isAuthenticationError(error);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function formatProbeError(error: unknown): string {
|
|
241
|
-
if (error instanceof Error && error.message.trim()) {
|
|
242
|
-
return error.message.trim();
|
|
243
|
-
}
|
|
244
|
-
return String(error);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
type RuntimeMethodsProbeResult = {
|
|
248
|
-
available: boolean;
|
|
249
|
-
reason?: string;
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
async function probeRuntimeMethods(
|
|
253
|
-
address: string,
|
|
254
|
-
): Promise<RuntimeMethodsProbeResult> {
|
|
255
|
-
const client = new RpcSessionClient({ address });
|
|
256
|
-
try {
|
|
257
|
-
try {
|
|
258
|
-
await client.stopRuntimeSession("__rpc_probe__");
|
|
259
|
-
} catch (error) {
|
|
260
|
-
if (isProbeBlocked(error)) {
|
|
261
|
-
return {
|
|
262
|
-
available: false,
|
|
263
|
-
reason: `runtime probe blocked (${formatProbeError(error)})`,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return { available: true };
|
|
268
|
-
} catch (error) {
|
|
269
|
-
if (isProbeBlocked(error)) {
|
|
270
|
-
return {
|
|
271
|
-
available: false,
|
|
272
|
-
reason: `runtime probe blocked (${formatProbeError(error)})`,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
return {
|
|
276
|
-
available: false,
|
|
277
|
-
reason: `runtime probe failed (${formatProbeError(error)})`,
|
|
278
|
-
};
|
|
279
|
-
} finally {
|
|
280
|
-
client.close();
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
async function hasRuntimeMethods(address: string): Promise<boolean> {
|
|
285
|
-
return (await probeRuntimeMethods(address)).available;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export async function isCompatibleRuntime(address: string): Promise<boolean> {
|
|
289
|
-
const health = await getRpcServerHealth(address);
|
|
290
|
-
return (
|
|
291
|
-
!!health?.running &&
|
|
292
|
-
isHealthCompatible(health) &&
|
|
293
|
-
(await hasRuntimeMethods(address))
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
async function describeRpcRuntimeReadinessFailure(
|
|
298
|
-
address: string,
|
|
299
|
-
): Promise<string> {
|
|
300
|
-
let health: Awaited<ReturnType<typeof getRpcServerHealth>> | undefined;
|
|
301
|
-
try {
|
|
302
|
-
health = await getRpcServerHealth(address);
|
|
303
|
-
} catch (error) {
|
|
304
|
-
return `health probe failed (${formatProbeError(error)})`;
|
|
305
|
-
}
|
|
306
|
-
if (!health?.running) {
|
|
307
|
-
return "health probe reported no running server";
|
|
308
|
-
}
|
|
309
|
-
if (!isHealthCompatible(health)) {
|
|
310
|
-
const actualVersion =
|
|
311
|
-
typeof health.rpcVersion === "string" && health.rpcVersion.trim()
|
|
312
|
-
? health.rpcVersion.trim()
|
|
313
|
-
: "unknown";
|
|
314
|
-
return `protocol mismatch (expected=${RPC_PROTOCOL_VERSION}, actual=${actualVersion})`;
|
|
315
|
-
}
|
|
316
|
-
const runtimeProbe = await probeRuntimeMethods(address);
|
|
317
|
-
if (!runtimeProbe.available) {
|
|
318
|
-
return runtimeProbe.reason ?? "runtime methods unavailable";
|
|
319
|
-
}
|
|
320
|
-
return "runtime did not become compatible before readiness deadline";
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
async function isPortFree(host: string, port: number): Promise<boolean> {
|
|
324
|
-
return new Promise<boolean>((resolve) => {
|
|
325
|
-
const server = createServer();
|
|
326
|
-
server.once("error", () => resolve(false));
|
|
327
|
-
server.once("listening", () => server.close(() => resolve(true)));
|
|
328
|
-
server.listen({ host, port });
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async function findAvailableAddress(baseAddress: string): Promise<string> {
|
|
333
|
-
const { host, port } = parseRpcAddress(baseAddress);
|
|
334
|
-
for (let offset = 1; offset <= 40; offset += 1) {
|
|
335
|
-
const candidate = port + offset;
|
|
336
|
-
if (candidate > 65535) break;
|
|
337
|
-
if (await isPortFree(host, candidate)) return `${host}:${candidate}`;
|
|
338
|
-
}
|
|
339
|
-
throw new Error(`no available rpc port near ${baseAddress}`);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function getRpcStartupLockDir(address: string): string {
|
|
343
|
-
const normalized = address.trim().replace(/[^a-zA-Z0-9_.-]+/g, "_");
|
|
344
|
-
return join(resolveClineDataDir(), "locks", `rpc-start-${normalized}.lock`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function isPidAlive(pid: number | undefined): boolean {
|
|
348
|
-
if (!Number.isInteger(pid) || !pid || pid <= 0) return false;
|
|
349
|
-
try {
|
|
350
|
-
process.kill(pid, 0);
|
|
351
|
-
return true;
|
|
352
|
-
} catch (error) {
|
|
353
|
-
return errorCode(error) === "EPERM";
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
async function writeRpcStartupLockRecord(
|
|
358
|
-
lockDir: string,
|
|
359
|
-
record: RpcStartupLockRecord,
|
|
360
|
-
): Promise<void> {
|
|
361
|
-
await writeFile(
|
|
362
|
-
join(lockDir, "owner.json"),
|
|
363
|
-
JSON.stringify(record, null, 2),
|
|
364
|
-
"utf8",
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async function readRpcStartupLockRecord(
|
|
369
|
-
lockDir: string,
|
|
370
|
-
): Promise<RpcStartupLockRecord | undefined> {
|
|
371
|
-
try {
|
|
372
|
-
const parsed = JSON.parse(
|
|
373
|
-
await readFile(join(lockDir, "owner.json"), "utf8"),
|
|
374
|
-
) as Partial<RpcStartupLockRecord>;
|
|
375
|
-
if (
|
|
376
|
-
typeof parsed.pid !== "number" ||
|
|
377
|
-
typeof parsed.address !== "string" ||
|
|
378
|
-
typeof parsed.acquiredAt !== "string" ||
|
|
379
|
-
typeof parsed.updatedAt !== "string" ||
|
|
380
|
-
(parsed.status !== "starting" && parsed.status !== "running")
|
|
381
|
-
) {
|
|
382
|
-
return undefined;
|
|
383
|
-
}
|
|
384
|
-
return {
|
|
385
|
-
pid: parsed.pid,
|
|
386
|
-
address: parsed.address,
|
|
387
|
-
acquiredAt: parsed.acquiredAt,
|
|
388
|
-
updatedAt: parsed.updatedAt,
|
|
389
|
-
status: parsed.status,
|
|
390
|
-
resolvedAddress:
|
|
391
|
-
typeof parsed.resolvedAddress === "string"
|
|
392
|
-
? parsed.resolvedAddress
|
|
393
|
-
: undefined,
|
|
394
|
-
serverId:
|
|
395
|
-
typeof parsed.serverId === "string" ? parsed.serverId : undefined,
|
|
396
|
-
};
|
|
397
|
-
} catch {
|
|
398
|
-
return undefined;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
async function removeRpcStartupLockDir(lockDir: string): Promise<void> {
|
|
403
|
-
await rm(lockDir, { recursive: true, force: true }).catch(() => {});
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
async function updateRpcStartupLockRecord(
|
|
407
|
-
lockDir: string,
|
|
408
|
-
patch: Partial<Omit<RpcStartupLockRecord, "pid" | "address" | "acquiredAt">>,
|
|
409
|
-
): Promise<void> {
|
|
410
|
-
const current = await readRpcStartupLockRecord(lockDir);
|
|
411
|
-
if (!current) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
await writeRpcStartupLockRecord(lockDir, {
|
|
415
|
-
...current,
|
|
416
|
-
...patch,
|
|
417
|
-
updatedAt: new Date().toISOString(),
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
async function isRpcStartupLockStale(
|
|
422
|
-
existing: RpcStartupLockRecord | undefined,
|
|
423
|
-
): Promise<boolean> {
|
|
424
|
-
const acquiredAtMs = existing ? new Date(existing.acquiredAt).getTime() : NaN;
|
|
425
|
-
if (
|
|
426
|
-
!existing ||
|
|
427
|
-
!Number.isFinite(acquiredAtMs) ||
|
|
428
|
-
Date.now() - acquiredAtMs > RPC_STARTUP_LOCK_MAX_AGE_MS ||
|
|
429
|
-
!isPidAlive(existing.pid)
|
|
430
|
-
) {
|
|
431
|
-
return true;
|
|
432
|
-
}
|
|
433
|
-
if (existing.status !== "running") {
|
|
434
|
-
return false;
|
|
435
|
-
}
|
|
436
|
-
const targetAddress = existing.resolvedAddress?.trim() || existing.address;
|
|
437
|
-
try {
|
|
438
|
-
return !(await getRpcServerHealth(targetAddress))?.running;
|
|
439
|
-
} catch {
|
|
440
|
-
return true;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
export type RpcStartupLockHandle = {
|
|
445
|
-
markRunning: (details?: {
|
|
446
|
-
resolvedAddress?: string;
|
|
447
|
-
serverId?: string;
|
|
448
|
-
}) => Promise<void>;
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
export async function withRpcStartupLock<T>(
|
|
452
|
-
address: string,
|
|
453
|
-
action: (lock: RpcStartupLockHandle) => Promise<T>,
|
|
454
|
-
): Promise<T> {
|
|
455
|
-
if (process.env[RPC_STARTUP_LOCK_BYPASS_ENV] === "1") {
|
|
456
|
-
return await action({
|
|
457
|
-
markRunning: async () => undefined,
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
const lockDir = getRpcStartupLockDir(address);
|
|
462
|
-
const startedAt = Date.now();
|
|
463
|
-
await mkdir(dirname(lockDir), { recursive: true });
|
|
464
|
-
|
|
465
|
-
while (true) {
|
|
466
|
-
try {
|
|
467
|
-
await mkdir(lockDir, { recursive: false });
|
|
468
|
-
await writeRpcStartupLockRecord(lockDir, {
|
|
469
|
-
pid: process.pid,
|
|
470
|
-
address,
|
|
471
|
-
acquiredAt: new Date().toISOString(),
|
|
472
|
-
updatedAt: new Date().toISOString(),
|
|
473
|
-
status: "starting",
|
|
474
|
-
});
|
|
475
|
-
try {
|
|
476
|
-
return await action({
|
|
477
|
-
markRunning: async (details) => {
|
|
478
|
-
await updateRpcStartupLockRecord(lockDir, {
|
|
479
|
-
status: "running",
|
|
480
|
-
resolvedAddress: details?.resolvedAddress?.trim() || undefined,
|
|
481
|
-
serverId: details?.serverId?.trim() || undefined,
|
|
482
|
-
});
|
|
483
|
-
},
|
|
484
|
-
});
|
|
485
|
-
} finally {
|
|
486
|
-
await removeRpcStartupLockDir(lockDir);
|
|
487
|
-
}
|
|
488
|
-
} catch (error) {
|
|
489
|
-
if (errorCode(error) !== "EEXIST") throw error;
|
|
490
|
-
|
|
491
|
-
const existing = await readRpcStartupLockRecord(lockDir);
|
|
492
|
-
const isStale = await isRpcStartupLockStale(existing);
|
|
493
|
-
if (isStale) {
|
|
494
|
-
await removeRpcStartupLockDir(lockDir);
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
if (Date.now() - startedAt >= RPC_STARTUP_LOCK_WAIT_MS) {
|
|
499
|
-
const ownerPid =
|
|
500
|
-
typeof existing?.pid === "number" ? existing.pid : "unknown";
|
|
501
|
-
throw new Error(
|
|
502
|
-
`timed out waiting for rpc startup lock at ${address} (owner pid=${ownerPid})`,
|
|
503
|
-
);
|
|
504
|
-
}
|
|
505
|
-
await sleep(RPC_STARTUP_LOCK_POLL_MS);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
async function tryShutdownOwnedServer(
|
|
511
|
-
owner: RpcOwnerContext,
|
|
512
|
-
discovery: RpcDiscoveryRecord | undefined,
|
|
513
|
-
): Promise<void> {
|
|
514
|
-
const address = discovery?.address?.trim();
|
|
515
|
-
if (!address) {
|
|
516
|
-
await clearRpcDiscovery(owner);
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
const shutdown = await requestRpcServerShutdown(address).catch(
|
|
520
|
-
() => undefined,
|
|
521
|
-
);
|
|
522
|
-
if (shutdown?.accepted) {
|
|
523
|
-
for (let i = 0; i < 20; i += 1) {
|
|
524
|
-
if (!(await getRpcServerHealth(address))?.running) {
|
|
525
|
-
await clearRpcDiscovery(owner);
|
|
526
|
-
return;
|
|
527
|
-
}
|
|
528
|
-
await sleep(100);
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
if (!(await getRpcServerHealth(address))?.running) {
|
|
532
|
-
await clearRpcDiscovery(owner);
|
|
533
|
-
}
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
export async function resolveEnsuredRpcRuntime(
|
|
537
|
-
requestedAddress: string,
|
|
538
|
-
options: {
|
|
539
|
-
owner?: RpcOwnerContext;
|
|
540
|
-
resolveOwner?: () => RpcOwnerContext;
|
|
541
|
-
/**
|
|
542
|
-
* When true, skip startup lock acquisition. Use this when the caller
|
|
543
|
-
* already holds the lock via {@link withRpcStartupLock} to avoid a
|
|
544
|
-
* deadlock from nested lock acquisition on the same address.
|
|
545
|
-
*/
|
|
546
|
-
lockAlreadyHeld?: boolean;
|
|
547
|
-
} = {},
|
|
548
|
-
): Promise<ResolveRpcRuntimeResult> {
|
|
549
|
-
const owner =
|
|
550
|
-
options.owner ?? options.resolveOwner?.() ?? resolveRpcOwnerContext();
|
|
551
|
-
|
|
552
|
-
const core = async (): Promise<ResolveRpcRuntimeResult> => {
|
|
553
|
-
const discovery = await readRpcDiscovery(owner);
|
|
554
|
-
if (discovery?.address) {
|
|
555
|
-
const discoveredHealth = await getRpcServerHealth(discovery.address);
|
|
556
|
-
if (
|
|
557
|
-
discoveredHealth?.running &&
|
|
558
|
-
discovery.buildId === owner.buildId &&
|
|
559
|
-
discovery.protocolVersion === RPC_PROTOCOL_VERSION &&
|
|
560
|
-
isHealthCompatible(discoveredHealth) &&
|
|
561
|
-
(await hasRuntimeMethods(discovery.address))
|
|
562
|
-
) {
|
|
563
|
-
return {
|
|
564
|
-
address: discovery.address,
|
|
565
|
-
action: "reuse",
|
|
566
|
-
owner,
|
|
567
|
-
} satisfies ResolveRpcRuntimeResult;
|
|
568
|
-
}
|
|
569
|
-
await tryShutdownOwnedServer(owner, discovery);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
const requestedHealth = await getRpcServerHealth(requestedAddress);
|
|
573
|
-
const { host, port } = parseRpcAddress(requestedAddress);
|
|
574
|
-
|
|
575
|
-
if (!requestedHealth?.running) {
|
|
576
|
-
if (await isPortFree(host, port)) {
|
|
577
|
-
return {
|
|
578
|
-
address: requestedAddress,
|
|
579
|
-
action: "started",
|
|
580
|
-
owner,
|
|
581
|
-
} satisfies ResolveRpcRuntimeResult;
|
|
582
|
-
}
|
|
583
|
-
return {
|
|
584
|
-
address: await findAvailableAddress(requestedAddress),
|
|
585
|
-
action: "new-port",
|
|
586
|
-
owner,
|
|
587
|
-
} satisfies ResolveRpcRuntimeResult;
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (
|
|
591
|
-
isHealthCompatible(requestedHealth) &&
|
|
592
|
-
(await hasRuntimeMethods(requestedAddress))
|
|
593
|
-
) {
|
|
594
|
-
if (!discovery) {
|
|
595
|
-
return {
|
|
596
|
-
address: requestedAddress,
|
|
597
|
-
action: "reuse",
|
|
598
|
-
owner,
|
|
599
|
-
} satisfies ResolveRpcRuntimeResult;
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
return {
|
|
604
|
-
address: await findAvailableAddress(requestedAddress),
|
|
605
|
-
action: "new-port",
|
|
606
|
-
owner,
|
|
607
|
-
} satisfies ResolveRpcRuntimeResult;
|
|
608
|
-
};
|
|
609
|
-
|
|
610
|
-
if (options.lockAlreadyHeld) {
|
|
611
|
-
return await core();
|
|
612
|
-
}
|
|
613
|
-
return await withRpcStartupLock(requestedAddress, core);
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
export async function waitForCompatibleRpcRuntime(
|
|
617
|
-
address: string,
|
|
618
|
-
readinessCheck: (address: string) => Promise<boolean> = isCompatibleRuntime,
|
|
619
|
-
): Promise<boolean> {
|
|
620
|
-
for (let attempt = 0; attempt < 60; attempt += 1) {
|
|
621
|
-
if (await readinessCheck(address)) return true;
|
|
622
|
-
await sleep(100);
|
|
623
|
-
}
|
|
624
|
-
return false;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
export async function ensureRpcRuntimeAddress(
|
|
628
|
-
requestedAddress: string,
|
|
629
|
-
options: EnsureRpcRuntimeOptions,
|
|
630
|
-
): Promise<ResolveRpcRuntimeResult> {
|
|
631
|
-
const resolved = await resolveEnsuredRpcRuntime(requestedAddress, {
|
|
632
|
-
owner: options.owner,
|
|
633
|
-
resolveOwner: options.resolveOwner,
|
|
634
|
-
});
|
|
635
|
-
if (resolved.action !== "reuse") {
|
|
636
|
-
await options.spawnIfNeeded(resolved.address, resolved.owner);
|
|
637
|
-
}
|
|
638
|
-
if (
|
|
639
|
-
!(await waitForCompatibleRpcRuntime(
|
|
640
|
-
resolved.address,
|
|
641
|
-
options.readinessCheck,
|
|
642
|
-
))
|
|
643
|
-
) {
|
|
644
|
-
const reason = await describeRpcRuntimeReadinessFailure(resolved.address);
|
|
645
|
-
throw new Error(
|
|
646
|
-
`failed to ensure rpc runtime at ${resolved.address}: ${reason}`,
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
const health = await getRpcServerHealth(resolved.address);
|
|
650
|
-
await recordRpcDiscovery(resolved.owner, {
|
|
651
|
-
address: resolved.address,
|
|
652
|
-
pid: undefined,
|
|
653
|
-
serverId: health?.serverId,
|
|
654
|
-
startedAt: health?.startedAt,
|
|
655
|
-
protocolVersion: RPC_PROTOCOL_VERSION,
|
|
656
|
-
entryPath: resolved.owner.entryPath,
|
|
657
|
-
});
|
|
658
|
-
return resolved;
|
|
659
|
-
}
|