@clinebot/core 0.0.28 → 0.0.29
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 +7 -0
- package/dist/ClineCore.d.ts +28 -2
- package/dist/ClineCore.d.ts.map +1 -1
- package/dist/account/cline-account-service.d.ts +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/types.d.ts +5 -0
- package/dist/account/types.d.ts.map +1 -1
- package/dist/auth/bounded-ttl-cache.d.ts +14 -0
- package/dist/auth/bounded-ttl-cache.d.ts.map +1 -0
- package/dist/auth/cline.d.ts +27 -2
- package/dist/auth/cline.d.ts.map +1 -1
- package/dist/auth/oca.d.ts.map +1 -1
- package/dist/chat/chat-schema.d.ts +11 -11
- package/dist/extensions/config/agent-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/agent-config-parser.d.ts +2 -2
- package/dist/extensions/config/agent-config-parser.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/hooks-config-loader.d.ts +1 -1
- package/dist/extensions/config/hooks-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/config}/index.d.ts +2 -4
- package/dist/extensions/config/index.d.ts.map +1 -0
- package/dist/{runtime/commands.d.ts → extensions/config/runtime-commands.d.ts} +2 -3
- package/dist/extensions/config/runtime-commands.d.ts.map +1 -0
- package/dist/extensions/config/unified-config-file-watcher.d.ts.map +1 -0
- package/dist/extensions/config/user-instruction-config-loader.d.ts.map +1 -0
- package/dist/extensions/context/agentic-compaction.d.ts +13 -0
- package/dist/extensions/context/agentic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/basic-compaction.d.ts +9 -0
- package/dist/extensions/context/basic-compaction.d.ts.map +1 -0
- package/dist/extensions/context/compaction-shared.d.ts +60 -0
- package/dist/extensions/context/compaction-shared.d.ts.map +1 -0
- package/dist/extensions/context/compaction.d.ts +20 -0
- package/dist/extensions/context/compaction.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +5 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/mcp/client.d.ts +3 -0
- package/dist/extensions/mcp/client.d.ts.map +1 -0
- package/dist/extensions/mcp/config-loader.d.ts.map +1 -0
- package/dist/extensions/mcp/index.d.ts +9 -0
- package/dist/extensions/mcp/index.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/manager.d.ts +1 -2
- package/dist/extensions/mcp/manager.d.ts.map +1 -0
- package/dist/extensions/mcp/name-transform.d.ts +3 -0
- package/dist/extensions/mcp/name-transform.d.ts.map +1 -0
- package/dist/extensions/mcp/policies.d.ts +15 -0
- package/dist/extensions/mcp/policies.d.ts.map +1 -0
- package/dist/extensions/mcp/tools.d.ts +4 -0
- package/dist/extensions/mcp/tools.d.ts.map +1 -0
- package/dist/{mcp → extensions/mcp}/types.d.ts +29 -1
- package/dist/extensions/mcp/types.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-config-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-config-loader.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-loader.d.ts +1 -1
- package/dist/extensions/plugin/plugin-loader.d.ts.map +1 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts +5 -0
- package/dist/extensions/plugin/plugin-module-import.d.ts.map +1 -0
- package/dist/{agents → extensions/plugin}/plugin-sandbox.d.ts +1 -1
- package/dist/extensions/plugin/plugin-sandbox.d.ts.map +1 -0
- package/dist/extensions/plugin-sandbox-bootstrap.js +485 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/persistent.d.ts +64 -0
- package/dist/hooks/persistent.d.ts.map +1 -0
- package/dist/hooks/subprocess-runner.d.ts +22 -0
- package/dist/hooks/subprocess-runner.d.ts.map +1 -0
- package/dist/hooks/subprocess.d.ts +189 -0
- package/dist/hooks/subprocess.d.ts.map +1 -0
- package/dist/index.d.ts +22 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +560 -447
- package/dist/prompt/default-system.d.ts +2 -0
- package/dist/prompt/default-system.d.ts.map +1 -0
- package/dist/providers/local-provider-service.d.ts +1 -1
- package/dist/providers/local-provider-service.d.ts.map +1 -1
- package/dist/runtime/checkpoint-hooks.d.ts +21 -0
- package/dist/runtime/checkpoint-hooks.d.ts.map +1 -0
- package/dist/runtime/hook-file-hooks.d.ts +1 -1
- package/dist/runtime/hook-file-hooks.d.ts.map +1 -1
- package/dist/runtime/rules.d.ts +1 -1
- package/dist/runtime/rules.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/runtime/session-runtime.d.ts +25 -5
- package/dist/runtime/session-runtime.d.ts.map +1 -1
- package/dist/runtime/subprocess-sandbox.d.ts.map +1 -0
- package/dist/runtime/team-runtime-registry.d.ts +1 -1
- package/dist/runtime/team-runtime-registry.d.ts.map +1 -1
- package/dist/runtime/tool-approval.d.ts +1 -1
- package/dist/session/default-session-manager.d.ts +4 -3
- package/dist/session/default-session-manager.d.ts.map +1 -1
- package/dist/session/file-session-service.d.ts +1 -1
- package/dist/session/file-session-service.d.ts.map +1 -1
- package/dist/session/{unified-session-persistence-service.d.ts → persistence-service.d.ts} +11 -42
- package/dist/session/persistence-service.d.ts.map +1 -0
- package/dist/session/rpc-session-service.d.ts +1 -1
- package/dist/session/rpc-session-service.d.ts.map +1 -1
- package/dist/session/session-agent-events.d.ts +1 -1
- package/dist/session/session-artifacts.d.ts.map +1 -1
- package/dist/session/session-config-builder.d.ts.map +1 -1
- package/dist/session/session-graph.d.ts +1 -1
- package/dist/session/session-graph.d.ts.map +1 -1
- package/dist/session/session-host.d.ts.map +1 -1
- package/dist/session/session-manager.d.ts +6 -5
- package/dist/session/session-manager.d.ts.map +1 -1
- package/dist/session/session-manifest.d.ts +1 -1
- package/dist/session/session-service.d.ts +3 -2
- package/dist/session/session-service.d.ts.map +1 -1
- package/dist/session/session-team-coordination.d.ts +2 -1
- package/dist/session/session-team-coordination.d.ts.map +1 -1
- package/dist/session/utils/helpers.d.ts +51 -3
- package/dist/session/utils/helpers.d.ts.map +1 -1
- package/dist/session/utils/types.d.ts +41 -7
- package/dist/session/utils/types.d.ts.map +1 -1
- package/dist/session/workspace-manager.d.ts +1 -2
- package/dist/session/workspace-manager.d.ts.map +1 -1
- package/dist/session/workspace-manifest.d.ts +1 -22
- package/dist/session/workspace-manifest.d.ts.map +1 -1
- package/dist/storage/file-team-store.d.ts +2 -1
- package/dist/storage/file-team-store.d.ts.map +1 -1
- package/dist/storage/sqlite-team-store.d.ts +4 -1
- package/dist/storage/sqlite-team-store.d.ts.map +1 -1
- package/dist/storage/team-store.d.ts.map +1 -1
- package/dist/team/delegated-agent.d.ts +44 -0
- package/dist/team/delegated-agent.d.ts.map +1 -0
- package/dist/team/index.d.ts +1 -0
- package/dist/team/index.d.ts.map +1 -1
- package/dist/team/multi-agent.d.ts +229 -0
- package/dist/team/multi-agent.d.ts.map +1 -0
- package/dist/team/projections.d.ts +2 -2
- package/dist/team/projections.d.ts.map +1 -1
- package/dist/team/runtime.d.ts +5 -0
- package/dist/team/runtime.d.ts.map +1 -0
- package/dist/team/spawn-agent-tool.d.ts +85 -0
- package/dist/team/spawn-agent-tool.d.ts.map +1 -0
- package/dist/team/subagent-prompts.d.ts +4 -0
- package/dist/team/subagent-prompts.d.ts.map +1 -0
- package/dist/team/team-tools.d.ts +35 -0
- package/dist/team/team-tools.d.ts.map +1 -0
- package/dist/telemetry/OpenTelemetryProvider.d.ts +11 -1
- package/dist/telemetry/OpenTelemetryProvider.d.ts.map +1 -1
- package/dist/telemetry/{LoggerTelemetryAdapter.d.ts → TelemetryLoggerSink.d.ts} +10 -4
- package/dist/telemetry/TelemetryLoggerSink.d.ts.map +1 -0
- package/dist/telemetry/TelemetryService.d.ts.map +1 -1
- package/dist/telemetry/index.js +15 -28
- package/dist/tools/definitions.d.ts +4 -3
- package/dist/tools/definitions.d.ts.map +1 -1
- package/dist/tools/index.d.ts +5 -5
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/model-tool-routing.d.ts.map +1 -1
- package/dist/tools/presets.d.ts +26 -0
- package/dist/tools/presets.d.ts.map +1 -1
- package/dist/tools/schemas.d.ts +8 -0
- package/dist/tools/schemas.d.ts.map +1 -1
- package/dist/tools/types.d.ts +23 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/config.d.ts +47 -3
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +1 -1
- package/dist/types/provider-settings.d.ts +1 -1
- package/dist/types/provider-settings.d.ts.map +1 -1
- package/dist/types/storage.d.ts +2 -1
- package/dist/types/storage.d.ts.map +1 -1
- package/dist/types.d.ts +7 -16
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -12
- package/src/ClineCore.test.ts +150 -0
- package/src/ClineCore.ts +114 -8
- package/src/account/cline-account-service.test.ts +84 -0
- package/src/account/cline-account-service.ts +2 -2
- package/src/account/index.ts +1 -0
- package/src/account/types.ts +6 -0
- package/src/auth/bounded-ttl-cache.test.ts +38 -0
- package/src/auth/bounded-ttl-cache.ts +53 -0
- package/src/auth/cline.test.ts +173 -36
- package/src/auth/cline.ts +395 -93
- package/src/auth/oca.test.ts +125 -0
- package/src/auth/oca.ts +17 -4
- package/src/{agents → extensions/config}/agent-config-loader.test.ts +1 -1
- package/src/{agents → extensions/config}/agent-config-parser.ts +2 -2
- package/src/{agents → extensions/config}/hooks-config-loader.ts +1 -1
- package/src/{agents → extensions/config}/index.ts +7 -11
- package/src/{runtime/commands.test.ts → extensions/config/runtime-commands.test.ts} +20 -3
- package/src/{runtime/commands.ts → extensions/config/runtime-commands.ts} +1 -8
- package/src/{agents → extensions/config}/unified-config-file-watcher.ts +15 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.test.ts +90 -2
- package/src/{agents → extensions/config}/user-instruction-config-loader.ts +126 -12
- package/src/extensions/context/agentic-compaction.ts +119 -0
- package/src/extensions/context/basic-compaction.ts +275 -0
- package/src/extensions/context/compaction-shared.ts +458 -0
- package/src/extensions/context/compaction.test.ts +477 -0
- package/src/extensions/context/compaction.ts +203 -0
- package/src/extensions/index.ts +12 -0
- package/src/extensions/mcp/client.ts +420 -0
- package/src/{mcp → extensions/mcp}/index.ts +16 -0
- package/src/{mcp → extensions/mcp}/manager.test.ts +1 -2
- package/src/{mcp → extensions/mcp}/manager.ts +3 -5
- package/src/extensions/mcp/name-transform.ts +33 -0
- package/src/extensions/mcp/policies.ts +47 -0
- package/src/extensions/mcp/tools.ts +47 -0
- package/src/{mcp → extensions/mcp}/types.ts +35 -7
- package/src/{agents → extensions/plugin}/plugin-config-loader.test.ts +18 -13
- package/src/{agents → extensions/plugin}/plugin-config-loader.ts +1 -1
- package/src/{agents → extensions/plugin}/plugin-loader.test.ts +41 -4
- package/src/extensions/plugin/plugin-loader.ts +106 -0
- package/src/extensions/plugin/plugin-module-import.ts +278 -0
- package/src/{agents → extensions/plugin}/plugin-sandbox-bootstrap.ts +30 -92
- package/src/{agents → extensions/plugin}/plugin-sandbox.test.ts +60 -3
- package/src/{agents → extensions/plugin}/plugin-sandbox.ts +146 -56
- package/src/hooks/index.ts +25 -0
- package/src/hooks/persistent.ts +661 -0
- package/src/hooks/subprocess-runner.ts +196 -0
- package/src/hooks/subprocess.ts +669 -0
- package/src/index.ts +200 -118
- package/src/prompt/default-system.ts +21 -0
- package/src/providers/local-provider-registry.ts +1 -1
- package/src/providers/local-provider-service.test.ts +23 -2
- package/src/providers/local-provider-service.ts +2 -2
- package/src/runtime/checkpoint-hooks.test.ts +167 -0
- package/src/runtime/checkpoint-hooks.ts +186 -0
- package/src/runtime/hook-file-hooks.test.ts +40 -1
- package/src/runtime/hook-file-hooks.ts +35 -16
- package/src/runtime/index.ts +4 -19
- package/src/runtime/rules.ts +4 -1
- package/src/runtime/runtime-builder.team-persistence.test.ts +3 -6
- package/src/runtime/runtime-builder.test.ts +266 -160
- package/src/runtime/runtime-builder.ts +120 -47
- package/src/runtime/runtime-parity.test.ts +22 -22
- package/src/runtime/session-runtime.ts +36 -6
- package/src/runtime/{sandbox/subprocess-sandbox.ts → subprocess-sandbox.ts} +24 -3
- package/src/runtime/team-runtime-registry.ts +1 -4
- package/src/runtime/tool-approval.ts +1 -1
- package/src/session/default-session-manager.e2e.test.ts +2 -2
- package/src/session/default-session-manager.test.ts +553 -9
- package/src/session/default-session-manager.ts +140 -46
- package/src/session/file-session-service.ts +3 -3
- package/src/session/index.ts +6 -6
- package/src/session/persistence-service.test.ts +212 -0
- package/src/session/{unified-session-persistence-service.ts → persistence-service.ts} +106 -172
- package/src/session/rpc-session-service.ts +3 -3
- package/src/session/runtime-oauth-token-manager.ts +1 -1
- package/src/session/session-agent-events.ts +1 -1
- package/src/session/session-artifacts.ts +32 -4
- package/src/session/session-config-builder.ts +22 -9
- package/src/session/session-graph.ts +1 -1
- package/src/session/session-host.ts +19 -11
- package/src/session/session-manager.ts +11 -6
- package/src/session/session-service.team-persistence.test.ts +1 -1
- package/src/session/session-service.ts +6 -9
- package/src/session/session-team-coordination.ts +7 -3
- package/src/session/session-telemetry.ts +1 -1
- package/src/session/utils/helpers.test.ts +160 -0
- package/src/session/utils/helpers.ts +289 -42
- package/src/session/utils/types.ts +47 -7
- package/src/session/workspace-manager.ts +5 -3
- package/src/session/workspace-manifest.ts +3 -49
- package/src/storage/file-team-store.ts +2 -5
- package/src/storage/provider-settings-legacy-migration.ts +2 -2
- package/src/storage/provider-settings-manager.test.ts +1 -1
- package/src/storage/sqlite-team-store.ts +212 -125
- package/src/storage/team-store.ts +1 -5
- package/src/team/delegated-agent.ts +131 -0
- package/src/team/index.ts +1 -0
- package/src/team/multi-agent.lifecycle.test.ts +201 -0
- package/src/team/multi-agent.ts +1666 -0
- package/src/team/projections.ts +2 -4
- package/src/team/runtime.ts +54 -0
- package/src/team/spawn-agent-tool.test.ts +387 -0
- package/src/team/spawn-agent-tool.ts +207 -0
- package/src/team/subagent-prompts.ts +41 -0
- package/src/team/team-tools.test.ts +802 -0
- package/src/team/team-tools.ts +792 -0
- package/src/telemetry/OpenTelemetryProvider.test.ts +25 -3
- package/src/telemetry/OpenTelemetryProvider.ts +108 -18
- package/src/telemetry/TelemetryLoggerSink.test.ts +42 -0
- package/src/telemetry/{LoggerTelemetryAdapter.ts → TelemetryLoggerSink.ts} +21 -14
- package/src/telemetry/TelemetryService.test.ts +7 -7
- package/src/telemetry/TelemetryService.ts +2 -4
- package/src/tools/definitions.test.ts +76 -0
- package/src/tools/definitions.ts +41 -2
- package/src/tools/executors/apply-patch.ts +1 -1
- package/src/tools/executors/editor.ts +1 -1
- package/src/tools/executors/file-read.ts +1 -1
- package/src/tools/executors/search.ts +1 -1
- package/src/tools/executors/web-fetch.ts +1 -1
- package/src/tools/index.ts +6 -1
- package/src/tools/model-tool-routing.ts +2 -0
- package/src/tools/presets.test.ts +8 -0
- package/src/tools/presets.ts +40 -2
- package/src/tools/schemas.ts +19 -0
- package/src/tools/types.ts +31 -2
- package/src/types/config.ts +61 -7
- package/src/types/events.ts +1 -1
- package/src/types/index.ts +0 -1
- package/src/types/provider-settings.ts +1 -1
- package/src/types/storage.ts +2 -5
- package/src/types.ts +32 -44
- package/dist/agents/agent-config-loader.d.ts.map +0 -1
- package/dist/agents/agent-config-parser.d.ts.map +0 -1
- package/dist/agents/hooks-config-loader.d.ts.map +0 -1
- package/dist/agents/index.d.ts.map +0 -1
- package/dist/agents/plugin-config-loader.d.ts.map +0 -1
- package/dist/agents/plugin-loader.d.ts.map +0 -1
- package/dist/agents/plugin-sandbox-bootstrap.js +0 -446
- package/dist/agents/plugin-sandbox.d.ts.map +0 -1
- package/dist/agents/unified-config-file-watcher.d.ts.map +0 -1
- package/dist/agents/user-instruction-config-loader.d.ts.map +0 -1
- package/dist/mcp/config-loader.d.ts.map +0 -1
- package/dist/mcp/index.d.ts +0 -5
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/manager.d.ts.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/runtime/commands.d.ts.map +0 -1
- package/dist/runtime/sandbox/subprocess-sandbox.d.ts.map +0 -1
- package/dist/runtime/skills.d.ts +0 -14
- package/dist/runtime/skills.d.ts.map +0 -1
- package/dist/runtime/workflows.d.ts +0 -14
- package/dist/runtime/workflows.d.ts.map +0 -1
- package/dist/session/unified-session-persistence-service.d.ts.map +0 -1
- package/dist/telemetry/LoggerTelemetryAdapter.d.ts.map +0 -1
- package/dist/types/workspace.d.ts +0 -8
- package/dist/types/workspace.d.ts.map +0 -1
- package/src/agents/plugin-loader.ts +0 -175
- package/src/runtime/skills.ts +0 -44
- package/src/runtime/workflows.test.ts +0 -119
- package/src/runtime/workflows.ts +0 -45
- package/src/session/unified-session-persistence-service.test.ts +0 -85
- package/src/telemetry/LoggerTelemetryAdapter.test.ts +0 -42
- package/src/types/workspace.ts +0 -7
- /package/dist/{agents → extensions/config}/agent-config-loader.d.ts +0 -0
- /package/dist/{agents → extensions/config}/unified-config-file-watcher.d.ts +0 -0
- /package/dist/{agents → extensions/config}/user-instruction-config-loader.d.ts +0 -0
- /package/dist/{mcp → extensions/mcp}/config-loader.d.ts +0 -0
- /package/dist/runtime/{sandbox/subprocess-sandbox.d.ts → subprocess-sandbox.d.ts} +0 -0
- /package/src/{agents → extensions/config}/agent-config-loader.ts +0 -0
- /package/src/{agents → extensions/config}/hooks-config-loader.test.ts +0 -0
- /package/src/{agents → extensions/config}/unified-config-file-watcher.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.test.ts +0 -0
- /package/src/{mcp → extensions/mcp}/config-loader.ts +0 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import type {
|
|
3
|
+
StartSessionInput,
|
|
4
|
+
StartSessionResult,
|
|
5
|
+
} from "./session/session-manager";
|
|
6
|
+
|
|
7
|
+
const { createSessionHostMock } = vi.hoisted(() => ({
|
|
8
|
+
createSessionHostMock: vi.fn(),
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("./session/session-host", () => ({
|
|
12
|
+
createSessionHost: createSessionHostMock,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
import { ClineCore } from "./ClineCore";
|
|
16
|
+
|
|
17
|
+
function createStartInput(): StartSessionInput {
|
|
18
|
+
return {
|
|
19
|
+
config: {
|
|
20
|
+
providerId: "anthropic",
|
|
21
|
+
modelId: "claude-sonnet-4-6",
|
|
22
|
+
apiKey: "test",
|
|
23
|
+
cwd: "/tmp/workspace",
|
|
24
|
+
workspaceRoot: "/tmp/workspace",
|
|
25
|
+
systemPrompt: "You are concise.",
|
|
26
|
+
enableTools: true,
|
|
27
|
+
enableSpawnAgent: false,
|
|
28
|
+
enableAgentTeams: false,
|
|
29
|
+
},
|
|
30
|
+
prompt: "hello",
|
|
31
|
+
interactive: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createStartResult(sessionId: string): StartSessionResult {
|
|
36
|
+
return {
|
|
37
|
+
sessionId,
|
|
38
|
+
manifest: {} as StartSessionResult["manifest"],
|
|
39
|
+
manifestPath: `/tmp/${sessionId}.json`,
|
|
40
|
+
transcriptPath: `/tmp/${sessionId}.log`,
|
|
41
|
+
hookPath: `/tmp/${sessionId}.hooks.jsonl`,
|
|
42
|
+
messagesPath: `/tmp/${sessionId}.messages.json`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
describe("ClineCore", () => {
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
createSessionHostMock.mockReset();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("applies start-session bootstraps before delegating to the host", async () => {
|
|
52
|
+
const listeners: Array<
|
|
53
|
+
(event: { type: string; payload: { sessionId: string } }) => void
|
|
54
|
+
> = [];
|
|
55
|
+
const host = {
|
|
56
|
+
start: vi.fn(async (input: StartSessionInput) => {
|
|
57
|
+
expect(input.config.systemPrompt).toBe("Bootstrapped prompt");
|
|
58
|
+
expect(input.config.extensions).toEqual([{ name: "enterprise" }]);
|
|
59
|
+
return createStartResult("session-1");
|
|
60
|
+
}),
|
|
61
|
+
send: vi.fn(),
|
|
62
|
+
getAccumulatedUsage: vi.fn(),
|
|
63
|
+
abort: vi.fn(),
|
|
64
|
+
stop: vi.fn(),
|
|
65
|
+
dispose: vi.fn(),
|
|
66
|
+
get: vi.fn(async () => undefined),
|
|
67
|
+
list: vi.fn(),
|
|
68
|
+
delete: vi.fn(),
|
|
69
|
+
readMessages: vi.fn(),
|
|
70
|
+
readTranscript: vi.fn(),
|
|
71
|
+
readHooks: vi.fn(),
|
|
72
|
+
subscribe: vi.fn((listener) => {
|
|
73
|
+
listeners.push(listener);
|
|
74
|
+
return () => {};
|
|
75
|
+
}),
|
|
76
|
+
updateSessionModel: vi.fn(),
|
|
77
|
+
};
|
|
78
|
+
createSessionHostMock.mockResolvedValue(host);
|
|
79
|
+
|
|
80
|
+
const dispose = vi.fn(async () => {});
|
|
81
|
+
const applyToStartSessionInput = vi.fn(
|
|
82
|
+
async (input: StartSessionInput) => ({
|
|
83
|
+
...input,
|
|
84
|
+
config: {
|
|
85
|
+
...input.config,
|
|
86
|
+
systemPrompt: "Bootstrapped prompt",
|
|
87
|
+
extensions: [
|
|
88
|
+
{ name: "enterprise" },
|
|
89
|
+
] as StartSessionInput["config"]["extensions"],
|
|
90
|
+
},
|
|
91
|
+
}),
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const core = await ClineCore.create({
|
|
95
|
+
prepare: async () => ({
|
|
96
|
+
applyToStartSessionInput,
|
|
97
|
+
dispose,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await core.start(createStartInput());
|
|
102
|
+
|
|
103
|
+
expect(applyToStartSessionInput).toHaveBeenCalledTimes(1);
|
|
104
|
+
expect(host.start).toHaveBeenCalledTimes(1);
|
|
105
|
+
expect(dispose).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(listeners).toHaveLength(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("disposes active session bootstraps when the session ends", async () => {
|
|
110
|
+
let listener:
|
|
111
|
+
| ((event: { type: string; payload: { sessionId: string } }) => void)
|
|
112
|
+
| undefined;
|
|
113
|
+
const host = {
|
|
114
|
+
start: vi.fn(async () => createStartResult("session-2")),
|
|
115
|
+
send: vi.fn(),
|
|
116
|
+
getAccumulatedUsage: vi.fn(),
|
|
117
|
+
abort: vi.fn(),
|
|
118
|
+
stop: vi.fn(),
|
|
119
|
+
dispose: vi.fn(),
|
|
120
|
+
get: vi.fn(async () => ({ sessionId: "session-2" })),
|
|
121
|
+
list: vi.fn(),
|
|
122
|
+
delete: vi.fn(),
|
|
123
|
+
readMessages: vi.fn(),
|
|
124
|
+
readTranscript: vi.fn(),
|
|
125
|
+
readHooks: vi.fn(),
|
|
126
|
+
subscribe: vi.fn((nextListener) => {
|
|
127
|
+
listener = nextListener;
|
|
128
|
+
return () => {};
|
|
129
|
+
}),
|
|
130
|
+
updateSessionModel: vi.fn(),
|
|
131
|
+
};
|
|
132
|
+
createSessionHostMock.mockResolvedValue(host);
|
|
133
|
+
|
|
134
|
+
const dispose = vi.fn(async () => {});
|
|
135
|
+
const core = await ClineCore.create({
|
|
136
|
+
prepare: async () => ({
|
|
137
|
+
applyToStartSessionInput: (input) => input,
|
|
138
|
+
dispose,
|
|
139
|
+
}),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await core.start(createStartInput());
|
|
143
|
+
expect(dispose).not.toHaveBeenCalled();
|
|
144
|
+
|
|
145
|
+
listener?.({ type: "ended", payload: { sessionId: "session-2" } });
|
|
146
|
+
await Promise.resolve();
|
|
147
|
+
|
|
148
|
+
expect(dispose).toHaveBeenCalledTimes(1);
|
|
149
|
+
});
|
|
150
|
+
});
|
package/src/ClineCore.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentConfig,
|
|
3
|
+
ITelemetryService,
|
|
3
4
|
ToolApprovalRequest,
|
|
4
5
|
ToolApprovalResult,
|
|
5
|
-
} from "@clinebot/
|
|
6
|
-
import type {
|
|
6
|
+
} from "@clinebot/shared";
|
|
7
|
+
import type { TeamToolsFactory } from "./runtime/session-runtime";
|
|
7
8
|
import {
|
|
8
9
|
createSessionHost,
|
|
9
10
|
type SessionBackend,
|
|
10
11
|
type SessionHost,
|
|
11
12
|
} from "./session/session-host";
|
|
13
|
+
import type { StartSessionInput } from "./session/session-manager";
|
|
12
14
|
import type { ToolExecutors } from "./tools";
|
|
13
15
|
|
|
14
16
|
/** Advanced options for connecting to or spawning the Cline RPC server. */
|
|
@@ -87,6 +89,34 @@ export interface ClineCoreOptions {
|
|
|
87
89
|
* @internal
|
|
88
90
|
*/
|
|
89
91
|
sessionService?: SessionBackend;
|
|
92
|
+
/**
|
|
93
|
+
* Factory that creates team management tools for the multi-agent team system.
|
|
94
|
+
* When provided, team tools are registered whenever `enableAgentTeams` is `true`
|
|
95
|
+
* on a session config.
|
|
96
|
+
*
|
|
97
|
+
* Consumers that depend on `@clinebot/enterprise` can pass
|
|
98
|
+
* `bootstrapAgentTeams` here directly.
|
|
99
|
+
*/
|
|
100
|
+
teamToolsFactory?: TeamToolsFactory;
|
|
101
|
+
/**
|
|
102
|
+
* Optional hook invoked before each session starts.
|
|
103
|
+
* Use this to prepare workspace-scoped runtime state and then return an
|
|
104
|
+
* adapter that mutates the `StartSessionInput` generically before core
|
|
105
|
+
* builds the runtime.
|
|
106
|
+
*/
|
|
107
|
+
prepare?: (
|
|
108
|
+
input: StartSessionInput,
|
|
109
|
+
) =>
|
|
110
|
+
| Promise<StartSessionBootstrap | undefined>
|
|
111
|
+
| StartSessionBootstrap
|
|
112
|
+
| undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface StartSessionBootstrap {
|
|
116
|
+
applyToStartSessionInput(
|
|
117
|
+
input: StartSessionInput,
|
|
118
|
+
): Promise<StartSessionInput> | StartSessionInput;
|
|
119
|
+
dispose?(): Promise<void> | void;
|
|
90
120
|
}
|
|
91
121
|
|
|
92
122
|
/**
|
|
@@ -103,27 +133,103 @@ export interface ClineCoreOptions {
|
|
|
103
133
|
export class ClineCore implements SessionHost {
|
|
104
134
|
readonly clientName: string | undefined;
|
|
105
135
|
private readonly host: SessionHost;
|
|
136
|
+
private readonly prepare: ClineCoreOptions["prepare"] | undefined;
|
|
137
|
+
private readonly teamToolsFactory: TeamToolsFactory | undefined;
|
|
138
|
+
private readonly activeSessionBootstraps = new Map<
|
|
139
|
+
string,
|
|
140
|
+
StartSessionBootstrap
|
|
141
|
+
>();
|
|
142
|
+
private readonly unsubscribeBootstrapCleanup: () => void;
|
|
106
143
|
|
|
107
|
-
private constructor(
|
|
144
|
+
private constructor(
|
|
145
|
+
host: SessionHost,
|
|
146
|
+
clientName: string | undefined,
|
|
147
|
+
prepare: ClineCoreOptions["prepare"],
|
|
148
|
+
teamToolsFactory: TeamToolsFactory | undefined,
|
|
149
|
+
) {
|
|
108
150
|
this.clientName = clientName;
|
|
109
151
|
this.host = host;
|
|
152
|
+
this.prepare = prepare;
|
|
153
|
+
this.teamToolsFactory = teamToolsFactory;
|
|
154
|
+
this.unsubscribeBootstrapCleanup = this.host.subscribe((event) => {
|
|
155
|
+
if (event.type !== "ended") {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
void this.disposeSessionBootstrap(event.payload.sessionId);
|
|
159
|
+
});
|
|
110
160
|
}
|
|
111
161
|
|
|
112
162
|
static async create(options: ClineCoreOptions = {}): Promise<ClineCore> {
|
|
113
163
|
const host = await createSessionHost(options);
|
|
114
|
-
return new ClineCore(
|
|
164
|
+
return new ClineCore(
|
|
165
|
+
host,
|
|
166
|
+
options.clientName,
|
|
167
|
+
options.prepare,
|
|
168
|
+
options.teamToolsFactory,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private async disposeSessionBootstrap(sessionId: string): Promise<void> {
|
|
173
|
+
const bootstrap = this.activeSessionBootstraps.get(sessionId);
|
|
174
|
+
if (!bootstrap) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.activeSessionBootstraps.delete(sessionId);
|
|
178
|
+
await Promise.resolve(bootstrap.dispose?.());
|
|
115
179
|
}
|
|
116
180
|
|
|
117
|
-
start: SessionHost["start"] = (
|
|
181
|
+
start: SessionHost["start"] = async (input) => {
|
|
182
|
+
const inputWithFactory: StartSessionInput = this.teamToolsFactory
|
|
183
|
+
? { teamToolsFactory: this.teamToolsFactory, ...input }
|
|
184
|
+
: input;
|
|
185
|
+
const bootstrap = await this.prepare?.(inputWithFactory);
|
|
186
|
+
try {
|
|
187
|
+
const effectiveInput = bootstrap
|
|
188
|
+
? await bootstrap.applyToStartSessionInput(inputWithFactory)
|
|
189
|
+
: inputWithFactory;
|
|
190
|
+
const result = await this.host.start(effectiveInput);
|
|
191
|
+
if (bootstrap) {
|
|
192
|
+
const activeSession = await this.host.get(result.sessionId);
|
|
193
|
+
if (activeSession) {
|
|
194
|
+
this.activeSessionBootstraps.set(result.sessionId, bootstrap);
|
|
195
|
+
} else {
|
|
196
|
+
await Promise.resolve(bootstrap.dispose?.());
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
await Promise.resolve(bootstrap?.dispose?.());
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
118
205
|
send: SessionHost["send"] = (...args) => this.host.send(...args);
|
|
119
206
|
getAccumulatedUsage: SessionHost["getAccumulatedUsage"] = (...args) =>
|
|
120
207
|
this.host.getAccumulatedUsage(...args);
|
|
121
208
|
abort: SessionHost["abort"] = (...args) => this.host.abort(...args);
|
|
122
|
-
stop: SessionHost["stop"] = (
|
|
123
|
-
|
|
209
|
+
stop: SessionHost["stop"] = async (sessionId) => {
|
|
210
|
+
await this.host.stop(sessionId);
|
|
211
|
+
await this.disposeSessionBootstrap(sessionId);
|
|
212
|
+
};
|
|
213
|
+
dispose: SessionHost["dispose"] = async (...args) => {
|
|
214
|
+
try {
|
|
215
|
+
await this.host.dispose(...args);
|
|
216
|
+
} finally {
|
|
217
|
+
this.unsubscribeBootstrapCleanup();
|
|
218
|
+
const sessionIds = [...this.activeSessionBootstraps.keys()];
|
|
219
|
+
await Promise.allSettled(
|
|
220
|
+
sessionIds.map((sessionId) => this.disposeSessionBootstrap(sessionId)),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
124
224
|
get: SessionHost["get"] = (...args) => this.host.get(...args);
|
|
125
225
|
list: SessionHost["list"] = (...args) => this.host.list(...args);
|
|
126
|
-
delete: SessionHost["delete"] = (
|
|
226
|
+
delete: SessionHost["delete"] = async (sessionId) => {
|
|
227
|
+
const deleted = await this.host.delete(sessionId);
|
|
228
|
+
if (deleted) {
|
|
229
|
+
await this.disposeSessionBootstrap(sessionId);
|
|
230
|
+
}
|
|
231
|
+
return deleted;
|
|
232
|
+
};
|
|
127
233
|
readMessages: SessionHost["readMessages"] = (...args) =>
|
|
128
234
|
this.host.readMessages(...args);
|
|
129
235
|
readTranscript: SessionHost["readTranscript"] = (...args) =>
|
|
@@ -82,6 +82,90 @@ describe("ClineAccountService", () => {
|
|
|
82
82
|
expect(transactions).toEqual([{ id: "tx-1" }]);
|
|
83
83
|
});
|
|
84
84
|
|
|
85
|
+
it("fetches remote config with organizations list", async () => {
|
|
86
|
+
const remoteConfigPayload = {
|
|
87
|
+
organizationId: "org-1",
|
|
88
|
+
value: '{"model":"claude-4"}',
|
|
89
|
+
enabled: true,
|
|
90
|
+
organizations: [
|
|
91
|
+
{ organizationId: "org-1", name: "Acme Corp" },
|
|
92
|
+
{ organizationId: "org-2", name: "Beta Inc" },
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const fetchImpl = vi.fn(async (input: unknown) => {
|
|
97
|
+
expect(String(input)).toBe(
|
|
98
|
+
"https://api.cline.bot/api/v1/users/me/remote-config",
|
|
99
|
+
);
|
|
100
|
+
return new Response(
|
|
101
|
+
JSON.stringify({ success: true, data: remoteConfigPayload }),
|
|
102
|
+
{ status: 200, headers: { "Content-Type": "application/json" } },
|
|
103
|
+
);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const service = new ClineAccountService({
|
|
107
|
+
apiBaseUrl: "https://api.cline.bot",
|
|
108
|
+
getAuthToken: async () => "workos:token-123",
|
|
109
|
+
fetchImpl: fetchImpl as unknown as typeof fetch,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const config = await service.fetchRemoteConfig();
|
|
113
|
+
expect(config).toEqual(remoteConfigPayload);
|
|
114
|
+
expect(config?.organizations).toHaveLength(2);
|
|
115
|
+
expect(config?.organizations?.[0]).toEqual({
|
|
116
|
+
organizationId: "org-1",
|
|
117
|
+
name: "Acme Corp",
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("fetches remote config with fallback org selected", async () => {
|
|
122
|
+
const remoteConfigPayload = {
|
|
123
|
+
organizationId: "org-fallback",
|
|
124
|
+
value: '{"model":"claude-4"}',
|
|
125
|
+
enabled: true,
|
|
126
|
+
organizations: [{ organizationId: "org-fallback", name: "Fallback Org" }],
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const fetchImpl = vi.fn(async () => {
|
|
130
|
+
return new Response(
|
|
131
|
+
JSON.stringify({ success: true, data: remoteConfigPayload }),
|
|
132
|
+
{ status: 200, headers: { "Content-Type": "application/json" } },
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const service = new ClineAccountService({
|
|
137
|
+
apiBaseUrl: "https://api.cline.bot",
|
|
138
|
+
getAuthToken: async () => "workos:token-123",
|
|
139
|
+
fetchImpl: fetchImpl as unknown as typeof fetch,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const config = await service.fetchRemoteConfig();
|
|
143
|
+
expect(config?.organizationId).toBe("org-fallback");
|
|
144
|
+
expect(config?.organizations).toHaveLength(1);
|
|
145
|
+
expect(config?.organizations?.[0]).toEqual({
|
|
146
|
+
organizationId: "org-fallback",
|
|
147
|
+
name: "Fallback Org",
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("returns null when no org has remote config (data: null)", async () => {
|
|
152
|
+
const fetchImpl = vi.fn(async () => {
|
|
153
|
+
return new Response(JSON.stringify({ success: true, data: null }), {
|
|
154
|
+
status: 200,
|
|
155
|
+
headers: { "Content-Type": "application/json" },
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const service = new ClineAccountService({
|
|
160
|
+
apiBaseUrl: "https://api.cline.bot",
|
|
161
|
+
getAuthToken: async () => "workos:token-123",
|
|
162
|
+
fetchImpl: fetchImpl as unknown as typeof fetch,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const config = await service.fetchRemoteConfig();
|
|
166
|
+
expect(config).toBeNull();
|
|
167
|
+
});
|
|
168
|
+
|
|
85
169
|
it("switchAccount sends null org id for personal account", async () => {
|
|
86
170
|
const fetchImpl = vi.fn(async (_input: unknown, init?: RequestInit) => {
|
|
87
171
|
expect(init?.method).toBe("PUT");
|
|
@@ -66,8 +66,8 @@ export class ClineAccountService {
|
|
|
66
66
|
return this.request<ClineAccountUser>("/api/v1/users/me");
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
public async fetchRemoteConfig(): Promise<UserRemoteConfigResponse> {
|
|
70
|
-
return this.request<UserRemoteConfigResponse>(
|
|
69
|
+
public async fetchRemoteConfig(): Promise<UserRemoteConfigResponse | null> {
|
|
70
|
+
return this.request<UserRemoteConfigResponse | null>(
|
|
71
71
|
"/api/v1/users/me/remote-config",
|
|
72
72
|
);
|
|
73
73
|
}
|
package/src/account/index.ts
CHANGED
package/src/account/types.ts
CHANGED
|
@@ -16,10 +16,16 @@ export interface ClineAccountUser {
|
|
|
16
16
|
organizations: ClineAccountOrganization[];
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
export interface UserRemoteConfigOrganization {
|
|
20
|
+
organizationId: string;
|
|
21
|
+
name: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
19
24
|
export interface UserRemoteConfigResponse {
|
|
20
25
|
organizationId: string;
|
|
21
26
|
value: string;
|
|
22
27
|
enabled: boolean;
|
|
28
|
+
organizations?: UserRemoteConfigOrganization[];
|
|
23
29
|
}
|
|
24
30
|
|
|
25
31
|
export interface ClineAccountBalance {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { BoundedTtlCache } from "./bounded-ttl-cache";
|
|
3
|
+
|
|
4
|
+
describe("BoundedTtlCache", () => {
|
|
5
|
+
it("returns undefined after TTL", () => {
|
|
6
|
+
const cache = new BoundedTtlCache(1_000, 10);
|
|
7
|
+
cache.set("a", "one", 0);
|
|
8
|
+
expect(cache.get("a", 500)).toBe("one");
|
|
9
|
+
expect(cache.get("a", 1_500)).toBeUndefined();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("evicts oldest entries when over max size", () => {
|
|
13
|
+
const cache = new BoundedTtlCache(60_000, 2);
|
|
14
|
+
cache.set("a", "1", 0);
|
|
15
|
+
cache.set("b", "2", 0);
|
|
16
|
+
cache.set("c", "3", 0);
|
|
17
|
+
expect(cache.get("a", 0)).toBeUndefined();
|
|
18
|
+
expect(cache.get("b", 0)).toBe("2");
|
|
19
|
+
expect(cache.get("c", 0)).toBe("3");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("refreshes recency on get so hot keys survive eviction", () => {
|
|
23
|
+
const cache = new BoundedTtlCache(60_000, 2);
|
|
24
|
+
cache.set("a", "1", 0);
|
|
25
|
+
cache.set("b", "2", 0);
|
|
26
|
+
expect(cache.get("a", 0)).toBe("1");
|
|
27
|
+
cache.set("c", "3", 0);
|
|
28
|
+
expect(cache.get("a", 0)).toBe("1");
|
|
29
|
+
expect(cache.get("b", 0)).toBeUndefined();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("supports per-entry TTL override", () => {
|
|
33
|
+
const cache = new BoundedTtlCache(60_000, 2);
|
|
34
|
+
cache.set("short", "v", 0, 1_000);
|
|
35
|
+
expect(cache.get("short", 500)).toBe("v");
|
|
36
|
+
expect(cache.get("short", 1_500)).toBeUndefined();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small process-local string cache with TTL expiry and a hard entry cap.
|
|
3
|
+
* Used where unbounded Maps would grow without bound in long-running processes.
|
|
4
|
+
*/
|
|
5
|
+
export class BoundedTtlCache {
|
|
6
|
+
private readonly entries = new Map<
|
|
7
|
+
string,
|
|
8
|
+
{ value: string; expiresAt: number }
|
|
9
|
+
>();
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly ttlMs: number,
|
|
13
|
+
private readonly maxEntries: number,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
get(key: string, now = Date.now()): string | undefined {
|
|
17
|
+
this.pruneExpired(now);
|
|
18
|
+
const hit = this.entries.get(key);
|
|
19
|
+
if (!hit) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
// Bump recency for FIFO eviction under cap.
|
|
23
|
+
this.entries.delete(key);
|
|
24
|
+
this.entries.set(key, hit);
|
|
25
|
+
return hit.value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
set(
|
|
29
|
+
key: string,
|
|
30
|
+
value: string,
|
|
31
|
+
now = Date.now(),
|
|
32
|
+
ttlMsOverride = this.ttlMs,
|
|
33
|
+
): void {
|
|
34
|
+
this.pruneExpired(now);
|
|
35
|
+
this.entries.delete(key);
|
|
36
|
+
while (this.entries.size >= this.maxEntries) {
|
|
37
|
+
const first = this.entries.keys().next().value as string | undefined;
|
|
38
|
+
if (first === undefined) {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
this.entries.delete(first);
|
|
42
|
+
}
|
|
43
|
+
this.entries.set(key, { value, expiresAt: now + ttlMsOverride });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private pruneExpired(now: number): void {
|
|
47
|
+
for (const [k, v] of this.entries) {
|
|
48
|
+
if (v.expiresAt <= now) {
|
|
49
|
+
this.entries.delete(k);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|