cartethyia 2.5.2 → 2.5.4
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/dist/dashboard/assets/{BannedPage-MsQaeQTs.js → BannedPage-C2orBsI2.js} +1 -1
- package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +1 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DfWHTJ7v.js → CliToolsPage-BV6pxVQo.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BrCBQDAc.js → CombosPage-Bsan4679.js} +1 -1
- package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-C6Uh33er.js → ConsoleLogPage-CW-wPmJ6.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-8aS9hyJu.js → CustomizationPage-0p8uX7vB.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-C8hKyXBe.js → LoginPage-BvzCx8Kr.js} +1 -1
- package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-CWkTUtpX.js → ModelPicker-BY1aKEkP.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +7 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +1 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CXjUlfqr.js → SetupPage-DDbMQsoo.js} +1 -1
- package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-C-_oD3F2.js → SortableList-CB3Z7VTf.js} +1 -1
- package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-u9IxmYOI.js → StudioPage-D95UCPHI.js} +3 -3
- package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-BEVLVrwP.js → UsagePage-Cnae9SWA.js} +13 -13
- package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-uNywYlfv.js → api-keys-VY68Mhd1.js} +1 -1
- package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
- package/dist/dashboard/assets/app-COlK95oi.css +2 -0
- package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
- package/dist/dashboard/assets/{assert-NHwYq95t.js → assert-Chi7pCnt.js} +1 -1
- package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
- package/dist/dashboard/assets/{badge-6uzDDvqs.js → badge-D4pQapKj.js} +1 -1
- package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
- package/dist/dashboard/assets/{banner-4_WNg2WZ.js → banner-DH6cg-_B.js} +1 -1
- package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
- package/dist/dashboard/assets/{card--AtFedAq.js → card-BKqlUOe4.js} +1 -1
- package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-B3e7dx3N.js → cli-tools-fTgljTGA.js} +1 -1
- package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-NreUx6c8.js → clipboard-button-D5Ys_sM0.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js +1 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BtpsJU98.js → dialog-BYj-8WuK.js} +1 -1
- package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-WwwtzihF.js → drawer-CmXIZ6H1.js} +1 -1
- package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js +1 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js +1 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js +4 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-D_eM3IgG.js → github-badge-BlptL8Uf.js} +1 -1
- package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
- package/dist/dashboard/assets/{index-DCBtROoK.js → index-js6TJvdr.js} +2 -2
- package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BcNGF8Gr.js → inline-DUWDSmDV.js} +1 -1
- package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
- package/dist/dashboard/assets/{input-BG41et9G.js → input-LVjgZq4f.js} +1 -1
- package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C8mer_Ak.js → layout-CPfxpsfy.js} +1 -1
- package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Gh_W4OR_.js → list-row-DupvLfDx.js} +1 -1
- package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
- package/dist/dashboard/assets/{live-BJGYRBnR.js → live-C4pEJUqI.js} +1 -1
- package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js +1 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-BkoLM5Ba.js → mutation-B4ROwk8L.js} +1 -1
- package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js +2 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js → query-keys-gmjzC3RS.js} +1 -1
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js.gz → query-keys-gmjzC3RS.js.gz} +0 -0
- package/dist/dashboard/assets/{routing-CcusqXA7.js → routing-C7tBT5o-.js} +1 -1
- package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
- package/dist/dashboard/assets/{select-DsX5QT8K.js → select-WUCXorXw.js} +2 -2
- package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
- package/dist/dashboard/assets/{settings-mpmXTgUa.js → settings-C_zKl1GS.js} +1 -1
- package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DwLmjUFK.js → stack-_3O0F8Xn.js} +1 -1
- package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
- package/dist/dashboard/assets/{state-DYdQmdAl.js → state-BgTxHcJS.js} +1 -1
- package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js +1 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js +1 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-w4u4CVue.js → useMutation-BWSC0UAS.js} +1 -1
- package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js +1 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js.gz +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -54
- package/package.json +1 -1
- package/scripts/cli/autostart.ts +237 -0
- package/scripts/cli/command/console-menu.ts +244 -246
- package/scripts/cli/command/tray.ts +208 -204
- package/scripts/cli/command/update.ts +27 -10
- package/scripts/cli/main.ts +28 -1
- package/src/boot/app.ts +693 -693
- package/src/boot/dependencies.ts +646 -616
- package/src/config/spec.ts +81 -2
- package/src/config/telemetry.ts +46 -0
- package/src/console/api-keys/bucket-spend.ts +15 -4
- package/src/console/backup/contracts.ts +15 -2
- package/src/console/backup/routes.ts +52 -1
- package/src/console/backup/service.ts +60 -4
- package/src/console/console-router.ts +8 -0
- package/src/console/data-management/contracts.ts +93 -0
- package/src/console/data-management/operations.ts +229 -0
- package/src/console/data-management/routes.ts +104 -0
- package/src/console/domain-registration.ts +39 -0
- package/src/console/observability/contracts.ts +524 -485
- package/src/console/observability/store.ts +1115 -1018
- package/src/console/providers/catalog/contracts.ts +6 -0
- package/src/console/providers/catalog/provider-operations.ts +20 -0
- package/src/console/providers/catalog/routes.ts +7 -0
- package/src/console/providers/catalog/store.ts +22 -1
- package/src/console/quota/account-quota-shared.ts +52 -39
- package/src/console/quota/refresh.ts +441 -429
- package/src/console/routing/pools/import-parse.ts +206 -0
- package/src/console/routing/pools/operations.ts +543 -501
- package/src/console/routing/pools/routes.ts +181 -164
- package/src/console/settings/contracts.ts +37 -0
- package/src/console/settings/store.ts +51 -0
- package/src/console/share/share-router.ts +6 -9
- package/src/console/updates/routes.ts +16 -0
- package/src/main.ts +10 -0
- package/src/observability/event-compaction.ts +315 -0
- package/src/observability/event-day-index.ts +442 -0
- package/src/observability/event-log.ts +152 -3
- package/src/observability/payload-capture.ts +373 -344
- package/src/observability/payload-store.ts +440 -366
- package/src/observability/telemetry-status.ts +28 -16
- package/src/persistence/health-event-flush.ts +36 -0
- package/src/persistence/schema.ts +1402 -1360
- package/src/persistence/stores/api-key-store.ts +6 -0
- package/src/persistence/stores/share-store.ts +583 -556
- package/src/persistence/stores/telemetry-store.ts +237 -214
- package/src/protocol/codecs.ts +1 -2
- package/src/protocol/image-clamp.ts +19 -1
- package/src/protocol/registry.ts +8 -0
- package/src/protocol/request/gemini.ts +9 -2
- package/src/protocol/request/messages.ts +14 -2
- package/src/protocol/response/gemini.ts +18 -4
- package/src/providers/adapters/compatible-adapter.ts +3 -0
- package/src/providers/bundled-discovery-providers.ts +122 -119
- package/src/providers/configured-openai-providers.ts +136 -134
- package/src/providers/default-registry.ts +5 -4
- package/src/providers/discovery/openai-model-discovery.ts +5 -0
- package/src/providers/discovery/openrouter-free-roster.ts +15 -17
- package/src/providers/integrations/antigravity/antigravity-quota.ts +11 -3
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +4 -4
- package/src/providers/integrations/buddy/workbuddy/shared.ts +201 -200
- package/src/providers/integrations/cline/cline-quota.ts +132 -128
- package/src/providers/integrations/codex/codex-headers.ts +25 -39
- package/src/providers/integrations/codex/codex.ts +2 -29
- package/src/providers/integrations/cursor/cursor-quota.ts +310 -0
- package/src/providers/integrations/cursor/cursor-request.ts +616 -471
- package/src/providers/integrations/cursor/cursor-session-manager.ts +319 -281
- package/src/providers/integrations/cursor/cursor.ts +1485 -960
- package/src/providers/integrations/cursor/protocol/messages.ts +25 -0
- package/src/providers/integrations/factory/factory.ts +8 -1
- package/src/providers/integrations/gemini.ts +6 -1
- package/src/providers/integrations/grok/grok-quota.ts +279 -177
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -0
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -0
- package/src/providers/integrations/opencode/provider.ts +531 -532
- package/src/providers/integrations/qoder/qoder-quota.ts +192 -0
- package/src/providers/integrations/tokenharbor.ts +2 -2
- package/src/providers/integrations/trae/trae-catalog.ts +5 -3
- package/src/providers/integrations/trae/trae-quota.ts +384 -0
- package/src/providers/operations/account-health-service.ts +1523 -1457
- package/src/providers/operations/client-versions.ts +9 -2
- package/src/providers/provider-contracts.ts +7 -0
- package/src/providers/provider-metadata.ts +13 -1
- package/src/providers/quota/quota-support.ts +8 -0
- package/src/security/api-key-auth.ts +504 -494
- package/src/transport/dispatch/attempt-finalize.ts +46 -5
- package/src/transport/dispatch/generation.ts +6 -0
- package/src/transport/dispatch/proxy-request.ts +33 -1
- package/src/transport/dispatch/ratelimit-capture.ts +37 -0
- package/src/transport/dispatch/streaming/stream.ts +30 -2
- package/src/transport/dispatch/upstream.ts +9 -0
- package/src/transport/request/preparer.ts +7 -6
- package/src/transport/request/state.ts +9 -0
- package/src/transport/request/tenant-preferences.ts +60 -0
- package/src/transport/routing/route-catalog.ts +854 -799
- package/dist/dashboard/assets/BannedPage-MsQaeQTs.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DfWHTJ7v.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BrCBQDAc.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-C6Uh33er.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-8aS9hyJu.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-C8hKyXBe.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js +0 -1
- package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js +0 -7
- package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BihkgQSq.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BihkgQSq.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js +0 -1
- package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CXjUlfqr.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-C-_oD3F2.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-u9IxmYOI.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BEVLVrwP.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-uNywYlfv.js.gz +0 -0
- package/dist/dashboard/assets/app-DxivpfYG.css +0 -2
- package/dist/dashboard/assets/app-DxivpfYG.css.gz +0 -0
- package/dist/dashboard/assets/assert-NHwYq95t.js.gz +0 -0
- package/dist/dashboard/assets/badge-6uzDDvqs.js.gz +0 -0
- package/dist/dashboard/assets/banner-4_WNg2WZ.js.gz +0 -0
- package/dist/dashboard/assets/card--AtFedAq.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-B3e7dx3N.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-NreUx6c8.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BtpsJU98.js.gz +0 -0
- package/dist/dashboard/assets/download-A0SW9OCW.js +0 -1
- package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-WwwtzihF.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dj9AR0gY.js +0 -4
- package/dist/dashboard/assets/entry-Dj9AR0gY.js.gz +0 -0
- package/dist/dashboard/assets/entry-TJIye_jT.js +0 -1
- package/dist/dashboard/assets/entry-TJIye_jT.js.gz +0 -0
- package/dist/dashboard/assets/entry-jy9_4-Ke.js +0 -1
- package/dist/dashboard/assets/entry-jy9_4-Ke.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-D_eM3IgG.js.gz +0 -0
- package/dist/dashboard/assets/index-DCBtROoK.js.gz +0 -0
- package/dist/dashboard/assets/inline-BcNGF8Gr.js.gz +0 -0
- package/dist/dashboard/assets/input-BG41et9G.js.gz +0 -0
- package/dist/dashboard/assets/layout-C8mer_Ak.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Gh_W4OR_.js.gz +0 -0
- package/dist/dashboard/assets/live-BJGYRBnR.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js +0 -1
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js.gz +0 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js +0 -2
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js.gz +0 -0
- package/dist/dashboard/assets/routing-CcusqXA7.js.gz +0 -0
- package/dist/dashboard/assets/select-DsX5QT8K.js.gz +0 -0
- package/dist/dashboard/assets/settings-mpmXTgUa.js.gz +0 -0
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js +0 -1
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
- package/dist/dashboard/assets/stack-DwLmjUFK.js.gz +0 -0
- package/dist/dashboard/assets/state-DYdQmdAl.js.gz +0 -0
- package/dist/dashboard/assets/switch-CidSfbG7.js +0 -1
- package/dist/dashboard/assets/switch-CidSfbG7.js.gz +0 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js +0 -1
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-w4u4CVue.js.gz +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js → app-DCQZRmHY.js} +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js.gz → app-DCQZRmHY.js.gz} +0 -0
|
@@ -1,281 +1,319 @@
|
|
|
1
|
-
// Live Cursor Run sessions, and the tool-call continuation they make possible.
|
|
2
|
-
//
|
|
3
|
-
// Cursor's tool loop spans *two* client HTTP requests: the first returns a tool
|
|
4
|
-
// call, the second submits that tool's result. The upstream Run must be the same
|
|
5
|
-
// Run, and it must stay open between them, so the Run cannot be owned by either
|
|
6
|
-
// request — it is owned here.
|
|
7
|
-
//
|
|
8
|
-
// This manager is process-local by construction. A Run is an HTTP/2 socket; it
|
|
9
|
-
// cannot survive a restart, and it is not shared across processes. After a
|
|
10
|
-
// restart the adapter rebases from the complete request history instead (see
|
|
11
|
-
// `cursor.ts`), which is why an orphan tool result with no history fails
|
|
12
|
-
// explicitly rather than silently starting a new Run.
|
|
13
|
-
//
|
|
14
|
-
// Everything the manager holds is bounded: one idle TTL, one release per
|
|
15
|
-
// session, one frame pump per Run, and one terminal path that closes the stream
|
|
16
|
-
// and releases the borrowed lease exactly once.
|
|
17
|
-
import { GatewayError } from "../../../protocol/gateway-error";
|
|
18
|
-
import type { UsageRecord } from "../../../protocol/canonical-model";
|
|
19
|
-
import type { AttemptLeaseOwnership } from "../../provider-contracts";
|
|
20
|
-
import { RUN_IDLE_TTL_MS } from "./cursor-shared";
|
|
21
|
-
import type { CursorToolDescriptor } from "./cursor-request";
|
|
22
|
-
|
|
23
|
-
/** Identity a later request must present to claim a pending tool call. */
|
|
24
|
-
export interface CursorContinuationScope {
|
|
25
|
-
readonly tenantId: string;
|
|
26
|
-
readonly apiKeyId: string;
|
|
27
|
-
readonly providerId: string;
|
|
28
|
-
readonly providerAccountId: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
readonly
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
readonly
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
entry.
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const
|
|
200
|
-
if (
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
1
|
+
// Live Cursor Run sessions, and the tool-call continuation they make possible.
|
|
2
|
+
//
|
|
3
|
+
// Cursor's tool loop spans *two* client HTTP requests: the first returns a tool
|
|
4
|
+
// call, the second submits that tool's result. The upstream Run must be the same
|
|
5
|
+
// Run, and it must stay open between them, so the Run cannot be owned by either
|
|
6
|
+
// request — it is owned here.
|
|
7
|
+
//
|
|
8
|
+
// This manager is process-local by construction. A Run is an HTTP/2 socket; it
|
|
9
|
+
// cannot survive a restart, and it is not shared across processes. After a
|
|
10
|
+
// restart the adapter rebases from the complete request history instead (see
|
|
11
|
+
// `cursor.ts`), which is why an orphan tool result with no history fails
|
|
12
|
+
// explicitly rather than silently starting a new Run.
|
|
13
|
+
//
|
|
14
|
+
// Everything the manager holds is bounded: one idle TTL, one release per
|
|
15
|
+
// session, one frame pump per Run, and one terminal path that closes the stream
|
|
16
|
+
// and releases the borrowed lease exactly once.
|
|
17
|
+
import { GatewayError } from "../../../protocol/gateway-error";
|
|
18
|
+
import type { UsageRecord } from "../../../protocol/canonical-model";
|
|
19
|
+
import type { AttemptLeaseOwnership } from "../../provider-contracts";
|
|
20
|
+
import { RUN_IDLE_TTL_MS } from "./cursor-shared";
|
|
21
|
+
import type { CursorToolDescriptor } from "./cursor-request";
|
|
22
|
+
|
|
23
|
+
/** Identity a later request must present to claim a pending tool call. */
|
|
24
|
+
export interface CursorContinuationScope {
|
|
25
|
+
readonly tenantId: string;
|
|
26
|
+
readonly apiKeyId: string;
|
|
27
|
+
readonly providerId: string;
|
|
28
|
+
readonly providerAccountId: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The host exec frame a pending call forwards: Cursor asked its executor for a
|
|
33
|
+
* native host tool (shell, write, read) and the canonical client is executing
|
|
34
|
+
* it locally, so the result leg must answer the variant's typed result frame —
|
|
35
|
+
* not the generic `mcp_result` the MCP channel waits on.
|
|
36
|
+
*/
|
|
37
|
+
export interface CursorHostExecDetail {
|
|
38
|
+
readonly variant: "shell" | "write" | "read";
|
|
39
|
+
/** The shell command Cursor's executor re-reports in the result echo. */
|
|
40
|
+
readonly command?: string;
|
|
41
|
+
/** The shell working directory echo, when the args carried one. */
|
|
42
|
+
readonly workingDirectory?: string;
|
|
43
|
+
/** The target path echo for write/read frames. */
|
|
44
|
+
readonly path?: string;
|
|
45
|
+
/** Line count of the written content, computed from the call's args. */
|
|
46
|
+
readonly lines?: number;
|
|
47
|
+
/** Byte size of the written content, computed from the call's args. */
|
|
48
|
+
readonly fileSize?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** One pending external tool call awaiting the client's result. */
|
|
52
|
+
export interface CursorPendingToolCall {
|
|
53
|
+
/** Unguessable call id handed to the client. */
|
|
54
|
+
readonly callId: string;
|
|
55
|
+
/** Cursor's exec message id the result must echo. */
|
|
56
|
+
readonly execId: number;
|
|
57
|
+
/**
|
|
58
|
+
* Cursor's exec UUID for the frame, when the build carries one.
|
|
59
|
+
* Newer edges pair exec replies on it as well as the numeric id.
|
|
60
|
+
*/
|
|
61
|
+
readonly execIdString?: string;
|
|
62
|
+
/** Bare function name the client declared. */
|
|
63
|
+
readonly toolName: string;
|
|
64
|
+
/** The forwarded host exec, when this call is one. */
|
|
65
|
+
readonly host?: CursorHostExecDetail;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Everything one live Run session owns. */
|
|
69
|
+
export interface CursorRunSession {
|
|
70
|
+
readonly runId: string;
|
|
71
|
+
readonly conversationId: string;
|
|
72
|
+
readonly scope: CursorContinuationScope;
|
|
73
|
+
/** Declared tools for this Run; an inbound call outside them is refused. */
|
|
74
|
+
readonly descriptors: readonly CursorToolDescriptor[];
|
|
75
|
+
/** Cursor exec id → pending call id. */
|
|
76
|
+
readonly pending: Map<number, string>;
|
|
77
|
+
/** Pending call id → Cursor exec id and name. */
|
|
78
|
+
readonly calls: Map<string, CursorPendingToolCall>;
|
|
79
|
+
/** Usage reported by the Run's `turn_ended`, when it has arrived. */
|
|
80
|
+
usage: UsageRecord | undefined;
|
|
81
|
+
/** Terminal reason this Run ended, once it has. */
|
|
82
|
+
failure: GatewayError | undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Registry entry: one live Run, its expiry, and its borrowed lease release. */
|
|
86
|
+
interface LiveRun {
|
|
87
|
+
readonly session: CursorRunSession;
|
|
88
|
+
/**
|
|
89
|
+
* The borrowed account/network-pool lease release. Optional and mutable: a
|
|
90
|
+
* continuation request that re-enters an already-registered Run hands over the
|
|
91
|
+
* lease it took, and `adoptLease` refuses when one is already stored — so the
|
|
92
|
+
* slot is released exactly once however many requests touched the Run.
|
|
93
|
+
*/
|
|
94
|
+
releaseLease?: (() => void) | undefined;
|
|
95
|
+
readonly close: (reason?: string) => void;
|
|
96
|
+
expiryTimer: ReturnType<typeof setTimeout>;
|
|
97
|
+
expiresAt: number;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Bounded, tenant/API-key-scoped registry of live Cursor Runs.
|
|
102
|
+
*
|
|
103
|
+
* A continuation is authorized by *server-recorded* affinity only: a call id is
|
|
104
|
+
* unguessable, and resolving one additionally requires the same tenant, API key,
|
|
105
|
+
* provider, and account that created it. A caller that guesses or replays a call
|
|
106
|
+
* id from another key resolves nothing, so one tenant's tool result can never be
|
|
107
|
+
* written onto another tenant's Run.
|
|
108
|
+
*/
|
|
109
|
+
export class CursorRunSessionManager {
|
|
110
|
+
/** runId → live Run. */
|
|
111
|
+
private readonly runs = new Map<string, LiveRun>();
|
|
112
|
+
/** Pending call id → runId. Second index: resolution is by call id. */
|
|
113
|
+
private readonly callOwners = new Map<string, string>();
|
|
114
|
+
|
|
115
|
+
/** Live Run count, for tests and runtime assertions. */
|
|
116
|
+
get size(): number {
|
|
117
|
+
return this.runs.size;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Registers one live Run.
|
|
122
|
+
*
|
|
123
|
+
* `releaseLease` is the borrowed account/network-pool lease the manager now
|
|
124
|
+
* owns: the request that opened the Run transferred it instead of releasing it
|
|
125
|
+
* at response time. It is called exactly once, on the Run's single terminal
|
|
126
|
+
* path.
|
|
127
|
+
*/
|
|
128
|
+
register(input: {
|
|
129
|
+
readonly session: CursorRunSession;
|
|
130
|
+
readonly releaseLease?: (() => void) | undefined;
|
|
131
|
+
readonly close: (reason?: string) => void;
|
|
132
|
+
readonly idleTtlMs?: number;
|
|
133
|
+
}): void {
|
|
134
|
+
const idleTtlMs = input.idleTtlMs ?? RUN_IDLE_TTL_MS;
|
|
135
|
+
const runId = input.session.runId;
|
|
136
|
+
const entry: LiveRun = {
|
|
137
|
+
session: input.session,
|
|
138
|
+
...(input.releaseLease === undefined ? {} : { releaseLease: input.releaseLease }),
|
|
139
|
+
close: input.close,
|
|
140
|
+
expiresAt: Date.now() + idleTtlMs,
|
|
141
|
+
expiryTimer: setTimeout(() => {
|
|
142
|
+
this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
|
|
143
|
+
}, idleTtlMs),
|
|
144
|
+
};
|
|
145
|
+
entry.expiryTimer.unref?.();
|
|
146
|
+
this.runs.set(runId, entry);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Ends one Run: closes its stream and releases what it borrowed, once. */
|
|
150
|
+
terminate(runId: string, reason?: string): void {
|
|
151
|
+
const entry = this.runs.get(runId);
|
|
152
|
+
if (entry === undefined) return;
|
|
153
|
+
this.runs.delete(runId);
|
|
154
|
+
for (const callId of entry.session.pending.values()) {
|
|
155
|
+
if (this.callOwners.get(callId) === runId) this.callOwners.delete(callId);
|
|
156
|
+
}
|
|
157
|
+
for (const call of entry.session.calls.values()) {
|
|
158
|
+
if (this.callOwners.get(call.callId) === runId) this.callOwners.delete(call.callId);
|
|
159
|
+
}
|
|
160
|
+
clearTimeout(entry.expiryTimer);
|
|
161
|
+
try {
|
|
162
|
+
entry.close(reason);
|
|
163
|
+
} catch {
|
|
164
|
+
// Closing a dead stream must not skip the lease release below.
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
entry.releaseLease?.();
|
|
168
|
+
} catch {
|
|
169
|
+
// A failed release must not propagate out of teardown.
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Registers one pending external tool call on a live Run. */
|
|
174
|
+
registerPendingCall(runId: string, call: CursorPendingToolCall): boolean {
|
|
175
|
+
const entry = this.runs.get(runId);
|
|
176
|
+
if (entry === undefined) return false;
|
|
177
|
+
entry.session.pending.set(call.execId, call.callId);
|
|
178
|
+
entry.session.calls.set(call.callId, call);
|
|
179
|
+
this.callOwners.set(call.callId, runId);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Resolves one pending call id to its live Run, scoped to the caller.
|
|
185
|
+
*
|
|
186
|
+
* Returns the Run only when the id is pending *and* every scope field matches
|
|
187
|
+
* the Run that created it. A mismatch is a hard refusal, not a fallback:
|
|
188
|
+
* routing one account's tool result onto another account's Run would corrupt
|
|
189
|
+
* both conversations and leak the first account's context into the second.
|
|
190
|
+
*/
|
|
191
|
+
resolveCall(
|
|
192
|
+
callId: string,
|
|
193
|
+
scope: CursorContinuationScope,
|
|
194
|
+
): { session: CursorRunSession; call: CursorPendingToolCall } | undefined {
|
|
195
|
+
const runId = this.callOwners.get(callId);
|
|
196
|
+
if (runId === undefined) return undefined;
|
|
197
|
+
const entry = this.runs.get(runId);
|
|
198
|
+
if (entry === undefined) return undefined;
|
|
199
|
+
const { session } = entry;
|
|
200
|
+
if (
|
|
201
|
+
session.scope.tenantId !== scope.tenantId ||
|
|
202
|
+
session.scope.apiKeyId !== scope.apiKeyId ||
|
|
203
|
+
session.scope.providerId !== scope.providerId ||
|
|
204
|
+
session.scope.providerAccountId !== scope.providerAccountId
|
|
205
|
+
) {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
const call = session.calls.get(callId);
|
|
209
|
+
if (call === undefined) return undefined;
|
|
210
|
+
return { session, call };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Whether the call id is held by a live Run in this process, under any
|
|
215
|
+
* scope. A foreign caller carrying a live call id must stay refused; the
|
|
216
|
+
* scopeless check distinguishes that case from a post-restart replay whose
|
|
217
|
+
* call exists nowhere anymore.
|
|
218
|
+
*/
|
|
219
|
+
hasAnyCall(callId: string): boolean {
|
|
220
|
+
const runId = this.callOwners.get(callId);
|
|
221
|
+
return runId !== undefined && this.runs.get(runId) !== undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Clears one pending call after its result has been written to the Run. */
|
|
225
|
+
clearPendingCall(runId: string, callId: string): void {
|
|
226
|
+
const entry = this.runs.get(runId);
|
|
227
|
+
if (entry === undefined) return;
|
|
228
|
+
const call = entry.session.calls.get(callId);
|
|
229
|
+
if (call !== undefined) entry.session.pending.delete(call.execId);
|
|
230
|
+
entry.session.calls.delete(callId);
|
|
231
|
+
this.callOwners.delete(callId);
|
|
232
|
+
this.touch(runId);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Extends one Run's idle expiry: the client answered, so the Run is live. */
|
|
236
|
+
touch(runId: string, idleTtlMs = RUN_IDLE_TTL_MS): void {
|
|
237
|
+
const entry = this.runs.get(runId);
|
|
238
|
+
if (entry === undefined) return;
|
|
239
|
+
clearTimeout(entry.expiryTimer);
|
|
240
|
+
entry.expiresAt = Date.now() + idleTtlMs;
|
|
241
|
+
entry.expiryTimer = setTimeout(() => {
|
|
242
|
+
this.terminate(runId, "Cursor Run idle-expired waiting for a tool result");
|
|
243
|
+
}, idleTtlMs);
|
|
244
|
+
entry.expiryTimer.unref?.();
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Records the Run's authoritative terminal usage before it is closed. */
|
|
248
|
+
recordUsage(runId: string, usage: UsageRecord): void {
|
|
249
|
+
const entry = this.runs.get(runId);
|
|
250
|
+
if (entry === undefined) return;
|
|
251
|
+
entry.session.usage = usage;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Records why a Run failed, so the next request reports it rather than hanging. */
|
|
255
|
+
recordFailure(runId: string, failure: GatewayError): void {
|
|
256
|
+
const entry = this.runs.get(runId);
|
|
257
|
+
if (entry === undefined) return;
|
|
258
|
+
entry.session.failure = failure;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Reads one live Run by id, for the frame continuation path. */
|
|
262
|
+
get(runId: string): CursorRunSession | undefined {
|
|
263
|
+
return this.runs.get(runId)?.session;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Describes one pending call by id and caller identity.
|
|
268
|
+
*
|
|
269
|
+
* The routing layer needs the owning account *before* it knows which provider
|
|
270
|
+
* a candidate belongs to, so this reads the same server-recorded scope the
|
|
271
|
+
* adapter will later re-check: tenant and API key here, provider and account
|
|
272
|
+
* in the answer. A call id from another tenant or key resolves nothing.
|
|
273
|
+
*/
|
|
274
|
+
describePendingCall(
|
|
275
|
+
callId: string,
|
|
276
|
+
scope: { readonly tenantId: string; readonly apiKeyId: string },
|
|
277
|
+
): { readonly providerId: string; readonly providerAccountId: string } | undefined {
|
|
278
|
+
const runId = this.callOwners.get(callId);
|
|
279
|
+
if (runId === undefined) return undefined;
|
|
280
|
+
const entry = this.runs.get(runId);
|
|
281
|
+
if (entry === undefined) return undefined;
|
|
282
|
+
const { session } = entry;
|
|
283
|
+
if (
|
|
284
|
+
session.scope.tenantId !== scope.tenantId ||
|
|
285
|
+
session.scope.apiKeyId !== scope.apiKeyId
|
|
286
|
+
) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
if (!session.calls.has(callId)) return undefined;
|
|
290
|
+
return {
|
|
291
|
+
providerId: session.scope.providerId,
|
|
292
|
+
providerAccountId: session.scope.providerAccountId,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Takes over the borrowed lease for a Run that is already registered.
|
|
298
|
+
*
|
|
299
|
+
* Idempotent: a second transfer stores nothing, so a retry of the same
|
|
300
|
+
* continuation request cannot double-release the slot.
|
|
301
|
+
*/
|
|
302
|
+
adoptLease(runId: string, ownership: AttemptLeaseOwnership | undefined): void {
|
|
303
|
+
if (ownership === undefined) return;
|
|
304
|
+
const entry = this.runs.get(runId);
|
|
305
|
+
if (entry === undefined || entry.releaseLease !== undefined) return;
|
|
306
|
+
const release = ownership.transferToProviderSession();
|
|
307
|
+
if (release === undefined) return;
|
|
308
|
+
entry.releaseLease = release;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/** Drops every live Run. Shutdown and test seam. */
|
|
312
|
+
terminateAll(reason?: string): void {
|
|
313
|
+
for (const runId of [...this.runs.keys()]) this.terminate(runId, reason);
|
|
314
|
+
this.callOwners.clear();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Process-local manager: one active Run set per gateway process. */
|
|
319
|
+
export const cursorRunSessions = new CursorRunSessionManager();
|