@clinebot/core 0.0.33 → 0.0.35
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 +12 -8
- package/dist/ClineCore.d.ts +48 -29
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/auth/client.d.ts +19 -0
- package/dist/auth/client.d.ts.map +1 -1
- package/dist/auth/cline.d.ts.map +1 -1
- package/dist/auth/oca.d.ts.map +1 -1
- package/dist/auth/server.d.ts +32 -0
- package/dist/auth/server.d.ts.map +1 -1
- package/dist/auth/types.d.ts +29 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/extensions/config/agent-config-loader.d.ts +2 -2
- package/dist/extensions/config/agent-config-loader.d.ts.map +1 -1
- package/dist/extensions/config/agent-config-parser.d.ts +1 -1
- package/dist/extensions/config/agent-config-parser.d.ts.map +1 -1
- package/dist/extensions/config/hooks-config-loader.d.ts +2 -2
- package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -1
- package/dist/extensions/config/index.d.ts +3 -3
- package/dist/extensions/config/index.d.ts.map +1 -1
- package/dist/extensions/config/user-instruction-config-loader.d.ts +2 -2
- package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -1
- package/dist/extensions/index.d.ts +2 -1
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts +2 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-load-report.d.ts +19 -0
- package/dist/extensions/plugin/plugin-load-report.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-loader.d.ts +6 -0
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts +2 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -1
- package/dist/extensions/plugin-sandbox-bootstrap.js +242 -242
- package/dist/extensions/tools/constants.d.ts.map +1 -0
- package/dist/extensions/tools/definitions.d.ts.map +1 -0
- package/dist/extensions/tools/executors/apply-patch-parser.d.ts.map +1 -0
- package/dist/extensions/tools/executors/apply-patch.d.ts.map +1 -0
- package/dist/extensions/tools/executors/bash.d.ts.map +1 -0
- package/dist/extensions/tools/executors/editor.d.ts.map +1 -0
- package/dist/extensions/tools/executors/file-read.d.ts.map +1 -0
- package/dist/extensions/tools/executors/index.d.ts.map +1 -0
- package/dist/extensions/tools/executors/search.d.ts.map +1 -0
- package/dist/extensions/tools/executors/web-fetch.d.ts.map +1 -0
- package/dist/extensions/tools/helpers.d.ts.map +1 -0
- package/dist/extensions/tools/index.d.ts.map +1 -0
- package/dist/{tools → extensions/tools}/model-tool-routing.d.ts +1 -1
- package/dist/extensions/tools/model-tool-routing.d.ts.map +1 -0
- package/dist/{tools → extensions/tools}/presets.d.ts +1 -2
- package/dist/extensions/tools/presets.d.ts.map +1 -0
- package/dist/extensions/tools/schemas.d.ts.map +1 -0
- package/dist/extensions/tools/team/delegated-agent.d.ts.map +1 -0
- package/dist/extensions/tools/team/index.d.ts.map +1 -0
- package/dist/{team → extensions/tools/team}/multi-agent.d.ts +1 -3
- package/dist/extensions/tools/team/multi-agent.d.ts.map +1 -0
- package/dist/extensions/tools/team/projections.d.ts.map +1 -0
- package/dist/extensions/tools/team/runtime.d.ts.map +1 -0
- package/dist/{team → extensions/tools/team}/spawn-agent-tool.d.ts +0 -1
- package/dist/extensions/tools/team/spawn-agent-tool.d.ts.map +1 -0
- package/dist/extensions/tools/team/subagent-prompts.d.ts.map +1 -0
- package/dist/extensions/tools/team/team-tools.d.ts.map +1 -0
- package/dist/{tools → extensions/tools}/types.d.ts +4 -3
- package/dist/extensions/tools/types.d.ts.map +1 -0
- package/dist/{runtime → hooks}/checkpoint-hooks.d.ts +7 -0
- package/dist/hooks/checkpoint-hooks.d.ts.map +1 -0
- package/dist/{runtime → hooks}/hook-file-hooks.d.ts +0 -2
- package/dist/hooks/hook-file-hooks.d.ts.map +1 -0
- package/dist/hooks/subprocess.d.ts +3 -130
- package/dist/hooks/subprocess.d.ts.map +1 -1
- package/dist/index.d.ts +38 -35
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +386 -384
- package/dist/runtime/history.d.ts +4 -0
- package/dist/runtime/history.d.ts.map +1 -0
- package/dist/runtime/host.d.ts +9 -0
- package/dist/runtime/host.d.ts.map +1 -0
- package/dist/{session → runtime}/rpc-runtime-ensure.d.ts +13 -1
- package/dist/{session → runtime}/rpc-runtime-ensure.d.ts.map +1 -1
- package/dist/{session → runtime}/rpc-spawn-lease.d.ts.map +1 -1
- package/dist/runtime/runtime-builder.d.ts +1 -1
- package/dist/runtime/runtime-builder.d.ts.map +1 -1
- package/dist/{session/session-manager.d.ts → runtime/runtime-host.d.ts} +55 -12
- package/dist/runtime/runtime-host.d.ts.map +1 -0
- package/dist/{session → runtime}/runtime-oauth-token-manager.d.ts +1 -1
- package/dist/{session → runtime}/runtime-oauth-token-manager.d.ts.map +1 -1
- package/dist/runtime/session-runtime.d.ts +2 -2
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/subprocess-sandbox.d.ts +2 -0
- package/dist/runtime/subprocess-sandbox.d.ts.map +1 -1
- package/dist/runtime/tool-approval.d.ts.map +1 -1
- package/dist/{session/session-agent-events.d.ts → services/agent-events.d.ts} +4 -4
- package/dist/services/agent-events.d.ts.map +1 -0
- package/dist/services/config.d.ts +3 -0
- package/dist/services/config.d.ts.map +1 -0
- package/dist/services/local-runtime-bootstrap.d.ts +41 -0
- package/dist/services/local-runtime-bootstrap.d.ts.map +1 -0
- package/dist/services/providers/local-provider-registry.d.ts.map +1 -0
- package/dist/services/providers/local-provider-service.d.ts.map +1 -0
- package/dist/{session → services}/session-artifacts.d.ts +2 -4
- package/dist/services/session-artifacts.d.ts.map +1 -0
- package/dist/{session/utils/helpers.d.ts → services/session-data.d.ts} +19 -27
- package/dist/services/session-data.d.ts.map +1 -0
- package/dist/{session → services}/session-telemetry.d.ts +2 -2
- package/dist/services/session-telemetry.d.ts.map +1 -0
- package/dist/{storage → services/storage}/file-team-store.d.ts +2 -2
- package/dist/services/storage/file-team-store.d.ts.map +1 -0
- package/dist/{storage → services/storage}/provider-settings-legacy-migration.d.ts +1 -1
- package/dist/services/storage/provider-settings-legacy-migration.d.ts.map +1 -0
- package/dist/{storage → services/storage}/provider-settings-manager.d.ts +1 -1
- package/dist/services/storage/provider-settings-manager.d.ts.map +1 -0
- package/dist/{storage → services/storage}/sqlite-session-store.d.ts +3 -3
- package/dist/services/storage/sqlite-session-store.d.ts.map +1 -0
- package/dist/{storage → services/storage}/sqlite-team-store.d.ts +2 -2
- package/dist/services/storage/sqlite-team-store.d.ts.map +1 -0
- package/dist/{storage → services/storage}/team-store.d.ts +1 -1
- package/dist/services/storage/team-store.d.ts.map +1 -0
- package/dist/services/telemetry/ITelemetryAdapter.d.ts.map +1 -0
- package/dist/services/telemetry/OpenTelemetryAdapter.d.ts.map +1 -0
- package/dist/services/telemetry/OpenTelemetryProvider.d.ts.map +1 -0
- package/dist/services/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
- package/dist/services/telemetry/TelemetryService.d.ts.map +1 -0
- package/dist/services/telemetry/core-events.d.ts.map +1 -0
- package/dist/services/telemetry/distinct-id.d.ts.map +1 -0
- package/dist/services/telemetry/index.d.ts.map +1 -0
- package/dist/{telemetry → services/telemetry}/index.js +6 -6
- package/dist/{session/utils → services}/usage.d.ts +1 -1
- package/dist/services/usage.d.ts.map +1 -0
- package/dist/services/workspace/file-indexer.d.ts.map +1 -0
- package/dist/services/workspace/index.d.ts.map +1 -0
- package/dist/services/workspace/mention-enricher.d.ts.map +1 -0
- package/dist/services/workspace-manifest.d.ts.map +1 -0
- package/dist/session/file-session-service.d.ts +4 -1
- package/dist/session/file-session-service.d.ts.map +1 -1
- package/dist/session/persistence-service.d.ts +8 -6
- package/dist/session/persistence-service.d.ts.map +1 -1
- package/dist/session/rpc-session-service.d.ts +3 -0
- package/dist/session/rpc-session-service.d.ts.map +1 -1
- package/dist/session/session-service.d.ts +8 -9
- package/dist/session/session-service.d.ts.map +1 -1
- package/dist/session/session-team-coordination.d.ts +4 -4
- package/dist/session/session-team-coordination.d.ts.map +1 -1
- package/dist/session/sqlite-rpc-session-backend.d.ts.map +1 -1
- package/dist/{session/default-session-manager.d.ts → transports/local.d.ts} +24 -14
- package/dist/transports/local.d.ts.map +1 -0
- package/dist/transports/rpc.d.ts +51 -0
- package/dist/transports/rpc.d.ts.map +1 -0
- package/dist/transports/runtime-host-support.d.ts +21 -0
- package/dist/transports/runtime-host-support.d.ts.map +1 -0
- package/dist/types/chat-schema.d.ts.map +1 -0
- package/dist/types/config.d.ts +3 -2
- package/dist/types/config.d.ts.map +1 -1
- package/dist/{session/utils/types.d.ts → types/session.d.ts} +15 -6
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/sessions.d.ts +19 -0
- package/dist/types/sessions.d.ts.map +1 -1
- package/dist/types/storage.d.ts +1 -3
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types.d.ts +7 -6
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -12
- package/src/ClineCore.test.ts +95 -19
- package/src/ClineCore.ts +120 -50
- package/src/auth/client.test.ts +29 -0
- package/src/auth/client.ts +21 -0
- package/src/auth/cline.ts +3 -1
- package/src/auth/codex.ts +1 -1
- package/src/auth/oca.ts +3 -1
- package/src/auth/server.test.ts +287 -0
- package/src/auth/server.ts +50 -1
- package/src/auth/types.ts +29 -0
- package/src/extensions/config/agent-config-loader.test.ts +3 -3
- package/src/extensions/config/agent-config-loader.ts +1 -5
- package/src/extensions/config/agent-config-parser.ts +1 -1
- package/src/extensions/config/hooks-config-loader.ts +1 -2
- package/src/extensions/config/index.ts +0 -4
- package/src/extensions/config/user-instruction-config-loader.ts +0 -4
- package/src/extensions/index.ts +6 -0
- package/src/extensions/plugin/plugin-config-loader.test.ts +39 -0
- package/src/extensions/plugin/plugin-config-loader.ts +18 -10
- package/src/extensions/plugin/plugin-load-report.ts +20 -0
- package/src/extensions/plugin/plugin-loader.test.ts +45 -0
- package/src/extensions/plugin/plugin-loader.ts +57 -3
- package/src/extensions/plugin/plugin-sandbox-bootstrap.ts +158 -86
- package/src/extensions/plugin/plugin-sandbox.test.ts +70 -0
- package/src/extensions/plugin/plugin-sandbox.ts +17 -6
- package/src/{tools → extensions/tools}/definitions.ts +1 -1
- package/src/extensions/tools/executors/file-read.test.ts +125 -0
- package/src/{tools → extensions/tools}/executors/file-read.ts +29 -4
- package/src/{tools → extensions/tools}/executors/search.ts +1 -1
- package/src/{tools → extensions/tools}/model-tool-routing.ts +1 -1
- package/src/{tools → extensions/tools}/presets.ts +2 -3
- package/src/extensions/tools/team/multi-agent.lifecycle.test.ts +455 -0
- package/src/{team → extensions/tools/team}/multi-agent.ts +80 -17
- package/src/{team → extensions/tools/team}/spawn-agent-tool.test.ts +0 -6
- package/src/{team → extensions/tools/team}/spawn-agent-tool.ts +1 -7
- package/src/{team → extensions/tools/team}/subagent-prompts.ts +2 -2
- package/src/{team → extensions/tools/team}/team-tools.test.ts +146 -30
- package/src/{team → extensions/tools/team}/team-tools.ts +98 -69
- package/src/{tools → extensions/tools}/types.ts +5 -3
- package/src/{runtime → hooks}/checkpoint-hooks.ts +27 -0
- package/src/{runtime → hooks}/hook-file-hooks.test.ts +42 -7
- package/src/{runtime → hooks}/hook-file-hooks.ts +6 -11
- package/src/hooks/subprocess.ts +48 -257
- package/src/index.ts +178 -158
- package/src/runtime/history.test.ts +114 -0
- package/src/runtime/history.ts +237 -0
- package/src/runtime/host.test.ts +230 -0
- package/src/runtime/host.ts +362 -0
- package/src/runtime/rpc-runtime-ensure.test.ts +123 -0
- package/src/{session → runtime}/rpc-runtime-ensure.ts +165 -27
- package/src/{session → runtime}/rpc-spawn-lease.test.ts +33 -1
- package/src/{session → runtime}/rpc-spawn-lease.ts +54 -20
- package/src/runtime/runtime-builder.team-persistence.test.ts +6 -3
- package/src/runtime/runtime-builder.test.ts +101 -4
- package/src/runtime/runtime-builder.ts +125 -86
- package/src/runtime/runtime-host.ts +178 -0
- package/src/{session → runtime}/runtime-oauth-token-manager.ts +1 -1
- package/src/runtime/runtime-parity.test.ts +1 -1
- package/src/runtime/session-runtime.ts +2 -2
- package/src/runtime/subprocess-sandbox.ts +26 -23
- package/src/runtime/tool-approval.ts +13 -15
- package/src/{session/session-agent-events.ts → services/agent-events.ts} +7 -7
- package/src/services/config.ts +5 -0
- package/src/services/local-runtime-bootstrap.ts +280 -0
- package/src/{providers → services/providers}/local-provider-service.ts +4 -4
- package/src/{session → services}/session-artifacts.ts +23 -19
- package/src/{session/utils/helpers.test.ts → services/session-data.test.ts} +1 -1
- package/src/{session/utils/helpers.ts → services/session-data.ts} +76 -72
- package/src/{session → services}/session-telemetry.ts +7 -9
- package/src/services/storage/artifact-store.ts +1 -0
- package/src/{storage → services/storage}/file-team-store.ts +2 -2
- package/src/{storage → services/storage}/provider-settings-legacy-migration.test.ts +1 -1
- package/src/{storage → services/storage}/provider-settings-legacy-migration.ts +2 -2
- package/src/{storage → services/storage}/provider-settings-manager.ts +2 -2
- package/src/services/storage/session-store.ts +1 -0
- package/src/{storage → services/storage}/sqlite-session-store.ts +7 -12
- package/src/{storage → services/storage}/sqlite-team-store.ts +4 -4
- package/src/{storage → services/storage}/team-store.ts +1 -1
- package/src/{session/utils → services}/usage.ts +1 -1
- package/src/{input → services/workspace}/file-indexer.test.ts +30 -1
- package/src/{input → services/workspace}/file-indexer.ts +26 -2
- package/src/{input → services/workspace}/mention-enricher.test.ts +21 -0
- package/src/{input → services/workspace}/mention-enricher.ts +1 -1
- package/src/session/file-session-service.ts +9 -7
- package/src/session/index.ts +25 -17
- package/src/session/persistence-service.test.ts +121 -24
- package/src/session/persistence-service.ts +118 -102
- package/src/session/rpc-session-service.ts +9 -2
- package/src/session/session-service.team-persistence.test.ts +1 -1
- package/src/session/session-service.ts +32 -19
- package/src/session/session-team-coordination.ts +13 -6
- package/src/session/sqlite-rpc-session-backend.ts +4 -6
- package/src/session/workspace-manager.ts +1 -1
- package/src/{session/default-session-manager.e2e.test.ts → transports/local.e2e.test.ts} +13 -17
- package/src/{session/default-session-manager.test.ts → transports/local.test.ts} +316 -230
- package/src/{session/default-session-manager.ts → transports/local.ts} +138 -172
- package/src/transports/rpc.test.ts +82 -0
- package/src/transports/rpc.ts +665 -0
- package/src/transports/runtime-host-support.ts +86 -0
- package/src/types/config.ts +3 -2
- package/src/{session/utils/types.ts → types/session.ts} +18 -5
- package/src/types/sessions.ts +21 -0
- package/src/types/storage.ts +1 -6
- package/src/types.ts +25 -18
- package/dist/chat/chat-schema.d.ts.map +0 -1
- package/dist/input/file-indexer.d.ts.map +0 -1
- package/dist/input/index.d.ts.map +0 -1
- package/dist/input/mention-enricher.d.ts.map +0 -1
- package/dist/prompt/default-system.d.ts +0 -2
- package/dist/prompt/default-system.d.ts.map +0 -1
- package/dist/providers/local-provider-registry.d.ts.map +0 -1
- package/dist/providers/local-provider-service.d.ts.map +0 -1
- package/dist/runtime/checkpoint-hooks.d.ts.map +0 -1
- package/dist/runtime/hook-file-hooks.d.ts.map +0 -1
- package/dist/runtime/team-runtime-registry.d.ts +0 -13
- package/dist/runtime/team-runtime-registry.d.ts.map +0 -1
- package/dist/session/default-session-manager.d.ts.map +0 -1
- package/dist/session/session-agent-events.d.ts.map +0 -1
- package/dist/session/session-artifacts.d.ts.map +0 -1
- package/dist/session/session-config-builder.d.ts +0 -16
- package/dist/session/session-config-builder.d.ts.map +0 -1
- package/dist/session/session-host.d.ts +0 -15
- package/dist/session/session-host.d.ts.map +0 -1
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/session/session-telemetry.d.ts.map +0 -1
- package/dist/session/utils/helpers.d.ts.map +0 -1
- package/dist/session/utils/types.d.ts.map +0 -1
- package/dist/session/utils/usage.d.ts.map +0 -1
- package/dist/session/workspace-manifest.d.ts.map +0 -1
- package/dist/storage/file-team-store.d.ts.map +0 -1
- package/dist/storage/provider-settings-legacy-migration.d.ts.map +0 -1
- package/dist/storage/provider-settings-manager.d.ts.map +0 -1
- package/dist/storage/sqlite-session-store.d.ts.map +0 -1
- package/dist/storage/sqlite-team-store.d.ts.map +0 -1
- package/dist/storage/team-store.d.ts.map +0 -1
- package/dist/team/delegated-agent.d.ts.map +0 -1
- package/dist/team/index.d.ts.map +0 -1
- package/dist/team/multi-agent.d.ts.map +0 -1
- package/dist/team/projections.d.ts.map +0 -1
- package/dist/team/runtime.d.ts.map +0 -1
- package/dist/team/spawn-agent-tool.d.ts.map +0 -1
- package/dist/team/subagent-prompts.d.ts.map +0 -1
- package/dist/team/team-tools.d.ts.map +0 -1
- package/dist/telemetry/ITelemetryAdapter.d.ts.map +0 -1
- package/dist/telemetry/OpenTelemetryAdapter.d.ts.map +0 -1
- package/dist/telemetry/OpenTelemetryProvider.d.ts.map +0 -1
- package/dist/telemetry/TelemetryLoggerSink.d.ts.map +0 -1
- package/dist/telemetry/TelemetryService.d.ts.map +0 -1
- package/dist/telemetry/core-events.d.ts.map +0 -1
- package/dist/telemetry/distinct-id.d.ts.map +0 -1
- package/dist/telemetry/index.d.ts.map +0 -1
- package/dist/tools/constants.d.ts.map +0 -1
- package/dist/tools/definitions.d.ts.map +0 -1
- package/dist/tools/executors/apply-patch-parser.d.ts.map +0 -1
- package/dist/tools/executors/apply-patch.d.ts.map +0 -1
- package/dist/tools/executors/bash.d.ts.map +0 -1
- package/dist/tools/executors/editor.d.ts.map +0 -1
- package/dist/tools/executors/file-read.d.ts.map +0 -1
- package/dist/tools/executors/index.d.ts.map +0 -1
- package/dist/tools/executors/search.d.ts.map +0 -1
- package/dist/tools/executors/web-fetch.d.ts.map +0 -1
- package/dist/tools/helpers.d.ts.map +0 -1
- package/dist/tools/index.d.ts.map +0 -1
- package/dist/tools/model-tool-routing.d.ts.map +0 -1
- package/dist/tools/presets.d.ts.map +0 -1
- package/dist/tools/schemas.d.ts.map +0 -1
- package/dist/tools/types.d.ts.map +0 -1
- package/src/prompt/default-system.ts +0 -21
- package/src/runtime/team-runtime-registry.ts +0 -43
- package/src/session/session-config-builder.ts +0 -126
- package/src/session/session-host.test.ts +0 -89
- package/src/session/session-host.ts +0 -213
- package/src/session/session-manager.ts +0 -74
- package/src/storage/artifact-store.ts +0 -1
- package/src/storage/session-store.ts +0 -1
- package/src/team/multi-agent.lifecycle.test.ts +0 -201
- package/src/tools/executors/file-read.test.ts +0 -49
- /package/dist/{tools → extensions/tools}/constants.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/definitions.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/apply-patch-parser.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/apply-patch.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/bash.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/editor.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/file-read.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/index.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/search.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/executors/web-fetch.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/helpers.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/index.d.ts +0 -0
- /package/dist/{tools → extensions/tools}/schemas.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/delegated-agent.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/index.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/projections.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/runtime.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/subagent-prompts.d.ts +0 -0
- /package/dist/{team → extensions/tools/team}/team-tools.d.ts +0 -0
- /package/dist/{session → runtime}/rpc-spawn-lease.d.ts +0 -0
- /package/dist/{providers → services/providers}/local-provider-registry.d.ts +0 -0
- /package/dist/{providers → services/providers}/local-provider-service.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/ITelemetryAdapter.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/OpenTelemetryAdapter.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/OpenTelemetryProvider.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/TelemetryLoggerSink.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/TelemetryService.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/core-events.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/distinct-id.d.ts +0 -0
- /package/dist/{telemetry → services/telemetry}/index.d.ts +0 -0
- /package/dist/{input → services/workspace}/file-indexer.d.ts +0 -0
- /package/dist/{input → services/workspace}/index.d.ts +0 -0
- /package/dist/{input → services/workspace}/mention-enricher.d.ts +0 -0
- /package/dist/{session → services}/workspace-manifest.d.ts +0 -0
- /package/dist/{chat → types}/chat-schema.d.ts +0 -0
- /package/src/{tools → extensions/tools}/constants.ts +0 -0
- /package/src/{tools → extensions/tools}/definitions.test.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/apply-patch-parser.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/apply-patch.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/bash.test.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/bash.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/editor.test.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/editor.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/index.ts +0 -0
- /package/src/{tools → extensions/tools}/executors/web-fetch.ts +0 -0
- /package/src/{tools → extensions/tools}/helpers.ts +0 -0
- /package/src/{tools → extensions/tools}/index.ts +0 -0
- /package/src/{tools → extensions/tools}/model-tool-routing.test.ts +0 -0
- /package/src/{tools → extensions/tools}/presets.test.ts +0 -0
- /package/src/{tools → extensions/tools}/schemas.ts +0 -0
- /package/src/{team → extensions/tools/team}/delegated-agent.ts +0 -0
- /package/src/{team → extensions/tools/team}/index.ts +0 -0
- /package/src/{team → extensions/tools/team}/projections.ts +0 -0
- /package/src/{team → extensions/tools/team}/runtime.ts +0 -0
- /package/src/{runtime → hooks}/checkpoint-hooks.test.ts +0 -0
- /package/src/{session → runtime}/runtime-oauth-token-manager.test.ts +0 -0
- /package/src/{providers → services/providers}/local-provider-registry.ts +0 -0
- /package/src/{providers → services/providers}/local-provider-service.test.ts +0 -0
- /package/src/{storage → services/storage}/index.ts +0 -0
- /package/src/{storage → services/storage}/provider-settings-manager.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/ITelemetryAdapter.ts +0 -0
- /package/src/{telemetry → services/telemetry}/OpenTelemetryAdapter.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/OpenTelemetryAdapter.ts +0 -0
- /package/src/{telemetry → services/telemetry}/OpenTelemetryProvider.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/OpenTelemetryProvider.ts +0 -0
- /package/src/{telemetry → services/telemetry}/TelemetryLoggerSink.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/TelemetryLoggerSink.ts +0 -0
- /package/src/{telemetry → services/telemetry}/TelemetryService.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/TelemetryService.ts +0 -0
- /package/src/{telemetry → services/telemetry}/core-events.ts +0 -0
- /package/src/{telemetry → services/telemetry}/distinct-id.test.ts +0 -0
- /package/src/{telemetry → services/telemetry}/distinct-id.ts +0 -0
- /package/src/{telemetry → services/telemetry}/index.ts +0 -0
- /package/src/{input → services/workspace}/file-indexer.d.ts +0 -0
- /package/src/{input → services/workspace}/index.ts +0 -0
- /package/src/{session → services}/workspace-manifest.ts +0 -0
- /package/src/{chat → types}/chat-schema.ts +0 -0
|
@@ -24,6 +24,10 @@ type RpcStartupLockRecord = {
|
|
|
24
24
|
pid: number;
|
|
25
25
|
address: string;
|
|
26
26
|
acquiredAt: string;
|
|
27
|
+
updatedAt: string;
|
|
28
|
+
status: "starting" | "running";
|
|
29
|
+
resolvedAddress?: string;
|
|
30
|
+
serverId?: string;
|
|
27
31
|
};
|
|
28
32
|
|
|
29
33
|
export type RpcDiscoveryRecord = {
|
|
@@ -233,22 +237,54 @@ function isProbeBlocked(error: unknown): boolean {
|
|
|
233
237
|
return isUnimplementedError(error) || isAuthenticationError(error);
|
|
234
238
|
}
|
|
235
239
|
|
|
236
|
-
|
|
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> {
|
|
237
255
|
const client = new RpcSessionClient({ address });
|
|
238
256
|
try {
|
|
239
257
|
try {
|
|
240
258
|
await client.stopRuntimeSession("__rpc_probe__");
|
|
241
259
|
} catch (error) {
|
|
242
|
-
if (isProbeBlocked(error))
|
|
260
|
+
if (isProbeBlocked(error)) {
|
|
261
|
+
return {
|
|
262
|
+
available: false,
|
|
263
|
+
reason: `runtime probe blocked (${formatProbeError(error)})`,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
243
266
|
}
|
|
244
|
-
return true;
|
|
267
|
+
return { available: true };
|
|
245
268
|
} catch (error) {
|
|
246
|
-
|
|
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
|
+
};
|
|
247
279
|
} finally {
|
|
248
280
|
client.close();
|
|
249
281
|
}
|
|
250
282
|
}
|
|
251
283
|
|
|
284
|
+
async function hasRuntimeMethods(address: string): Promise<boolean> {
|
|
285
|
+
return (await probeRuntimeMethods(address)).available;
|
|
286
|
+
}
|
|
287
|
+
|
|
252
288
|
export async function isCompatibleRuntime(address: string): Promise<boolean> {
|
|
253
289
|
const health = await getRpcServerHealth(address);
|
|
254
290
|
return (
|
|
@@ -258,6 +294,32 @@ export async function isCompatibleRuntime(address: string): Promise<boolean> {
|
|
|
258
294
|
);
|
|
259
295
|
}
|
|
260
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
|
+
|
|
261
323
|
async function isPortFree(host: string, port: number): Promise<boolean> {
|
|
262
324
|
return new Promise<boolean>((resolve) => {
|
|
263
325
|
const server = createServer();
|
|
@@ -294,13 +356,8 @@ function isPidAlive(pid: number | undefined): boolean {
|
|
|
294
356
|
|
|
295
357
|
async function writeRpcStartupLockRecord(
|
|
296
358
|
lockDir: string,
|
|
297
|
-
|
|
359
|
+
record: RpcStartupLockRecord,
|
|
298
360
|
): Promise<void> {
|
|
299
|
-
const record: RpcStartupLockRecord = {
|
|
300
|
-
pid: process.pid,
|
|
301
|
-
address,
|
|
302
|
-
acquiredAt: new Date().toISOString(),
|
|
303
|
-
};
|
|
304
361
|
await writeFile(
|
|
305
362
|
join(lockDir, "owner.json"),
|
|
306
363
|
JSON.stringify(record, null, 2),
|
|
@@ -318,7 +375,9 @@ async function readRpcStartupLockRecord(
|
|
|
318
375
|
if (
|
|
319
376
|
typeof parsed.pid !== "number" ||
|
|
320
377
|
typeof parsed.address !== "string" ||
|
|
321
|
-
typeof parsed.acquiredAt !== "string"
|
|
378
|
+
typeof parsed.acquiredAt !== "string" ||
|
|
379
|
+
typeof parsed.updatedAt !== "string" ||
|
|
380
|
+
(parsed.status !== "starting" && parsed.status !== "running")
|
|
322
381
|
) {
|
|
323
382
|
return undefined;
|
|
324
383
|
}
|
|
@@ -326,6 +385,14 @@ async function readRpcStartupLockRecord(
|
|
|
326
385
|
pid: parsed.pid,
|
|
327
386
|
address: parsed.address,
|
|
328
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,
|
|
329
396
|
};
|
|
330
397
|
} catch {
|
|
331
398
|
return undefined;
|
|
@@ -336,12 +403,59 @@ async function removeRpcStartupLockDir(lockDir: string): Promise<void> {
|
|
|
336
403
|
await rm(lockDir, { recursive: true, force: true }).catch(() => {});
|
|
337
404
|
}
|
|
338
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
|
+
|
|
339
451
|
export async function withRpcStartupLock<T>(
|
|
340
452
|
address: string,
|
|
341
|
-
action: () => Promise<T>,
|
|
453
|
+
action: (lock: RpcStartupLockHandle) => Promise<T>,
|
|
342
454
|
): Promise<T> {
|
|
343
455
|
if (process.env[RPC_STARTUP_LOCK_BYPASS_ENV] === "1") {
|
|
344
|
-
return await action(
|
|
456
|
+
return await action({
|
|
457
|
+
markRunning: async () => undefined,
|
|
458
|
+
});
|
|
345
459
|
}
|
|
346
460
|
|
|
347
461
|
const lockDir = getRpcStartupLockDir(address);
|
|
@@ -351,9 +465,23 @@ export async function withRpcStartupLock<T>(
|
|
|
351
465
|
while (true) {
|
|
352
466
|
try {
|
|
353
467
|
await mkdir(lockDir, { recursive: false });
|
|
354
|
-
await writeRpcStartupLockRecord(lockDir,
|
|
468
|
+
await writeRpcStartupLockRecord(lockDir, {
|
|
469
|
+
pid: process.pid,
|
|
470
|
+
address,
|
|
471
|
+
acquiredAt: new Date().toISOString(),
|
|
472
|
+
updatedAt: new Date().toISOString(),
|
|
473
|
+
status: "starting",
|
|
474
|
+
});
|
|
355
475
|
try {
|
|
356
|
-
return await action(
|
|
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
|
+
});
|
|
357
485
|
} finally {
|
|
358
486
|
await removeRpcStartupLockDir(lockDir);
|
|
359
487
|
}
|
|
@@ -361,22 +489,17 @@ export async function withRpcStartupLock<T>(
|
|
|
361
489
|
if (errorCode(error) !== "EEXIST") throw error;
|
|
362
490
|
|
|
363
491
|
const existing = await readRpcStartupLockRecord(lockDir);
|
|
364
|
-
const
|
|
365
|
-
? new Date(existing.acquiredAt).getTime()
|
|
366
|
-
: Number.NaN;
|
|
367
|
-
const isStale =
|
|
368
|
-
!existing ||
|
|
369
|
-
!Number.isFinite(acquiredAtMs) ||
|
|
370
|
-
Date.now() - acquiredAtMs > RPC_STARTUP_LOCK_MAX_AGE_MS ||
|
|
371
|
-
!isPidAlive(existing.pid);
|
|
492
|
+
const isStale = await isRpcStartupLockStale(existing);
|
|
372
493
|
if (isStale) {
|
|
373
494
|
await removeRpcStartupLockDir(lockDir);
|
|
374
495
|
continue;
|
|
375
496
|
}
|
|
376
497
|
|
|
377
498
|
if (Date.now() - startedAt >= RPC_STARTUP_LOCK_WAIT_MS) {
|
|
499
|
+
const ownerPid =
|
|
500
|
+
typeof existing?.pid === "number" ? existing.pid : "unknown";
|
|
378
501
|
throw new Error(
|
|
379
|
-
`timed out waiting for rpc startup lock at ${address} (owner pid=${
|
|
502
|
+
`timed out waiting for rpc startup lock at ${address} (owner pid=${ownerPid})`,
|
|
380
503
|
);
|
|
381
504
|
}
|
|
382
505
|
await sleep(RPC_STARTUP_LOCK_POLL_MS);
|
|
@@ -415,11 +538,18 @@ export async function resolveEnsuredRpcRuntime(
|
|
|
415
538
|
options: {
|
|
416
539
|
owner?: RpcOwnerContext;
|
|
417
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;
|
|
418
547
|
} = {},
|
|
419
548
|
): Promise<ResolveRpcRuntimeResult> {
|
|
420
549
|
const owner =
|
|
421
550
|
options.owner ?? options.resolveOwner?.() ?? resolveRpcOwnerContext();
|
|
422
|
-
|
|
551
|
+
|
|
552
|
+
const core = async (): Promise<ResolveRpcRuntimeResult> => {
|
|
423
553
|
const discovery = await readRpcDiscovery(owner);
|
|
424
554
|
if (discovery?.address) {
|
|
425
555
|
const discoveredHealth = await getRpcServerHealth(discovery.address);
|
|
@@ -475,7 +605,12 @@ export async function resolveEnsuredRpcRuntime(
|
|
|
475
605
|
action: "new-port",
|
|
476
606
|
owner,
|
|
477
607
|
} satisfies ResolveRpcRuntimeResult;
|
|
478
|
-
}
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
if (options.lockAlreadyHeld) {
|
|
611
|
+
return await core();
|
|
612
|
+
}
|
|
613
|
+
return await withRpcStartupLock(requestedAddress, core);
|
|
479
614
|
}
|
|
480
615
|
|
|
481
616
|
export async function waitForCompatibleRpcRuntime(
|
|
@@ -506,7 +641,10 @@ export async function ensureRpcRuntimeAddress(
|
|
|
506
641
|
options.readinessCheck,
|
|
507
642
|
))
|
|
508
643
|
) {
|
|
509
|
-
|
|
644
|
+
const reason = await describeRpcRuntimeReadinessFailure(resolved.address);
|
|
645
|
+
throw new Error(
|
|
646
|
+
`failed to ensure rpc runtime at ${resolved.address}: ${reason}`,
|
|
647
|
+
);
|
|
510
648
|
}
|
|
511
649
|
const health = await getRpcServerHealth(resolved.address);
|
|
512
650
|
await recordRpcDiscovery(resolved.owner, {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
3
|
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { afterEach, describe, expect, it } from "vitest";
|
|
@@ -46,4 +47,35 @@ describe("tryAcquireRpcSpawnLease", () => {
|
|
|
46
47
|
first?.release();
|
|
47
48
|
second?.release();
|
|
48
49
|
});
|
|
50
|
+
|
|
51
|
+
it("reclaims a leftover lease owned by the current process", () => {
|
|
52
|
+
const dataDir = mkdtempSync(path.join(os.tmpdir(), "rpc-spawn-lease-"));
|
|
53
|
+
tempDirs.push(dataDir);
|
|
54
|
+
process.env.CLINE_DATA_DIR = dataDir;
|
|
55
|
+
|
|
56
|
+
const first = tryAcquireRpcSpawnLease("127.0.0.1:4317");
|
|
57
|
+
expect(first).toBeDefined();
|
|
58
|
+
const leasePath = first?.path;
|
|
59
|
+
expect(leasePath).toBeTruthy();
|
|
60
|
+
first?.release();
|
|
61
|
+
|
|
62
|
+
writeFileSync(
|
|
63
|
+
leasePath!,
|
|
64
|
+
JSON.stringify({
|
|
65
|
+
address: "127.0.0.1:4317",
|
|
66
|
+
pid: process.pid,
|
|
67
|
+
createdAt: Date.now(),
|
|
68
|
+
}),
|
|
69
|
+
"utf8",
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
const second = tryAcquireRpcSpawnLease("127.0.0.1:4317");
|
|
73
|
+
assert(second);
|
|
74
|
+
expect(
|
|
75
|
+
JSON.parse(readFileSync(second.path, "utf8")) as { pid: number },
|
|
76
|
+
).toMatchObject({
|
|
77
|
+
pid: process.pid,
|
|
78
|
+
});
|
|
79
|
+
second.release();
|
|
80
|
+
});
|
|
49
81
|
});
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { dirname, resolve } from "node:path";
|
|
11
11
|
import { resolveSessionDataDir } from "@clinebot/shared/storage";
|
|
12
12
|
|
|
13
|
-
const DEFAULT_LEASE_TTL_MS =
|
|
13
|
+
const DEFAULT_LEASE_TTL_MS = 5_000;
|
|
14
14
|
|
|
15
15
|
interface RpcSpawnLeaseRecord {
|
|
16
16
|
address: string;
|
|
@@ -23,6 +23,10 @@ export interface RpcSpawnLease {
|
|
|
23
23
|
release: () => void;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
const ACTIVE_LEASE_RELEASES = new Set<() => void>();
|
|
27
|
+
const ACTIVE_LEASE_PATHS = new Set<string>();
|
|
28
|
+
let EXIT_CLEANUP_REGISTERED = false;
|
|
29
|
+
|
|
26
30
|
function encodeAddress(address: string): string {
|
|
27
31
|
return Buffer.from(address).toString("base64url");
|
|
28
32
|
}
|
|
@@ -52,19 +56,43 @@ function shouldClearLease(path: string, ttlMs: number): boolean {
|
|
|
52
56
|
try {
|
|
53
57
|
const raw = readFileSync(path, "utf8");
|
|
54
58
|
const parsed = JSON.parse(raw) as Partial<RpcSpawnLeaseRecord>;
|
|
59
|
+
const pid = Number(parsed.pid ?? 0);
|
|
55
60
|
const createdAt = Number(parsed.createdAt ?? 0);
|
|
61
|
+
if (pid === process.pid && !ACTIVE_LEASE_PATHS.has(path)) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
56
64
|
if (!Number.isFinite(createdAt) || createdAt <= 0) {
|
|
57
65
|
return true;
|
|
58
66
|
}
|
|
59
67
|
if (Date.now() - createdAt > ttlMs) {
|
|
60
68
|
return true;
|
|
61
69
|
}
|
|
62
|
-
return !isProcessAlive(
|
|
70
|
+
return !isProcessAlive(pid);
|
|
63
71
|
} catch {
|
|
64
72
|
return true;
|
|
65
73
|
}
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
function cleanupActiveLeases(): void {
|
|
77
|
+
for (const release of [...ACTIVE_LEASE_RELEASES]) {
|
|
78
|
+
try {
|
|
79
|
+
release();
|
|
80
|
+
} catch {
|
|
81
|
+
// Best effort.
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function registerExitCleanupOnce(): void {
|
|
87
|
+
if (EXIT_CLEANUP_REGISTERED) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
EXIT_CLEANUP_REGISTERED = true;
|
|
91
|
+
process.once("exit", cleanupActiveLeases);
|
|
92
|
+
process.once("SIGINT", cleanupActiveLeases);
|
|
93
|
+
process.once("SIGTERM", cleanupActiveLeases);
|
|
94
|
+
}
|
|
95
|
+
|
|
68
96
|
export function tryAcquireRpcSpawnLease(
|
|
69
97
|
address: string,
|
|
70
98
|
options?: { ttlMs?: number },
|
|
@@ -98,25 +126,31 @@ export function tryAcquireRpcSpawnLease(
|
|
|
98
126
|
}
|
|
99
127
|
|
|
100
128
|
let released = false;
|
|
129
|
+
const release = () => {
|
|
130
|
+
if (released) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
released = true;
|
|
134
|
+
ACTIVE_LEASE_RELEASES.delete(release);
|
|
135
|
+
ACTIVE_LEASE_PATHS.delete(path);
|
|
136
|
+
try {
|
|
137
|
+
if (typeof fd === "number") {
|
|
138
|
+
closeSync(fd);
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
// Best effort.
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
rmSync(path, { force: true });
|
|
145
|
+
} catch {
|
|
146
|
+
// Best effort.
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
registerExitCleanupOnce();
|
|
150
|
+
ACTIVE_LEASE_RELEASES.add(release);
|
|
151
|
+
ACTIVE_LEASE_PATHS.add(path);
|
|
101
152
|
return {
|
|
102
153
|
path,
|
|
103
|
-
release
|
|
104
|
-
if (released) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
released = true;
|
|
108
|
-
try {
|
|
109
|
-
if (typeof fd === "number") {
|
|
110
|
-
closeSync(fd);
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
// Best effort.
|
|
114
|
-
}
|
|
115
|
-
try {
|
|
116
|
-
rmSync(path, { force: true });
|
|
117
|
-
} catch {
|
|
118
|
-
// Best effort.
|
|
119
|
-
}
|
|
120
|
-
},
|
|
154
|
+
release,
|
|
121
155
|
};
|
|
122
156
|
}
|
|
@@ -35,7 +35,7 @@ class MockAgentTeamsRuntime {
|
|
|
35
35
|
shutdownTeammate = vi.fn();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
vi.mock("../team", () => ({
|
|
38
|
+
vi.mock("../extensions/tools/team", () => ({
|
|
39
39
|
AgentTeamsRuntime: MockAgentTeamsRuntime,
|
|
40
40
|
bootstrapAgentTeams: bootstrapAgentTeamsMock,
|
|
41
41
|
createDelegatedAgentConfigProvider: (config: Record<string, unknown>) => {
|
|
@@ -59,13 +59,16 @@ vi.mock("../team", () => ({
|
|
|
59
59
|
},
|
|
60
60
|
}));
|
|
61
61
|
|
|
62
|
-
vi.mock("../
|
|
62
|
+
vi.mock("../extensions/tools", () => ({
|
|
63
63
|
ALL_DEFAULT_TOOL_NAMES: [],
|
|
64
64
|
createBuiltinTools: createBuiltinToolsMock,
|
|
65
65
|
ToolPresets: {
|
|
66
66
|
development: {},
|
|
67
67
|
readonly: {},
|
|
68
68
|
},
|
|
69
|
+
resolveToolPresetName: () => "development",
|
|
70
|
+
resolveToolRoutingConfig: () => [],
|
|
71
|
+
DEFAULT_MODEL_TOOL_ROUTING_RULES: [],
|
|
69
72
|
}));
|
|
70
73
|
|
|
71
74
|
let teamStoreInstance: MockTeamStore | undefined;
|
|
@@ -100,7 +103,7 @@ class MockTeamStore {
|
|
|
100
103
|
persistRuntime = vi.fn();
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
vi.mock("../storage/team-store", () => ({
|
|
106
|
+
vi.mock("../services/storage/team-store", () => ({
|
|
104
107
|
createLocalTeamStore: () => new MockTeamStore(),
|
|
105
108
|
}));
|
|
106
109
|
|
|
@@ -3,7 +3,7 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import type { Tool } from "@clinebot/shared";
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
|
-
import { TelemetryService } from "../telemetry/TelemetryService";
|
|
6
|
+
import { TelemetryService } from "../services/telemetry/TelemetryService";
|
|
7
7
|
import type { CoreSessionConfig } from "../types/config";
|
|
8
8
|
import { DefaultRuntimeBuilder } from "./runtime-builder";
|
|
9
9
|
|
|
@@ -83,8 +83,7 @@ describe("DefaultRuntimeBuilder", () => {
|
|
|
83
83
|
it("uses yolo preset only when yolo mode is explicit", async () => {
|
|
84
84
|
const runtime = await new DefaultRuntimeBuilder().build({
|
|
85
85
|
config: makeBaseConfig({
|
|
86
|
-
mode: "
|
|
87
|
-
yolo: true,
|
|
86
|
+
mode: "yolo",
|
|
88
87
|
}),
|
|
89
88
|
defaultToolExecutors: {
|
|
90
89
|
submit: async () => "submitted",
|
|
@@ -120,7 +119,7 @@ describe("DefaultRuntimeBuilder", () => {
|
|
|
120
119
|
config: {
|
|
121
120
|
...makeBaseConfig({
|
|
122
121
|
enableTools: false,
|
|
123
|
-
|
|
122
|
+
mode: "yolo",
|
|
124
123
|
}),
|
|
125
124
|
} as CoreSessionConfig,
|
|
126
125
|
createSpawnTool: makeSpawnTool,
|
|
@@ -186,6 +185,22 @@ describe("DefaultRuntimeBuilder", () => {
|
|
|
186
185
|
expect(runtime.tools).toEqual([]);
|
|
187
186
|
});
|
|
188
187
|
|
|
188
|
+
it("omits tools disabled by policy from the advertised runtime tool list", async () => {
|
|
189
|
+
const runtime = await new DefaultRuntimeBuilder().build({
|
|
190
|
+
config: makeBaseConfig({
|
|
191
|
+
toolPolicies: {
|
|
192
|
+
run_commands: { enabled: false },
|
|
193
|
+
read_files: { enabled: false },
|
|
194
|
+
},
|
|
195
|
+
}),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const names = runtime.tools.map((tool) => tool.name);
|
|
199
|
+
expect(names).not.toContain("run_commands");
|
|
200
|
+
expect(names).not.toContain("read_files");
|
|
201
|
+
expect(names).toContain("search_codebase");
|
|
202
|
+
});
|
|
203
|
+
|
|
189
204
|
it("adds spawn tool when enabled", async () => {
|
|
190
205
|
const runtime = await new DefaultRuntimeBuilder().build({
|
|
191
206
|
config: makeBaseConfig({
|
|
@@ -284,6 +299,88 @@ process.stdin.on("data", (chunk) => {
|
|
|
284
299
|
}
|
|
285
300
|
});
|
|
286
301
|
|
|
302
|
+
it("skips MCP settings tools when disableMcpSettingsTools is true", async () => {
|
|
303
|
+
const tempRoot = mkdtempSync(
|
|
304
|
+
join(tmpdir(), "runtime-builder-mcp-disabled-"),
|
|
305
|
+
);
|
|
306
|
+
const serverPath = join(tempRoot, "mock-mcp-server.js");
|
|
307
|
+
const settingsPath = join(tempRoot, "cline_mcp_settings.json");
|
|
308
|
+
const previousSettingsPath = process.env.CLINE_MCP_SETTINGS_PATH;
|
|
309
|
+
|
|
310
|
+
writeFileSync(
|
|
311
|
+
serverPath,
|
|
312
|
+
`let buffer = "";
|
|
313
|
+
function write(payload) {
|
|
314
|
+
const body = JSON.stringify(payload);
|
|
315
|
+
process.stdout.write("Content-Length: " + Buffer.byteLength(body, "utf8") + "\\r\\n\\r\\n" + body);
|
|
316
|
+
}
|
|
317
|
+
function handle(message) {
|
|
318
|
+
if (message.method === "initialize") {
|
|
319
|
+
write({ jsonrpc: "2.0", id: message.id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "mock", version: "1.0.0" } } });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (message.method === "tools/list") {
|
|
323
|
+
write({ jsonrpc: "2.0", id: message.id, result: { tools: [{ name: "echo", description: "Echo tool", inputSchema: { type: "object", properties: { value: { type: "string" } }, required: [] } }] } });
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (message.method === "tools/call") {
|
|
327
|
+
write({ jsonrpc: "2.0", id: message.id, result: { echoed: message.params?.arguments?.value ?? null } });
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
process.stdin.on("data", (chunk) => {
|
|
331
|
+
buffer += chunk.toString("utf8");
|
|
332
|
+
while (true) {
|
|
333
|
+
const separator = buffer.indexOf("\\r\\n\\r\\n");
|
|
334
|
+
if (separator < 0) break;
|
|
335
|
+
const header = buffer.slice(0, separator);
|
|
336
|
+
const match = header.match(/Content-Length:\\s*(\\d+)/i);
|
|
337
|
+
if (!match) throw new Error("missing content length");
|
|
338
|
+
const length = Number(match[1]);
|
|
339
|
+
const start = separator + 4;
|
|
340
|
+
const end = start + length;
|
|
341
|
+
if (buffer.length < end) break;
|
|
342
|
+
const body = buffer.slice(start, end);
|
|
343
|
+
buffer = buffer.slice(end);
|
|
344
|
+
const message = JSON.parse(body);
|
|
345
|
+
if (message.method === "notifications/initialized") continue;
|
|
346
|
+
handle(message);
|
|
347
|
+
}
|
|
348
|
+
});`,
|
|
349
|
+
"utf8",
|
|
350
|
+
);
|
|
351
|
+
writeFileSync(
|
|
352
|
+
settingsPath,
|
|
353
|
+
JSON.stringify(
|
|
354
|
+
{
|
|
355
|
+
mcpServers: {
|
|
356
|
+
mock: {
|
|
357
|
+
command: process.execPath,
|
|
358
|
+
args: [serverPath],
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
null,
|
|
363
|
+
2,
|
|
364
|
+
),
|
|
365
|
+
"utf8",
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
process.env.CLINE_MCP_SETTINGS_PATH = settingsPath;
|
|
369
|
+
try {
|
|
370
|
+
const runtime = await new DefaultRuntimeBuilder().build({
|
|
371
|
+
config: makeBaseConfig({
|
|
372
|
+
disableMcpSettingsTools: true,
|
|
373
|
+
}),
|
|
374
|
+
});
|
|
375
|
+
expect(runtime.tools.map((tool) => tool.name)).not.toContain(
|
|
376
|
+
"mock__echo",
|
|
377
|
+
);
|
|
378
|
+
await runtime.shutdown("test");
|
|
379
|
+
} finally {
|
|
380
|
+
process.env.CLINE_MCP_SETTINGS_PATH = previousSettingsPath;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
287
384
|
it("skips broken MCP servers without crashing", async () => {
|
|
288
385
|
const tempRoot = mkdtempSync(join(tmpdir(), "runtime-builder-mcp-bad-"));
|
|
289
386
|
const serverPath = join(tempRoot, "malformed-mcp-server.js");
|