@code-yeongyu/senpi 2026.11.6-2 → 2026.11.9
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/CHANGELOG.md +52 -0
- package/dist/bundle/chunks/{bun-extension-importer-RCGPQTI2.js → bun-extension-importer-GQ6IKEXD.js} +2 -2
- package/dist/bundle/chunks/{chunk-GSKCWXXG.js → chunk-3CRPNPTR.js} +1 -1
- package/dist/bundle/chunks/{chunk-RQ6CHXQ2.js → chunk-3TZQXZKH.js} +1 -1
- package/dist/bundle/chunks/{chunk-QN2BHP3M.js → chunk-44BJPS5I.js} +1 -1
- package/dist/bundle/chunks/{chunk-WGRKM3N6.js → chunk-45MVD7BU.js} +1 -1
- package/dist/bundle/chunks/chunk-4JIBEZZE.js +106 -0
- package/dist/bundle/chunks/{chunk-CF5OGBC4.js → chunk-4NYNMAYF.js} +1 -1
- package/dist/bundle/chunks/{chunk-X5ZVYNOL.js → chunk-4UR6UFBH.js} +1 -1
- package/dist/bundle/chunks/{chunk-LNPAT22L.js → chunk-527Q2UYM.js} +9 -8
- package/dist/bundle/chunks/{chunk-HLM46XEB.js → chunk-622VYTRI.js} +1 -1
- package/dist/bundle/chunks/{chunk-GKAYPJ4E.js → chunk-7PROV6BB.js} +1 -1
- package/dist/bundle/chunks/{chunk-4E7GDG4H.js → chunk-7VMEE62L.js} +1 -1
- package/dist/bundle/chunks/{chunk-ECW7VBMB.js → chunk-HXNXISJD.js} +1 -1
- package/dist/bundle/chunks/{chunk-C7OKUC7L.js → chunk-K3UHGDUQ.js} +1 -1
- package/dist/bundle/chunks/{chunk-47PPZKPO.js → chunk-LM6DOWQH.js} +4 -4
- package/dist/bundle/chunks/chunk-LPYBKMPT.js +2 -0
- package/dist/bundle/chunks/{chunk-2FDW2LQL.js → chunk-M7GF73FO.js} +2 -2
- package/dist/bundle/chunks/{chunk-D5MRJWUK.js → chunk-OCMGRBJ5.js} +221 -229
- package/dist/bundle/chunks/{chunk-TIPKAMSS.js → chunk-SGAFIMAU.js} +1 -1
- package/dist/bundle/chunks/{chunk-7PSBD5KS.js → chunk-STGOYIXC.js} +1 -1
- package/dist/bundle/chunks/{chunk-DSWDJ7HT.js → chunk-WQ4RBPMS.js} +1 -1
- package/dist/bundle/chunks/{chunk-7III44PV.js → chunk-WX2HB4DD.js} +1 -1
- package/dist/bundle/chunks/chunk-XZDCMDUH.js +2 -0
- package/dist/bundle/chunks/{chunk-GNSMNSL7.js → chunk-Y5L4UFMI.js} +2 -2
- package/dist/bundle/chunks/{cli-main-T74YJGIF.js → cli-main-E4NDWAUD.js} +1 -1
- package/dist/bundle/chunks/{dispatch-BAK2YZKD.js → dispatch-VDIYSXQN.js} +1 -1
- package/dist/bundle/chunks/{hand-entry-AYRUGE2A.js → hand-entry-5X5Z5Y3D.js} +1 -1
- package/dist/bundle/chunks/{headless-host-ES74ZB6M.js → headless-host-YXUGONR3.js} +1 -1
- package/dist/bundle/chunks/{host-command-YRXZE4TV.js → host-command-VHX2ILLM.js} +1 -1
- package/dist/bundle/chunks/{host-session-command-N7IN7ZDV.js → host-session-command-P3MRW63Z.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-XUSBLLWI.js +2 -0
- package/dist/bundle/chunks/main-3TWVKTJN.js +2 -0
- package/dist/bundle/chunks/{multi-session-host-XSUJDHFZ.js → multi-session-host-HRGM66PY.js} +20 -17
- package/dist/bundle/chunks/{package-manager-cli-GLUNPQJU.js → package-manager-cli-WSH7U4YE.js} +1 -1
- package/dist/bundle/chunks/{role-RRFFHZF5.js → role-4BUU46VW.js} +3 -3
- package/dist/bundle/chunks/{rotation-stream-BN2YK2MC.js → rotation-stream-TODBIHXJ.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-OAPIV46G.js +2 -0
- package/dist/bundle/chunks/{run-attached-tui-W236SEOR.js → run-attached-tui-MXCC5IZR.js} +1 -1
- package/dist/bundle/chunks/{runtime-session-OBXYK4PI.js → runtime-session-VO3X4OE3.js} +1 -1
- package/dist/bundle/chunks/{schedule-command-B2EJTBOE.js → schedule-command-MX56D6UE.js} +1 -1
- package/dist/bundle/chunks/{session-control-endpoint-YIMLHGLG.js → session-control-endpoint-IL6ERD4U.js} +1 -1
- package/dist/bundle/chunks/{session-picker-E6ZONUJB.js → session-picker-6VRC25MJ.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +114 -110
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/core/agent-session-runtime.d.ts +2 -0
- package/dist/core/agent-session-runtime.js +9 -2
- package/dist/core/agent-session-services.d.ts +2 -0
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session.d.ts +32 -3
- package/dist/core/agent-session.js +142 -29
- package/dist/core/credential-pool/rotation-slots.d.ts +3 -3
- package/dist/core/credential-pool/state-store.d.ts +1 -1
- package/dist/core/egress/classify.d.ts +8 -3
- package/dist/core/egress/classify.js +177 -158
- package/dist/core/egress/console-redactor.d.ts +7 -0
- package/dist/core/egress/console-redactor.js +74 -0
- package/dist/core/egress/credentials.d.ts +73 -0
- package/dist/core/egress/credentials.js +20 -0
- package/dist/core/egress/device-custody.d.ts +1 -1
- package/dist/core/egress/device-custody.js +18 -15
- package/dist/core/egress/device-proxy-call.d.ts +59 -0
- package/dist/core/egress/device-proxy-call.js +148 -0
- package/dist/core/egress/device-proxy-lost-calls.d.ts +27 -0
- package/dist/core/egress/device-proxy-lost-calls.js +28 -0
- package/dist/core/egress/device-proxy-ports.d.ts +49 -0
- package/dist/core/egress/device-proxy-ports.js +2 -0
- package/dist/core/egress/device-proxy-request.d.ts +34 -0
- package/dist/core/egress/device-proxy-request.js +69 -0
- package/dist/core/egress/device-proxy-waits.d.ts +40 -0
- package/dist/core/egress/device-proxy-waits.js +67 -0
- package/dist/core/egress/device-proxy.d.ts +3 -0
- package/dist/core/egress/device-proxy.js +214 -0
- package/dist/core/egress/endpoint.js +2 -1
- package/dist/core/egress/entry-verify.d.ts +13 -0
- package/dist/core/egress/entry-verify.js +33 -0
- package/dist/core/egress/hpke.d.ts +63 -0
- package/dist/core/egress/hpke.js +192 -0
- package/dist/core/egress/key-policy-template.d.ts +7 -1
- package/dist/core/egress/ledger-schema.d.ts +80 -0
- package/dist/core/egress/ledger-schema.js +117 -0
- package/dist/core/egress/ledger.d.ts +55 -0
- package/dist/core/egress/ledger.js +159 -0
- package/dist/core/egress/pinned-infra.d.ts +23 -2
- package/dist/core/egress/pinned-infra.js +9 -2
- package/dist/core/egress/placement-claim.d.ts +69 -0
- package/dist/core/egress/placement-claim.js +115 -0
- package/dist/core/egress/pool-state.d.ts +18 -0
- package/dist/core/egress/pool-state.js +5 -0
- package/dist/core/egress/redact.d.ts +10 -0
- package/dist/core/egress/redact.js +134 -0
- package/dist/core/egress/sealed-format.d.ts +101 -0
- package/dist/core/egress/sealed-format.js +174 -0
- package/dist/core/egress/sealed-source.d.ts +35 -0
- package/dist/core/egress/sealed-source.js +140 -0
- package/dist/core/egress/verified-keys.js +1 -1
- package/dist/core/egress/wire.d.ts +228 -0
- package/dist/core/egress/wire.js +49 -0
- package/dist/core/extensions/builtin/ask-user/escape-residue.d.ts +50 -0
- package/dist/core/extensions/builtin/ask-user/escape-residue.js +113 -0
- package/dist/core/extensions/builtin/ask-user/extension.js +7 -1
- package/dist/core/extensions/builtin/ask-user/resume.js +2 -1
- package/dist/core/extensions/builtin/ask-user/tool.d.ts +3 -0
- package/dist/core/extensions/builtin/ask-user/tool.js +8 -0
- package/dist/core/extensions/builtin/goal/index.js +46 -0
- package/dist/core/extensions/builtin/goal/stop-pause.d.ts +1 -0
- package/dist/core/extensions/builtin/goal/stop-pause.js +4 -2
- package/dist/core/extensions/builtin/monitor-state-event.d.ts +26 -0
- package/dist/core/extensions/builtin/monitor-state-event.js +2 -0
- package/dist/core/extensions/builtin/permission-system/index.js +10 -4
- package/dist/core/extensions/builtin/permission-system/preset-registry.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/preset-registry.js +11 -0
- package/dist/core/extensions/builtin/permission-system/settings.d.ts +2 -0
- package/dist/core/extensions/builtin/permission-system/settings.js +10 -1
- package/dist/core/extensions/builtin/terminal/background-age.d.ts +25 -0
- package/dist/core/extensions/builtin/terminal/background-age.js +91 -0
- package/dist/core/extensions/builtin/terminal/extension-state.d.ts +1 -1
- package/dist/core/extensions/builtin/terminal/extension-state.js +21 -3
- package/dist/core/extensions/builtin/terminal/notify.d.ts +6 -0
- package/dist/core/extensions/builtin/terminal/notify.js +39 -5
- package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +9 -2
- package/dist/core/extensions/builtin/terminal/session-bundle.js +36 -1
- package/dist/core/extensions/builtin/terminal/settings.d.ts +2 -0
- package/dist/core/extensions/builtin/terminal/settings.js +8 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.d.ts +15 -0
- package/dist/core/extensions/builtin/terminal/tools/background-auto-reap.js +87 -0
- package/dist/core/extensions/builtin/terminal/tools/bash.d.ts +3 -1
- package/dist/core/extensions/builtin/terminal/tools/bash.js +44 -15
- package/dist/core/extensions/builtin/terminal/tools/child-placement.d.ts +8 -0
- package/dist/core/extensions/builtin/terminal/tools/child-placement.js +43 -6
- package/dist/core/extensions/builtin/terminal/tools/context.d.ts +14 -2
- package/dist/core/extensions/bun-extension-importer.js +4 -3
- package/dist/core/extensions/bun-extension-load-turns.d.ts +4 -0
- package/dist/core/extensions/bun-extension-load-turns.js +45 -0
- package/dist/core/extensions/bun-extension-registry.d.ts +1 -0
- package/dist/core/extensions/bun-extension-registry.js +19 -1
- package/dist/core/extensions/loader.js +5 -0
- package/dist/core/extensions/session-control-types.d.ts +15 -0
- package/dist/core/extensions/session-control-types.js +11 -0
- package/dist/core/extensions/session-dialog-api.d.ts +5 -0
- package/dist/core/extensions/session-dialog-api.js +13 -0
- package/dist/core/extensions/types.d.ts +14 -1
- package/dist/core/external-admission.d.ts +16 -2
- package/dist/core/external-admission.js +22 -4
- package/dist/core/permission-decision.d.ts +22 -0
- package/dist/core/permission-decision.js +53 -0
- package/dist/core/permission-mode.d.ts +56 -0
- package/dist/core/permission-mode.js +133 -0
- package/dist/core/retry-fallback/controller-types.d.ts +6 -0
- package/dist/core/retry-fallback/controller.d.ts +9 -0
- package/dist/core/retry-fallback/controller.js +34 -3
- package/dist/core/retry-fallback/unusable.d.ts +25 -1
- package/dist/core/retry-fallback/unusable.js +87 -2
- package/dist/core/retry-fallback/usage-limit.d.ts +6 -1
- package/dist/core/retry-fallback/usage-limit.js +12 -4
- package/dist/core/sdk.d.ts +6 -1
- package/dist/core/sdk.js +3 -0
- package/dist/core/session-log.js +1 -1
- package/dist/core/stall-warning.d.ts +41 -0
- package/dist/core/stall-warning.js +72 -0
- package/dist/core/terminal-settings.d.ts +1 -0
- package/dist/core/turn-origin.d.ts +31 -0
- package/dist/core/turn-origin.js +64 -0
- package/dist/modes/interactive/components/remote-delivery-message.d.ts +2 -1
- package/dist/modes/interactive/components/remote-delivery-message.js +13 -5
- package/dist/modes/rpc/admit-external-message-command.d.ts +37 -0
- package/dist/modes/rpc/admit-external-message-command.js +61 -0
- package/dist/modes/rpc/admit-external-message-wire.d.ts +42 -0
- package/dist/modes/rpc/admit-external-message-wire.js +55 -0
- package/dist/modes/rpc/client-input-handler.d.ts +2 -0
- package/dist/modes/rpc/client-input-handler.js +2 -0
- package/dist/modes/rpc/connection-handler.js +30 -5
- package/dist/modes/rpc/connection-roles.d.ts +6 -0
- package/dist/modes/rpc/connection-roles.js +13 -0
- package/dist/modes/rpc/delegated-drive-origin.d.ts +9 -0
- package/dist/modes/rpc/delegated-drive-origin.js +16 -0
- package/dist/modes/rpc/effect-commands.d.ts +7 -1
- package/dist/modes/rpc/host-bare-endpoint-registration.d.ts +7 -0
- package/dist/modes/rpc/host-bare-endpoint-registration.js +35 -0
- package/dist/modes/rpc/host-capabilities.d.ts +2 -0
- package/dist/modes/rpc/host-capabilities.js +3 -0
- package/dist/modes/rpc/host-handover-parked.d.ts +11 -0
- package/dist/modes/rpc/host-handover-parked.js +17 -0
- package/dist/modes/rpc/host-handover-reopen.js +18 -6
- package/dist/modes/rpc/host-handover-resident-writer.d.ts +16 -0
- package/dist/modes/rpc/host-handover-resident-writer.js +57 -0
- package/dist/modes/rpc/host-idle-handover.js +1 -0
- package/dist/modes/rpc/host-warm.d.ts +16 -1
- package/dist/modes/rpc/host-warm.js +33 -6
- package/dist/modes/rpc/method-classes-schema-delivery.d.ts +32 -0
- package/dist/modes/rpc/method-classes-schema-delivery.js +22 -0
- package/dist/modes/rpc/method-classes-schema-session.d.ts +36 -0
- package/dist/modes/rpc/method-classes-schema-session.js +3 -0
- package/dist/modes/rpc/method-classes-schema.d.ts +36 -0
- package/dist/modes/rpc/method-classes.d.ts +2 -0
- package/dist/modes/rpc/method-classes.js +4 -0
- package/dist/modes/rpc/multi-session-host.js +6 -1
- package/dist/modes/rpc/permission-preset-command.d.ts +6 -0
- package/dist/modes/rpc/permission-preset-command.js +27 -0
- package/dist/modes/rpc/rpc-input-validation.js +4 -3
- package/dist/modes/rpc/rpc-mutation-response-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-response-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-command-types.d.ts +6 -1
- package/dist/modes/rpc/rpc-session-event-types.d.ts +5 -2
- package/dist/modes/rpc/rpc-session-state-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-session-state.js +2 -0
- package/dist/modes/rpc/session-attachment-commands.js +3 -3
- package/dist/modes/rpc/session-event-writer-connections.js +1 -0
- package/dist/modes/rpc/session-event-writer.d.ts +1 -1
- package/dist/modes/rpc/session-registry-attach.d.ts +0 -9
- package/dist/modes/rpc/session-registry-attach.js +16 -3
- package/dist/modes/rpc/session-registry-types.d.ts +2 -0
- package/dist/modes/rpc/session-registry.d.ts +2 -0
- package/dist/modes/rpc/session-registry.js +16 -3
- package/dist/modes/rpc/session-router-close.js +43 -6
- package/dist/modes/rpc/session-router-context.js +2 -0
- package/dist/modes/rpc/session-router-occupancy.js +2 -11
- package/dist/modes/rpc/session-router-open-profile.js +4 -0
- package/dist/modes/rpc/session-router-open.d.ts +1 -1
- package/dist/modes/rpc/session-router-open.js +6 -17
- package/dist/modes/rpc/session-router-residency.d.ts +24 -0
- package/dist/modes/rpc/session-router-residency.js +90 -0
- package/dist/modes/rpc/session-router-routing.js +7 -1
- package/dist/modes/rpc/session-status.js +4 -1
- package/dist/modes/rpc/session-worker.js +4 -0
- package/dist/modes/rpc/tool-child/terminal-jobs.d.ts +1 -0
- package/dist/modes/rpc/tool-child/terminal-jobs.js +17 -1
- package/dist/modes/rpc/worker-session-registry.js +5 -2
- package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
- package/docs/engine-socket/fixtures/rpc-inbound-samples.json +29 -2
- package/docs/extensions.md +12 -0
- package/docs/rpc.md +129 -12
- package/docs/terminal-tools.md +25 -1
- package/native/socket-secret/prebuilds/win32-arm64/senpi_socket_secret.win32-arm64.node +0 -0
- package/native/socket-secret/prebuilds/win32-x64/senpi_socket_secret.win32-x64.node +0 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-C7HEEBFH.js +0 -2
- package/dist/bundle/chunks/chunk-XCMII2VQ.js +0 -98
- package/dist/bundle/chunks/interactive-mode-B5SQDLH7.js +0 -2
- package/dist/bundle/chunks/main-UQFVFCNY.js +0 -2
- package/dist/bundle/chunks/rpc-mode-JYN3E7P7.js +0 -2
package/dist/bundle/chunks/{multi-session-host-XSUJDHFZ.js → multi-session-host-HRGM66PY.js}
RENAMED
|
@@ -1,48 +1,51 @@
|
|
|
1
1
|
import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url); { const __piWorkerThreads = require("node:worker_threads"); if (typeof __piWorkerThreads.markAsUncloneable !== "function") { __piWorkerThreads.markAsUncloneable = () => {}; } }
|
|
2
|
-
import{getInternalHostBootstrap}from"./chunk-POTKWOUB.js";import{GeneratedFramesCursor,PRESENTER_CONTROL_INFO_COMMAND,SessionEventWriter,answerSetSessionContext,answerSubscribeSessions,answerUnsubscribeSessions,captureAdmissionReply,enqueueLegacyRecord,jsonChunks,notAttachedRefusal,presenterPipePath,recordLoopBlockedMs,refused,registryStatusSource,requestId,socketSink,startMcpPresenterControl,storageUnavailable,withAdmissionReply,withAdmissionRequest}from"./chunk-GNSMNSL7.js";import{ACCEPT_EDITS_PERMISSION_PRESET_CAPABILITY,AUTO_PERMISSION_PRESET_CAPABILITY,EXTENSION_STATE_PAYLOAD,EXTENSION_STATE_PREFIX,HostMcpRegistry,MANIFEST_FILE,MOVE_BUNDLE_FORMAT,MoveBundleInvalidError,ProviderScope,RpcSessionRegistry,RpcSessionRegistryError,SESSION_BUNDLE_PATH,STATE_ATTEMPT_FIELD,SessionAcceptanceLane,SessionPendingInputs,StructuredLaneUnavailableError,answerWarm,attachLiveSession,bindToProviderScope,canonicalLoss,code,compactTransportDisabled,createRpcConnectionHandler,createWebViewBroker,detail,error,frozenProfile,isMoveId,isPlainId,isSecurityNoticeState,movedStateDir,outgoingStateDir,parseMoveId,parsePermissionPresetName,parsePlainId,pathExists,prepareOutgoingState,protocolClone,protocolDepthLimitOf,readCodemodeKernelRows,readMainThreadHeapBytes,readManifest,readRecordedRepositoryIdentity,readSessionCwd,rebindSessionFile,refreshesSessionActivity,releaseWithinGrace,routingIdOf,runWithProviderScope,sealedOutgoingStateDir,sessionIdentity,sessionWorkerDataRegistry,sha256File,sharedPathIdentityResolver,startHostChildReaper,startOpenTimer,structuredLaneEnabled,verifyBundle}from"./chunk-D5MRJWUK.js";import"./chunk-X5ZVYNOL.js";import{SessionHeldError,encodedSessionId,foreignSessionHolders,liveSessionHolders,readProcessStartMs,serializeByKey,withSessionMoveLock}from"./chunk-7PSBD5KS.js";import"./chunk-GSKCWXXG.js";import{liveToolMediaScope,toolMediaPersister}from"./chunk-WGRKM3N6.js";import{SESSION_MOVED,SESSION_MOVED_IN,SESSION_RECLAIMED,SESSION_RELEASED,SessionManager,SessionMovedAwayError,assertValidSessionId,compareRepositoryIdentities,getDefaultSessionDir,headerSessionId,ownershipStep,readRepositoryIdentity,sessionFileNameId,sessionOwnership}from"./chunk-CF5OGBC4.js";import"./chunk-GTJJ73DE.js";import"./chunk-FEQDJBDL.js";import"./chunk-C7OKUC7L.js";import{OPEN_AFTER_QUEUED_DEADLINE_MS}from"./chunk-H33A33M4.js";import{flushRawStdout,takeOverStdout,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-RQ6CHXQ2.js";import"./chunk-22YXCY7K.js";import"./chunk-3QPE75AR.js";import"./chunk-4GKU755E.js";import{CONNECTION_ROLE_FIXED,ClientAdmissions,CommandAuthority,CompactReadError,CompactStorageReadError,ConnectionRoles,DELEGATION_INCARNATION_STALE,DURABLE_CLIENT_MESSAGE_ID_CAPABILITY,EFFECT_LEDGER_CAPABILITY,EffectLedger,FRAGMENT_ENVELOPE_MAX_BYTES,FRAGMENT_MAX_BYTES,TRANSFER_STAGING_MAX_BYTES,TransferStagingError,advertisedCompactCapabilities,answerEffectFromTranscript,answeredUiRequestId,applyContextPatch,beginEffect,buildRpcSessionState,carriesExtensionOwner,commandAuthority,drainSessionEffects,effectAnswer,installSessionEffectSink,isEffectBegin,isGrantSelectRequest,latestSessionEffect,originField,outsideCommand,parseBoundedId,protocolId,publishedSessionContext,recoveryAgentDir,recoveryCarrier,refusedExtensionUiResponse,remoteOriginDeclaration,roleConnection,rpcCommandShapeError,sessionAutoTitleError,sessionBrowserEngineError,sessionContextError,sessionKindError,sessionPromptSurfaceError,sessionRetryFallbackError,setSessionRecoveryEpoch,takeRelayExec}from"./chunk-XCMII2VQ.js";import{RPC_ERROR_ATTACHED,RPC_ERROR_HOST_DRAINING,RPC_ERROR_INVALID_LAUNCH_PROFILE,RPC_ERROR_INVALID_RELEASE_REASON,RPC_ERROR_INVALID_SESSION_CONTEXT,RPC_ERROR_INVALID_SESSION_ENV,RPC_ERROR_INVALID_SESSION_KIND,RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OWNER_CHANGED,RPC_ERROR_RELEASE_FAILED,RPC_ERROR_RELEASE_UNSUPPORTED,RPC_ERROR_SESSION_BUSY,RPC_ERROR_SESSION_CLOSING,RPC_ERROR_SESSION_HELD,RPC_ERROR_TURN_ACTIVE,RPC_ERROR_UNKNOWN_SESSION,RPC_ERROR_UNSUPPORTED_TRANSPORT,SESSION_MODEL_SCOPE_CAPABILITY,STEER_WHEN_IDLE_CAPABILITY,USER_ACTIVITY_CAPABILITY}from"./chunk-SJI6UB23.js";import"./chunk-436DNN4Z.js";import{compactUpdatesEnabled,executionCallKey,loadEntriesFromFileAsync}from"./chunk-J2I56WLK.js";import"./chunk-TQHNFP77.js";import"./chunk-C7HEEBFH.js";import"./chunk-47PPZKPO.js";import"./chunk-MOVB6H22.js";import"./chunk-NH7SYIGN.js";import"./chunk-WAOGBBZR.js";import"./chunk-VD7AKTGP.js";import"./chunk-Y3TMJV3J.js";import{readOwnFootprint}from"./chunk-MTQQ2VQH.js";import{BEGIN_HANDOVER_COMMAND,EXPECTED_RUNTIME_BUILD_ID_ENV,HostIdleHandover,agentDirMismatch,beginHandoverResponse,handoverRefusal,isHandoffBusy,isHostIdle,isTransientDaemonEnvName,parseBeginHandover,performIdleHandover,readDrainVerdicts,runAsHostGenerationProcess,withHostIdentity}from"./chunk-2FDW2LQL.js";import{ACCOUNT_RESET_CAPABILITY,ATTENDED_CAPABILITY,AUTH_KEY_VERIFY_CAPABILITY,AUTO_TITLE_PER_SESSION_CAPABILITY,AUTO_TITLE_SESSIONS_CAPABILITY,BROWSER_ENGINE_CAPABILITY,CONTINUE_FROM_LEAF_CAPABILITY,DELEGATED_CONNECTION_CAPABILITY,DELEGATION_ROLES_CAPABILITY,DETACH_CONNECTION_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,ENDPOINT_OWNER_FENCE_CAPABILITY,ENTRIES_TAIL_CAPABILITY,EVAL_CELLS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HAND_SELECTION_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,MOVED_PATH_GUARD_CAPABILITY,OBSERVE_READS_CAPABILITY,PROMPT_SURFACE_CAPABILITY,PROMPT_SURFACE_CHAT_CAPABILITY,PROVIDER_ACCOUNT_TEST_CAPABILITY,QUEUED_MESSAGE_REVISION_CAPABILITY,RESUME_SESSION_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,RETRY_FALLBACK_PROFILE_CAPABILITY,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_ENV_CAPABILITY,SESSION_HELD_CAPABILITY,SESSION_KIND_CAPABILITY,SESSION_RELOCATION_CAPABILITY,SESSION_STATUS_CAPABILITY,TOOL_BARRIER_CAPABILITY,WARM_CAPABILITY,computeRuntimeBuildId,hostGeneration,hostInstanceId,parseClientCapabilities,pathIdentityResolverStatus,protocolIdentity}from"./chunk-HLM46XEB.js";import"./chunk-QMRJYMNH.js";import"./chunk-Y7Z7XPUF.js";import{isHostOwnedToolRuntimeCapability,isSpawnedBy,toolRuntimeCapabilities}from"./chunk-54YTJCYZ.js";import"./chunk-26UBFF6N.js";import"./chunk-I5ASHSLZ.js";import"./chunk-2CNSCMYC.js";import{presenterBootstrapStream}from"./chunk-7WYJAYHH.js";import{ClientOccupancy,PublicRpcConnection,acceptInternalConnection,armHostWatchdog,closeShieldedEndpoint,consumeHostWatchdogEnv,formatSocketAddress,listen,loopLagErrorMs,prepareSocketPath,resolveSocketPath,scrubHostWatchdogEnv,unlinkOwnedEndpoint}from"./chunk-I3PHVJAS.js";import{reportStartupMilestone}from"./chunk-R2Z7CX77.js";import{CHILD_STOP_TIMEOUT_MS,SESSION_PATH_RETRY_AFTER_MS,createEndpointReservations,holderGenerationEnded,hostChildDrainRequestFile,ownGenerationDir,parseIdleExitMs,watchDrainRequest,writeHeartbeat,writeStallEvidence}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_DIR_ENV,canonicalSessionPath,createHostDaemonPaths,sessionDirectoryRemoved}from"./chunk-YI6KRJDC.js";import{RpcPublicEndpoint}from"./chunk-DBQBJTMF.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,serializeJsonLine}from"./chunk-SF4MQDKZ.js";import"./chunk-VPVD5G32.js";import"./chunk-H4QOEVS5.js";import"./chunk-PPQPV52D.js";import"./chunk-4E7GDG4H.js";import{subscriptionLimits}from"./chunk-UBNUGVW6.js";import"./chunk-ADT36P7E.js";import"./chunk-KLAX467B.js";import"./chunk-J7FW7MED.js";import{lockWithLossHandling}from"./chunk-2EJ4BGBM.js";import"./chunk-GZVCRV7I.js";import{external_exports}from"./chunk-KUPQO7MC.js";import"./chunk-U3VOXCGP.js";import{FILE_STORAGE_LOCK_RETRY_MAX_DELAY_MS,FILE_STORAGE_LOCK_RETRY_MIN_DELAY_MS,isLockError}from"./chunk-7X72IACK.js";import"./chunk-MSDBBOB2.js";import"./chunk-WHQ2QPP5.js";import"./chunk-YUTUD26F.js";import"./chunk-WB4BUHOH.js";import"./chunk-6VWIMHMH.js";import"./chunk-SOMFLLPD.js";import"./chunk-KDUJCDLM.js";import"./chunk-YU2P3CAR.js";import"./chunk-ADOOQW3O.js";import"./chunk-KJR3XXMI.js";import"./chunk-IYL5E4QQ.js";import"./chunk-7THM57HH.js";import"./chunk-AC72EWI5.js";import"./chunk-RQFD6LG2.js";import"./chunk-LNPAT22L.js";import"./chunk-TMXRR3N7.js";import{killTrackedDetachedChildren}from"./chunk-DSWDJ7HT.js";import"./chunk-GKAYPJ4E.js";import"./chunk-EVTTLPIY.js";import"./chunk-BPNSOZ2C.js";import"./chunk-DLAY7CIU.js";import"./chunk-YUVC7SJB.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-Y7QPP7BG.js";import"./chunk-ZDHAJROE.js";import"./chunk-GVSBCJFI.js";import"./chunk-QTS2XGPQ.js";import"./chunk-Z6TEQEZO.js";import"./chunk-HJDTYAPV.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-WIOV3AXZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-OKMHSVCA.js";import"./chunk-JGKH3D6W.js";import"./chunk-3SASTB6Y.js";import"./chunk-NDNQ23SK.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-6APXZK7W.js";import"./chunk-WOHQJ6JB.js";import"./chunk-GLTOBXZY.js";import"./chunk-ECW7VBMB.js";import"./chunk-ZOFZRJSL.js";import"./chunk-ZFIC2DZV.js";import"./chunk-YK3ZZCHI.js";import{privateTablePresent}from"./chunk-T2SMQPRE.js";import"./chunk-RUGTHELO.js";import"./chunk-42XRJQM6.js";import"./chunk-2SOVDETB.js";import"./chunk-IHES3JES.js";import{PUBLIC_SOCKET_IDENTITY_FILE,readSocketIdentityFile,socketEntryReplaced,waitForSocketIdentityFile}from"./chunk-5XHOHZIR.js";import{SOCKET_SECRET_FILE_ENV,authenticateSocket,ensureSocketSecret,socketSecretPath}from"./chunk-HW6AAS3R.js";import{VERSION,envValue,isBunBinary,normalizePath,resolvePath}from"./chunk-SODMQEHO.js";import"./chunk-ATQFN5HI.js";import"./chunk-EYSV6A7S.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import{ownProcessStartedAtMs}from"./chunk-QN2BHP3M.js";import"./chunk-AOTHPTMU.js";import{processStartTimeMs}from"./chunk-O5RYI3IW.js";import"./chunk-IKOFCODM.js";import{createServer}from"node:net";import{rm as rm8}from"node:fs/promises";import{basename as basename2,dirname as dirname3,join as join9}from"node:path";function warmAtBootForPrivateFds(warm,profile,log){warm===void 0||!privateTablePresent()||warm(profile).catch(cause=>{log(`boot extension load failed: ${cause instanceof Error?cause.message:String(cause)}`)})}function relayExecRefusal(record){let object=typeof record=="object"&&record!==null?record:{},type=Reflect.get(object,"type");return refused(requestId(object),typeof type=="string"?type:"parse","delegation_malformed","relayExec must be a positive safe integer")}async function answerDelegation(writer,verdict,record){switch(verdict.kind){case"consumed":return;case"reply":await writer.enqueueControl(verdict.response);return;case"private":writer.writeMcpFormReply(verdict.id,{error:verdict.error});return;case"presenter":writer.handleMcpForm(record)||writer.writeMcpFormReply(verdict.id,{error:"presenter_not_authorized"});return;case"control_info":{let controlEndpoint=writer.mcpPresenterControlEndpoint;await writer.enqueueControl({...verdict.id===void 0?{}:{id:verdict.id},type:"response",command:PRESENTER_CONTROL_INFO_COMMAND,success:!0,data:controlEndpoint===void 0?{}:{controlEndpoint}});return}}}var HostCoreGate=class{constructor(registry,route,hooks){this.inFlight=new Map,this.answering=new Set,this.route=route,this.runtimeBuildId=hooks.runtimeBuildId,this.endpoint=hooks.endpoint,this.handover=hooks.handover===void 0?void 0:new HostIdleHandover({...hooks.handover,isIdle:()=>isHostIdle(registry,this.inFlight)})}async intercept(parsed,deliver){if(!isRecord(parsed)||parsed.type!==BEGIN_HANDOVER_COMMAND)return!1;let answering=this.answerBegin(parsed).then(deliver);this.answering.add(answering);try{await answering}finally{this.answering.delete(answering)}return!0}async answerBegin(parsed){if(this.handover===void 0)return beginHandoverResponse(parsed.id,{kind:"refused",reason:"handover_unsupported"});let request=parseBeginHandover(parsed);if(typeof request=="string")return beginHandoverResponse(parsed.id,request);let detail2=request.agentDir===void 0||this.endpoint===void 0?void 0:await agentDirMismatch(this.endpoint.socket,request.agentDir,this.endpoint.agentDir);return beginHandoverResponse(parsed.id,detail2===void 0?await this.handover.begin(request):{kind:"refused",reason:"foreign_agent_dir",detail:detail2})}async answered(){for(;this.answering.size>0;)await Promise.allSettled([...this.answering])}async dispatch(command){let pending=this.handover?.view();if(pending!==void 0&&this.handover?.admits(command.type)===!1)return handoverRefusal(command,pending);let key="sessionId"in command?command.sessionId:void 0;this.inFlight.set(key,(this.inFlight.get(key)??0)+1);let response;try{response=await this.route(command)}finally{let remaining=(this.inFlight.get(key)??1)-1;remaining>0?this.inFlight.set(key,remaining):this.inFlight.delete(key),this.handover?.observe()}return response===void 0?void 0:withHostIdentity(response,this.runtimeBuildId,this.handover?.view())}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var HandoffAnnouncement=class{begin(superseded,identity,publicSocket,log){return this.record=superseded.then(replaced=>({type:"host_superseded",...identity,successor:replaced?{socket:publicSocket}:null}),cause=>{log(`handoff announcement failed: ${String(cause)}`)}),this.record}deliverLate(stream,arrivedBeforeDrain){let record=this.record;return!arrivedBeforeDrain||record===void 0?!1:(record.then(announced=>announced===void 0?stream.destroy():stream.end(`${JSON.stringify(announced)}
|
|
3
|
-
`)),!0)}};import{existsSync as existsSync2}from"node:fs";import{createHash}from"node:crypto";import{existsSync,renameSync}from"node:fs";import{mkdir,readdir,readFile,rm,writeFile}from"node:fs/promises";import{join}from"node:path";var CALLER_ENV_NAMES_ENV="SENPI_RPC_CALLER_ENV_NAMES",DEFAULT_CALLER_ENV_NAMES=Object.freeze(["OMOCAT_LANE"]),MAX_SESSION_ENV_ENTRIES=16,MAX_SESSION_ENV_VALUE_LENGTH=4096,ENV_NAME=/^[A-Z_][A-Z0-9_]*$/u,MAX_ECHOED_NAME_LENGTH=64;function callerEnvPassableNames(hostEnv=process.env){let names=new Set(DEFAULT_CALLER_ENV_NAMES);for(let raw of(hostEnv[CALLER_ENV_NAMES_ENV]??"").split(",")){let name=raw.trim();ENV_NAME.test(name)&&!isTransientDaemonEnvName(name)&&names.add(name)}return names}function sessionEnvShapeError(value){if(value===void 0)return;if(!isPlainRecord(value))return"env must be an object of strings.";let entries=Object.entries(value);if(entries.length>MAX_SESSION_ENV_ENTRIES)return`env allows at most ${MAX_SESSION_ENV_ENTRIES} entries.`;for(let[name,entry]of entries){if(!ENV_NAME.test(name))return`env name "${echoedName(name)}" must match ${ENV_NAME.source}.`;if(typeof entry!="string")return`env.${echoedName(name)} must be a string.`;if(entry.includes("\0"))return`env.${echoedName(name)} must not contain NUL.`;if(entry.length>MAX_SESSION_ENV_VALUE_LENGTH)return`env.${echoedName(name)} must be at most ${MAX_SESSION_ENV_VALUE_LENGTH} characters.`}}function sessionEnvError(value,hostEnv=process.env){let shape=sessionEnvShapeError(value);if(shape!==void 0||!isPlainRecord(value))return shape;let passable=callerEnvPassableNames(hostEnv);for(let name of Object.keys(value))if(!passable.has(name))return`env.${echoedName(name)} is not a caller-passable name (passable: ${[...passable].sort().join(", ")}).`}function inheritedSessionEnv(parent,requested){let merged={...parent,...requested};return Object.keys(merged).length===0?void 0:merged}function echoedName(name){return name.length>MAX_ECHOED_NAME_LENGTH?`${name.slice(0,MAX_ECHOED_NAME_LENGTH)}...`:name}function isPlainRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var recordDir=daemonDir=>join(daemonDir,"handover-parked"),entryFile=(daemonDir,sessionPath)=>join(recordDir(daemonDir),`${createHash("sha256").update(sessionPath,"utf8").digest("hex").slice(0,16)}.json`),mutationChain=Promise.resolve();function enqueueMutation(mutation){let next=mutationChain.then(mutation,mutation);return mutationChain=next.catch(()=>{}),next}function isEntry(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;let record=value;return typeof record.sessionPath=="string"&&typeof record.retainOnDisconnect=="boolean"&&(record.durableSessionId===void 0||typeof record.durableSessionId=="string")&&(record.cwd===void 0||typeof record.cwd=="string")&&(record.parkedBy===void 0||typeof record.parkedBy=="string")&&(record.thinkingLevel===void 0||typeof record.thinkingLevel=="string")&&(record.permissionPreset===void 0||typeof record.permissionPreset=="string"&&parsePermissionPresetName(record.permissionPreset)!==void 0)&&sessionPromptSurfaceError(record.promptSurface)===void 0&&sessionBrowserEngineError(record.browserEngine)===void 0&&sessionKindError(record.sessionKind)===void 0&&sessionContextError(record.sessionContext)===void 0&&(record.contextOverlay===void 0||!("refusal"in applyContextPatch(void 0,record.contextOverlay)))&&sessionAutoTitleError(record.autoTitle)===void 0&&sessionRetryFallbackError(record.retryFallback)===void 0&&sessionEnvShapeError(record.sessionEnv)===void 0&&(record.model===void 0||typeof record.model=="object"&&record.model!==null&&typeof record.model.provider=="string"&&typeof record.model.modelId=="string")}async function writeEntryFile(daemonDir,entry){await mkdir(recordDir(daemonDir),{recursive:!0,mode:448});let file=entryFile(daemonDir,entry.sessionPath),tmp=`${file}.${process.pid}.${Math.random().toString(16).slice(2,10)}.tmp`;await writeFile(tmp,`${JSON.stringify(entry,null,2)}
|
|
2
|
+
import{getInternalHostBootstrap}from"./chunk-POTKWOUB.js";import{GeneratedFramesCursor,PRESENTER_CONTROL_INFO_COMMAND,SessionEventWriter,answerSetSessionContext,answerSubscribeSessions,answerUnsubscribeSessions,captureAdmissionReply,enqueueLegacyRecord,jsonChunks,notAttachedRefusal,presenterPipePath,recordLoopBlockedMs,refused,registryStatusSource,requestId,socketSink,startMcpPresenterControl,storageUnavailable,withAdmissionReply,withAdmissionRequest}from"./chunk-Y5L4UFMI.js";import{EXTENSION_STATE_PAYLOAD,EXTENSION_STATE_PREFIX,HostMcpRegistry,MANIFEST_FILE,MOVE_BUNDLE_FORMAT,MoveBundleInvalidError,ProviderScope,RPC_ERROR_INVALID_MOVE_REQUEST,RPC_ERROR_MOVE_FAILED,RPC_ERROR_MOVE_NOT_RELEASED,RPC_ERROR_SESSION_OPEN_HERE,RpcSessionRegistry,RpcSessionRegistryError,SESSION_BUNDLE_PATH,STATE_ATTEMPT_FIELD,SessionAcceptanceLane,SessionPendingInputs,StructuredLaneUnavailableError,answerWarm,attachLiveSession,bindToProviderScope,canonicalLoss,code,compactTransportDisabled,createRpcConnectionHandler,createWebViewBroker,detail,error,frozenProfile,isMoveId,isPlainId,isSecurityNoticeState,movedStateDir,multiSessionHostCapabilities,outgoingStateDir,parseMoveId,parsePlainId,pathExists,prepareOutgoingState,protocolClone,protocolDepthLimitOf,readCodemodeKernelRows,readMainThreadHeapBytes,readManifest,readRecordedRepositoryIdentity,readSessionCwd,rebindSessionFile,refreshesSessionActivity,releaseWithinGrace,routingIdOf,runWithProviderScope,sealedOutgoingStateDir,sessionIdentity,sessionWorkerDataRegistry,sha256File,sharedPathIdentityResolver,startHostChildReaper,startOpenTimer,structuredLaneEnabled,verifyBundle}from"./chunk-OCMGRBJ5.js";import"./chunk-4UR6UFBH.js";import{SessionHeldError,encodedSessionId,errorCode,foreignSessionHolders,liveSessionHolders,readProcessStartMs,serializeByKey,withSessionMoveLock}from"./chunk-STGOYIXC.js";import"./chunk-3CRPNPTR.js";import{liveToolMediaScope,toolMediaPersister}from"./chunk-45MVD7BU.js";import{SESSION_MOVED,SESSION_MOVED_IN,SESSION_RECLAIMED,SESSION_RELEASED,SessionManager,SessionMovedAwayError,assertValidSessionId,compareRepositoryIdentities,getDefaultSessionDir,headerSessionId,ownershipStep,readRepositoryIdentity,sessionFileNameId,sessionOwnership}from"./chunk-4NYNMAYF.js";import"./chunk-GTJJ73DE.js";import"./chunk-FEQDJBDL.js";import"./chunk-K3UHGDUQ.js";import{OPEN_AFTER_QUEUED_DEADLINE_MS}from"./chunk-H33A33M4.js";import{flushRawStdout,takeOverStdout,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-3TZQXZKH.js";import"./chunk-22YXCY7K.js";import"./chunk-3QPE75AR.js";import"./chunk-4GKU755E.js";import{CONNECTION_ROLE_FIXED,ClientAdmissions,CommandAuthority,CompactReadError,CompactStorageReadError,ConnectionRoles,DELEGATION_INCARNATION_STALE,EffectLedger,FRAGMENT_ENVELOPE_MAX_BYTES,FRAGMENT_MAX_BYTES,TRANSFER_STAGING_MAX_BYTES,TransferStagingError,advertisedCompactCapabilities,answerEffectFromTranscript,answeredUiRequestId,applyContextPatch,beginEffect,buildRpcSessionState,carriesExtensionOwner,clientNamedPreset,commandAuthority,drainSessionEffects,effectAnswer,installSessionEffectSink,isEffectBegin,isGrantSelectRequest,latestSessionEffect,openReplyPermissionMode,originField,outsideCommand,parseBoundedId,parsePermissionPresetName,protocolId,publishedSessionContext,recoveryAgentDir,recoveryCarrier,refusedExtensionUiResponse,remoteOriginDeclaration,roleConnection,rpcCommandShapeError,sessionAutoTitleError,sessionBrowserEngineError,sessionContextError,sessionKindError,sessionPromptSurfaceError,sessionRetryFallbackError,setSessionRecoveryEpoch,takeRelayExec,withClientPreset}from"./chunk-4JIBEZZE.js";import{RPC_ERROR_ATTACHED,RPC_ERROR_HOST_DRAINING,RPC_ERROR_INVALID_LAUNCH_PROFILE,RPC_ERROR_INVALID_RELEASE_REASON,RPC_ERROR_INVALID_SESSION_CONTEXT,RPC_ERROR_INVALID_SESSION_ENV,RPC_ERROR_INVALID_SESSION_KIND,RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OWNER_CHANGED,RPC_ERROR_RELEASE_FAILED,RPC_ERROR_RELEASE_UNSUPPORTED,RPC_ERROR_SESSION_BUSY,RPC_ERROR_SESSION_CLOSING,RPC_ERROR_SESSION_HELD,RPC_ERROR_TURN_ACTIVE,RPC_ERROR_UNKNOWN_SESSION,RPC_ERROR_UNSUPPORTED_TRANSPORT}from"./chunk-SJI6UB23.js";import"./chunk-436DNN4Z.js";import{compactUpdatesEnabled,executionCallKey,loadEntriesFromFileAsync}from"./chunk-J2I56WLK.js";import"./chunk-TQHNFP77.js";import"./chunk-XZDCMDUH.js";import"./chunk-LM6DOWQH.js";import"./chunk-MOVB6H22.js";import"./chunk-NH7SYIGN.js";import"./chunk-WAOGBBZR.js";import"./chunk-VD7AKTGP.js";import"./chunk-Y3TMJV3J.js";import{readOwnFootprint}from"./chunk-MTQQ2VQH.js";import{BEGIN_HANDOVER_COMMAND,EXPECTED_RUNTIME_BUILD_ID_ENV,HostIdleHandover,agentDirMismatch,beginHandoverResponse,handoverRefusal,isHandoffBusy,isHostIdle,isTransientDaemonEnvName,parseBeginHandover,performIdleHandover,readDrainVerdicts,runAsHostGenerationProcess,withHostIdentity}from"./chunk-M7GF73FO.js";import{ENDPOINT_OWNER_FENCE_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,HAND_SELECTION_CAPABILITY,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SESSION_RELOCATION_CAPABILITY,computeRuntimeBuildId,hostGeneration,hostInstanceId,parseClientCapabilities,pathIdentityResolverStatus,protocolIdentity}from"./chunk-622VYTRI.js";import"./chunk-QMRJYMNH.js";import"./chunk-Y7Z7XPUF.js";import{isSpawnedBy}from"./chunk-54YTJCYZ.js";import"./chunk-26UBFF6N.js";import"./chunk-I5ASHSLZ.js";import"./chunk-2CNSCMYC.js";import{presenterBootstrapStream}from"./chunk-7WYJAYHH.js";import{ClientOccupancy,PublicRpcConnection,acceptInternalConnection,armHostWatchdog,closeShieldedEndpoint,consumeHostWatchdogEnv,formatSocketAddress,listen,loopLagErrorMs,prepareSocketPath,resolveSocketPath,scrubHostWatchdogEnv,unlinkOwnedEndpoint}from"./chunk-I3PHVJAS.js";import{reportStartupMilestone}from"./chunk-R2Z7CX77.js";import{CHILD_STOP_TIMEOUT_MS,SESSION_PATH_RETRY_AFTER_MS,acquireHostEnsureLock,createEndpointReservations,holderGenerationEnded,hostChildDrainRequestFile,ownGenerationDir,parseIdleExitMs,watchDrainRequest,writeHeartbeat,writeStallEvidence}from"./chunk-EAEEM2KN.js";import{HOST_DAEMON_DIR_ENV,canonicalSessionPath,createDaemonDirectories,createHostDaemonPaths,sessionDirectoryRemoved}from"./chunk-YI6KRJDC.js";import{RpcPublicEndpoint}from"./chunk-DBQBJTMF.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,serializeJsonLine}from"./chunk-SF4MQDKZ.js";import"./chunk-VPVD5G32.js";import"./chunk-H4QOEVS5.js";import"./chunk-PPQPV52D.js";import"./chunk-7VMEE62L.js";import{subscriptionLimits}from"./chunk-UBNUGVW6.js";import"./chunk-ADT36P7E.js";import"./chunk-KLAX467B.js";import"./chunk-J7FW7MED.js";import{lockWithLossHandling}from"./chunk-2EJ4BGBM.js";import"./chunk-GZVCRV7I.js";import{external_exports}from"./chunk-KUPQO7MC.js";import"./chunk-U3VOXCGP.js";import{FILE_STORAGE_LOCK_RETRY_MAX_DELAY_MS,FILE_STORAGE_LOCK_RETRY_MIN_DELAY_MS,isLockError}from"./chunk-7X72IACK.js";import"./chunk-MSDBBOB2.js";import"./chunk-WHQ2QPP5.js";import"./chunk-YUTUD26F.js";import"./chunk-WB4BUHOH.js";import"./chunk-6VWIMHMH.js";import"./chunk-SOMFLLPD.js";import"./chunk-KDUJCDLM.js";import"./chunk-YU2P3CAR.js";import"./chunk-ADOOQW3O.js";import"./chunk-KJR3XXMI.js";import"./chunk-IYL5E4QQ.js";import"./chunk-7THM57HH.js";import"./chunk-AC72EWI5.js";import"./chunk-RQFD6LG2.js";import"./chunk-527Q2UYM.js";import"./chunk-TMXRR3N7.js";import"./chunk-LPYBKMPT.js";import{killTrackedDetachedChildren}from"./chunk-WQ4RBPMS.js";import"./chunk-7PROV6BB.js";import"./chunk-EVTTLPIY.js";import"./chunk-BPNSOZ2C.js";import"./chunk-DLAY7CIU.js";import"./chunk-YUVC7SJB.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-Y7QPP7BG.js";import"./chunk-ZDHAJROE.js";import"./chunk-GVSBCJFI.js";import"./chunk-QTS2XGPQ.js";import"./chunk-Z6TEQEZO.js";import"./chunk-HJDTYAPV.js";import"./chunk-WHPDEDCC.js";import"./chunk-HK46JMSC.js";import"./chunk-WIOV3AXZ.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-OKMHSVCA.js";import"./chunk-JGKH3D6W.js";import"./chunk-3SASTB6Y.js";import"./chunk-NDNQ23SK.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-6APXZK7W.js";import"./chunk-WOHQJ6JB.js";import"./chunk-GLTOBXZY.js";import"./chunk-HXNXISJD.js";import"./chunk-ZOFZRJSL.js";import"./chunk-ZFIC2DZV.js";import"./chunk-YK3ZZCHI.js";import{privateTablePresent}from"./chunk-T2SMQPRE.js";import"./chunk-RUGTHELO.js";import"./chunk-42XRJQM6.js";import"./chunk-2SOVDETB.js";import"./chunk-IHES3JES.js";import{PUBLIC_SOCKET_IDENTITY_FILE,readSocketIdentityFile,socketEntryReplaced,waitForSocketIdentityFile}from"./chunk-5XHOHZIR.js";import{SOCKET_SECRET_FILE_ENV,authenticateSocket,ensureSocketSecret,socketSecretPath}from"./chunk-HW6AAS3R.js";import{VERSION,envValue,isBunBinary,normalizePath,resolvePath}from"./chunk-SODMQEHO.js";import"./chunk-ATQFN5HI.js";import"./chunk-EYSV6A7S.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import{BOOT_INSTANT_TOLERANCE_MS,ownProcessStartedAtMs,processBootAtMs,sameBoot}from"./chunk-44BJPS5I.js";import"./chunk-AOTHPTMU.js";import{processStartTimeMs}from"./chunk-O5RYI3IW.js";import"./chunk-IKOFCODM.js";import{createServer}from"node:net";import{rm as rm8}from"node:fs/promises";import{basename as basename2,dirname as dirname3,join as join9}from"node:path";function warmAtBootForPrivateFds(warm,profile,log){warm===void 0||!privateTablePresent()||warm(profile).catch(cause=>{log(`boot extension load failed: ${cause instanceof Error?cause.message:String(cause)}`)})}function relayExecRefusal(record){let object=typeof record=="object"&&record!==null?record:{},type=Reflect.get(object,"type");return refused(requestId(object),typeof type=="string"?type:"parse","delegation_malformed","relayExec must be a positive safe integer")}async function answerDelegation(writer,verdict,record){switch(verdict.kind){case"consumed":return;case"reply":await writer.enqueueControl(verdict.response);return;case"private":writer.writeMcpFormReply(verdict.id,{error:verdict.error});return;case"presenter":writer.handleMcpForm(record)||writer.writeMcpFormReply(verdict.id,{error:"presenter_not_authorized"});return;case"control_info":{let controlEndpoint=writer.mcpPresenterControlEndpoint;await writer.enqueueControl({...verdict.id===void 0?{}:{id:verdict.id},type:"response",command:PRESENTER_CONTROL_INFO_COMMAND,success:!0,data:controlEndpoint===void 0?{}:{controlEndpoint}});return}}}var HostCoreGate=class{constructor(registry,route,hooks){this.inFlight=new Map,this.answering=new Set,this.route=route,this.runtimeBuildId=hooks.runtimeBuildId,this.endpoint=hooks.endpoint,this.handover=hooks.handover===void 0?void 0:new HostIdleHandover({...hooks.handover,isIdle:()=>isHostIdle(registry,this.inFlight)})}async intercept(parsed,deliver){if(!isRecord(parsed)||parsed.type!==BEGIN_HANDOVER_COMMAND)return!1;let answering=this.answerBegin(parsed).then(deliver);this.answering.add(answering);try{await answering}finally{this.answering.delete(answering)}return!0}async answerBegin(parsed){if(this.handover===void 0)return beginHandoverResponse(parsed.id,{kind:"refused",reason:"handover_unsupported"});let request=parseBeginHandover(parsed);if(typeof request=="string")return beginHandoverResponse(parsed.id,request);let detail2=request.agentDir===void 0||this.endpoint===void 0?void 0:await agentDirMismatch(this.endpoint.socket,request.agentDir,this.endpoint.agentDir);return beginHandoverResponse(parsed.id,detail2===void 0?await this.handover.begin(request):{kind:"refused",reason:"foreign_agent_dir",detail:detail2})}async answered(){for(;this.answering.size>0;)await Promise.allSettled([...this.answering])}async dispatch(command){let pending=this.handover?.view();if(pending!==void 0&&this.handover?.admits(command.type)===!1)return handoverRefusal(command,pending);let key="sessionId"in command?command.sessionId:void 0;this.inFlight.set(key,(this.inFlight.get(key)??0)+1);let response;try{response=await this.route(command)}finally{let remaining=(this.inFlight.get(key)??1)-1;remaining>0?this.inFlight.set(key,remaining):this.inFlight.delete(key),this.handover?.observe()}return response===void 0?void 0:withHostIdentity(response,this.runtimeBuildId,this.handover?.view())}};function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}var REGISTRATION_LOCK_WAIT_MS=1e4;async function bindRegisteredEndpoint(registration,bind){if(registration.socket.startsWith("\0"))return bind();let release=await acquireHostEnsureLock(registration.socket,REGISTRATION_LOCK_WAIT_MS).catch(cause=>{registration.log(`endpoint ensure lock unavailable, registering without it: ${messageOf(cause)}`)});try{return await createDaemonDirectories(createHostDaemonPaths({socket:registration.socket,agentDir:registration.agentDir})).catch(cause=>registration.log(`endpoint registry record not written: ${messageOf(cause)}`)),await bind()}finally{await release?.()}}function messageOf(cause){return cause instanceof Error?cause.message:String(cause)}var HandoffAnnouncement=class{begin(superseded,identity,publicSocket,log){return this.record=superseded.then(replaced=>({type:"host_superseded",...identity,successor:replaced?{socket:publicSocket}:null}),cause=>{log(`handoff announcement failed: ${String(cause)}`)}),this.record}deliverLate(stream,arrivedBeforeDrain){let record=this.record;return!arrivedBeforeDrain||record===void 0?!1:(record.then(announced=>announced===void 0?stream.destroy():stream.end(`${JSON.stringify(announced)}
|
|
3
|
+
`)),!0)}};import{existsSync as existsSync2}from"node:fs";import{createHash}from"node:crypto";import{existsSync,renameSync}from"node:fs";import{mkdir,readdir,readFile,rm,writeFile}from"node:fs/promises";import{join}from"node:path";var CALLER_ENV_NAMES_ENV="SENPI_RPC_CALLER_ENV_NAMES",DEFAULT_CALLER_ENV_NAMES=Object.freeze(["OMOCAT_LANE"]),MAX_SESSION_ENV_ENTRIES=16,MAX_SESSION_ENV_VALUE_LENGTH=4096,ENV_NAME=/^[A-Z_][A-Z0-9_]*$/u,MAX_ECHOED_NAME_LENGTH=64;function callerEnvPassableNames(hostEnv=process.env){let names=new Set(DEFAULT_CALLER_ENV_NAMES);for(let raw of(hostEnv[CALLER_ENV_NAMES_ENV]??"").split(",")){let name=raw.trim();ENV_NAME.test(name)&&!isTransientDaemonEnvName(name)&&names.add(name)}return names}function sessionEnvShapeError(value){if(value===void 0)return;if(!isPlainRecord(value))return"env must be an object of strings.";let entries=Object.entries(value);if(entries.length>MAX_SESSION_ENV_ENTRIES)return`env allows at most ${MAX_SESSION_ENV_ENTRIES} entries.`;for(let[name,entry]of entries){if(!ENV_NAME.test(name))return`env name "${echoedName(name)}" must match ${ENV_NAME.source}.`;if(typeof entry!="string")return`env.${echoedName(name)} must be a string.`;if(entry.includes("\0"))return`env.${echoedName(name)} must not contain NUL.`;if(entry.length>MAX_SESSION_ENV_VALUE_LENGTH)return`env.${echoedName(name)} must be at most ${MAX_SESSION_ENV_VALUE_LENGTH} characters.`}}function sessionEnvError(value,hostEnv=process.env){let shape=sessionEnvShapeError(value);if(shape!==void 0||!isPlainRecord(value))return shape;let passable=callerEnvPassableNames(hostEnv);for(let name of Object.keys(value))if(!passable.has(name))return`env.${echoedName(name)} is not a caller-passable name (passable: ${[...passable].sort().join(", ")}).`}function inheritedSessionEnv(parent,requested){let merged={...parent,...requested};return Object.keys(merged).length===0?void 0:merged}function echoedName(name){return name.length>MAX_ECHOED_NAME_LENGTH?`${name.slice(0,MAX_ECHOED_NAME_LENGTH)}...`:name}function isPlainRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}import{hostname}from"node:os";var realWriterProbes={pidAlive:pid=>{try{return process.kill(pid,0),!0}catch(error2){return errorCode(error2)==="EPERM"}},readProcessStartMs,bootAtMs:()=>processBootAtMs(),host:()=>hostname(),self:()=>({pid:process.pid,processStartedAtMs:ownProcessStartedAtMs()})};function currentResidentWriter(probes=realWriterProbes){let self=probes.self();return{host:probes.host(),pid:self.pid,bootAtMs:probes.bootAtMs(),processStartedAtMs:self.processStartedAtMs}}function isResidentWriter(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;let record=value;return typeof record.host=="string"&&Number.isInteger(record.pid)&&typeof record.bootAtMs=="number"&&typeof record.processStartedAtMs=="number"}function residentWriterProbe(probes=realWriterProbes){let gone=new Set,verified=new Set;return async writer=>{let key=`${writer.host}:${writer.pid}:${writer.processStartedAtMs}`;if(gone.has(key))return!1;if(writer.host!==probes.host())return!0;if(!sameBoot(probes.bootAtMs(),writer.bootAtMs)||!probes.pidAlive(writer.pid))return gone.add(key),!1;if(verified.has(key))return!0;let startedAtMs=await probes.readProcessStartMs(writer.pid);return startedAtMs!==void 0&&Math.abs(startedAtMs-writer.processStartedAtMs)>BOOT_INSTANT_TOLERANCE_MS?(gone.add(key),!1):(verified.add(key),!0)}}var recordDir=daemonDir=>join(daemonDir,"handover-parked"),entryFile=(daemonDir,sessionPath)=>join(recordDir(daemonDir),`${createHash("sha256").update(sessionPath,"utf8").digest("hex").slice(0,16)}.json`),mutationChain=Promise.resolve();function enqueueMutation(mutation){let next=mutationChain.then(mutation,mutation);return mutationChain=next.catch(()=>{}),next}function isEntry(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;let record=value;return typeof record.sessionPath=="string"&&typeof record.retainOnDisconnect=="boolean"&&(record.durableSessionId===void 0||typeof record.durableSessionId=="string")&&(record.cwd===void 0||typeof record.cwd=="string")&&(record.parkedBy===void 0||typeof record.parkedBy=="string")&&(record.residentWriter===void 0||isResidentWriter(record.residentWriter))&&(record.thinkingLevel===void 0||typeof record.thinkingLevel=="string")&&(record.permissionPreset===void 0||typeof record.permissionPreset=="string"&&parsePermissionPresetName(record.permissionPreset)!==void 0)&&sessionPromptSurfaceError(record.promptSurface)===void 0&&sessionBrowserEngineError(record.browserEngine)===void 0&&sessionKindError(record.sessionKind)===void 0&&sessionContextError(record.sessionContext)===void 0&&(record.contextOverlay===void 0||!("refusal"in applyContextPatch(void 0,record.contextOverlay)))&&sessionAutoTitleError(record.autoTitle)===void 0&&sessionRetryFallbackError(record.retryFallback)===void 0&&sessionEnvShapeError(record.sessionEnv)===void 0&&(record.model===void 0||typeof record.model=="object"&&record.model!==null&&typeof record.model.provider=="string"&&typeof record.model.modelId=="string")}async function writeEntryFile(daemonDir,entry){await mkdir(recordDir(daemonDir),{recursive:!0,mode:448});let file=entryFile(daemonDir,entry.sessionPath),tmp=`${file}.${process.pid}.${Math.random().toString(16).slice(2,10)}.tmp`;await writeFile(tmp,`${JSON.stringify(entry,null,2)}
|
|
4
4
|
`,{mode:384}),renameSync(tmp,file)}function recordHandoverParkedSession(daemonDir,entry){return enqueueMutation(()=>writeEntryFile(daemonDir,entry))}async function readHandoverParkedSessions(daemonDir){let names;try{names=(await readdir(recordDir(daemonDir))).filter(name=>name.endsWith(".json"))}catch{return[]}let entries=[];for(let name of names){let file=join(recordDir(daemonDir),name);try{let parsed=JSON.parse(await readFile(file,"utf8"));isEntry(parsed)&&entries.push(parsed)}catch(cause){cause instanceof SyntaxError&&(process.stderr.write(`senpi rpc handover-parked entry ${name} is corrupt; dropping it
|
|
5
|
-
`),await rm(file,{force:!0}))}}return entries}function clearHandoverParkedSession(daemonDir,sessionPath){return enqueueMutation(()=>rm(entryFile(daemonDir,sessionPath),{force:!0}))}function dropHandoverParkedSessionIfFileGone(daemonDir,sessionPath){return existsSync(sessionPath)?Promise.resolve():clearHandoverParkedSession(daemonDir,sessionPath)}var HANDOVER_PARKED_REOPEN_BUDGET_MS=12e4,HANDOVER_PARKED_REOPEN_POLL_MS=250,HANDOVER_PARKED_REOPEN_MAX_ATTEMPTS=8,HANDOVER_PARKED_REOPEN_QUIET_STREAK=8;async function reopenHandoverParkedSessions(open2,agentDir,socket,holder){let daemonDir=createHostDaemonPaths({socket,agentDir}).dir,deadline=Date.now()+HANDOVER_PARKED_REOPEN_BUDGET_MS,reopenAttempts=new Map,heldPolls=new Map,emptyStreak=0,sawAnyPark=!1;for(;;){if(holder?.shouldReopen!==void 0&&!holder.shouldReopen())return;let parked=await inheritedParks(daemonDir,holder);for(let entry of parked)sawAnyPark=!0,await reopenOne(daemonDir,open2,entry,reopenAttempts,heldPolls,holder);let remaining=(await inheritedParks(daemonDir,holder)).length;if(holder?.shouldReopen!==void 0&&!holder.shouldReopen()||(emptyStreak=remaining===0?emptyStreak+1:0,sawAnyPark&&emptyStreak>=HANDOVER_PARKED_REOPEN_QUIET_STREAK)||Date.now()>=deadline)return;await new Promise(resolve2=>setTimeout(resolve2,HANDOVER_PARKED_REOPEN_POLL_MS))}}async function inheritedParks(daemonDir,holder){
|
|
5
|
+
`),await rm(file,{force:!0}))}}return entries}function clearHandoverParkedSession(daemonDir,sessionPath){return enqueueMutation(()=>rm(entryFile(daemonDir,sessionPath),{force:!0}))}function clearInheritedParkedSession(daemonDir,sessionPath,holder){return enqueueMutation(async()=>{let file=entryFile(daemonDir,sessionPath);if(holder!==void 0){let recorded=await readFile(file,"utf8").then(text2=>JSON.parse(text2),()=>{});if(isEntry(recorded)&&recorded.parkedBy===holder)return}await rm(file,{force:!0})})}function dropHandoverParkedSessionIfFileGone(daemonDir,sessionPath){return existsSync(sessionPath)?Promise.resolve():clearHandoverParkedSession(daemonDir,sessionPath)}var HANDOVER_PARKED_REOPEN_BUDGET_MS=12e4,HANDOVER_PARKED_REOPEN_POLL_MS=250,HANDOVER_PARKED_REOPEN_MAX_ATTEMPTS=8,HANDOVER_PARKED_REOPEN_QUIET_STREAK=8;async function reopenHandoverParkedSessions(open2,agentDir,socket,holder){let daemonDir=createHostDaemonPaths({socket,agentDir}).dir,deadline=Date.now()+HANDOVER_PARKED_REOPEN_BUDGET_MS,reopenAttempts=new Map,heldPolls=new Map,writerAlive=residentWriterProbe(),emptyStreak=0,sawAnyPark=!1;for(;;){if(holder?.shouldReopen!==void 0&&!holder.shouldReopen())return;let parked=await inheritedParks(daemonDir,holder,writerAlive);for(let entry of parked)sawAnyPark=!0,await reopenOne(daemonDir,open2,entry,reopenAttempts,heldPolls,holder);let remaining=(await inheritedParks(daemonDir,holder,writerAlive)).length;if(holder?.shouldReopen!==void 0&&!holder.shouldReopen()||(emptyStreak=remaining===0?emptyStreak+1:0,sawAnyPark&&emptyStreak>=HANDOVER_PARKED_REOPEN_QUIET_STREAK)||Date.now()>=deadline)return;await new Promise(resolve2=>setTimeout(resolve2,HANDOVER_PARKED_REOPEN_POLL_MS))}}async function inheritedParks(daemonDir,holder,writerAlive){let parked=await readHandoverParkedSessions(daemonDir),inherited=[];for(let entry of parked)entry.parkedBy!==void 0&&entry.parkedBy===holder?.hostInstance||entry.residentWriter!==void 0&&await writerAlive(entry.residentWriter)||inherited.push(entry);return inherited}async function reopenOne(daemonDir,open2,entry,attempts,heldPolls,holder){let taskStatus=entry.contextOverlay&&Object.hasOwn(entry.contextOverlay,"task_status")?entry.contextOverlay.task_status:entry.sessionContext?.task_status;if(typeof taskStatus=="string"&&["completed","cancelled","error","failed","lost","interrupted"].includes(taskStatus)){await clearHandoverParkedSession(daemonDir,entry.sessionPath),process.stderr.write(`senpi rpc successor dropped a terminal parked session (${taskStatus}): ${entry.sessionPath}
|
|
6
6
|
`);return}if(await dropHandoverParkedSessionIfFileGone(daemonDir,entry.sessionPath),!existsSync2(entry.sessionPath)){process.stderr.write(`senpi rpc successor dropped a parked session whose file is gone: ${entry.sessionPath}
|
|
7
|
-
`);return}try{if(await open2(entry),holder?.shouldReopen!==void 0&&!holder.shouldReopen())return;await
|
|
7
|
+
`);return}try{if(await open2(entry),holder?.shouldReopen!==void 0&&!holder.shouldReopen())return;await clearInheritedParkedSession(daemonDir,entry.sessionPath,holder?.hostInstance)}catch(cause){if(cause instanceof RpcSessionRegistryError&&cause.code==="session_path_in_use"){let polls=(heldPolls?.get(entry.sessionPath)??0)+1;heldPolls?.set(entry.sessionPath,polls),(polls===1||polls%40===0)&&process.stderr.write(`senpi rpc successor reopen parked session ${entry.sessionPath} waiting on the holder: ${String(cause)}
|
|
8
8
|
`);return}let tried=(attempts.get(entry.sessionPath)??0)+1;if(attempts.set(entry.sessionPath,tried),tried>=HANDOVER_PARKED_REOPEN_MAX_ATTEMPTS){process.stderr.write(`senpi rpc successor gave up reopening parked session ${entry.sessionPath} after ${tried} attempts: ${String(cause)}
|
|
9
9
|
`),await clearHandoverParkedSession(daemonDir,entry.sessionPath);return}process.stderr.write(`senpi rpc successor reopen parked session ${entry.sessionPath} failed: ${String(cause)}
|
|
10
10
|
`)}}var RPC_SESSION_IDLE_EVICTION_MS_ENV="SENPI_RPC_SESSION_IDLE_EVICTION_MS",RPC_HOST_EMPTY_EXIT_MS_ENV="SENPI_RPC_HOST_EMPTY_EXIT_MS",RPC_CLOSE_GRACE_MS_ENV="SENPI_RPC_CLOSE_GRACE_MS",DEFAULT_SESSION_IDLE_EVICTION_MS=30*6e4,DEFAULT_HOST_EMPTY_EXIT_MS=15*6e4;function resolveHostIdlePolicy(env,overrides={}){return{now:overrides.now??Date.now,idleEvictionMs:overrides.idleEvictionMs??parseIdleExitMs(env[RPC_SESSION_IDLE_EVICTION_MS_ENV])??DEFAULT_SESSION_IDLE_EVICTION_MS,emptyExitMs:overrides.emptyExitMs??parseIdleExitMs(env[RPC_HOST_EMPTY_EXIT_MS_ENV])??DEFAULT_HOST_EMPTY_EXIT_MS}}var binding;function hostWatchdogBinding(){return binding??={config:consumeHostWatchdogEnv()},binding.config}function internalHostTransport(configured,secret,endpoint){let bootstrap=getInternalHostBootstrap();scrubHostWatchdogEnv();let watchdogConfig=configured&&{...configured,...bootstrap?.lifetimeFd===void 0?{}:{lifetimeFd:bootstrap.lifetimeFd}},publicEndpoint=endpoint!==void 0&&process.platform!=="win32"&&bootstrap===void 0?new RpcPublicEndpoint(endpoint.agentDir,endpoint.socket):void 0;return{watchdogConfig,admit(socket,accept){bootstrap?acceptInternalConnection(socket,bootstrap.key,{protocolVersion:1,serverVersion:VERSION}).then(hop=>accept(hop,"in_band")).catch(cause=>{process.stderr.write(`senpi rpc host: internal connection refused: ${cause instanceof Error?cause.message:"unknown"}
|
|
11
11
|
`),socket.destroy()}):secret?authenticateSocket(socket,secret,()=>accept(void 0,"proven")):publicEndpoint?accept(new PublicRpcConnection(socket,publicEndpoint).stream,"in_band"):accept()},async publish(onFailure){try{await publicEndpoint?.publish()}catch(cause){endpoint?.log(cause instanceof Error?cause.message:String(cause)),await onFailure()}},async dispose(){await publicEndpoint?.dispose().catch(cause=>{endpoint?.log(`endpoint key cleanup failed: ${cause instanceof Error?cause.message:String(cause)}`)})}}}var HOST_RSS_WARN_MB_ENV="SENPI_RPC_HOST_RSS_WARN_MB",DEFAULT_HOST_RSS_WARN_MB=4096,HOST_MEMORY_SAMPLE_MS=3e4,HOST_MEMORY_STDERR_INTERVAL_MS=5*6e4,BYTES_PER_MEGABYTE=1024*1024;function parsePositiveInteger(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isFinite(parsed)&&parsed>0?parsed:void 0}var HostMemorySampler=class{constructor(options){this.pressure=!1,this.idleReported=!1;let env=options.env??process.env;this.emit=options.emit,this.sessions=options.sessions,this.onPressure=options.onPressure,options.onIdlePressure&&(this.onIdlePressure=options.onIdlePressure),this.log=options.log??(message=>{process.stderr.write(message)}),this.now=options.now??Date.now,this.readFootprint=options.readFootprint??readOwnFootprint,this.readRssBytes=options.readRssBytes??(()=>process.memoryUsage.rss()),this.readKernels=options.readKernels??readCodemodeKernelRows,this.readMainHeap=options.readMainHeap??readMainThreadHeapBytes,this.warnMb=parsePositiveInteger(env[HOST_RSS_WARN_MB_ENV])??DEFAULT_HOST_RSS_WARN_MB}start(){this.timer===void 0&&(this.timer=setInterval(()=>this.sample(),HOST_MEMORY_SAMPLE_MS),this.timer.unref?.())}stop(){this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0)}sample(){let footprint=this.readFootprint(),reading={footprintMb:Math.round(footprint.bytes/BYTES_PER_MEGABYTE),measure:footprint.measure,rssMb:Math.round(this.readRssBytes()/BYTES_PER_MEGABYTE),main:{heapBytes:this.readMainHeap()},kernels:this.readKernels()};if(reading.footprintMb<=this.warnMb){if(this.idleReported=!1,!this.pressure)return;this.pressure=!1,this.onPressure(!1);return}this.pressure||(this.pressure=!0,this.onPressure(!0));let sessions=this.sessions();sessions>0?this.idleReported=!1:this.idleReported||(this.idleReported=!0,this.onIdlePressure?.(reading));let{footprintMb,measure,rssMb}=reading;this.emit({type:"host_memory_pressure",rssMb,footprintMb,measure,sessions,main:reading.main,kernels:reading.kernels});let now=this.now();this.lastLoggedAt!==void 0&&now-this.lastLoggedAt<HOST_MEMORY_STDERR_INTERVAL_MS||(this.lastLoggedAt=now,this.log(`senpi rpc host memory pressure: footprintMb=${footprintMb} (${measure}) rssMb=${rssMb} sessions=${sessions} (idle parking halved)
|
|
12
12
|
`))}};var ZERO_SESSION_TRIM_TICK_MS=1e3,ZERO_SESSION_TRIM_MIN_INTERVAL_MS=6e4,DECLINE_TRIM_FLOOR_BYTES=2*1024*1024*1024,DECLINE_TRIM_PAUSE_FACTOR=100,BYTES_PER_MEGABYTE2=1024*1024,ZeroSessionTrimmer=class{constructor(options){this.heldSessions=!1,this.lastSessionCount=0,this.declined=!1,this.zeroPending=!1,this.lastPauseMs=0,this.started=!1,this.options=options,this.now=options.now??Date.now}start(){this.started=!0,this.arm()}stop(){this.started=!1,this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0)}observe(size){size>0&&(this.heldSessions=!0),size<this.lastSessionCount&&(this.declined=!0),this.lastSessionCount=size,this.arm()}check(){this.evaluate(),this.arm()}owesTick(){return this.pending!==void 0||this.declined||this.zeroPending||this.heldSessions&&this.lastSessionCount===0}arm(){!this.started||this.timer!==void 0||!this.owesTick()||(this.timer=setTimeout(()=>{this.timer=void 0,this.check()},ZERO_SESSION_TRIM_TICK_MS),this.timer.unref?.())}evaluate(){this.pending!==void 0&&this.report(this.pending);let sessions=this.options.sessions();if(sessions<this.lastSessionCount&&(this.declined=!0),this.lastSessionCount=sessions,sessions>0){if(this.heldSessions=!0,this.zeroPending=!1,!this.declined||!this.busyIntervalElapsed())return;this.declined=!1,this.readFootprint().bytes>=DECLINE_TRIM_FLOOR_BYTES&&this.trim(sessions);return}if(this.declined=!1,!(!this.heldSessions&&!this.zeroPending)){if(this.heldSessions=!1,!this.intervalElapsed(ZERO_SESSION_TRIM_MIN_INTERVAL_MS)){this.zeroPending=!0;return}this.zeroPending=!1,this.trim(0)}}intervalElapsed(minimumMs){return this.lastTrimAt===void 0||this.now()-this.lastTrimAt>=minimumMs}busyIntervalElapsed(){return this.intervalElapsed(Math.max(ZERO_SESSION_TRIM_MIN_INTERVAL_MS,this.lastPauseMs*DECLINE_TRIM_PAUSE_FACTOR))}trim(sessions){let beforeBytes=this.readFootprint().bytes,monotonicNow=this.options.monotonicNow??performance.now.bind(performance),startedAt=monotonicNow(),collected=(this.options.collect??collectFully)();this.lastPauseMs=Math.round(monotonicNow()-startedAt),this.lastTrimAt=this.now(),this.pending={beforeBytes,collected,sessions,pauseMs:this.lastPauseMs}}report(pending){this.pending=void 0;let after=this.readFootprint();this.options.emit({type:"host_trimmed",footprintBeforeMb:Math.round(pending.beforeBytes/BYTES_PER_MEGABYTE2),footprintAfterMb:Math.round(after.bytes/BYTES_PER_MEGABYTE2),measure:after.measure,collected:pending.collected,sessions:pending.sessions,pauseMs:pending.pauseMs})}readFootprint(){return(this.options.readFootprint??readOwnFootprint)()}};function collectFully(){let bun=Reflect.get(globalThis,"Bun"),bunGc=typeof bun=="object"&&bun!==null?Reflect.get(bun,"gc"):void 0;if(typeof bunGc=="function")return Reflect.apply(bunGc,bun,[!0]),!0;let nodeGc=Reflect.get(globalThis,"gc");return typeof nodeGc!="function"?!1:(Reflect.apply(nodeGc,globalThis,[]),!0)}import{AsyncLocalStorage}from"node:async_hooks";var attributionStore=new AsyncLocalStorage,sequence=0,openActivities=new Map,activityStartListeners=new Set;function onSessionActivityStart(listener){return activityStartListeners.add(listener),()=>activityStartListeners.delete(listener)}function notifyActivityStarted(){for(let listener of activityStartListeners)listener()}var lastFinished;function runWithSessionAttribution(attribution,task){let mark=++sequence;openActivities.set(mark,attribution),notifyActivityStarted();let finish=()=>{openActivities.delete(mark)&&(lastFinished={sequence:++sequence,attribution})},awaited=!1;try{let result=attributionStore.run(attribution,task);return isPromiseLike(result)&&(awaited=!0,Promise.resolve(result).then(finish,finish)),result}finally{awaited||finish()}}function isPromiseLike(value){return typeof value=="object"&&value!==null&&"then"in value&&typeof value.then=="function"}function openSessionAttributionSpan(attribution){let ambient=attributionStore.getStore(),sessionId=attribution.sessionId??ambient?.sessionId,merged={...sessionId!==void 0?{sessionId}:{},...attribution.tool!==void 0?{tool:attribution.tool}:{},...attribution.job!==void 0?{job:attribution.job}:{}},mark=++sequence;return openActivities.set(mark,merged),notifyActivityStarted(),()=>{openActivities.delete(mark)&&(lastFinished={sequence:++sequence,attribution:merged})}}function describeAttribution(attribution){if(attribution?.sessionId===void 0&&attribution?.tool===void 0&&attribution?.job===void 0)return"no attributed session";let tool=attribution.tool?` tool=${attribution.tool}`:"",job=attribution.job?` job=${attribution.job}`:"";return`sessionId=${attribution.sessionId??"unknown"}${tool}${job}`}function sessionActivityMark(){return sequence}function sessionActivitySince(mark){if(lastFinished!==void 0&&lastFinished.sequence>mark)return lastFinished.attribution;let newest;for(let attribution of openActivities.values())newest=attribution;return newest}function toolRecord(record){if(!(!("type"in record)||typeof record.type!="string"))return{type:record.type,toolCallId:"toolCallId"in record&&typeof record.toolCallId=="string"?record.toolCallId:void 0,toolName:"toolName"in record&&typeof record.toolName=="string"?record.toolName:void 0}}function createToolAttributionSpans(sessionId){let spans=new Map,closeAll=()=>{for(let close2 of spans.values())close2();spans.clear()};return{closeAll,observe:record=>{let parsed=toolRecord(record);if(parsed!==void 0){if(parsed.type==="tool_execution_start"&&parsed.toolCallId!==void 0){spans.get(parsed.toolCallId)?.(),spans.set(parsed.toolCallId,openSessionAttributionSpan({sessionId,tool:parsed.toolName}));return}if(parsed.type==="tool_execution_end"&&parsed.toolCallId!==void 0){spans.get(parsed.toolCallId)?.(),spans.delete(parsed.toolCallId);return}(parsed.type==="agent_settled"||parsed.type==="agent_idle")&&closeAll()}}}}var LOOP_LAG_WARN_MS_ENV="SENPI_RPC_LOOP_LAG_WARN_MS",DEFAULT_LOOP_LAG_WARN_MS=500,LOOP_LAG_TICK_MS=200,LOOP_LAG_IDLE_TICK_MS=1e3,LOOP_LAG_IDLE_AFTER_MS=2e3,LOOP_LAG_WARN_INTERVAL_MS=1e4,HEARTBEAT_THRESHOLD_FRACTION=5,HEARTBEAT_EARLY_TOLERANCE_MS=LOOP_LAG_TICK_MS/2,BYTES_PER_MB=1024*1024;function describeWindow(processCpuMs,heapDeltaMb){return`cpu=${processCpuMs}ms heap=${heapDeltaMb>=0?"+":""}${heapDeltaMb}MB`}var LoopLagWatchdog=class{constructor(options){this.intervalMs=LOOP_LAG_TICK_MS,this.quietMs=0,this.activityMark=0,this.cpuMicrosAtTick=0,this.heapBytesAtTick=0,this.heartbeatInFlight=!1,this.launchParentPid=process.ppid,this.evidenceFailureLogged=!1;let env=options.env??process.env;this.emit=options.emit,this.log=options.log??(message=>{process.stderr.write(message)}),this.now=options.now??Date.now,this.cpuUsage=options.cpuUsage??(()=>process.cpuUsage()),this.heapUsed=options.heapUsed??(()=>process.memoryUsage().heapUsed),this.writeHeartbeat=options.writeHeartbeat??writeHeartbeat,this.warnMs=parseIdleExitMs(env[LOOP_LAG_WARN_MS_ENV])??DEFAULT_LOOP_LAG_WARN_MS,this.errorMs=loopLagErrorMs(env),this.heartbeatIntervalMs=Math.max(LOOP_LAG_TICK_MS,Math.floor(this.errorMs/HEARTBEAT_THRESHOLD_FRACTION)),this.idleIntervalMs=Math.min(LOOP_LAG_IDLE_TICK_MS,this.heartbeatIntervalMs),this.evidenceDir=ownGenerationDir(env)}start(){if(this.timer!==void 0)return;this.intervalMs=LOOP_LAG_TICK_MS,this.quietMs=0,this.expectedTickAt=this.now()+LOOP_LAG_TICK_MS,this.activityMark=sessionActivityMark();let cpu=this.cpuUsage();this.cpuMicrosAtTick=cpu.user+cpu.system,this.heapBytesAtTick=this.heapUsed(),this.unsubscribeActivity=onSessionActivityStart(()=>this.wake()),this.schedule()}wake(){this.quietMs=0,!(this.timer===void 0||this.intervalMs===LOOP_LAG_TICK_MS)&&(clearTimeout(this.timer),this.intervalMs=LOOP_LAG_TICK_MS,this.expectedTickAt=this.now()+LOOP_LAG_TICK_MS,this.schedule())}schedule(){this.timer=setTimeout(()=>{this.tick(),this.timer!==void 0&&this.schedule()},this.intervalMs),this.timer.unref?.()}stop(){this.unsubscribeActivity?.(),this.unsubscribeActivity=void 0,this.timer!==void 0&&(clearTimeout(this.timer),this.timer=void 0,this.expectedTickAt=void 0)}tick(){let now=this.now(),expectedAt=this.expectedTickAt??now,previousMark=this.activityMark;this.activityMark=sessionActivityMark();let quiet=this.activityMark===previousMark&&sessionActivitySince(previousMark)===void 0;this.quietMs=quiet?this.quietMs+this.intervalMs:0,this.intervalMs=this.quietMs>=LOOP_LAG_IDLE_AFTER_MS?this.idleIntervalMs:LOOP_LAG_TICK_MS,this.expectedTickAt=now+this.intervalMs;let cpu=this.cpuUsage(),cpuMicros=cpu.user+cpu.system,heapBytes=this.heapUsed(),previousCpuMicros=this.cpuMicrosAtTick,previousHeapBytes=this.heapBytesAtTick;this.cpuMicrosAtTick=cpuMicros,this.heapBytesAtTick=heapBytes;let driftMs=Math.round(now-expectedAt);if(recordLoopBlockedMs(driftMs),driftMs<=this.warnMs){this.beat(now);return}let attribution=sessionActivitySince(previousMark),processCpuMs=Math.round((cpuMicros-previousCpuMicros)/1e3),heapDeltaMb=Math.round((heapBytes-previousHeapBytes)/BYTES_PER_MB);if(driftMs>this.errorMs){let record={type:"host_stalled",driftMs,sessionId:attribution?.sessionId,tool:attribution?.tool,processCpuMs,heapDeltaMb};this.emit(record),this.persistStall(now,record)}this.lastWarnAt!==void 0&&now-this.lastWarnAt<LOOP_LAG_WARN_INTERVAL_MS||(this.lastWarnAt=now,this.log(`senpi rpc host stall: event loop blocked ${driftMs}ms (${describeAttribution(attribution)}; ${describeWindow(processCpuMs,heapDeltaMb)})
|
|
13
13
|
`))}beat(now){if(!this.ownsEvidenceDir()||this.evidenceDir===void 0||this.heartbeatInFlight)return;let due=this.heartbeatIntervalMs-HEARTBEAT_EARLY_TOLERANCE_MS;this.lastHeartbeatAt!==void 0&&now-this.lastHeartbeatAt<due||(this.lastHeartbeatAt=now,this.heartbeatInFlight=!0,this.writeHeartbeat(this.evidenceDir,new Date(now).toISOString()).catch(cause=>this.evidenceFailed(cause)).finally(()=>{this.heartbeatInFlight=!1}))}persistStall(now,record){!this.ownsEvidenceDir()||this.evidenceDir===void 0||writeStallEvidence(this.evidenceDir,{at:new Date(now).toISOString(),driftMs:record.driftMs,processCpuMs:record.processCpuMs??0,heapDeltaMb:record.heapDeltaMb??0,...record.sessionId?{sessionId:record.sessionId}:{},...record.tool?{tool:record.tool}:{}}).catch(cause=>this.evidenceFailed(cause))}ownsEvidenceDir(){return process.ppid===this.launchParentPid}evidenceFailed(cause){this.evidenceFailureLogged||(this.evidenceFailureLogged=!0,this.log(`senpi rpc host stall evidence not written: ${cause instanceof Error?cause.message:String(cause)}
|
|
14
|
-
`))}};function startHostObservers(router,writer,options){let loopLag=new LoopLagWatchdog({emit:record=>writer.broadcastHostRecord(record)}),kernels=readCodemodeKernelRows,memory=new HostMemorySampler({emit:record=>writer.broadcastHostRecord(record),sessions:()=>router.sessionCount,onPressure:pressure=>router.setMemoryPressure(pressure),readKernels:kernels,...options.onIdlePressure?{onIdlePressure:options.onIdlePressure}:{}});router.setHostMemoryView({mainHeapBytes:readMainThreadHeapBytes,kernels});let{trim}=options;return loopLag.start(),memory.start(),trim.start(),{stop:()=>{loopLag.stop(),memory.stop(),trim.stop()}}}function createZeroSessionTrim(writer,sessions){return new ZeroSessionTrimmer({emit:record=>writer.broadcastHostRecord(record),sessions})}var HOST_EXIT_RESERVE_MS=3e3,HOST_SHUTDOWN_BUDGET_MS=CHILD_STOP_TIMEOUT_MS-HOST_EXIT_RESERVE_MS;async function closeHostConnections(connections,drain,startedAt,log){let deadline=startedAt+HOST_SHUTDOWN_BUDGET_MS;await Promise.all(connections.map(async connection=>{await beforeDeadline(drain(connection.id),deadline),await beforeDeadline(connection.close("host_shutdown"),deadline)}));for(let connection of connections)connection.detach();let force=setTimeout(()=>{let open2=connections.filter(({socket})=>!socket.destroyed);if(open2.length!==0){log(`shutdown budget spent after ${Date.now()-startedAt} ms; destroying ${open2.length} open connection(s)`);for(let{socket}of open2)socket.destroy()}},Math.max(0,deadline-Date.now()));return()=>clearTimeout(force)}function beforeDeadline(work,deadline){let timer,expired=new Promise(resolve2=>{timer=setTimeout(resolve2,Math.max(0,deadline-Date.now()))});return Promise.race([work.then(()=>{}),expired]).finally(()=>clearTimeout(timer))}
|
|
15
|
-
`),
|
|
16
|
-
`)
|
|
17
|
-
`)}).
|
|
18
|
-
`)})
|
|
14
|
+
`))}};function startHostObservers(router,writer,options){let loopLag=new LoopLagWatchdog({emit:record=>writer.broadcastHostRecord(record)}),kernels=readCodemodeKernelRows,memory=new HostMemorySampler({emit:record=>writer.broadcastHostRecord(record),sessions:()=>router.sessionCount,onPressure:pressure=>router.setMemoryPressure(pressure),readKernels:kernels,...options.onIdlePressure?{onIdlePressure:options.onIdlePressure}:{}});router.setHostMemoryView({mainHeapBytes:readMainThreadHeapBytes,kernels});let{trim}=options;return loopLag.start(),memory.start(),trim.start(),{stop:()=>{loopLag.stop(),memory.stop(),trim.stop()}}}function createZeroSessionTrim(writer,sessions){return new ZeroSessionTrimmer({emit:record=>writer.broadcastHostRecord(record),sessions})}var HOST_EXIT_RESERVE_MS=3e3,HOST_SHUTDOWN_BUDGET_MS=CHILD_STOP_TIMEOUT_MS-HOST_EXIT_RESERVE_MS;async function closeHostConnections(connections,drain,startedAt,log){let deadline=startedAt+HOST_SHUTDOWN_BUDGET_MS;await Promise.all(connections.map(async connection=>{await beforeDeadline(drain(connection.id),deadline),await beforeDeadline(connection.close("host_shutdown"),deadline)}));for(let connection of connections)connection.detach();let force=setTimeout(()=>{let open2=connections.filter(({socket})=>!socket.destroyed);if(open2.length!==0){log(`shutdown budget spent after ${Date.now()-startedAt} ms; destroying ${open2.length} open connection(s)`);for(let{socket}of open2)socket.destroy()}},Math.max(0,deadline-Date.now()));return()=>clearTimeout(force)}function beforeDeadline(work,deadline){let timer,expired=new Promise(resolve2=>{timer=setTimeout(resolve2,Math.max(0,deadline-Date.now()))});return Promise.race([work.then(()=>{}),expired]).finally(()=>clearTimeout(timer))}function holdUnattendedTurns(host){for(let{sessionId,status,attachments}of host.registry.list()){if(status!=="open"||attachments>0||host.drainHeldSessions.has(sessionId))continue;let session=host.registry.peek(sessionId)?.runtime?.session;if(session!==void 0){host.drainHeldSessions.add(sessionId);try{session.holdAutomaticTurns()}catch(cause){process.stderr.write(`senpi rpc handoff could not hold automatic turns of ${sessionId}: ${String(cause)}
|
|
15
|
+
`)}}}}var THINKING_LEVELS=["off","minimal","low","medium","high","xhigh","max"],thinkingLevelOf=value=>THINKING_LEVELS.find(level=>level===value);function parkedEntryFromProfile(session,profile,hostContextKeys){let clientContext=profile?.sessionContext===void 0?void 0:Object.fromEntries(Object.entries(profile.sessionContext).filter(([key])=>!hostContextKeys.includes(key)));return{sessionPath:session.sessionPath,...session.durableSessionId!==void 0?{durableSessionId:session.durableSessionId}:{},retainOnDisconnect:!0,...session.contextOverlay!==void 0?{contextOverlay:session.contextOverlay}:{},...profile?.cwd!==void 0?{cwd:profile.cwd}:{},...profile?.creationModel!==void 0?{model:profile.creationModel}:{},...profile?.initialThinkingLevel!==void 0?{thinkingLevel:profile.initialThinkingLevel}:{},...profile?.permissionPreset!==void 0?{permissionPreset:profile.permissionPreset}:{},...profile?.promptSurface!==void 0?{promptSurface:profile.promptSurface}:{},...profile?.browserEngine!==void 0?{browserEngine:profile.browserEngine}:{},...profile?.sessionKind!==void 0?{sessionKind:profile.sessionKind}:{},...clientContext!==void 0&&Object.keys(clientContext).length>0?{sessionContext:clientContext}:{},...profile?.autoTitle!==void 0?{autoTitle:profile.autoTitle}:{},...profile?.retryFallback!==void 0?{retryFallback:profile.retryFallback}:{},...profile?.sessionEnv!==void 0?{sessionEnv:profile.sessionEnv}:{}}}function parkedOpenCommand(entry){let thinkingLevel=thinkingLevelOf(entry.thinkingLevel);return entry.thinkingLevel!==void 0&&thinkingLevel===void 0&&process.stderr.write(`senpi rpc successor reopens ${entry.sessionPath} without its unknown thinking level "${entry.thinkingLevel}"
|
|
16
|
+
`),{type:"open_session",sessionPath:entry.sessionPath,...entry.cwd!==void 0?{cwd:entry.cwd}:{},...entry.durableSessionId!==void 0?{durableSessionId:entry.durableSessionId}:{},...entry.model!==void 0?{provider:entry.model.provider,modelId:entry.model.modelId}:{},...thinkingLevel!==void 0?{thinkingLevel}:{},...entry.permissionPreset!==void 0?{permissionPreset:entry.permissionPreset}:{},...entry.promptSurface!==void 0?{promptSurface:entry.promptSurface}:{},...entry.browserEngine!==void 0?{browserEngine:entry.browserEngine}:{},...entry.sessionKind!==void 0?{kind:entry.sessionKind}:{},...entry.sessionContext!==void 0?{context:entry.sessionContext}:{},...entry.autoTitle!==void 0?{auto_title:entry.autoTitle}:{},...entry.retryFallback!==void 0?{retryFallback:entry.retryFallback}:{},...entry.sessionEnv!==void 0?{env:{...entry.sessionEnv}}:{},retain_on_disconnect:entry.retainOnDisconnect}}var reportRecordFailure=sessionId=>cause=>{process.stderr.write(`senpi rpc retained session record ${sessionId} failed: ${String(cause)}
|
|
17
|
+
`)};async function recordRetainedSession(host,retained,sessionPath,resident){let dir=host.handoverParkedDir;if(dir===void 0)return;let previous=retained.recordedPath;retained.recordedPath=sessionPath,previous!==void 0&&previous!==sessionPath&&await clearHandoverParkedSession(dir,previous);let durableSessionId=retained.runtime?.session.sessionId??retained.durableSessionId;await recordHandoverParkedSession(dir,{...parkedEntryFromProfile({sessionPath,contextOverlay:retained.contextOverlay,...durableSessionId!==void 0?{durableSessionId}:{}},retained.profile,Object.keys(host.defaults.hostContext??{})),parkedBy:host.defaults.hostContext?.host_instance??hostInstanceId(),...resident?{residentWriter:currentResidentWriter()}:{}})}var currentPath=entry=>entry.runtime?.session.sessionFile??entry.sessionPath;async function syncRetainedRecord(host,sessionId,requestedPath){let dir=host.handoverParkedDir;if(dir===void 0)return;let entry=host.registry.peek(sessionId),sessionPath=entry===void 0?void 0:currentPath(entry);entry?.retainOnDisconnect===!0&&sessionPath!==void 0&&(await recordRetainedSession(host,entry,sessionPath,!0).catch(reportRecordFailure(sessionId)),requestedPath===void 0||requestedPath===sessionPath)||requestedPath!==void 0&&await clearHandoverParkedSession(dir,requestedPath).catch(()=>{})}function followRetainedRecord(host,sessionId){if(host.handoverParkedDir===void 0)return;let entry=host.registry.peek(sessionId);if(entry?.retainOnDisconnect!==!0||entry.recordedPath===void 0||entry.state!=="open")return;let sessionPath=currentPath(entry);sessionPath===void 0||sessionPath===entry.recordedPath||recordRetainedSession(host,entry,sessionPath,!0).catch(reportRecordFailure(sessionId))}async function clearRetainedRecord(host,entry){let dir=host.handoverParkedDir;if(dir===void 0||entry===void 0)return;let keys=new Set([entry.recordedPath,entry.sessionPath,entry.runtime?.session.sessionFile]);entry.recordedPath=void 0;for(let key of keys)key!==void 0&&await clearHandoverParkedSession(dir,key).catch(()=>{})}var DETACHED_RETIREMENT_GRACE_MS=5e3;function selectSweepEvictions(registry,now,idleEvictionMs,hasPendingRequest=()=>!1){let idle=[],orphaned=[];for(let{sessionId,status,sessionPath}of registry.list()){if(status!=="open")continue;let entry=registry.peek(sessionId);if(!entry)continue;if(entry.attachments===0&&sessionPath!==void 0&&sessionDirectoryRemoved(sessionPath)){orphaned.push(sessionId);continue}if(!Number.isFinite(idleEvictionMs)||hasPendingRequest(sessionId))continue;let session=entry.runtime?.session;if(entry.worker?.busy||session?.isSessionBusy){entry.lastCommandAt=now;continue}if(entry.attachments>0){now-entry.lastCommandAt>=idleEvictionMs&&idle.push(sessionId);continue}if(entry.kind==="worker"&&entry.retainOnDisconnect&&session?.sessionManager.isTranscriptFlushed()){if(session.pendingMessageCount>0||session.externalAdmission.list().pending.length>0)continue;if(entry.detachedAt!==void 0){if(now-entry.detachedAt<DETACHED_RETIREMENT_GRACE_MS)continue;idle.push(sessionId);continue}}now-entry.lastCommandAt>=idleEvictionMs&&idle.push(sessionId)}return{idle,orphaned}}var DRAIN_SWEEP_MS=50;function beginDrain(host){host.draining=!0,stopSweep(host),host.drainTimer===void 0&&!host.drainExitRequested&&(host.drainTimer=setInterval(()=>sweepDrain(host),DRAIN_SWEEP_MS),host.drainTimer.unref?.()),sweepDrain(host)}function sweepDrain(host){if(host.activeRequests.has(void 0))return;let verdicts=readDrainVerdicts(host.registry,sessionId=>host.activeRequests.has(sessionId));if(verdicts){holdUnattendedTurns(host);for(let sessionId of verdicts.gone)parkForHandoff(host,sessionId,"session_dir_removed");for(let sessionId of verdicts.park)parkForHandoff(host,sessionId,"handoff_parked");host.registry.size>0||host.handoffParks>0||host.finalizations.size>0||(host.drainTimer!==void 0&&(clearInterval(host.drainTimer),host.drainTimer=void 0),stopSweep(host),!host.drainExitRequested&&(host.drainExitRequested=!0,host.onEmptyExit?.()))}}function parkForHandoff(host,sessionId,reason){host.handoffClosed.add(sessionId),host.handoffParks++,evictIdleSession(host,sessionId,reason).catch(cause=>{process.stderr.write(`senpi rpc handoff park ${sessionId} failed: ${String(cause)}
|
|
18
|
+
`)}).finally(()=>{host.handoffParks--,sweepDrain(host)})}function sweepIdleSessions(host){let now=host.idleNow(),idleEvictionMs=host.memoryPressure?host.idleEvictionMs/2:host.idleEvictionMs,verdicts=selectSweepEvictions(host.registry,now,idleEvictionMs,sessionId=>host.activeRequests.has(sessionId)||(host.bindings.get(sessionId)?.pendingPrompts?.().length??0)>0);for(let sessionId of verdicts.orphaned)evictIdleSession(host,sessionId,"session_dir_removed");for(let sessionId of verdicts.idle)evictIdleSession(host,sessionId);Number.isFinite(host.emptyExitMs)&&(host.registry.size===0&&(host.canExitWhenEmpty?.()??!0)?host.emptySince===void 0?host.emptySince=now:now-host.emptySince>=host.emptyExitMs&&(stopSweep(host),host.onEmptyExit?.()):host.emptySince=void 0)}async function evictIdleSession(host,sessionId,reason){let retained=host.registry.peek(sessionId),parkedPath=retained?.retainOnDisconnect===!0||reason==="handoff_parked"?retained?.sessionPath:void 0,handoff=reason==="handoff_parked"||reason==="session_dir_removed"&&host.draining,owners=handoff?[...host.sessionsByConnection].filter(([,owned])=>owned.has(sessionId)).map(([connection])=>connection):[],claim=tryClaimClose(host,sessionId,{drainAttachments:!0});if(!claim)return;host.handoverParkedDir!==void 0&&parkedPath!==void 0&&retained?.retainOnDisconnect===!0&&retained.sessionPath!==void 0&&await recordRetainedSession(host,retained,retained.sessionPath,!1).catch(cause=>{process.stderr.write(`senpi rpc handover park record ${sessionId} failed: ${String(cause)}
|
|
19
|
+
`)});let binding2=host.bindings.get(sessionId);binding2?.cancelPendingExtensionUiRequests?.(),handoff||forgetSessionOwnership(host,sessionId),claim.finalizer?await finalizeClose(host,sessionId,binding2,()=>parkedPath!==void 0&&reason===void 0?host.writer.parkSession(sessionId,parkedPath,"idle"):host.writer.closeSession(sessionId,{type:"response",command:"close_session",success:!0,data:{}},reason??"idle_evicted",reason==="handoff_parked"?parkedPath:void 0)):await host.finalizations.get(sessionId)?.promise,handoff&&(forgetSessionOwnership(host,sessionId),await host.onHandoffParked?.(owners.filter(connection=>!host.sessionsByConnection.has(connection)))),host.writer.forgetSession(sessionId)}function stopSweep(host){host.sweepTimer!==void 0&&(clearInterval(host.sweepTimer),host.sweepTimer=void 0)}var HOST_SHUTDOWN_ABORT_BOUND_MS=1e4;async function abortForHostShutdownWithin(sessionId,entry){let aborting=(async()=>{await entry?.runtime?.session.abortForHostShutdown()})().catch(cause=>{process.stderr.write(`senpi rpc host shutdown abort ${sessionId} failed: ${String(cause)}
|
|
20
|
+
`)}),timer,bound=new Promise(resolve2=>{timer=setTimeout(resolve2,HOST_SHUTDOWN_ABORT_BOUND_MS),timer.unref?.()});try{await Promise.race([aborting,bound])}finally{clearTimeout(timer)}}function claimClose(host,sessionId,options){let finalizer=!0,onRole=isFinalizer=>{finalizer=isFinalizer,isFinalizer&&!host.finalizations.has(sessionId)&&host.finalizations.set(sessionId,createFinalization())},entry=host.registry.beginClose(sessionId,onRole,{detach:options.detach});for(;options.drainAttachments&&entry.state==="open";)entry=host.registry.beginClose(sessionId,onRole);return{finalizer:finalizer&&entry.state==="closing"}}function tryClaimClose(host,sessionId,options){try{return claimClose(host,sessionId,options)}catch{return}}async function close(host,command){let response={id:command.id,type:"response",command:"close_session",success:!0,data:{}},owner=host.writer.currentConnection();if(owner!==void 0&&host.sessionsByConnection.get(owner)?.has(command.sessionId)!==!0)return error(command.id,"close_session",RPC_ERROR_UNKNOWN_SESSION);let reply=host.writer.reserveCloseResponse(command.sessionId,response);if(!reply)return;let claim;try{claim=claimClose(host,command.sessionId,{drainAttachments:!1})}catch(cause){return reply.release(),error(command.id,"close_session",code(cause))}try{owner!==void 0&&releaseOwnerAttachment(host,owner,command.sessionId),claim.finalizer?(host.handoverParkedDir!==void 0&&await clearRetainedRecord(host,host.registry.peek(command.sessionId)),await finalizeClose(host,command.sessionId,host.bindings.get(command.sessionId),()=>reply.complete(!0,"client_close"))):(host.writer.status.publish(command.sessionId,"detach","client"),await host.finalizations.get(command.sessionId)?.promise,reply.complete(!1));return}finally{reply.release()}}async function finalizeClose(host,sessionId,binding2,terminal){let finalization=host.finalizations.get(sessionId)??createFinalization();host.finalizations.set(sessionId,finalization);try{try{await disposeWithinGrace(binding2,host.registry.closeGraceMs,sessionId)}catch(cause){process.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}
|
|
19
21
|
`)}host.bindings.delete(sessionId);try{await host.registry.closeMarked(sessionId)}catch(cause){process.stderr.write(`senpi rpc close for session ${sessionId} failed: ${String(cause)}
|
|
20
22
|
`)}await host.registry.peek(sessionId)?.closeCompletion,terminal?.()}finally{finalization.resolve(),host.finalizations.delete(sessionId)}}async function disposeWithinGrace(binding2,graceMs,sessionId){if(binding2===void 0)return;let timer,late=new Promise(resolve2=>{timer=setTimeout(()=>resolve2("late"),graceMs)}),disposed=binding2.dispose().then(()=>"disposed");try{if(await Promise.race([disposed,late])==="disposed")return}finally{clearTimeout(timer)}process.stderr.write(`senpi rpc binding dispose for session ${sessionId} did not settle within ${graceMs} ms; closing anyway
|
|
21
23
|
`),disposed.catch(cause=>process.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}
|
|
22
|
-
`))}function createFinalization(){let resolveFinalization;return{promise:new Promise(resolve2=>{resolveFinalization=resolve2}),resolve:()=>resolveFinalization?.()}}async function tearDownReleased(host,sessionId,sessionPath){let claim=tryClaimClose(host,sessionId,{drainAttachments:!0});if(!claim)return!1;let binding2=host.bindings.get(sessionId);return binding2?.cancelPendingExtensionUiRequests?.(),forgetSessionOwnership(host,sessionId),claim.finalizer?await finalizeClose(host,sessionId,binding2,()=>host.writer.releaseSession(sessionId,sessionPath)):await host.finalizations.get(sessionId)?.promise,host.writer.forgetSession(sessionId),!0}async function tearDownUnloaded(host,sessionId,sessionPath){let claim=tryClaimClose(host,sessionId,{drainAttachments:!0});if(!claim)return!1;let binding2=host.bindings.get(sessionId);return binding2?.cancelPendingExtensionUiRequests?.(),forgetSessionOwnership(host,sessionId),claim.finalizer?await finalizeClose(host,sessionId,binding2,()=>host.writer.parkSession(sessionId,sessionPath,"unloaded")):await host.finalizations.get(sessionId)?.promise,host.writer.forgetSession(sessionId),!0}async function dispose(host){host.stopLimitBroadcast(),host.drainExitRequested=!0,stopSweep(host),host.drainTimer!==void 0&&clearInterval(host.drainTimer),host.admissions&&await host.admissions.dispose(),await Promise.all([...host.bindings.entries()].map(async([sessionId,binding2])=>{let
|
|
24
|
+
`))}function createFinalization(){let resolveFinalization;return{promise:new Promise(resolve2=>{resolveFinalization=resolve2}),resolve:()=>resolveFinalization?.()}}async function tearDownReleased(host,sessionId,sessionPath){let claim=tryClaimClose(host,sessionId,{drainAttachments:!0});if(!claim)return!1;let binding2=host.bindings.get(sessionId);return binding2?.cancelPendingExtensionUiRequests?.(),forgetSessionOwnership(host,sessionId),claim.finalizer?await finalizeClose(host,sessionId,binding2,()=>host.writer.releaseSession(sessionId,sessionPath)):await host.finalizations.get(sessionId)?.promise,host.writer.forgetSession(sessionId),!0}async function tearDownUnloaded(host,sessionId,sessionPath){let claim=tryClaimClose(host,sessionId,{drainAttachments:!0});if(!claim)return!1;let binding2=host.bindings.get(sessionId);return binding2?.cancelPendingExtensionUiRequests?.(),forgetSessionOwnership(host,sessionId),claim.finalizer?await finalizeClose(host,sessionId,binding2,()=>host.writer.parkSession(sessionId,sessionPath,"unloaded")):await host.finalizations.get(sessionId)?.promise,host.writer.forgetSession(sessionId),!0}async function dispose(host){host.stopLimitBroadcast(),host.drainExitRequested=!0,stopSweep(host),host.drainTimer!==void 0&&clearInterval(host.drainTimer),host.admissions&&await host.admissions.dispose(),await Promise.all([...host.bindings.entries()].map(async([sessionId,binding2])=>{let entry=host.registry.peek(sessionId),parkedPath=host.handoverParkedDir!==void 0&&entry?.retainOnDisconnect===!0?entry.runtime?.session.sessionFile??entry.sessionPath:void 0,claim=tryClaimClose(host,sessionId,{drainAttachments:!0});claim&&(claim.finalizer?(await abortForHostShutdownWithin(sessionId,entry),entry!==void 0&&parkedPath!==void 0&&await recordRetainedSession(host,entry,parkedPath,!1).catch(cause=>{process.stderr.write(`senpi rpc host shutdown park record ${sessionId} failed: ${String(cause)}
|
|
25
|
+
`)}),await finalizeClose(host,sessionId,binding2,()=>parkedPath!==void 0?host.writer.parkSession(sessionId,parkedPath,"host_shutdown"):host.writer.closeSession(sessionId,{type:"response",command:"close_session",success:!0,data:{}},"host_shutdown"))):await host.finalizations.get(sessionId)?.promise,host.writer.forgetSession(sessionId))})),host.bindings.clear(),host.uninstallEffectSink?.(),host.uninstallEffectSink=void 0}function relocationConnection(host,sessionId){return host.attachOrder.connections(sessionId).find(connection=>host.sessionsByConnection.get(connection)?.has(sessionId)===!0&&host.writer.getConnectionCapabilities(connection)?.includes(SESSION_RELOCATION_CAPABILITY)===!0)}function connectionLeft(host,sessionId,connection){host.attachOrder.detached(sessionId,connection),host.bindings.get(sessionId)?.connectionDetached?.(connection)}async function releaseDisconnectAttachment(host,sessionId){let live=host.registry.peek(sessionId),endsSession=live?.retainOnDisconnect!==!0&&(live?.attachments??0)<=1,session=live?.state==="open"?live.runtime?.session:void 0;if(endsSession&&live?.state==="open"&&live.worker?.snapshot?.streaming){let unsubscribe=live.worker.subscribeSettled(()=>{unsubscribe(),releaseOwnedSession(host,sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred worker release ${sessionId} failed: ${String(cause)}
|
|
23
26
|
`)})});return!0}if(endsSession&&session?.isStreaming){let released=!1,unsubscribe=session.subscribe(event=>{event.type==="agent_idle"&&(released||(released=!0,unsubscribe(),releaseOwnedSession(host,sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}
|
|
24
27
|
`)})))});return!0}return await releaseOwnedSession(host,sessionId),!1}function recordAttachment(host,owner,sessionId){host.writer.attachConnectionToSession(owner,sessionId);let owned=host.sessionsByConnection.get(owner)??new Map;owned.set(sessionId,(owned.get(sessionId)??0)+1),host.sessionsByConnection.set(owner,owned),host.attachOrder.attached(sessionId,owner)}function releaseConnection(host,connectionId){return host.admissions?releaseAdmittedConnection(host,host.admissions,connectionId):releaseConnectionHolds(host,connectionId)}async function releaseAdmittedConnection(host,admissions,connectionId){admissions.endConnection(connectionId);try{return await releaseConnectionHolds(host,connectionId)}finally{await admissions.forgetConnection(connectionId)}}async function releaseConnectionHolds(host,connectionId){host.releasedConnections.add(connectionId),host.writer.clearConnectionCapabilities(connectionId),host.connectionRoles.release(connectionId);for(let sessionId of host.sessionsByConnection.get(connectionId)?.keys()??[])host.writer.detachConnectionFromSession(connectionId,sessionId),connectionLeft(host,sessionId,connectionId);host.writer.hasConnection(connectionId)||(host.pendingCapabilities.delete(connectionId),host.writer.delegations.forget(connectionId),host.connectionRoles.forget(connectionId));let opens=host.opensByConnection.get(connectionId),owned=host.sessionsByConnection.get(connectionId);if(host.sessionsByConnection.delete(connectionId),host.draining)return opens&&await Promise.all([...opens]),host.releasedConnections.delete(connectionId),[...owned?.keys()??[]];if(owned===void 0)return opens&&await Promise.all([...opens]),host.releasedConnections.delete(connectionId),[];let deferred=new Set;return await Promise.all([...owned].map(async([sessionId,count])=>{for(let attachment=0;attachment<count;attachment++)await releaseDisconnectAttachment(host,sessionId)&&deferred.add(sessionId)})),opens&&await Promise.all([...opens]),host.releasedConnections.delete(connectionId),[...deferred]}async function releaseOwnedSession(host,sessionId){let live=host.registry.peek(sessionId),parks=live?.state==="open"&&live.retainOnDisconnect===!0&&live.attachments===1,claim=tryClaimClose(host,sessionId,{drainAttachments:!1,detach:!0});if(!claim)return;if(!claim.finalizer){host.writer.status.publish(sessionId,"detach","client"),parks&&live.runtime&&(live.lifecycleMutex=live.lifecycleMutex.then(()=>live.runtime?.emitAttachmentEvent("session_parked")),await live.lifecycleMutex),await host.finalizations.get(sessionId)?.promise;return}let binding2=host.bindings.get(sessionId);binding2?.cancelPendingExtensionUiRequests?.(),await finalizeClose(host,sessionId,binding2)}function releaseOwnerAttachment(host,owner,sessionId){let owned=host.sessionsByConnection.get(owner),count=owned?.get(sessionId);!owned||count===void 0||(count===1?(host.writer.detachConnectionFromSession(owner,sessionId),owned.delete(sessionId),connectionLeft(host,sessionId,owner)):owned.set(sessionId,count-1),owned.size===0&&host.sessionsByConnection.delete(owner))}function forgetSessionOwnership(host,sessionId){host.attachOrder.forgetSession(sessionId);for(let[connection,owned]of host.sessionsByConnection)owned.delete(sessionId),owned.size===0&&host.sessionsByConnection.delete(connection)}import{createHash as createHash2}from"node:crypto";import{mkdtemp,rm as rm3}from"node:fs/promises";import{tmpdir}from"node:os";import{join as join4}from"node:path";var CompactAdmissionError=class extends Error{constructor(reason){super(reason),this.reason=reason,this.name="CompactAdmissionError"}};import{readFile as readFile2,writeFile as writeFile2}from"node:fs/promises";import{join as join2}from"node:path";var ADMISSION_LIMITS={entries:128,bytes:16*1024*1024,hot:16,row:131584,retired:4096},rowSchema=external_exports.object({fingerprint:external_exports.string().regex(/^[0-9a-f]{64}$/),state:external_exports.enum(["pending","complete","cancelled","failed"]),failure:external_exports.literal("storage_unavailable").optional(),answer:external_exports.string().max(65536).optional()});async function readAdmissionRow(epoch,key){let failure=epoch.failures?.get(key);if(failure)return failure;try{let text2=await readFile2(join2(await epoch.directory,key),"utf8");if(Buffer.byteLength(text2)>ADMISSION_LIMITS.row)throw new CompactAdmissionError("storage_unavailable");return rowSchema.parse(JSON.parse(text2))}catch(cause){if(cause instanceof Error&&"code"in cause&&cause.code==="ENOENT")return;throw cause instanceof CompactAdmissionError?cause:new CompactAdmissionError("storage_unavailable")}}async function writeAdmissionRow(epoch,key,row){let text2=JSON.stringify(row);if(Buffer.byteLength(text2)>ADMISSION_LIMITS.row)throw new CompactAdmissionError("storage_unavailable");try{await writeFile2(join2(await epoch.directory,key),text2,{mode:384,flush:!0})}catch(cause){throw cause instanceof Error?new CompactAdmissionError("storage_unavailable"):cause}}function runAdmissionProducer(signal,produce,release){return new Promise((resolve2,reject)=>{let abort=()=>reject(signal.reason);if(signal.aborted)return abort();signal.addEventListener("abort",abort,{once:!0}),produce().then(async value=>{signal.aborted?await release(value):resolve2(value)},reject).finally(()=>signal.removeEventListener("abort",abort)).catch(()=>{})})}function recordProducerLoss(losses,kind,count,cause){if(count<=0)return;losses[kind]+=count;let detail2=cause===void 0?"":`: ${cause instanceof Error?cause.message:String(cause)}`;process.stderr.write(`senpi rpc admission producer ${kind} ${count}${detail2}
|
|
25
28
|
`)}var AdmissionProducerLifetime=class{constructor(){this.controller=new AbortController,this.signal=this.controller.signal}end(abandoned){this.timer??=setTimeout(()=>{abandoned(),this.controller.abort(new CompactAdmissionError("storage_unavailable"))},OPEN_AFTER_QUEUED_DEADLINE_MS),this.timer.unref()}close(){clearTimeout(this.timer)}};import{rm as rm2}from"node:fs/promises";import{join as join3}from"node:path";function retainDone(epoch,key,admissionId){epoch.hot.has(key)||(epoch.done.delete(key),epoch.done.set(key,admissionId))}async function reserveRow(epoch,capacity,routed,overflowed){for(let[key,admissionId]of epoch.done){if(epoch.hot.size+epoch.done.size<capacity)return!0;if(!routed(admissionId)){try{await rm2(join3(await epoch.directory,key),{force:!0})}catch{throw new CompactAdmissionError("storage_unavailable")}epoch.done.delete(key),epoch.failures.delete(key),epoch.retired.add(key);for(let oldest of epoch.retired){if(epoch.retired.size<=ADMISSION_LIMITS.retired)break;epoch.retired.delete(oldest),overflowed()}}}return epoch.hot.size+epoch.done.size<capacity}async function settleProducedAdmission(epoch,key,fingerprint,produced,serial){let value=produced.answer,cancelled=await serial(async()=>{let row=await readAdmissionRow(epoch,key),retired=epoch.ended||row?.state==="cancelled",persist=async()=>{let answer3=JSON.stringify(value);if(Buffer.byteLength(answer3)>65536)throw new CompactAdmissionError("storage_unavailable");await writeAdmissionRow(epoch,key,{state:retired?"cancelled":"complete",fingerprint,answer:answer3})};value=produced.refusal?.()??value,await persist();let refused4=produced.refusal?.();if(refused4&&JSON.stringify(refused4)!==JSON.stringify(value)&&(value=refused4,await persist()),retired||epoch.ended||refused4)return!0;try{produced.activate?.()}catch(cause){throw process.stderr.write(`senpi rpc admission activation failed; releasing subscription: ${cause instanceof Error?cause.message:String(cause)}
|
|
26
29
|
`),epoch.failures.set(key,{state:"failed",fingerprint,failure:"storage_unavailable"}),new CompactAdmissionError("storage_unavailable")}return!1});return{value,cancelled}}var CompactAdmissions=class{status(){return{...this.losses,retiredOverflow:this.retiredOverflow}}overflowRetired(){this.retiredOverflow++===0&&process.stderr.write(`senpi rpc admission retired-ID ring overflowed (${ADMISSION_LIMITS.retired} digests); older IDs are forgotten
|
|
27
30
|
`)}end(epoch){epoch.ended=!0,epoch.producer.end(()=>recordProducerLoss(this.losses,"abandoned",epoch.hot.size))}constructor(limits=ADMISSION_LIMITS,routed=()=>!1){this.epochs=new Map,this.losses={abandoned:0,releaseFailed:0},this.retiredOverflow=0,this.limits=limits,this.routed=routed}key(id){if(!parseBoundedId(id).ok)throw new CompactAdmissionError("malformed_request");return createHash2("sha256").update(id).digest("hex")}epoch(id,peer){let epoch=this.epochs.get(id);return epoch||(epoch={producer:new AdmissionProducerLifetime,peer,directory:mkdtemp(join4(tmpdir(),"senpi-admissions-")),hot:new Map,failures:new Map,done:new Map,retired:new Set,tail:Promise.resolve(),ended:!1,waiting:0},this.epochs.set(id,epoch)),epoch}async serial(epoch,action){if(epoch.waiting>=ADMISSION_LIMITS.hot)throw new CompactAdmissionError("admission_busy");epoch.waiting++;let previous=epoch.tail,done=Promise.withResolvers();epoch.tail=done.promise,await previous;try{return await action()}finally{epoch.waiting--,done.resolve()}}async run(identity,produce){let key=this.key(identity.admissionId),epoch=this.epoch(identity.socketEpoch,identity.peer),registered=await this.serial(epoch,async()=>{if(epoch.ended)throw new CompactAdmissionError("admission_retired");let row=await readAdmissionRow(epoch,key);if(row){if(row.fingerprint!==identity.fingerprint)throw new CompactAdmissionError("admission_conflict");switch(retainDone(epoch,key,identity.admissionId),row.state){case"complete":if(row.answer===void 0)throw new CompactAdmissionError("storage_unavailable");return{kind:"complete",answer:external_exports.record(external_exports.string(),external_exports.unknown()).parse(JSON.parse(row.answer))};case"cancelled":throw new CompactAdmissionError("admission_retired");case"failed":throw new CompactAdmissionError(row.failure??"admission_retired");case"pending":{let pending2=epoch.hot.get(key);if(!pending2)throw new CompactAdmissionError("storage_unavailable");return{kind:"join",pending:pending2}}}}if(identity.retry)throw new CompactAdmissionError("admission_unknown");if(epoch.retired.has(key))throw new CompactAdmissionError("admission_retired");if(epoch.hot.size>=ADMISSION_LIMITS.hot)throw new CompactAdmissionError("admission_busy");let capacity=Math.min(this.limits.entries,Math.floor(this.limits.bytes/ADMISSION_LIMITS.row));if(!await reserveRow(epoch,capacity,admissionId=>this.routed(identity.socketEpoch,admissionId),()=>this.overflowRetired()))throw new CompactAdmissionError("admission_limit");await writeAdmissionRow(epoch,key,{state:"pending",fingerprint:identity.fingerprint});let pending=Promise.withResolvers();return pending.promise.catch(()=>{}),epoch.hot.set(key,pending),{kind:"fresh",pending}});switch(registered.kind){case"complete":return registered.answer;case"join":return registered.pending.promise;case"fresh":break}let produced;try{produced=await runAdmissionProducer(epoch.producer.signal,()=>produce(epoch.producer.signal),value2=>value2.release().catch(cause=>recordProducerLoss(this.losses,"releaseFailed",1,cause)));let{value,cancelled}=await settleProducedAdmission(epoch,key,identity.fingerprint,produced,action=>this.serial(epoch,action));if(cancelled){let release=produced.release;produced=void 0,await release()}return registered.pending.resolve(value),value}catch(cause){let failure=cause,row={state:"failed",fingerprint:identity.fingerprint,...cause instanceof CompactAdmissionError&&cause.reason==="storage_unavailable"?{failure:"storage_unavailable"}:{}};row.failure&&epoch.failures.set(key,row),produced&&await produced.release();try{await this.serial(epoch,()=>writeAdmissionRow(epoch,key,row))}catch(storageCause){process.stderr.write(`senpi rpc admission failure row write failed: ${storageCause instanceof Error?storageCause.message:String(storageCause)}
|
|
28
31
|
`),epoch.failures.set(key,{...row,failure:"storage_unavailable"}),failure=new CompactAdmissionError("storage_unavailable")}finally{registered.pending.reject(failure)}throw failure}finally{epoch.hot.delete(key),retainDone(epoch,key,identity.admissionId)}}async pending(socketEpoch,admissionId){let key=this.key(admissionId),epoch=this.epochs.get(socketEpoch);return!epoch||epoch.ended?!1:this.serial(epoch,async()=>(await readAdmissionRow(epoch,key))?.state==="pending")}async cancel(socketEpoch,admissionId){let key=this.key(admissionId),epoch=this.epochs.get(socketEpoch);return epoch?this.serial(epoch,async()=>{let row=await readAdmissionRow(epoch,key);if(!row)return epoch.retired.has(key)?"already_complete":"unknown";switch(row.state){case"complete":case"failed":return"already_complete";case"cancelled":return"cancelled";case"pending":return await writeAdmissionRow(epoch,key,{...row,state:"cancelled"}),"cancelled"}}):"unknown"}async result(socketEpoch,admissionId){let key=this.key(admissionId),epoch=this.epochs.get(socketEpoch);if(epoch)return this.serial(epoch,async()=>{let row=await readAdmissionRow(epoch,key);if(row?.answer!==void 0)return{state:row.state,answer:external_exports.record(external_exports.string(),external_exports.unknown()).parse(JSON.parse(row.answer))}})}async forgetPeer(socketEpoch){let epoch=this.epochs.get(socketEpoch);epoch&&(this.end(epoch),await Promise.allSettled([...epoch.hot.values()].map(pending=>pending.promise)),await epoch.tail,epoch.producer.close(),await rm3(await epoch.directory,{recursive:!0,force:!0}),this.epochs.delete(socketEpoch))}endConnection(peer){for(let epoch of this.epochs.values())epoch.peer===peer&&this.end(epoch)}async forgetConnection(peer){for(let[id,epoch]of this.epochs)epoch.peer===peer&&await this.forgetPeer(id)}async dispose(){for(let epoch of this.epochs.values())this.end(epoch);for(let id of this.epochs.keys())await this.forgetPeer(id)}};import{randomUUID}from"node:crypto";var CONTROLS=new Set(["message_block_state","message_block_metadata","message_tool_arguments_reset"]),carried=new WeakMap,carriedRefusals=new WeakSet,CanonicalPairing=class{constructor(){this.pending=new WeakMap,this.refusals=new WeakSet}structured(record){let carrier=recoveryCarrier(record);if(!carrier)return;let canonical;try{canonical=protocolClone(record)}catch(cause){throw protocolDepthLimitOf(cause)!==void 0&&this.refusals.add(carrier),cause}if(CONTROLS.has(canonical.type))return{record:canonical,carrier};this.pending.set(carrier,canonical)}take(legacy){let carrier=recoveryCarrier(legacy),canonical=carrier&&this.pending.get(carrier);return carrier&&this.pending.delete(carrier),canonical}refused(legacy){let carrier=recoveryCarrier(legacy);return carrier!==void 0&&this.refusals.delete(carrier)}};function carryCanonical(legacy,canonical,refused4){canonical&&carried.set(legacy,canonical),refused4&&carriedRefusals.add(legacy)}function frameUnit(frame){let{ordinal,firstOrdinal,recovery,canonical}=frame;return canonical&&recovery&&ordinal!==void 0&&firstOrdinal!==void 0?{record:canonical,carrier:recovery,ordinal,firstOrdinal}:void 0}var CompactProducerStamp=class{constructor(){this.next=0,this.first=new Map,this.last={ordinal:-1}}stamp(carrier,canonical,legacy){let ordinal=this.next++;if(this.last={ordinal},!carrier)return{ordinal};let ends=canonical?.type==="message_end"||legacy!==void 0&&Reflect.get(legacy,"type")==="message_end",firstOrdinal=canonical?this.first.get(carrier.messageId)??ordinal:void 0;return ends?this.first.delete(carrier.messageId):firstOrdinal!==void 0&&this.first.set(carrier.messageId,firstOrdinal),this.last={ordinal,firstOrdinal,messageId:carrier.messageId},firstOrdinal===void 0?{ordinal}:{ordinal,firstOrdinal}}defer(prefix){let{ordinal,firstOrdinal,messageId}=this.last,moved=ordinal+prefix;return this.next+=prefix,firstOrdinal===void 0?{ordinal:moved}:firstOrdinal!==ordinal?{ordinal:moved,firstOrdinal}:(messageId!==void 0&&this.first.get(messageId)===ordinal&&this.first.set(messageId,moved),{ordinal:moved,firstOrdinal:moved})}forget(){this.first.clear()}};async function createRpcSessionBinding(sessionId,entry,writer,requestClose,options={}){if(entry.worker)return entry.worker.bind(sessionId,writer,requestClose,options);if(!entry.runtime)throw new Error("Session runtime was not created");let rpcBindingGeneration=randomUUID(),rpcOwnersByConnection=new Map,toolSpans=createToolAttributionSpans(sessionId),lane=entry.acceptance;lane&&setSessionRecoveryEpoch(entry.runtime.session,lane.recoveryEpoch),lane&&writer.registerAcceptance(sessionId,lane);let journaled=lane?entry.runtime.session.sessionManager:void 0,structured=structuredLaneEnabled(),pairing=structured?new CanonicalPairing:void 0,stamp=new CompactProducerStamp,unit=(carrier,record,legacy)=>{let{ordinal,firstOrdinal}=stamp.stamp(carrier,record,legacy);return carrier&&record&&firstOrdinal!==void 0?{record,carrier,ordinal,firstOrdinal}:void 0},enqueueRecord=record=>{toolSpans.observe(record);let canonical=pairing?.take(record),refused4=pairing?.refused(record)===!0;if(lane&&"type"in record&&record.type==="session_replaced")journaled=entry.runtime?.session.sessionManager,lane.bootstrap({transcript:journaled?.beginTranscriptJournal()??[]}),stamp.forget(),entry.runtime&&setSessionRecoveryEpoch(entry.runtime.session,lane.recoveryEpoch);else if(lane){lane.applyTranscript(journaled?.drainTranscript()??[]);let carrier=recoveryCarrier(record);lane.accept(record,carrier,unit(carrier,canonical,record),refused4,executionCallKey(record))}else carryCanonical(record,canonical,refused4);enqueueLegacyRecord(writer,sessionId,record)},runtimeHost=new Proxy({},{get(_target,property){if(property==="switchSession"&&entry.switchSession)return entry.switchSession;if(property==="setRebindSession")return callback=>{entry.rebindSession=lane&&callback?async session=>{await lane.generations.bind(session.sessionId),await callback(session)}:callback,entry.runtime?.setRebindSession(entry.rebindSession)};let runtime=entry.runtime;if(!runtime)throw new Error("Session runtime was not created");let value=Reflect.get(runtime,property,runtime);return typeof value=="function"?value.bind(runtime):value}}),droppedAfterClose=!1,handler=await runWithProviderScope(entry.scope,async()=>{let writeInScope=bindToProviderScope(enqueueRecord),dropAfterClose=()=>{droppedAfterClose||process.stderr.write(`senpi rpc host: dropped a record for closed session ${sessionId} at ${new Date().toISOString()}
|
|
29
|
-
`),droppedAfterClose=!0},writeRecord=record=>{if(entry.scope.state==="closed")return dropAfterClose();writeInScope(record)},writeStructuredInScope=bindToProviderScope(record=>{writer.structuredLanes.accept(sessionId,record);let control=pairing?.structured(record);control&&lane?lane.acceptControl(unit(control.carrier,control.record)):control&&writer.enqueueCanonical(sessionId,control)}),taggedSink={writeRecord,...structured?{writeStructured:record=>{entry.scope.state!=="closed"&&writeStructuredInScope(record)},structuredFailed:cause=>{lane?lane.compactUnavailable(cause):writer.canonicalUnavailable(sessionId,cause)}}:{},writeRaw:()=>{if(entry.scope.state==="closed")return dropAfterClose();throw new Error("Shared session bindings deliver records through writeRecord, never writeRaw")},waitForBackpressure:bindToProviderScope(async()=>{})};return createRpcConnectionHandler(runtimeHost,taggedSink,{sessionId,shutdownHandler:bindToProviderScope(requestClose),disposeRuntime:!1,rpcOwner:()=>{let owner=writer.connectionContext.owner,connection=writer.currentConnection();return owner&&connection&&rpcOwnersByConnection.set(connection,owner),owner},retireRpcBinding:()=>{rpcBindingGeneration=randomUUID(),rpcOwnersByConnection.clear()},publishLoadedSurfacesChanged:(previous,digest)=>{entry.scope.state!=="closed"&&writer.publishLoadedSurfacesChanged(sessionId,previous,digest)},...options,workerSecurityBridge:writer.workerSecurityBridge,secretInputRoute:writer.secretInputRoute(sessionId,!0),grantDialogSettled:id=>writer.settleGrantDialog(sessionId,id),grantDialogRaised:(id,title)=>writer.noticeGrantDialog(sessionId,id,title),bindSecurityPresentation:(session,ui)=>writer.bindSecurityPresentations(sessionId,session.sessionId,session.securityNotices,ui),bindMcpForms:(session,ui)=>writer.bindMcpForms(sessionId,session.sessionId,ui,()=>session.admitHumanAnswer()),clientInfo:options.clientInfo===void 0?void 0:{...options.clientInfo,hasCapability:(connection,capability)=>writer.getConnectionCapabilities(connection)?.includes(capability)===!0}})});return await handler.ready,{handle:command=>{if(writer.handleMcpForm(command))return Promise.resolve();let invoke=()=>runWithProviderScope(entry.scope,()=>handler.handleInputLine(JSON.stringify(command)));return carriesExtensionOwner(command)?writer.connectionContext.withBinding(rpcBindingGeneration,invoke):invoke()},cancelPendingExtensionUiRequests:()=>runWithProviderScope(entry.scope,()=>handler.cancelPendingExtensionUiRequests()),pendingPrompts:()=>handler.pendingPrompts(),connectionDetached:connectionId=>{rpcOwnersByConnection.get(connectionId)?.retire(),rpcOwnersByConnection.delete(connectionId),runWithProviderScope(entry.scope,()=>handler.connectionDetached(connectionId))},dispose:()=>(toolSpans.closeAll(),runWithProviderScope(entry.scope,()=>handler.dispose()))}}var SessionAttachOrder=class{constructor(){this.next=0,this.order=new Map}attached(sessionId,connection){let connections=this.order.get(sessionId)??new Map;connections.has(connection)||connections.set(connection,this.next++),this.order.set(sessionId,connections)}detached(sessionId,connection){let connections=this.order.get(sessionId);connections?.delete(connection),connections?.size===0&&this.order.delete(sessionId)}forgetSession(sessionId){this.order.delete(sessionId)}connections(sessionId){return[...(this.order.get(sessionId)??new Map).entries()].sort((left,right)=>left[1]-right[1]).map(([connection])=>connection)}};var RouterContext=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(this.admissions=compactUpdatesEnabled()?new CompactAdmissions(ADMISSION_LIMITS,(socketEpoch,admissionId)=>this.writer.routesAdmission(socketEpoch,admissionId)):void 0,this.bindings=new Map,this.sessionsByConnection=new Map,this.attachOrder=new SessionAttachOrder,this.opensByConnection=new Map,this.releasedConnections=new Set,this.pendingCapabilities=new Map,this.connectionRoles=new ConnectionRoles,this.finalizations=new Map,this.draining=!1,this.handoffParks=0,this.drainExitRequested=!1,this.handoffClosed=new Set,this.drainHeldSessions=new Set,this.activeRequests=new Map,this.requestSettledListeners=new Map,this.memoryPressure=!1,this.releaseTeardown=(sessionId,sessionPath)=>tearDownReleased(this,sessionId,sessionPath),this.stopLimitBroadcast=subscriptionLimits.subscribe(limits=>writer.broadcastHostRecord({type:"subscription_limits",...limits})),this.registry=registry,this.writer=writer,writer.originOf=connection=>this.connectionRoles.originOf(connection),this.connectionRoles.useDelegations(connection=>writer.delegations.viewOf(connection)),this.defaults=defaults,this.createBinding=createBinding,this.connectionOptions={...connectionOptions,capabilities:connectionOptions.capabilities&&advertisedCompactCapabilities(connectionOptions.capabilities,!1)},this.idleNow=idle?.now??Date.now,this.idleEvictionMs=idle?.idleEvictionMs??Number.POSITIVE_INFINITY,this.emptyExitMs=idle?.emptyExitMs??Number.POSITIVE_INFINITY,this.onEmptyExit=idle?.onEmptyExit,this.onHandoffParked=idle?.onHandoffParked,this.handoverParkedDir=idle?.handoverParkedDir,this.canExitWhenEmpty=idle?.canExitWhenEmpty,writer.status.setSource(registryStatusSource(registry)),writer.status.setLastEffectProvider(sessionId=>{let session=this.registry.peek(sessionId)?.runtime?.session;if(session===void 0)return;let latest=latestSessionEffect(session);return latest===void 0?void 0:{effectId:latest.effectId,kind:latest.kind,state:latest.state}}),writer.afterRecord=sessionId=>{let session=this.registry.peek(sessionId)?.runtime?.session;if(session!==void 0)for(let status of drainSessionEffects(session))this.writer.status.publishEffect(sessionId,status)},this.uninstallEffectSink=installSessionEffectSink({owns:session=>routingIdOf(this,session)!==void 0,flush:(session,statuses)=>{let sessionId=routingIdOf(this,session);if(sessionId!==void 0)for(let status of statuses)this.writer.status.publishEffect(sessionId,status)}}),Number.isFinite(this.idleEvictionMs)||Number.isFinite(this.emptyExitMs)){let tickMs=Math.max(20,Math.min(5e3,Math.min(this.idleEvictionMs,this.emptyExitMs)/4));this.sweepTimer=setInterval(()=>sweepIdleSessions(this),tickMs),this.sweepTimer.unref?.()}}};import{createHash as createHash3}from"node:crypto";function admissionBaseline(reply,identity,live,routes){return new GeneratedFramesCursor(!1,async function*(){let answer3=await reply;if(answer3!==void 0&&(yield serializeJsonLine(answer3),live()))for(let admissionId of routes??[identity.admissionId])yield serializeJsonLine({type:"recovery_manifest",...identity,admissionId,componentRef:identity.componentRef??"manifest"})},()=>{})}var RouteAnnouncement=class _RouteAnnouncement{constructor(reason){this.reason=reason}static emit(reason,emit){return emit(),new _RouteAnnouncement(reason)}};var OpenRefused=class extends Error{constructor(response){super("compact open refused"),this.response=response,this.name="OpenRefused"}};async function compactOpen(host,command,physical){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),admissions=host.admissions;if(peer===void 0||socketEpoch===void 0||admissions===void 0)return error(command.id,command.type,"unsupported_transport");let{id:_request,admissionId,retry,...request}=command;if(admissionId===void 0)throw new CompactAdmissionError("malformed_request");let fingerprint=createHash3("sha256").update(JSON.stringify(Object.entries(request).sort(([a],[b])=>a.localeCompare(b)))).digest("hex"),delivery,baseline,completedOpen,accepted,announced,retireAfterReply,answerFinally=emit=>{announced=RouteAnnouncement.emit("open_ended",emit),retireAfterReply?.(announced),retireAfterReply=void 0},cancelledAnswer=async()=>{let result=await admissions.result(socketEpoch,admissionId);if(!(result?.state!=="cancelled"||typeof result.answer.generation!="number"))return{id:command.id,type:"response",command:command.type,success:!1,error:"attempt_cancelled",errorCode:"attempt_cancelled",code:"attempt_cancelled",admissionId,generation:result.answer.generation}};try{let identity={socketEpoch,peer,admissionId,fingerprint,retry:retry===!0},answer3=await admissions.run(identity,async signal=>{let result,physicalSucceeded=!1,response2=await physical(async opened=>{let sessionId=opened.sessionId,lane=host.writer.recoveryLane(sessionId);if(!lane)throw new CompactAdmissionError("storage_unavailable");let caller={socketEpoch,sessionId},checkpoints=host.writer.recoveryCheckpoints,frozen=checkpoints.freeze({...caller,peer,admissionId,routeKind:"ordinary"},lane,!0);if(!frozen.ok)throw new CompactAdmissionError("storage_unavailable");let token=frozen.value.token,identity2={sessionId,admissionId,generation:token.admission.generation,token:token.id},active=!0;delivery=Promise.withResolvers();let reply=delivery.promise;host.writer.registerAdmission(peer,admissionId,sessionId),baseline=()=>host.writer.installAdmissionBaseline(peer,admissionBaseline(reply,identity2,()=>active),()=>host.writer.socketEpochOf(peer)===socketEpoch),accepted={admissionId,generation:token.admission.generation};let retire=retirement=>{checkpoints.retireRoute(caller,admissionId,retirement),host.writer.unregisterAdmission(peer,admissionId)},release=async superseded=>{active&&(active=!1,superseded?retire("reopen_superseded"):announced?retire(announced):retireAfterReply=retire,physicalSucceeded&&(releaseOwnerAttachment(host,peer,sessionId),await releaseDisconnectAttachment(host,sessionId)))};completedOpen={sessionId,release:()=>release(!0)},result={answer:{type:"response",command:command.type,success:!0,sessionId,admissionId,generation:token.admission.generation,data:{sessionId,...opened.attached?{attached:!0}:{},recovery:{token:token.id,componentRef:"manifest"}}},release:()=>release(!1)}},signal).catch(async cause=>{throw await result?.release(),cause});if(response2!==void 0)throw await result?.release(),new OpenRefused(response2);if(result===void 0)throw new CompactAdmissionError("storage_unavailable");return physicalSucceeded=!0,result}),cancelled=await cancelledAnswer(),response=cancelled??{...answer3,id:command.id};if(delivery){(cancelled===void 0&&answer3.success===!0&&completedOpen?host.writer.supersedeOpen(peer,completedOpen.sessionId,admissionId,completedOpen.release):void 0)?.().catch(cause=>process.stderr.write(`senpi rpc superseded open release failed: ${String(cause)}
|
|
32
|
+
`),droppedAfterClose=!0},writeRecord=record=>{if(entry.scope.state==="closed")return dropAfterClose();writeInScope(record)},writeStructuredInScope=bindToProviderScope(record=>{writer.structuredLanes.accept(sessionId,record);let control=pairing?.structured(record);control&&lane?lane.acceptControl(unit(control.carrier,control.record)):control&&writer.enqueueCanonical(sessionId,control)}),taggedSink={writeRecord,...structured?{writeStructured:record=>{entry.scope.state!=="closed"&&writeStructuredInScope(record)},structuredFailed:cause=>{lane?lane.compactUnavailable(cause):writer.canonicalUnavailable(sessionId,cause)}}:{},writeRaw:()=>{if(entry.scope.state==="closed")return dropAfterClose();throw new Error("Shared session bindings deliver records through writeRecord, never writeRaw")},waitForBackpressure:bindToProviderScope(async()=>{})};return createRpcConnectionHandler(runtimeHost,taggedSink,{sessionId,shutdownHandler:bindToProviderScope(requestClose),disposeRuntime:!1,rpcOwner:()=>{let owner=writer.connectionContext.owner,connection=writer.currentConnection();return owner&&connection&&rpcOwnersByConnection.set(connection,owner),owner},retireRpcBinding:()=>{rpcBindingGeneration=randomUUID(),rpcOwnersByConnection.clear()},publishLoadedSurfacesChanged:(previous,digest)=>{entry.scope.state!=="closed"&&writer.publishLoadedSurfacesChanged(sessionId,previous,digest)},...options,workerSecurityBridge:writer.workerSecurityBridge,secretInputRoute:writer.secretInputRoute(sessionId,!0),grantDialogSettled:id=>writer.settleGrantDialog(sessionId,id),grantDialogRaised:(id,title)=>writer.noticeGrantDialog(sessionId,id,title),bindSecurityPresentation:(session,ui)=>writer.bindSecurityPresentations(sessionId,session.sessionId,session.securityNotices,ui),bindMcpForms:(session,ui)=>writer.bindMcpForms(sessionId,session.sessionId,ui,()=>session.admitHumanAnswer()),clientInfo:options.clientInfo===void 0?void 0:{...options.clientInfo,hasCapability:(connection,capability)=>writer.getConnectionCapabilities(connection)?.includes(capability)===!0}})});return await handler.ready,{handle:command=>{if(writer.handleMcpForm(command))return Promise.resolve();let invoke=()=>runWithProviderScope(entry.scope,()=>handler.handleInputLine(JSON.stringify(command)));return carriesExtensionOwner(command)?writer.connectionContext.withBinding(rpcBindingGeneration,invoke):invoke()},cancelPendingExtensionUiRequests:()=>runWithProviderScope(entry.scope,()=>handler.cancelPendingExtensionUiRequests()),pendingPrompts:()=>handler.pendingPrompts(),connectionDetached:connectionId=>{rpcOwnersByConnection.get(connectionId)?.retire(),rpcOwnersByConnection.delete(connectionId),runWithProviderScope(entry.scope,()=>handler.connectionDetached(connectionId))},dispose:()=>(toolSpans.closeAll(),runWithProviderScope(entry.scope,()=>handler.dispose()))}}var SessionAttachOrder=class{constructor(){this.next=0,this.order=new Map}attached(sessionId,connection){let connections=this.order.get(sessionId)??new Map;connections.has(connection)||connections.set(connection,this.next++),this.order.set(sessionId,connections)}detached(sessionId,connection){let connections=this.order.get(sessionId);connections?.delete(connection),connections?.size===0&&this.order.delete(sessionId)}forgetSession(sessionId){this.order.delete(sessionId)}connections(sessionId){return[...(this.order.get(sessionId)??new Map).entries()].sort((left,right)=>left[1]-right[1]).map(([connection])=>connection)}};var RouterContext=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(this.admissions=compactUpdatesEnabled()?new CompactAdmissions(ADMISSION_LIMITS,(socketEpoch,admissionId)=>this.writer.routesAdmission(socketEpoch,admissionId)):void 0,this.bindings=new Map,this.sessionsByConnection=new Map,this.attachOrder=new SessionAttachOrder,this.opensByConnection=new Map,this.releasedConnections=new Set,this.pendingCapabilities=new Map,this.connectionRoles=new ConnectionRoles,this.finalizations=new Map,this.draining=!1,this.handoffParks=0,this.drainExitRequested=!1,this.handoffClosed=new Set,this.drainHeldSessions=new Set,this.activeRequests=new Map,this.requestSettledListeners=new Map,this.memoryPressure=!1,this.releaseTeardown=(sessionId,sessionPath)=>tearDownReleased(this,sessionId,sessionPath),this.stopLimitBroadcast=subscriptionLimits.subscribe(limits=>writer.broadcastHostRecord({type:"subscription_limits",...limits})),this.registry=registry,this.writer=writer,writer.originOf=connection=>this.connectionRoles.originOf(connection),this.connectionRoles.useDelegations(connection=>writer.delegations.viewOf(connection)),this.defaults=defaults,this.createBinding=createBinding,this.connectionOptions={...connectionOptions,capabilities:connectionOptions.capabilities&&advertisedCompactCapabilities(connectionOptions.capabilities,!1)},this.idleNow=idle?.now??Date.now,this.idleEvictionMs=idle?.idleEvictionMs??Number.POSITIVE_INFINITY,this.emptyExitMs=idle?.emptyExitMs??Number.POSITIVE_INFINITY,this.onEmptyExit=idle?.onEmptyExit,this.onHandoffParked=idle?.onHandoffParked,this.handoverParkedDir=idle?.handoverParkedDir,this.canExitWhenEmpty=idle?.canExitWhenEmpty,writer.status.setSource(registryStatusSource(registry)),writer.status.setLastEffectProvider(sessionId=>{let session=this.registry.peek(sessionId)?.runtime?.session;if(session===void 0)return;let latest=latestSessionEffect(session);return latest===void 0?void 0:{effectId:latest.effectId,kind:latest.kind,state:latest.state}}),writer.afterRecord=sessionId=>{followRetainedRecord(this,sessionId);let session=this.registry.peek(sessionId)?.runtime?.session;if(session!==void 0)for(let status of drainSessionEffects(session))this.writer.status.publishEffect(sessionId,status)},this.uninstallEffectSink=installSessionEffectSink({owns:session=>routingIdOf(this,session)!==void 0,flush:(session,statuses)=>{let sessionId=routingIdOf(this,session);if(sessionId!==void 0)for(let status of statuses)this.writer.status.publishEffect(sessionId,status)}}),Number.isFinite(this.idleEvictionMs)||Number.isFinite(this.emptyExitMs)){let tickMs=Math.max(20,Math.min(5e3,Math.min(this.idleEvictionMs,this.emptyExitMs)/4));this.sweepTimer=setInterval(()=>sweepIdleSessions(this),tickMs),this.sweepTimer.unref?.()}}};import{createHash as createHash3}from"node:crypto";function admissionBaseline(reply,identity,live,routes){return new GeneratedFramesCursor(!1,async function*(){let answer3=await reply;if(answer3!==void 0&&(yield serializeJsonLine(answer3),live()))for(let admissionId of routes??[identity.admissionId])yield serializeJsonLine({type:"recovery_manifest",...identity,admissionId,componentRef:identity.componentRef??"manifest"})},()=>{})}var RouteAnnouncement=class _RouteAnnouncement{constructor(reason){this.reason=reason}static emit(reason,emit){return emit(),new _RouteAnnouncement(reason)}};var OpenRefused=class extends Error{constructor(response){super("compact open refused"),this.response=response,this.name="OpenRefused"}};async function compactOpen(host,command,physical){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),admissions=host.admissions;if(peer===void 0||socketEpoch===void 0||admissions===void 0)return error(command.id,command.type,"unsupported_transport");let{id:_request,admissionId,retry,...request}=command;if(admissionId===void 0)throw new CompactAdmissionError("malformed_request");let fingerprint=createHash3("sha256").update(JSON.stringify(Object.entries(request).sort(([a],[b])=>a.localeCompare(b)))).digest("hex"),delivery,baseline,completedOpen,accepted,announced,retireAfterReply,answerFinally=emit=>{announced=RouteAnnouncement.emit("open_ended",emit),retireAfterReply?.(announced),retireAfterReply=void 0},cancelledAnswer=async()=>{let result=await admissions.result(socketEpoch,admissionId);if(!(result?.state!=="cancelled"||typeof result.answer.generation!="number"))return{id:command.id,type:"response",command:command.type,success:!1,error:"attempt_cancelled",errorCode:"attempt_cancelled",code:"attempt_cancelled",admissionId,generation:result.answer.generation}};try{let identity={socketEpoch,peer,admissionId,fingerprint,retry:retry===!0},answer3=await admissions.run(identity,async signal=>{let result,physicalSucceeded=!1,response2=await physical(async opened=>{let sessionId=opened.sessionId,lane=host.writer.recoveryLane(sessionId);if(!lane)throw new CompactAdmissionError("storage_unavailable");let caller={socketEpoch,sessionId},checkpoints=host.writer.recoveryCheckpoints,frozen=checkpoints.freeze({...caller,peer,admissionId,routeKind:"ordinary"},lane,!0);if(!frozen.ok)throw new CompactAdmissionError("storage_unavailable");let token=frozen.value.token,identity2={sessionId,admissionId,generation:token.admission.generation,token:token.id},active=!0;delivery=Promise.withResolvers();let reply=delivery.promise;host.writer.registerAdmission(peer,admissionId,sessionId),baseline=()=>host.writer.installAdmissionBaseline(peer,admissionBaseline(reply,identity2,()=>active),()=>host.writer.socketEpochOf(peer)===socketEpoch),accepted={admissionId,generation:token.admission.generation};let retire=retirement=>{checkpoints.retireRoute(caller,admissionId,retirement),host.writer.unregisterAdmission(peer,admissionId)},release=async superseded=>{active&&(active=!1,superseded?retire("reopen_superseded"):announced?retire(announced):retireAfterReply=retire,physicalSucceeded&&(releaseOwnerAttachment(host,peer,sessionId),await releaseDisconnectAttachment(host,sessionId)))};completedOpen={sessionId,release:()=>release(!0)},result={answer:{type:"response",command:command.type,success:!0,sessionId,admissionId,generation:token.admission.generation,data:{sessionId,...opened.attached?{attached:!0}:{},recovery:{token:token.id,componentRef:"manifest"}}},release:()=>release(!1)}},signal).catch(async cause=>{throw await result?.release(),cause});if(response2!==void 0)throw await result?.release(),new OpenRefused(response2);if(result===void 0)throw new CompactAdmissionError("storage_unavailable");return physicalSucceeded=!0,result}),cancelled=await cancelledAnswer(),response=cancelled??{...answer3,id:command.id};if(delivery){(cancelled===void 0&&answer3.success===!0&&completedOpen?host.writer.supersedeOpen(peer,completedOpen.sessionId,admissionId,completedOpen.release):void 0)?.().catch(cause=>process.stderr.write(`senpi rpc superseded open release failed: ${String(cause)}
|
|
30
33
|
`));let reply=delivery,deliver=()=>{baseline?.(),reply.resolve(response)};cancelled?answerFinally(deliver):deliver()}else await host.writer.enqueueControl(response,peer);return}catch(cause){if(delivery?.resolve(void 0),!(cause instanceof OpenRefused)&&!(cause instanceof CompactAdmissionError)){let unexpected={...error(command.id,command.type,code(cause)),...accepted};throw accepted&&answerFinally(()=>{host.writer.enqueueControl(unexpected,peer).catch(written2=>{process.stderr.write(`senpi rpc failed open's refusal not written: ${String(written2)}
|
|
31
34
|
`)})}),cause}let refusal3=cause instanceof OpenRefused?cause.response:await cancelledAnswer()??error(command.id,command.type,`admission_${cause.reason}`,{kind:"request_refused",reason:cause.reason,hint:"new_request"});if(accepted===void 0)return refusal3;let ended={...refusal3,...accepted},written;answerFinally(()=>{written=host.writer.enqueueControl(ended,peer)}),await written;return}}import{execFile}from"node:child_process";var READ_ONLY_OR_CONTROL=new Set(["get_state","get_snapshot","get_effect_status","get_pending_inputs","get_steering_messages","get_follow_up_messages","get_available_models","get_available_thinking_levels","get_model_thinking_level","get_fast_mode","get_session_stats","resolve_path","get_fork_messages","get_entries","get_tree","get_last_assistant_text","get_messages","get_media","get_commands","get_loaded_surfaces","get_auth_providers","get_provider_accounts","memory_report","eval_cells.list","eval_cells.peek","eval_cells.stop","export_html","export_jsonl","abort","interrupt","abort_compaction","abort_branch_summary","abort_retry","abort_bash","clear_queue","check_reload_veto","cleanup_bash_output","set_client_info","extension_ui_response","extension_ui_progress","host_response"]);function readProcessStarts(){let windows=process.platform==="win32",command=windows?"powershell.exe":"ps",args=windows?["-NoProfile","-NonInteractive","-Command",'Get-CimInstance Win32_Process -ErrorAction Stop | ForEach-Object { if ($null -ne $_.CreationDate) { "{0} {1}" -f $_.ProcessId, $_.CreationDate.ToUniversalTime().ToString("o") } }']:["-axo","pid=,lstart="];return new Promise(resolve2=>{execFile(command,args,{timeout:windows?5e3:1e3,maxBuffer:4*1024*1024,windowsHide:!0,...windows?{}:{env:{...process.env,LC_ALL:"C",LANG:"C"}}},(error2,stdout)=>{if(error2)return resolve2(void 0);let starts=new Map;for(let line of stdout.split(`
|
|
32
|
-
`)){let row=/^\s*(\d+)\s+(.+)$/.exec(line);if(!row)continue;let start=processStartTimeMs(row[2]);start!==void 0&&starts.set(Number(row[1]),start)}resolve2(starts)})})}function sessionHeldCheck(resolveDaemonPids){let daemonPids,processStarts,pidStarts=new Map,observedStarts=new Map;return async(sessionFile,sessionId)=>{let holders=await foreignSessionHolders(sessionFile,sessionId,{holderEnded:generation=>holderGenerationEnded(generation),readProcessStartMs:pid=>{let probe=pidStarts.get(pid);return probe||(probe=(async()=>{process.platform!=="linux"&&(processStarts??=readProcessStarts());let start=(await processStarts)?.get(pid)??await readProcessStartMs(pid);return observedStarts.set(pid,start),start})(),pidStarts.set(pid,probe)),probe}});if(holders.length===0)return;daemonPids??=resolveDaemonPids?.(observedStarts)??Promise.resolve([]);let family=await daemonPids,foreign=holders.filter(holder=>!family.includes(holder.pid));if(foreign.length>0)throw new RpcSessionRegistryError(RPC_ERROR_SESSION_HELD,void 0,{holders:foreign.map(({pid,cwd,host_socket,host_instance})=>({pid,...cwd===void 0?{}:{cwd},...host_socket===void 0?{}:{host_socket},...host_instance===void 0?{}:{host_instance}}))})}}async function dispatchSessionBinding(command,entry,binding2,acknowledgePrompt2,daemonPids){if(!binding2)throw new RpcSessionRegistryError("unknown_session");if(!READ_ONLY_OR_CONTROL.has(command.type)){let assertSessionNotHeld=sessionHeldCheck(daemonPids),state=entry.worker?.snapshot?.state;await assertSessionNotHeld(entry.runtime?.session.sessionFile??state?.sessionFile??entry.sessionPath,entry.runtime?.session.sessionId??state?.sessionId??entry.durableSessionId),"sessionPath"in command&&await assertSessionNotHeld(command.sessionPath)}command.type==="prompt"&&acknowledgePrompt2(),await binding2.handle(command)}function invalidSpawnedBy(command){let ancestry=command.spawnedBy;return ancestry!==void 0&&!isSpawnedBy(ancestry)}function validatedOpenProfile(host,command,options){let defaults=options?.defaults===!1?void 0:host.defaults,instanceId=host.defaults.hostContext?.host_instance??hostInstanceId();if(command.expectedHostInstance!==void 0){if(typeof command.expectedHostInstance!="string"||command.expectedHostInstance.trim()==="")return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: expectedHostInstance must be a non-empty string`,{reason:"invalid_expected_host_instance",action:"supply_host_instance"});if(command.expectedHostInstance!==instanceId)return error(command.id,"open_session",RPC_ERROR_OWNER_CHANGED,{reason:"host_instance_mismatch",action:"rediscover_holder",expectedHostInstance:command.expectedHostInstance,hostInstance:instanceId})}let kindError=sessionKindError(command.kind);if(command.attended!==void 0&&command.attended!==!1)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: attended must be false or omitted`);if(kindError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_KIND}: ${kindError}`);let contextError=sessionContextError(command.context);if(contextError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_CONTEXT}: ${contextError}`);let autoTitleError=sessionAutoTitleError(command.auto_title);if(autoTitleError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${autoTitleError}`);let promptSurfaceError=sessionPromptSurfaceError(command.promptSurface);if(promptSurfaceError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${promptSurfaceError}`);let browserEngineError=sessionBrowserEngineError(command.browserEngine);if(browserEngineError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${browserEngineError}`);if(!command.provider!=!command.modelId)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: provider and modelId must be given together`);let retryFallbackError=sessionRetryFallbackError(command.retryFallback);if(retryFallbackError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${retryFallbackError}`);let envError=sessionEnvError(command.env);if(envError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_ENV}: ${envError}`);let sessionEnv=inheritedSessionEnv(parentSessionEnv(host,command.spawnedBy?.parentSessionId),command.env);return{cwd:command.cwd??host.defaults.cwd,...command.attended===!1?{attended:!1}:{},sessionPath:command.sessionPath,holderEndpoint:{host_instance:instanceId,...process.env[HOST_DAEMON_DIR_ENV]?{host_daemon_dir:process.env[HOST_DAEMON_DIR_ENV]}:{},...host.defaults.hostContext?.host_socket===void 0?{}:{host_socket:host.defaults.hostContext.host_socket}},permissionPreset:command.permissionPreset??defaults?.permissionPreset,creationModel:command.provider&&command.modelId?{provider:command.provider,modelId:command.modelId}:defaults?.creationModel,initialThinkingLevel:command.thinkingLevel??defaults?.initialThinkingLevel,sessionKind:command.kind,sessionContext:host.defaults.hostContext?{...command.context,...host.defaults.hostContext}:command.context,...command.durableSessionId!==void 0?{durableSessionId:command.durableSessionId}:{},...typeof command.auto_title=="boolean"?{autoTitle:command.auto_title}:{},...command.promptSurface!==void 0?{promptSurface:command.promptSurface}:{},...command.browserEngine!==void 0?{browserEngine:command.browserEngine}:{},...command.retryFallback!==void 0?{retryFallback:command.retryFallback}:{},...sessionEnv!==void 0?{sessionEnv}:{}}}function parentSessionEnv(host,parentSessionId){if(parentSessionId===void 0)return;let parent=host.registry.list().find(row=>row.durableSessionId===parentSessionId||row.sessionId===parentSessionId);if(parent===void 0)return;let entry=host.registry.peek(parent.sessionId);return entry?.state==="open"&&host.bindings.has(parent.sessionId)?entry.profile.sessionEnv:void 0}function openWithBarrier(host,command){return compactUpdatesEnabled()&&command.admissionId!==void 0?compactOpen(host,command,(accept,signal)=>openPhysicalWithBarrier(host,command,accept,signal)):openPhysicalWithBarrier(host,command)}function openPhysicalWithBarrier(host,command,accept,signal){let owner=host.writer.currentConnection();if(owner===void 0)return open(host,command);let resolveBarrier,barrier=new Promise(resolve2=>{resolveBarrier=resolve2}),opens=host.opensByConnection.get(owner)??new Set,inFlight=0;for(let pending of host.opensByConnection.values())inFlight+=pending.size;opens.add(barrier),host.opensByConnection.set(owner,opens),command.id!==void 0&&host.writer.sendOpenQueued(owner,{type:"queued",for_request:command.id,position:inFlight+1,in_flight:inFlight});let start=()=>open(host,command,owner,accept===void 0?void 0:{accept,signal}),opened=signal===void 0?start():runAdmissionProducer(signal,start,async()=>{});if(command.sessionPath!==void 0&&host.handoverParkedDir!==void 0){let dir=host.handoverParkedDir,sessionPath=command.sessionPath;opened.then(response=>{response===void 0&&clearHandoverParkedSession(dir,sessionPath).catch(()=>{})},()=>{})}return opened.finally(()=>{resolveBarrier(),opens.delete(barrier),opens.size===0&&host.opensByConnection.delete(owner)})}function reopenParked(host,entry){return open(host,{...parkedOpenCommand(entry),attended:!1},void 0,{reply:!1,defaults:!1,contextOverlay:entry.contextOverlay})}async function open(host,command,owner,options){let profile=validatedOpenProfile(host,command,options);if("type"in profile)return profile;let opened,timer=startOpenTimer(`host-open:${command.id??"-"}`),assertSessionNotHeld=sessionHeldCheck(observedStarts=>host.registry.holderPids?.(observedStarts)??Promise.resolve([]));try{if(await assertSessionNotHeld(command.sessionPath),timer.mark("held_check"),options?.signal?.throwIfAborted(),invalidSpawnedBy(command))return error(command.id,"open_session","invalid_spawned_by");let ancestry=command.spawnedBy;opened=await host.registry.openSession(ancestry?{...profile,spawnedBy:ancestry}:profile,{retainOnDisconnect:command.retain_on_disconnect===!0,attachOnly:command.expectedHostInstance!==void 0}),timer.mark("registry_open"),options?.signal?.throwIfAborted();let openedSession=opened;if(host.writer.isSessionSealed(openedSession.sessionId))return await releaseOwnedSession(host,openedSession.sessionId),opened=void 0,error(command.id,"open_session","session_output_overflow",{sessionId:openedSession.sessionId,sessionPath:openedSession.sessionPath,action:"unload_and_reopen"});let entry=host.registry.getForCommand(openedSession.sessionId,"open_session");!opened.attached&&options?.contextOverlay!==void 0&&(entry.contextOverlay=options.contextOverlay);let state=entry.worker?.snapshot?.state;await assertSessionNotHeld(entry.runtime?.session.sessionFile??state?.sessionFile??entry.sessionPath,entry.runtime?.session.sessionId??state?.sessionId??entry.durableSessionId),timer.mark("held_recheck"),host.writer.setSessionKind(openedSession.sessionId,entry.kind),host.writer.setSessionMedia(openedSession.sessionId,toolMediaPersister(()=>liveToolMediaScope(entry)));let lane=entry.acceptance??entry.worker?.acceptance;if(lane&&host.writer.registerAcceptance(openedSession.sessionId,lane),options?.accept&&await options.accept(openedSession),owner!==void 0&&(host.writer.hasRegisteredConnectionCapabilities(owner)||host.writer.setConnectionCapabilities(owner,host.pendingCapabilities.get(owner)??host.connectionOptions?.capabilities??[]),host.writer.attachConnectionToSession(owner,openedSession.sessionId,options?.accept!==void 0)),owner!==void 0){let owned=host.sessionsByConnection.get(owner)??new Map;owned.set(openedSession.sessionId,(owned.get(openedSession.sessionId)??0)+1),host.sessionsByConnection.set(owner,owned),host.attachOrder.attached(openedSession.sessionId,owner)}if(!host.bindings.has(openedSession.sessionId)){host.bindings.set(openedSession.sessionId,await host.createBinding(openedSession.sessionId,entry,host.writer,()=>{close(host,{type:"close_session",sessionId:openedSession.sessionId})},{...host.connectionOptions,capabilities:owner!==void 0?host.pendingCapabilities.get(owner)??host.connectionOptions?.capabilities??[]:host.connectionOptions?.capabilities,connectionRoles:host.connectionRoles,clientInfo:{setCapabilities:(connectionId,capabilities)=>{connectionId!==void 0&&(host.writer.setConnectionCapabilities(connectionId,capabilities),host.pendingCapabilities.set(connectionId,[...capabilities]))},connectionId:()=>host.writer.currentConnection(),relocationConnection:()=>relocationConnection(host,openedSession.sessionId),deliverTo:(connection,deliver)=>host.writer.withConnection(connection,deliver)}})),timer.mark("binding"),entry.worker&&(entry.worker.bindingReady=!0);let settled=()=>{host.draining&&queueMicrotask(()=>sweepDrain(host))};typeof entry.worker?.subscribeSettled=="function"?entry.worker.subscribeSettled(settled):typeof entry.runtime?.session.subscribe=="function"&&entry.runtime.session.subscribe(event=>{event.type==="agent_idle"&&settled()}),entry.worker&&entry.worker.exited.then(async()=>{await host.finalizations.get(openedSession.sessionId)?.promise,host.bindings.delete(openedSession.sessionId),forgetSessionOwnership(host,openedSession.sessionId),host.writer.forgetSession(openedSession.sessionId)})}if(options?.signal?.throwIfAborted(),opened.attached?host.writer.status.publish(openedSession.sessionId,"attach","client"):(host.writer.publishSessionOpened({type:"session_opened",sessionId:openedSession.sessionId,durableSessionId:openedSession.durableSessionId,...openedSession.sessionPath!==void 0?{sessionPath:openedSession.sessionPath}:{},kind:entry.kind,cwd:entry.cwd,context:entry.context}),host.writer.status.publish(openedSession.sessionId,"open","client")),!options?.accept&&!host.draining&&owner!==void 0&&host.releasedConnections.has(owner)&&(releaseOwnerAttachment(host,owner,openedSession.sessionId),await releaseOwnedSession(host,openedSession.sessionId)),options?.accept)return;let replyState=entry.worker?.snapshot?.state??(entry.runtime?buildRpcSessionState(entry.runtime.session):void 0);if(!replyState)throw new Error("Session state was not created");timer.mark("reply"),options?.reply!==!1&&host.writer.enqueue(opened.sessionId,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:opened.sessionId,state:replyState,...opened.attached?{attached:!0}:{},...host.defaults.sessionPresence?{presence:host.defaults.sessionPresence.view(replyState.sessionId)}:{}}});return}catch(cause){if(opened){if(!opened.attached&&!options?.signal?.aborted){let entry=host.registry.peek(opened.sessionId);(entry?.runtime!==void 0||entry?.worker!==void 0)&&host.writer.sealRolledBackOpen(opened.sessionId,entry.sessionPath)}try{opened.attached?await releaseOwnedSession(host,opened.sessionId):await host.registry.close(opened.sessionId)}catch{}(!opened.attached||!compactUpdatesEnabled())&&host.writer.forgetSession(opened.sessionId)}if(cause instanceof CompactAdmissionError)throw cause;return error(command.id,"open_session",code(cause),detail(cause))}}async function detachConnection(command,connectionId,release){if(connectionId===void 0)return{id:command.id,type:"response",command:"detach_connection",success:!1,error:"detach_connection needs a socket connection"};let deferred=await release(connectionId);return{id:command.id,type:"response",command:"detach_connection",success:!0,data:{deferred:[...deferred]}}}function staleError(id,command,message){return{id,type:"response",command,success:!1,error:message,errorCode:"delegation_incarnation_stale"}}function declareSocketClient(host,command){let peer=host.writer.currentConnection(),selection=peer===void 0?void 0:host.writer.compactSelection(peer),connection=roleConnection(peer),incarnation=commandAuthority.getStore()?.incarnation;if(host.connectionRoles.isStale(connection,incarnation))return staleError(command.id,command.type,DELEGATION_INCARNATION_STALE);let role=caps=>host.connectionRoles.declare(connection,caps,incarnation)==="declared",origin=remoteOriginDeclaration(command.remoteOrigin,declared=>host.connectionRoles.acceptsOrigin(roleConnection(peer),declared));if("refusal"in origin)return error(command.id,command.type,origin.refusal);let reason=selection?selection.declare(command.capabilities,host.registry.supportsCompact?.()===!0,role):command.capabilities!==void 0&&!role(command.capabilities)?"connection_role_fixed":void 0;if(reason)return error(command.id,command.type,reason==="connection_role_fixed"?CONNECTION_ROLE_FIXED:reason);if(origin.origin!==void 0&&host.connectionRoles.declareOrigin(roleConnection(peer),origin.origin),peer!==void 0){let caps=compactUpdatesEnabled()?selection?.capabilities??command.capabilities??host.pendingCapabilities.get(peer)??[]:command.capabilities??[];host.pendingCapabilities.set(peer,[...caps]),host.writer.setConnectionCapabilities(peer,caps)}else command.capabilities!==void 0&&host.writer.setSoleSecretCapabilities(command.capabilities);return{id:command.id,type:"response",command:"set_client_info",success:!0,...selection?.ack()?{data:selection.ack()}:{}}}function compactAdmissionGate(host,command){if(!compactUpdatesEnabled())return;let peer=host.writer.currentConnection(),selection=peer===void 0?void 0:host.writer.compactSelection(peer);if(!(command.type==="open_session"||command.type==="attach_session"||command.type==="reclaim_session"||command.type==="reset_stream"||command.type==="subscribe_sessions"&&(command.admissionId!==void 0||command.mirror!==void 0&&command.mirror!=="none")))return;let refuse=reason=>error(command.id,command.type,reason);if(selection?.refused)return refuse("compact_selection_refused");if(command.admissionId!==void 0&&!selection?.selected)return refuse("compact_not_negotiated");if(selection?.selected){if((command.type==="open_session"||command.type==="attach_session"||command.type==="subscribe_sessions")&&command.admissionId===void 0)return refuse("compact_admission_required");if(command.type==="open_session"&&host.registry.supportsCompact?.({...host.defaults,...command})!==!0||command.type==="attach_session"&&!host.writer.recoveryLane(command.sessionId)||command.type==="subscribe_sessions"&&host.registry.list().some(row=>row.status==="open"&&!host.writer.recoveryLane(row.sessionId)))return refuse("compact_endpoint_unsupported")}selection&&(selection.admitted=!0)}function invalidCompactAdmission(command){if(!compactUpdatesEnabled()||command.type!=="cancel_attempt"&&command.type!=="reset_stream"&&!("admissionId"in command))return;let id="admissionId"in command?command.admissionId:void 0;if(!(typeof id=="string"&&parseBoundedId(id).ok))return error(command.id,command.type,"admission_malformed_request",{kind:"request_refused",reason:"malformed_request",hint:"new_request"})}function unknownCompactAdmission(host,command){if(!host.admissions||command.admissionId===void 0||command.type==="open_session"||command.type==="attach_session"||command.type==="subscribe_sessions"||command.type==="get_recovery_page"||command.type==="release_recovery")return;let admissionId=command.admissionId,peer=host.writer.currentConnection(),epoch=peer===void 0?void 0:host.writer.socketEpochOf(peer);if(peer!==void 0&&host.writer.holdsAdmission(peer,admissionId,"sessionId"in command?command.sessionId:void 0))return;let refusal3={id:command.id,type:"response",command:command.type,success:!1,error:"unknown_admission",errorCode:"unknown_admission",errorData:{code:"unknown_admission",admissionId},code:"unknown_admission",admissionId};return command.type==="cancel_attempt"&&epoch!==void 0?host.admissions.pending(epoch,admissionId).then(pending=>pending?void 0:refusal3,cause=>{if(!(cause instanceof CompactAdmissionError))throw cause;return error(command.id,command.type,`admission_${cause.reason}`,{kind:"request_refused",reason:cause.reason,hint:"new_request"})}):refusal3}import{createHash as createHash4}from"node:crypto";function statusSnapshot(events,socketEpoch,admissionId,sessionId,rows){let chunks=function*(){yield'{"seq":0,"snapshot":[';let comma="";for(let row of rows())yield comma,yield*jsonChunks(row,FRAGMENT_MAX_BYTES/2),comma=",";yield"]}"},minted=events.mint({socketEpoch,sessionId,admissionId},{sessionEpoch:hostInstanceId(),sequence:0},{},{chunks});if(!minted.ok)throw new CompactAdmissionError("storage_unavailable");return minted.value}async function compactSubscribe(host,command){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),events=host.writer.recoveryEvents,{admissionId,id,retry,...request}=command;if(peer===void 0||socketEpoch===void 0||!events||!host.admissions||admissionId===void 0)return error(id,command.type,"unsupported_transport");let fingerprint=createHash4("sha256").update(JSON.stringify(Object.entries(request).sort(([a],[b])=>a.localeCompare(b)))).digest("hex"),delivery,baseline,cancelledAnswer=async()=>(await host.admissions?.result(socketEpoch,admissionId))?.state==="cancelled"?{id,type:"response",command:command.type,success:!1,code:"attempt_cancelled",errorCode:"attempt_cancelled",error:"attempt_cancelled",admissionId,generation:0}:void 0;try{let identity={peer,socketEpoch,admissionId,fingerprint,retry:retry===!0},answer3=await host.admissions.run(identity,async()=>{let lease,subscribed=answerSubscribeSessions(command,peer,host.writer.status,(rows,subscriptionId2)=>{host.writer.registerSubscription(peer,admissionId,subscriptionId2),lease=statusSnapshot(events,socketEpoch,admissionId,subscriptionId2,rows)}),subscriptionId=subscribed.activate;if(!subscribed.answer.success||subscribed.answer.command!=="subscribe_sessions"||subscriptionId===void 0)return{answer:{...subscribed.answer},release:async()=>{}};if(lease===void 0)throw new CompactAdmissionError("storage_unavailable");let pending=host.writer.status.pendingBuffer(subscriptionId);if(!pending)throw new CompactAdmissionError("storage_unavailable");let eventLease=lease,identity2={sessionId:subscriptionId,admissionId,generation:0};delivery=Promise.withResolvers();let reply=delivery.promise,live=!0,installed=!1;baseline=()=>{installed||(installed=!0,host.writer.installAdmissionBaseline(peer,admissionBaseline(reply,{...identity2,eventLease,componentRef:"record"},()=>live),()=>host.writer.socketEpochOf(peer)===socketEpoch))};let{snapshot:_snapshot,...data2}=subscribed.answer.data;return{answer:{...subscribed.answer,...identity2,data:{...data2,recovery:eventLease}},activate:()=>{baseline?.(),host.writer.status.activate(subscriptionId)},refusal:()=>pending.reason===void 0?void 0:{...error(void 0,command.type,pending.reason,{kind:"request_refused",reason:pending.reason,hint:"new_request"}),admissionId,generation:0},release:async()=>{live&&(live=!1,host.writer.unregisterSubscription(peer,subscriptionId),host.writer.status.unsubscribe(peer,subscriptionId),events.abandon(socketEpoch,eventLease.id))}}});if(host.writer.socketEpochOf(peer)!==socketEpoch){delivery?.resolve(void 0);return}let response={...await cancelledAnswer()??answer3,id};delivery?(baseline?.(),delivery.resolve(response)):await host.writer.enqueueControl(response,peer);return}catch(cause){if(!(cause instanceof CompactAdmissionError))throw cause;let refusal3=await cancelledAnswer()??error(id,command.type,`admission_${cause.reason}`,{kind:"request_refused",reason:cause.reason,hint:"new_request"});if(delivery){baseline?.(),delivery.resolve({...refusal3});return}return refusal3}}async function resetStream(host,command){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),{sessionId,admissionId}=command,refused4=()=>error(command.id,command.type,"recovery_unknown_token",{kind:"repair_needed",reason:"unknown_token"});if(!host.admissions||peer===void 0||socketEpoch===void 0||sessionId===void 0)return refused4();let result=await host.admissions.result(socketEpoch,admissionId);if(result?.state!=="complete"||result.answer.sessionId!==sessionId&&!host.writer.isCompactSubscription(peer,admissionId,sessionId))return refused4();let checkpoints=host.writer.recoveryCheckpoints,caller={socketEpoch,sessionId},stream=checkpoints.stream(caller),lane=host.writer.recoveryLane(sessionId);if(!lane||!stream?.routes.includes(admissionId))return refused4();let routeKind=host.writer.isCompactSubscription(peer,admissionId,sessionId)?"mirror":"ordinary",frozen=checkpoints.freeze({...caller,peer,admissionId,routeKind},lane);if(!frozen.ok)return error(command.id,command.type,`recovery_${frozen.failure.kind}`,{...frozen.failure});let token=frozen.value.token,generation=token.admission.generation,answer3={id:command.id,type:"response",command:"reset_stream",success:!0,sessionId,admissionId,generation,data:{recovery:{token:token.id,componentRef:"manifest"}}};host.writer.installAdmissionBaseline(peer,admissionBaseline(Promise.resolve(answer3),{sessionId,admissionId,generation,token:token.id},()=>!0,stream.routes),()=>host.writer.socketEpochOf(peer)===socketEpoch)}import{createHmac,randomBytes,randomInt}from"node:crypto";var repairAdviceKey=randomBytes(32),tokenRetryAfterMs=token=>100+createHmac("sha256",repairAdviceKey).update(token,"utf8").digest().readUInt32BE(0)%1901,codeOf=failure=>failure.kind==="request_refused"?`recovery_${failure.reason}`:`recovery_${failure.kind}`;function callerOf(writer,command){let{id,type,sessionId}=command;if(sessionId===void 0)return error(id,type,RPC_ERROR_MISSING_SESSION_ID);let connection=writer.currentConnection(),socketEpoch=connection===void 0?void 0:writer.socketEpochOf(connection);return socketEpoch===void 0?error(id,type,RPC_ERROR_UNSUPPORTED_TRANSPORT):{socketEpoch,sessionId}}function refused2(id,type,reason){let failure={kind:"request_refused",reason,hint:"new_request"};return error(id,type,codeOf(failure),{...failure})}async function answerRecoveryPage(pages,writer,command){let caller=callerOf(writer,command);if("type"in caller)return caller;let{id,type}=command,lane=writer.recoveryLane(caller.sessionId),outcome;try{outcome=await pages.request(caller,command)}catch(cause){if(!(cause instanceof CompactStorageReadError||cause instanceof CompactReadError))throw cause;outcome={ok:!1,failure:storageUnavailable("unavailable")}}let source=!outcome.ok&&(outcome.failure.kind==="request_refused"||outcome.failure.reason==="unknown_token")?void 0:lane,healthRevision=null;try{source&&(healthRevision=await source.staging.store.health.revision())}catch(cause){if(!(cause instanceof Error))throw cause;outcome={ok:!1,failure:storageUnavailable("unavailable")}}let failure=outcome.ok?void 0:outcome.failure;if(failure?.kind==="request_refused")return error(id,type,codeOf(failure),{...failure});let repair={state:failure?.kind??"ok",healthRevision,source:source?{sessionEpoch:source.sessionEpoch,sequence:source.acceptedSequence}:null,hint:"restart_from_catalog",retryAfterMs:outcome.ok?0:failure?.reason==="unknown_token"?tokenRetryAfterMs("lease"in command?command.lease.id:command.token):randomInt(100,2001)},ordinary=writer.ordinaryRoute(writer.currentConnection()??"",caller.sessionId),generation=outcome.ok&&"generation"in outcome.value?outcome.value.generation:ordinary?.routes.includes(command.admissionId)?ordinary.generation:writer.isCompactSubscription(writer.currentConnection()??"",command.admissionId,caller.sessionId)?0:void 0;return outcome.ok?{id,type:"response",command:type,success:!0,...generation!==void 0?{sessionId:caller.sessionId,admissionId:command.admissionId,generation}:{},data:{...outcome.value,repair}}:error(id,type,codeOf(outcome.failure),{...outcome.failure,repair})}function answerReleaseRecovery(events,writer,command){let caller=callerOf(writer,command);if("type"in caller)return caller;let{id,type,lease,admissionId}=command,kind=lease?.kind;if(kind==="checkpoint")return refused2(id,type,"lease_kind_unsupported");if(kind!=="event"||typeof lease?.id!="string"||typeof admissionId!="string")return refused2(id,type,"malformed_request");let outcome=events.release(caller,lease.id,admissionId);return outcome.ok?(writer.unregisterSubscription(writer.currentConnection()??"",caller.sessionId),{id,type:"response",command:type,success:!0,data:outcome.value}):error(id,type,codeOf(outcome.failure),{...outcome.failure})}var UNSUPPORTED="hand_selection_unsupported";function sessionOf(host,sessionId){return host.registry.peek(sessionId)?.runtime?.session}function answerListHands(host,command){let selection=host.defaults.handSelection;if(selection===void 0)return error(command.id,command.type,UNSUPPORTED);let hands=selection.hands().map(({device,label,platform,reachable})=>({device,label,platform,reachable}));if(command.sessionId===void 0)return{id:command.id,type:"response",command:"list_hands",success:!0,data:{hands}};let session=sessionOf(host,command.sessionId);return session===void 0?error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION):{id:command.id,type:"response",command:"list_hands",success:!0,data:{hands,selected:selection.selected(session.sessionId)}}}function answerSelectHand(host,command){let selection=host.defaults.handSelection;if(selection===void 0)return error(command.id,command.type,UNSUPPORTED);let session;try{session=host.registry.getForCommand(command.sessionId,command.type).runtime?.session}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}if(session===void 0)return error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION);let outcome=selection.select(session.sessionId,session,command.device);return outcome.ok?{id:command.id,type:"response",command:"select_hand",success:!0,data:{sessionId:command.sessionId,selected:command.device}}:error(command.id,command.type,outcome.refusal,{device:command.device})}function afterCommitRefusal(host,command,owner){if(host.draining||host.drainExitRequested)return error(command.id,command.type,"session_busy_lifecycle",{reason:"host_draining"});if(!host.writer.hasConnection(owner)||host.releasedConnections.has(owner))return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});if(host.registry.peek(command.sessionId)?.state!=="open"||!host.bindings.has(command.sessionId))return error(command.id,command.type,"unknown_session",{})}function takeOtherHolds(host,sessionId,owner){let taken=[];for(let[connection,owned]of[...host.sessionsByConnection]){let holds=connection===owner?0:owned.get(sessionId)??0;for(let hold=0;hold<holds;hold++)releaseOwnerAttachment(host,connection,sessionId);holds>0&&taken.push([connection,holds])}return taken}async function takeOver(host,command,owner,attach2){let ledger=host.defaults.sessionTakeover;if(host.defaults.sessionOwner!=="machine"||ledger===void 0)return error(command.id,command.type,"takeover_unsupported",{reason:"only a headless engine with a takeover ledger takes sessions over"});if(typeof command.holder!="string"||command.holder.length===0)return error(command.id,command.type,"takeover_holder_required",{});let record;try{record=await ledger.takeOver(command.durableSessionId,command.holder)}catch(cause){return error(command.id,command.type,"takeover_failed",{reason:cause instanceof Error?cause.message:String(cause)})}let refused4=afterCommitRefusal(host,command,owner);if(refused4!==void 0)return refused4;try{attach2()}catch(cause){return error(command.id,command.type,code(cause),detail(cause)??{})}let taken=takeOtherHolds(host,command.sessionId,owner),released={type:"session_released",sessionId:command.sessionId,reason:"taken_over"};for(let[connection,holds]of taken){host.writer.hasConnection(connection)&&await host.writer.enqueueControl(released,connection);for(let hold=0;hold<holds;hold++)await releaseDisconnectAttachment(host,command.sessionId)}return{id:command.id,type:"response",command:command.type,success:!0,data:{sessionId:command.sessionId,attached:!0,holder:record.holder,generation:record.generation,released:taken.length}}}function identityMatches(host,entry,durableSessionId,expectedHostInstance){let durable=entry.runtime?.session.sessionId??entry.worker?.snapshot?.state.sessionId??entry.durableSessionId;return typeof durableSessionId=="string"&&durableSessionId.length>0&&durableSessionId===durable&&(expectedHostInstance===void 0||expectedHostInstance===(host.defaults.hostContext?.host_instance??hostInstanceId()))}function hostStopping(host){return host.draining||host.drainExitRequested}function drainingRefusal(host,command){if(hostStopping(host))return error(command.id,command.type,"session_busy_lifecycle",{reason:"host_draining"})}function attach(host,owner,sessionId){if(!host.registry.attachSession)throw new Error("live attachment is unavailable");host.registry.attachSession(sessionId),recordAttachment(host,owner,sessionId),host.writer.status.publish(sessionId,"attach","client")}function attachSession(host,command){let draining=drainingRefusal(host,command);if(draining)return draining;let entry=host.registry.peek(command.sessionId);if(entry?.state!=="open"||!host.bindings.has(command.sessionId))return error(command.id,command.type,"unknown_session",{});if(!identityMatches(host,entry,command.durableSessionId,command.expectedHostInstance))return error(command.id,command.type,"session_identity_mismatch",{});let owner=host.writer.currentConnection();if(owner===void 0)return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});if(command.takeover===!0)return takeOver(host,command,owner,()=>attach(host,owner,command.sessionId));if(command.admissionId!==void 0&&host.admissions)return compactOpen(host,command,async(accept,signal)=>{signal.throwIfAborted(),attach(host,owner,command.sessionId);try{await accept({sessionId:command.sessionId,durableSessionId:command.durableSessionId,attached:!0})}catch(cause){throw releaseOwnerAttachment(host,owner,command.sessionId),await releaseDisconnectAttachment(host,command.sessionId),cause}});try{return attach(host,owner,command.sessionId),{id:command.id,type:"response",command:command.type,success:!0,data:{sessionId:command.sessionId,attached:!0}}}catch(cause){return error(command.id,command.type,code(cause),detail(cause)??{})}}async function releaseAttachment(host,command){let owner=host.writer.currentConnection();if(owner===void 0||!host.sessionsByConnection.get(owner)?.has(command.sessionId))return error(command.id,command.type,"session_not_attached",{reason:"not_attached"});releaseOwnerAttachment(host,owner,command.sessionId);let deferred=!hostStopping(host)&&await releaseDisconnectAttachment(host,command.sessionId);return{id:command.id,type:"response",command:command.type,success:!0,data:{deferred}}}async function reclaimSession(host,command){let draining=drainingRefusal(host,command);if(draining)return draining;if(typeof command.sessionPath!="string"||command.sessionPath.length===0)return error(command.id,command.type,"unknown_session",{});let key=canonicalSessionPath(command.sessionPath),row=host.registry.list().find(candidate=>candidate.sessionPath!==void 0&&canonicalSessionPath(candidate.sessionPath)===key),entry=row&&host.registry.peek(row.sessionId);if(!row||!entry)return error(command.id,command.type,"unknown_session",{});if(entry.state!=="open"||!host.bindings.has(row.sessionId))return error(command.id,command.type,"session_busy_lifecycle",{});if(typeof command.expectedHostInstance!="string"||!identityMatches(host,entry,command.durableSessionId,command.expectedHostInstance))return error(command.id,command.type,"session_identity_mismatch",{});let owner=host.writer.currentConnection();if(owner===void 0)return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});let own=host.sessionsByConnection.get(owner)?.get(row.sessionId)??0,elsewhere=Math.max(0,entry.attachments-own);if(elsewhere>0)return error(command.id,command.type,"attached_elsewhere",{attachments:elsewhere});attach(host,owner,row.sessionId);let claim=claimClose(host,row.sessionId,{drainAttachments:!0});if(host.sessionsByConnection.get(owner)?.delete(row.sessionId),host.sessionsByConnection.get(owner)?.size===0&&host.sessionsByConnection.delete(owner),connectionLeft(host,row.sessionId,owner),host.handoverParkedDir!==void 0&&entry.sessionPath!==void 0&&await clearHandoverParkedSession(host.handoverParkedDir,entry.sessionPath).catch(()=>{}),claim.finalizer){let binding2=host.bindings.get(row.sessionId);binding2?.cancelPendingExtensionUiRequests?.(),await finalizeClose(host,row.sessionId,binding2,()=>host.writer.sealLifecycle(row.sessionId,{type:"session_closed",sessionId:row.sessionId,reason:"client_close"},!0))}return host.writer.detachConnectionFromSession(owner,row.sessionId),host.writer.forgetSession(row.sessionId),{id:command.id,type:"response",command:command.type,success:!0,data:{reclaimed:!0,sessionId:row.sessionId}}}var ATTACH_GATE_EXEMPT=new Set(["get_protocol_info","list_sessions","list_hands","subscribe_sessions","unsubscribe_sessions","get_subscription_limits","warm","detach_connection","open_session","attach_session","reclaim_session","get_effect_status","get_state","get_snapshot","get_messages","get_entries","get_tree","get_fork_messages","get_last_assistant_text","get_media","get_commands","get_loaded_surfaces","get_project_trust","get_project_settings","get_available_models","get_available_thinking_levels","get_fast_mode","get_session_stats","get_pending_inputs","get_steering_messages","get_follow_up_messages","get_auth_providers","get_provider_accounts","resolve_path","memory_report","eval_cells.list","eval_cells.peek","check_reload_veto"]);function logSafe(value){return JSON.stringify(value).slice(1,-1)}function attachmentGate(host,command){let owner=host.writer.currentConnection();if(!(owner===void 0||ATTACH_GATE_EXEMPT.has(command.type))&&!(!("sessionId"in command)||command.sessionId===void 0)&&!(host.writer.recoveryPages!==void 0&&(command.type==="get_recovery_page"||command.type==="release_recovery"))&&!(host.writer.recoveryPages!==void 0&&command.type==="reset_stream"&&host.writer.isCompactSubscription(owner,command.admissionId,command.sessionId))&&!(command.type==="close_session"||command.type==="set_session_context"||command.type==="release_attachment")&&!host.sessionsByConnection.get(owner)?.has(command.sessionId)){if(process.env.SENPI_RPC_REQUIRE_ATTACH==="1")return error(command.id,command.type,"session_not_attached",{reason:"this connection is not attached to that session",action:"attach first with attach_session { sessionId, durableSessionId } or open_session { sessionPath }"});process.stderr.write(`senpi rpc host: ${command.type} on ${logSafe(command.sessionId)} from a connection not attached to it (refused from the next release)
|
|
35
|
+
`)){let row=/^\s*(\d+)\s+(.+)$/.exec(line);if(!row)continue;let start=processStartTimeMs(row[2]);start!==void 0&&starts.set(Number(row[1]),start)}resolve2(starts)})})}function sessionHeldCheck(resolveDaemonPids){let daemonPids,processStarts,pidStarts=new Map,observedStarts=new Map;return async(sessionFile,sessionId)=>{let holders=await foreignSessionHolders(sessionFile,sessionId,{holderEnded:generation=>holderGenerationEnded(generation),readProcessStartMs:pid=>{let probe=pidStarts.get(pid);return probe||(probe=(async()=>{process.platform!=="linux"&&(processStarts??=readProcessStarts());let start=(await processStarts)?.get(pid)??await readProcessStartMs(pid);return observedStarts.set(pid,start),start})(),pidStarts.set(pid,probe)),probe}});if(holders.length===0)return;daemonPids??=resolveDaemonPids?.(observedStarts)??Promise.resolve([]);let family=await daemonPids,foreign=holders.filter(holder=>!family.includes(holder.pid));if(foreign.length>0)throw new RpcSessionRegistryError(RPC_ERROR_SESSION_HELD,void 0,{holders:foreign.map(({pid,cwd,host_socket,host_instance})=>({pid,...cwd===void 0?{}:{cwd},...host_socket===void 0?{}:{host_socket},...host_instance===void 0?{}:{host_instance}}))})}}async function dispatchSessionBinding(command,entry,binding2,acknowledgePrompt2,daemonPids){if(!binding2)throw new RpcSessionRegistryError("unknown_session");if(!READ_ONLY_OR_CONTROL.has(command.type)){let assertSessionNotHeld=sessionHeldCheck(daemonPids),state=entry.worker?.snapshot?.state;await assertSessionNotHeld(entry.runtime?.session.sessionFile??state?.sessionFile??entry.sessionPath,entry.runtime?.session.sessionId??state?.sessionId??entry.durableSessionId),"sessionPath"in command&&await assertSessionNotHeld(command.sessionPath)}command.type==="prompt"&&acknowledgePrompt2(),await binding2.handle(command)}function invalidSpawnedBy(command){let ancestry=command.spawnedBy;return ancestry!==void 0&&!isSpawnedBy(ancestry)}function validatedOpenProfile(host,command,options){let defaults=options?.defaults===!1?void 0:host.defaults,instanceId=host.defaults.hostContext?.host_instance??hostInstanceId();if(command.expectedHostInstance!==void 0){if(typeof command.expectedHostInstance!="string"||command.expectedHostInstance.trim()==="")return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: expectedHostInstance must be a non-empty string`,{reason:"invalid_expected_host_instance",action:"supply_host_instance"});if(command.expectedHostInstance!==instanceId)return error(command.id,"open_session",RPC_ERROR_OWNER_CHANGED,{reason:"host_instance_mismatch",action:"rediscover_holder",expectedHostInstance:command.expectedHostInstance,hostInstance:instanceId})}let kindError=sessionKindError(command.kind);if(command.attended!==void 0&&command.attended!==!1)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: attended must be false or omitted`);if(kindError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_KIND}: ${kindError}`);let contextError=sessionContextError(command.context);if(contextError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_CONTEXT}: ${contextError}`);let autoTitleError=sessionAutoTitleError(command.auto_title);if(autoTitleError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${autoTitleError}`);let promptSurfaceError=sessionPromptSurfaceError(command.promptSurface);if(promptSurfaceError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${promptSurfaceError}`);let browserEngineError=sessionBrowserEngineError(command.browserEngine);if(browserEngineError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${browserEngineError}`);if(!command.provider!=!command.modelId)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: provider and modelId must be given together`);let retryFallbackError=sessionRetryFallbackError(command.retryFallback);if(retryFallbackError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${retryFallbackError}`);let envError=sessionEnvError(command.env);if(envError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_ENV}: ${envError}`);let sessionEnv=inheritedSessionEnv(parentSessionEnv(host,command.spawnedBy?.parentSessionId),command.env);return{cwd:command.cwd??host.defaults.cwd,...command.attended===!1?{attended:!1}:{},sessionPath:command.sessionPath,holderEndpoint:{host_instance:instanceId,...process.env[HOST_DAEMON_DIR_ENV]?{host_daemon_dir:process.env[HOST_DAEMON_DIR_ENV]}:{},...host.defaults.hostContext?.host_socket===void 0?{}:{host_socket:host.defaults.hostContext.host_socket}},permissionPreset:command.permissionPreset??defaults?.permissionPreset,...command.permissionPreset===void 0&&defaults?.permissionPreset!==void 0?{permissionPresetSource:"host_default"}:{},creationModel:command.provider&&command.modelId?{provider:command.provider,modelId:command.modelId}:defaults?.creationModel,initialThinkingLevel:command.thinkingLevel??defaults?.initialThinkingLevel,sessionKind:command.kind,sessionContext:host.defaults.hostContext?{...command.context,...host.defaults.hostContext}:command.context,...command.durableSessionId!==void 0?{durableSessionId:command.durableSessionId}:{},...typeof command.auto_title=="boolean"?{autoTitle:command.auto_title}:{},...command.promptSurface!==void 0?{promptSurface:command.promptSurface}:{},...command.browserEngine!==void 0?{browserEngine:command.browserEngine}:{},...command.retryFallback!==void 0?{retryFallback:command.retryFallback}:{},...sessionEnv!==void 0?{sessionEnv}:{}}}function parentSessionEnv(host,parentSessionId){if(parentSessionId===void 0)return;let parent=host.registry.list().find(row=>row.durableSessionId===parentSessionId||row.sessionId===parentSessionId);if(parent===void 0)return;let entry=host.registry.peek(parent.sessionId);return entry?.state==="open"&&host.bindings.has(parent.sessionId)?entry.profile.sessionEnv:void 0}function openWithBarrier(host,command){return compactUpdatesEnabled()&&command.admissionId!==void 0?compactOpen(host,command,(accept,signal)=>openPhysicalWithBarrier(host,command,accept,signal)):openPhysicalWithBarrier(host,command)}function openPhysicalWithBarrier(host,command,accept,signal){let owner=host.writer.currentConnection();if(owner===void 0)return open(host,command);let resolveBarrier,barrier=new Promise(resolve2=>{resolveBarrier=resolve2}),opens=host.opensByConnection.get(owner)??new Set,inFlight=0;for(let pending of host.opensByConnection.values())inFlight+=pending.size;opens.add(barrier),host.opensByConnection.set(owner,opens),command.id!==void 0&&host.writer.sendOpenQueued(owner,{type:"queued",for_request:command.id,position:inFlight+1,in_flight:inFlight});let start=()=>open(host,command,owner,accept===void 0?void 0:{accept,signal});return(signal===void 0?start():runAdmissionProducer(signal,start,async()=>{})).finally(()=>{resolveBarrier(),opens.delete(barrier),opens.size===0&&host.opensByConnection.delete(owner)})}function reopenParked(host,entry){return open(host,{...parkedOpenCommand(entry),attended:!1},void 0,{reply:!1,defaults:!1,contextOverlay:entry.contextOverlay})}async function open(host,command,owner,options){let profile=validatedOpenProfile(host,command,options);if("type"in profile)return profile;let opened,timer=startOpenTimer(`host-open:${command.id??"-"}`),assertSessionNotHeld=sessionHeldCheck(observedStarts=>host.registry.holderPids?.(observedStarts)??Promise.resolve([]));try{if(await assertSessionNotHeld(command.sessionPath),timer.mark("held_check"),options?.signal?.throwIfAborted(),invalidSpawnedBy(command))return error(command.id,"open_session","invalid_spawned_by");let ancestry=command.spawnedBy;opened=await host.registry.openSession(ancestry?{...profile,spawnedBy:ancestry}:profile,{retainOnDisconnect:command.retain_on_disconnect===!0,attachOnly:command.expectedHostInstance!==void 0}),timer.mark("registry_open"),options?.signal?.throwIfAborted();let openedSession=opened;if(host.writer.isSessionSealed(openedSession.sessionId))return await releaseOwnedSession(host,openedSession.sessionId),opened=void 0,error(command.id,"open_session","session_output_overflow",{sessionId:openedSession.sessionId,sessionPath:openedSession.sessionPath,action:"unload_and_reopen"});let entry=host.registry.getForCommand(openedSession.sessionId,"open_session");!opened.attached&&options?.contextOverlay!==void 0&&(entry.contextOverlay=options.contextOverlay);let state=entry.worker?.snapshot?.state;await assertSessionNotHeld(entry.runtime?.session.sessionFile??state?.sessionFile??entry.sessionPath,entry.runtime?.session.sessionId??state?.sessionId??entry.durableSessionId),timer.mark("held_recheck"),host.writer.setSessionKind(openedSession.sessionId,entry.kind),host.writer.setSessionMedia(openedSession.sessionId,toolMediaPersister(()=>liveToolMediaScope(entry)));let lane=entry.acceptance??entry.worker?.acceptance;if(lane&&host.writer.registerAcceptance(openedSession.sessionId,lane),options?.accept&&await options.accept(openedSession),owner!==void 0&&(host.writer.hasRegisteredConnectionCapabilities(owner)||host.writer.setConnectionCapabilities(owner,host.pendingCapabilities.get(owner)??host.connectionOptions?.capabilities??[]),host.writer.attachConnectionToSession(owner,openedSession.sessionId,options?.accept!==void 0)),owner!==void 0){let owned=host.sessionsByConnection.get(owner)??new Map;owned.set(openedSession.sessionId,(owned.get(openedSession.sessionId)??0)+1),host.sessionsByConnection.set(owner,owned),host.attachOrder.attached(openedSession.sessionId,owner)}if(!host.bindings.has(openedSession.sessionId)){host.bindings.set(openedSession.sessionId,await host.createBinding(openedSession.sessionId,entry,host.writer,()=>{close(host,{type:"close_session",sessionId:openedSession.sessionId})},{...host.connectionOptions,capabilities:owner!==void 0?host.pendingCapabilities.get(owner)??host.connectionOptions?.capabilities??[]:host.connectionOptions?.capabilities,connectionRoles:host.connectionRoles,clientInfo:{setCapabilities:(connectionId,capabilities)=>{connectionId!==void 0&&(host.writer.setConnectionCapabilities(connectionId,capabilities),host.pendingCapabilities.set(connectionId,[...capabilities]))},connectionId:()=>host.writer.currentConnection(),relocationConnection:()=>relocationConnection(host,openedSession.sessionId),deliverTo:(connection,deliver)=>host.writer.withConnection(connection,deliver)}})),timer.mark("binding"),entry.worker&&(entry.worker.bindingReady=!0);let settled=()=>{host.draining&&queueMicrotask(()=>sweepDrain(host))};typeof entry.worker?.subscribeSettled=="function"?entry.worker.subscribeSettled(settled):typeof entry.runtime?.session.subscribe=="function"&&entry.runtime.session.subscribe(event=>{event.type==="agent_idle"&&settled()}),entry.worker&&entry.worker.exited.then(async()=>{await host.finalizations.get(openedSession.sessionId)?.promise,host.bindings.delete(openedSession.sessionId),forgetSessionOwnership(host,openedSession.sessionId),host.writer.forgetSession(openedSession.sessionId)})}if(options?.signal?.throwIfAborted(),opened.attached?host.writer.status.publish(openedSession.sessionId,"attach","client"):(host.writer.publishSessionOpened({type:"session_opened",sessionId:openedSession.sessionId,durableSessionId:openedSession.durableSessionId,...openedSession.sessionPath!==void 0?{sessionPath:openedSession.sessionPath}:{},kind:entry.kind,cwd:entry.cwd,context:entry.context}),host.writer.status.publish(openedSession.sessionId,"open","client")),!options?.accept&&!host.draining&&owner!==void 0&&host.releasedConnections.has(owner)&&(releaseOwnerAttachment(host,owner,openedSession.sessionId),await releaseOwnedSession(host,openedSession.sessionId)),await syncRetainedRecord(host,openedSession.sessionId,command.sessionPath),options?.accept)return;let replyState=entry.worker?.snapshot?.state??(entry.runtime?buildRpcSessionState(entry.runtime.session):void 0);if(!replyState)throw new Error("Session state was not created");timer.mark("reply"),options?.reply!==!1&&host.writer.enqueue(opened.sessionId,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:opened.sessionId,state:replyState,...openReplyPermissionMode(replyState),...opened.attached?{attached:!0}:{},...host.defaults.sessionPresence?{presence:host.defaults.sessionPresence.view(replyState.sessionId)}:{}}});return}catch(cause){if(opened){if(!opened.attached&&!options?.signal?.aborted){let entry=host.registry.peek(opened.sessionId);(entry?.runtime!==void 0||entry?.worker!==void 0)&&host.writer.sealRolledBackOpen(opened.sessionId,entry.sessionPath)}try{opened.attached?await releaseOwnedSession(host,opened.sessionId):await host.registry.close(opened.sessionId)}catch{}(!opened.attached||!compactUpdatesEnabled())&&host.writer.forgetSession(opened.sessionId)}if(cause instanceof CompactAdmissionError)throw cause;return error(command.id,"open_session",code(cause),detail(cause))}}async function detachConnection(command,connectionId,release){if(connectionId===void 0)return{id:command.id,type:"response",command:"detach_connection",success:!1,error:"detach_connection needs a socket connection"};let deferred=await release(connectionId);return{id:command.id,type:"response",command:"detach_connection",success:!0,data:{deferred:[...deferred]}}}function staleError(id,command,message){return{id,type:"response",command,success:!1,error:message,errorCode:"delegation_incarnation_stale"}}function declareSocketClient(host,command){let peer=host.writer.currentConnection(),selection=peer===void 0?void 0:host.writer.compactSelection(peer),connection=roleConnection(peer),incarnation=commandAuthority.getStore()?.incarnation;if(host.connectionRoles.isStale(connection,incarnation))return staleError(command.id,command.type,DELEGATION_INCARNATION_STALE);let role=caps=>host.connectionRoles.declare(connection,caps,incarnation)==="declared",origin=remoteOriginDeclaration(command.remoteOrigin,declared=>host.connectionRoles.acceptsOrigin(roleConnection(peer),declared));if("refusal"in origin)return error(command.id,command.type,origin.refusal);let reason=selection?selection.declare(command.capabilities,host.registry.supportsCompact?.()===!0,role):command.capabilities!==void 0&&!role(command.capabilities)?"connection_role_fixed":void 0;if(reason)return error(command.id,command.type,reason==="connection_role_fixed"?CONNECTION_ROLE_FIXED:reason);if(origin.origin!==void 0&&host.connectionRoles.declareOrigin(roleConnection(peer),origin.origin),peer!==void 0){let caps=compactUpdatesEnabled()?selection?.capabilities??command.capabilities??host.pendingCapabilities.get(peer)??[]:command.capabilities??[];host.pendingCapabilities.set(peer,[...caps]),host.writer.setConnectionCapabilities(peer,caps)}else command.capabilities!==void 0&&host.writer.setSoleSecretCapabilities(command.capabilities);return{id:command.id,type:"response",command:"set_client_info",success:!0,...selection?.ack()?{data:selection.ack()}:{}}}function compactAdmissionGate(host,command){if(!compactUpdatesEnabled())return;let peer=host.writer.currentConnection(),selection=peer===void 0?void 0:host.writer.compactSelection(peer);if(!(command.type==="open_session"||command.type==="attach_session"||command.type==="reclaim_session"||command.type==="reset_stream"||command.type==="subscribe_sessions"&&(command.admissionId!==void 0||command.mirror!==void 0&&command.mirror!=="none")))return;let refuse=reason=>error(command.id,command.type,reason);if(selection?.refused)return refuse("compact_selection_refused");if(command.admissionId!==void 0&&!selection?.selected)return refuse("compact_not_negotiated");if(selection?.selected){if((command.type==="open_session"||command.type==="attach_session"||command.type==="subscribe_sessions")&&command.admissionId===void 0)return refuse("compact_admission_required");if(command.type==="open_session"&&host.registry.supportsCompact?.({...host.defaults,...command})!==!0||command.type==="attach_session"&&!host.writer.recoveryLane(command.sessionId)||command.type==="subscribe_sessions"&&host.registry.list().some(row=>row.status==="open"&&!host.writer.recoveryLane(row.sessionId)))return refuse("compact_endpoint_unsupported")}selection&&(selection.admitted=!0)}function invalidCompactAdmission(command){if(!compactUpdatesEnabled()||command.type!=="cancel_attempt"&&command.type!=="reset_stream"&&!("admissionId"in command))return;let id="admissionId"in command?command.admissionId:void 0;if(!(typeof id=="string"&&parseBoundedId(id).ok))return error(command.id,command.type,"admission_malformed_request",{kind:"request_refused",reason:"malformed_request",hint:"new_request"})}function unknownCompactAdmission(host,command){if(!host.admissions||command.admissionId===void 0||command.type==="open_session"||command.type==="attach_session"||command.type==="subscribe_sessions"||command.type==="get_recovery_page"||command.type==="release_recovery")return;let admissionId=command.admissionId,peer=host.writer.currentConnection(),epoch=peer===void 0?void 0:host.writer.socketEpochOf(peer);if(peer!==void 0&&host.writer.holdsAdmission(peer,admissionId,"sessionId"in command?command.sessionId:void 0))return;let refusal3={id:command.id,type:"response",command:command.type,success:!1,error:"unknown_admission",errorCode:"unknown_admission",errorData:{code:"unknown_admission",admissionId},code:"unknown_admission",admissionId};return command.type==="cancel_attempt"&&epoch!==void 0?host.admissions.pending(epoch,admissionId).then(pending=>pending?void 0:refusal3,cause=>{if(!(cause instanceof CompactAdmissionError))throw cause;return error(command.id,command.type,`admission_${cause.reason}`,{kind:"request_refused",reason:cause.reason,hint:"new_request"})}):refusal3}import{createHash as createHash4}from"node:crypto";function statusSnapshot(events,socketEpoch,admissionId,sessionId,rows){let chunks=function*(){yield'{"seq":0,"snapshot":[';let comma="";for(let row of rows())yield comma,yield*jsonChunks(row,FRAGMENT_MAX_BYTES/2),comma=",";yield"]}"},minted=events.mint({socketEpoch,sessionId,admissionId},{sessionEpoch:hostInstanceId(),sequence:0},{},{chunks});if(!minted.ok)throw new CompactAdmissionError("storage_unavailable");return minted.value}async function compactSubscribe(host,command){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),events=host.writer.recoveryEvents,{admissionId,id,retry,...request}=command;if(peer===void 0||socketEpoch===void 0||!events||!host.admissions||admissionId===void 0)return error(id,command.type,"unsupported_transport");let fingerprint=createHash4("sha256").update(JSON.stringify(Object.entries(request).sort(([a],[b])=>a.localeCompare(b)))).digest("hex"),delivery,baseline,cancelledAnswer=async()=>(await host.admissions?.result(socketEpoch,admissionId))?.state==="cancelled"?{id,type:"response",command:command.type,success:!1,code:"attempt_cancelled",errorCode:"attempt_cancelled",error:"attempt_cancelled",admissionId,generation:0}:void 0;try{let identity={peer,socketEpoch,admissionId,fingerprint,retry:retry===!0},answer3=await host.admissions.run(identity,async()=>{let lease,subscribed=answerSubscribeSessions(command,peer,host.writer.status,(rows,subscriptionId2)=>{host.writer.registerSubscription(peer,admissionId,subscriptionId2),lease=statusSnapshot(events,socketEpoch,admissionId,subscriptionId2,rows)}),subscriptionId=subscribed.activate;if(!subscribed.answer.success||subscribed.answer.command!=="subscribe_sessions"||subscriptionId===void 0)return{answer:{...subscribed.answer},release:async()=>{}};if(lease===void 0)throw new CompactAdmissionError("storage_unavailable");let pending=host.writer.status.pendingBuffer(subscriptionId);if(!pending)throw new CompactAdmissionError("storage_unavailable");let eventLease=lease,identity2={sessionId:subscriptionId,admissionId,generation:0};delivery=Promise.withResolvers();let reply=delivery.promise,live=!0,installed=!1;baseline=()=>{installed||(installed=!0,host.writer.installAdmissionBaseline(peer,admissionBaseline(reply,{...identity2,eventLease,componentRef:"record"},()=>live),()=>host.writer.socketEpochOf(peer)===socketEpoch))};let{snapshot:_snapshot,...data2}=subscribed.answer.data;return{answer:{...subscribed.answer,...identity2,data:{...data2,recovery:eventLease}},activate:()=>{baseline?.(),host.writer.status.activate(subscriptionId)},refusal:()=>pending.reason===void 0?void 0:{...error(void 0,command.type,pending.reason,{kind:"request_refused",reason:pending.reason,hint:"new_request"}),admissionId,generation:0},release:async()=>{live&&(live=!1,host.writer.unregisterSubscription(peer,subscriptionId),host.writer.status.unsubscribe(peer,subscriptionId),events.abandon(socketEpoch,eventLease.id))}}});if(host.writer.socketEpochOf(peer)!==socketEpoch){delivery?.resolve(void 0);return}let response={...await cancelledAnswer()??answer3,id};delivery?(baseline?.(),delivery.resolve(response)):await host.writer.enqueueControl(response,peer);return}catch(cause){if(!(cause instanceof CompactAdmissionError))throw cause;let refusal3=await cancelledAnswer()??error(id,command.type,`admission_${cause.reason}`,{kind:"request_refused",reason:cause.reason,hint:"new_request"});if(delivery){baseline?.(),delivery.resolve({...refusal3});return}return refusal3}}async function resetStream(host,command){let peer=host.writer.currentConnection(),socketEpoch=peer===void 0?void 0:host.writer.socketEpochOf(peer),{sessionId,admissionId}=command,refused4=()=>error(command.id,command.type,"recovery_unknown_token",{kind:"repair_needed",reason:"unknown_token"});if(!host.admissions||peer===void 0||socketEpoch===void 0||sessionId===void 0)return refused4();let result=await host.admissions.result(socketEpoch,admissionId);if(result?.state!=="complete"||result.answer.sessionId!==sessionId&&!host.writer.isCompactSubscription(peer,admissionId,sessionId))return refused4();let checkpoints=host.writer.recoveryCheckpoints,caller={socketEpoch,sessionId},stream=checkpoints.stream(caller),lane=host.writer.recoveryLane(sessionId);if(!lane||!stream?.routes.includes(admissionId))return refused4();let routeKind=host.writer.isCompactSubscription(peer,admissionId,sessionId)?"mirror":"ordinary",frozen=checkpoints.freeze({...caller,peer,admissionId,routeKind},lane);if(!frozen.ok)return error(command.id,command.type,`recovery_${frozen.failure.kind}`,{...frozen.failure});let token=frozen.value.token,generation=token.admission.generation,answer3={id:command.id,type:"response",command:"reset_stream",success:!0,sessionId,admissionId,generation,data:{recovery:{token:token.id,componentRef:"manifest"}}};host.writer.installAdmissionBaseline(peer,admissionBaseline(Promise.resolve(answer3),{sessionId,admissionId,generation,token:token.id},()=>!0,stream.routes),()=>host.writer.socketEpochOf(peer)===socketEpoch)}import{createHmac,randomBytes,randomInt}from"node:crypto";var repairAdviceKey=randomBytes(32),tokenRetryAfterMs=token=>100+createHmac("sha256",repairAdviceKey).update(token,"utf8").digest().readUInt32BE(0)%1901,codeOf=failure=>failure.kind==="request_refused"?`recovery_${failure.reason}`:`recovery_${failure.kind}`;function callerOf(writer,command){let{id,type,sessionId}=command;if(sessionId===void 0)return error(id,type,RPC_ERROR_MISSING_SESSION_ID);let connection=writer.currentConnection(),socketEpoch=connection===void 0?void 0:writer.socketEpochOf(connection);return socketEpoch===void 0?error(id,type,RPC_ERROR_UNSUPPORTED_TRANSPORT):{socketEpoch,sessionId}}function refused2(id,type,reason){let failure={kind:"request_refused",reason,hint:"new_request"};return error(id,type,codeOf(failure),{...failure})}async function answerRecoveryPage(pages,writer,command){let caller=callerOf(writer,command);if("type"in caller)return caller;let{id,type}=command,lane=writer.recoveryLane(caller.sessionId),outcome;try{outcome=await pages.request(caller,command)}catch(cause){if(!(cause instanceof CompactStorageReadError||cause instanceof CompactReadError))throw cause;outcome={ok:!1,failure:storageUnavailable("unavailable")}}let source=!outcome.ok&&(outcome.failure.kind==="request_refused"||outcome.failure.reason==="unknown_token")?void 0:lane,healthRevision=null;try{source&&(healthRevision=await source.staging.store.health.revision())}catch(cause){if(!(cause instanceof Error))throw cause;outcome={ok:!1,failure:storageUnavailable("unavailable")}}let failure=outcome.ok?void 0:outcome.failure;if(failure?.kind==="request_refused")return error(id,type,codeOf(failure),{...failure});let repair={state:failure?.kind??"ok",healthRevision,source:source?{sessionEpoch:source.sessionEpoch,sequence:source.acceptedSequence}:null,hint:"restart_from_catalog",retryAfterMs:outcome.ok?0:failure?.reason==="unknown_token"?tokenRetryAfterMs("lease"in command?command.lease.id:command.token):randomInt(100,2001)},ordinary=writer.ordinaryRoute(writer.currentConnection()??"",caller.sessionId),generation=outcome.ok&&"generation"in outcome.value?outcome.value.generation:ordinary?.routes.includes(command.admissionId)?ordinary.generation:writer.isCompactSubscription(writer.currentConnection()??"",command.admissionId,caller.sessionId)?0:void 0;return outcome.ok?{id,type:"response",command:type,success:!0,...generation!==void 0?{sessionId:caller.sessionId,admissionId:command.admissionId,generation}:{},data:{...outcome.value,repair}}:error(id,type,codeOf(outcome.failure),{...outcome.failure,repair})}function answerReleaseRecovery(events,writer,command){let caller=callerOf(writer,command);if("type"in caller)return caller;let{id,type,lease,admissionId}=command,kind=lease?.kind;if(kind==="checkpoint")return refused2(id,type,"lease_kind_unsupported");if(kind!=="event"||typeof lease?.id!="string"||typeof admissionId!="string")return refused2(id,type,"malformed_request");let outcome=events.release(caller,lease.id,admissionId);return outcome.ok?(writer.unregisterSubscription(writer.currentConnection()??"",caller.sessionId),{id,type:"response",command:type,success:!0,data:outcome.value}):error(id,type,codeOf(outcome.failure),{...outcome.failure})}var UNSUPPORTED="hand_selection_unsupported";function sessionOf(host,sessionId){return host.registry.peek(sessionId)?.runtime?.session}function answerListHands(host,command){let selection=host.defaults.handSelection;if(selection===void 0)return error(command.id,command.type,UNSUPPORTED);let hands=selection.hands().map(({device,label,platform,reachable})=>({device,label,platform,reachable}));if(command.sessionId===void 0)return{id:command.id,type:"response",command:"list_hands",success:!0,data:{hands}};let session=sessionOf(host,command.sessionId);return session===void 0?error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION):{id:command.id,type:"response",command:"list_hands",success:!0,data:{hands,selected:selection.selected(session.sessionId)}}}function answerSelectHand(host,command){let selection=host.defaults.handSelection;if(selection===void 0)return error(command.id,command.type,UNSUPPORTED);let session;try{session=host.registry.getForCommand(command.sessionId,command.type).runtime?.session}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}if(session===void 0)return error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION);let outcome=selection.select(session.sessionId,session,command.device);return outcome.ok?{id:command.id,type:"response",command:"select_hand",success:!0,data:{sessionId:command.sessionId,selected:command.device}}:error(command.id,command.type,outcome.refusal,{device:command.device})}function afterCommitRefusal(host,command,owner){if(host.draining||host.drainExitRequested)return error(command.id,command.type,"session_busy_lifecycle",{reason:"host_draining"});if(!host.writer.hasConnection(owner)||host.releasedConnections.has(owner))return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});if(host.registry.peek(command.sessionId)?.state!=="open"||!host.bindings.has(command.sessionId))return error(command.id,command.type,"unknown_session",{})}function takeOtherHolds(host,sessionId,owner){let taken=[];for(let[connection,owned]of[...host.sessionsByConnection]){let holds=connection===owner?0:owned.get(sessionId)??0;for(let hold=0;hold<holds;hold++)releaseOwnerAttachment(host,connection,sessionId);holds>0&&taken.push([connection,holds])}return taken}async function takeOver(host,command,owner,attach2){let ledger=host.defaults.sessionTakeover;if(host.defaults.sessionOwner!=="machine"||ledger===void 0)return error(command.id,command.type,"takeover_unsupported",{reason:"only a headless engine with a takeover ledger takes sessions over"});if(typeof command.holder!="string"||command.holder.length===0)return error(command.id,command.type,"takeover_holder_required",{});let record;try{record=await ledger.takeOver(command.durableSessionId,command.holder)}catch(cause){return error(command.id,command.type,"takeover_failed",{reason:cause instanceof Error?cause.message:String(cause)})}let refused4=afterCommitRefusal(host,command,owner);if(refused4!==void 0)return refused4;try{attach2()}catch(cause){return error(command.id,command.type,code(cause),detail(cause)??{})}let taken=takeOtherHolds(host,command.sessionId,owner),released={type:"session_released",sessionId:command.sessionId,reason:"taken_over"};for(let[connection,holds]of taken){host.writer.hasConnection(connection)&&await host.writer.enqueueControl(released,connection);for(let hold=0;hold<holds;hold++)await releaseDisconnectAttachment(host,command.sessionId)}return{id:command.id,type:"response",command:command.type,success:!0,data:{sessionId:command.sessionId,attached:!0,holder:record.holder,generation:record.generation,released:taken.length}}}function identityMatches(host,entry,durableSessionId,expectedHostInstance){let durable=entry.runtime?.session.sessionId??entry.worker?.snapshot?.state.sessionId??entry.durableSessionId;return typeof durableSessionId=="string"&&durableSessionId.length>0&&durableSessionId===durable&&(expectedHostInstance===void 0||expectedHostInstance===(host.defaults.hostContext?.host_instance??hostInstanceId()))}function hostStopping(host){return host.draining||host.drainExitRequested}function drainingRefusal(host,command){if(hostStopping(host))return error(command.id,command.type,"session_busy_lifecycle",{reason:"host_draining"})}function attach(host,owner,sessionId){if(!host.registry.attachSession)throw new Error("live attachment is unavailable");host.registry.attachSession(sessionId),recordAttachment(host,owner,sessionId),host.writer.status.publish(sessionId,"attach","client")}function attachSession(host,command){let draining=drainingRefusal(host,command);if(draining)return draining;let entry=host.registry.peek(command.sessionId);if(entry?.state!=="open"||!host.bindings.has(command.sessionId))return error(command.id,command.type,"unknown_session",{});if(!identityMatches(host,entry,command.durableSessionId,command.expectedHostInstance))return error(command.id,command.type,"session_identity_mismatch",{});let owner=host.writer.currentConnection();if(owner===void 0)return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});if(command.takeover===!0)return takeOver(host,command,owner,()=>attach(host,owner,command.sessionId));if(command.admissionId!==void 0&&host.admissions)return compactOpen(host,command,async(accept,signal)=>{signal.throwIfAborted(),attach(host,owner,command.sessionId);try{await accept({sessionId:command.sessionId,durableSessionId:command.durableSessionId,attached:!0})}catch(cause){throw releaseOwnerAttachment(host,owner,command.sessionId),await releaseDisconnectAttachment(host,command.sessionId),cause}});try{return attach(host,owner,command.sessionId),{id:command.id,type:"response",command:command.type,success:!0,data:{sessionId:command.sessionId,attached:!0}}}catch(cause){return error(command.id,command.type,code(cause),detail(cause)??{})}}async function releaseAttachment(host,command){let owner=host.writer.currentConnection();if(owner===void 0||!host.sessionsByConnection.get(owner)?.has(command.sessionId))return error(command.id,command.type,"session_not_attached",{reason:"not_attached"});releaseOwnerAttachment(host,owner,command.sessionId);let deferred=!hostStopping(host)&&await releaseDisconnectAttachment(host,command.sessionId);return{id:command.id,type:"response",command:command.type,success:!0,data:{deferred}}}async function reclaimSession(host,command){let draining=drainingRefusal(host,command);if(draining)return draining;if(typeof command.sessionPath!="string"||command.sessionPath.length===0)return error(command.id,command.type,"unknown_session",{});let key=canonicalSessionPath(command.sessionPath),row=host.registry.list().find(candidate=>candidate.sessionPath!==void 0&&canonicalSessionPath(candidate.sessionPath)===key),entry=row&&host.registry.peek(row.sessionId);if(!row||!entry)return error(command.id,command.type,"unknown_session",{});if(entry.state!=="open"||!host.bindings.has(row.sessionId))return error(command.id,command.type,"session_busy_lifecycle",{});if(typeof command.expectedHostInstance!="string"||!identityMatches(host,entry,command.durableSessionId,command.expectedHostInstance))return error(command.id,command.type,"session_identity_mismatch",{});let owner=host.writer.currentConnection();if(owner===void 0)return error(command.id,command.type,"session_not_attached",{reason:"no_connection"});let own=host.sessionsByConnection.get(owner)?.get(row.sessionId)??0,elsewhere=Math.max(0,entry.attachments-own);if(elsewhere>0)return error(command.id,command.type,"attached_elsewhere",{attachments:elsewhere});attach(host,owner,row.sessionId);let claim=claimClose(host,row.sessionId,{drainAttachments:!0});if(host.sessionsByConnection.get(owner)?.delete(row.sessionId),host.sessionsByConnection.get(owner)?.size===0&&host.sessionsByConnection.delete(owner),connectionLeft(host,row.sessionId,owner),host.handoverParkedDir!==void 0&&await clearRetainedRecord(host,entry),claim.finalizer){let binding2=host.bindings.get(row.sessionId);binding2?.cancelPendingExtensionUiRequests?.(),await finalizeClose(host,row.sessionId,binding2,()=>host.writer.sealLifecycle(row.sessionId,{type:"session_closed",sessionId:row.sessionId,reason:"client_close"},!0))}return host.writer.detachConnectionFromSession(owner,row.sessionId),host.writer.forgetSession(row.sessionId),{id:command.id,type:"response",command:command.type,success:!0,data:{reclaimed:!0,sessionId:row.sessionId}}}var ATTACH_GATE_EXEMPT=new Set(["get_protocol_info","list_sessions","list_hands","subscribe_sessions","unsubscribe_sessions","get_subscription_limits","warm","detach_connection","open_session","attach_session","reclaim_session","get_effect_status","get_state","get_snapshot","get_messages","get_entries","get_tree","get_fork_messages","get_last_assistant_text","get_media","get_commands","get_loaded_surfaces","get_project_trust","get_project_settings","get_available_models","get_available_thinking_levels","get_fast_mode","get_session_stats","get_pending_inputs","get_steering_messages","get_follow_up_messages","get_auth_providers","get_provider_accounts","resolve_path","memory_report","eval_cells.list","eval_cells.peek","check_reload_veto"]);function logSafe(value){return JSON.stringify(value).slice(1,-1)}function attachmentGate(host,command){let owner=host.writer.currentConnection();if(!(owner===void 0||ATTACH_GATE_EXEMPT.has(command.type))&&!(!("sessionId"in command)||command.sessionId===void 0)&&!(host.writer.recoveryPages!==void 0&&(command.type==="get_recovery_page"||command.type==="release_recovery"))&&!(host.writer.recoveryPages!==void 0&&command.type==="reset_stream"&&host.writer.isCompactSubscription(owner,command.admissionId,command.sessionId))&&!(command.type==="close_session"||command.type==="set_session_context"||command.type==="release_attachment")&&!host.sessionsByConnection.get(owner)?.has(command.sessionId)){if(process.env.SENPI_RPC_REQUIRE_ATTACH==="1")return error(command.id,command.type,"session_not_attached",{reason:"this connection is not attached to that session",action:"attach first with attach_session { sessionId, durableSessionId } or open_session { sessionPath }"});process.stderr.write(`senpi rpc host: ${command.type} on ${logSafe(command.sessionId)} from a connection not attached to it (refused from the next release)
|
|
33
36
|
`)}}import{join as join8}from"node:path";import{readdir as readdir2}from"node:fs/promises";var SessionCopyRefusal=class extends Error{constructor(code2,detail2){super(detail2),this.name="SessionCopyRefusal",this.code=code2}};async function idTaken(dir,sessionId){return(await readdir2(dir).catch(error2=>{if(error2.code==="ENOENT")return[];throw error2})).some(name=>sessionFileNameId(name)===sessionId)}async function copySessionAs(options){let entries=await loadEntriesFromFileAsync(options.sourceFile),cwd=entries.find(entry=>entry.type==="session")?.cwd;if(!cwd)throw new Error(`The session at ${options.sourceFile} has no working directory in its header.`);if(headerSessionId(entries)===options.sessionId)throw new SessionCopyRefusal("invalid_move_request","The copy needs a new session id: under the source's own id it would stay read-only.");let dir=options.sessionDir(cwd);return serializeByKey(`session-copy:${dir}:${options.sessionId}`,async()=>{if(await idTaken(dir,options.sessionId))throw new SessionCopyRefusal("move_target_occupied",`A session with id ${options.sessionId} already exists in ${dir}. Copy under another id.`);let sessionPath=SessionManager.forkFrom(options.sourceFile,cwd,dir,{id:options.sessionId}).getSessionFile();if(sessionPath===void 0)throw new Error("The copy was created without a session file.");return{session_id:options.sessionId,session_path:sessionPath}})}import{copyFile,mkdir as mkdir2,readdir as readdir3,rename,rm as rm4,writeFile as writeFile3}from"node:fs/promises";import{basename,dirname,join as join5,posix,relative,sep}from"node:path";import{realpath}from"node:fs/promises";import{resolve}from"node:path";async function realSessionPath(path){let absolute=resolve(path);try{return await realpath(absolute)}catch{return absolute}}var lockKey=resolvedPath=>`session-move:${resolvedPath}`,pathChains=new Map;function orderedRealPath(path){let key=resolve(path),next=(pathChains.get(key)??Promise.resolve("")).then(()=>realSessionPath(path));return pathChains.set(key,next),next.then(()=>{pathChains.get(key)===next&&pathChains.delete(key)}),next}var moveLockKey=async sessionFile=>lockKey(await orderedRealPath(sessionFile));async function withSessionMoveLock2(sessionFile,step,guard){let path=await orderedRealPath(sessionFile);return serializeByKey(lockKey(path),async()=>{await guard?.();let sessionId=headerSessionId(await loadEntriesFromFileAsync(path));return sessionId===void 0?step():withSessionMoveLock(path,sessionId,step)})}function exportSessionForMove(options){return withSessionMoveLock2(options.sessionFile,async()=>(await options.lockedGuard?.(),writeMoveBundle(options)),options.guard)}var MovedStateMissingError=class extends Error{constructor(dir){super(`The extension state the move release staged is missing (${dir}); the session was not exported without it. Finish the move as declined to take the session back, then release it again.`),this.name="MovedStateMissingError"}};async function writeMoveBundle(options){let{sessionFile}=options,moveId=parseMoveId(options.moveId),entries=await loadEntriesFromFileAsync(sessionFile),sessionId=parsePlainId(headerSessionId(entries),"session id"),holders=await liveSessionHolders(sessionFile,sessionId);if(holders.length>0)throw new SessionHeldError(sessionFile,holders);let ownership=sessionOwnership(entries);if(!ownership.writable&&!(ownership.state==="moving"&&ownership.moveId===moveId))throw new SessionMovedAwayError(sessionFile,ownership);ownership.writable&&(await SessionManager.openAsync(sessionFile)).appendCustomEntry(SESSION_RELEASED,{reason:"move",move_id:moveId,session_id:sessionId,target:options.target,released_at:new Date().toISOString()});let stateDir=typeof options.extensionStateDir=="function"?await options.extensionStateDir():options.extensionStateDir;if(stateDir!==void 0&&!await pathExists(stateDir))throw new MovedStateMissingError(stateDir);let staging=`${options.bundleDir}.partial-${process.pid}`;await rm4(staging,{recursive:!0,force:!0}),await mkdir2(join5(staging,dirname(SESSION_BUNDLE_PATH)),{recursive:!0}),await copyFile(sessionFile,join5(staging,SESSION_BUNDLE_PATH));let sidecars=await copySidecars(dirname(sessionFile),sessionId,staging),stateFiles=await copyExtensionState(stateDir,staging),manifest={format:MOVE_BUNDLE_FORMAT,moveId,sessionId,sessionFileName:basename(sessionFile),sourceCwd:await readSessionCwd(sessionFile)??"",repository:await readRecordedRepositoryIdentity(sessionFile),session:{path:SESSION_BUNDLE_PATH,sha256:await sha256File(join5(staging,SESSION_BUNDLE_PATH))},sidecars,droppedUserMessages:[...options.droppedUserMessages],payloads:stateFiles.length>0?[{kind:EXTENSION_STATE_PAYLOAD,files:stateFiles}]:[]};return await writeFile3(join5(staging,MANIFEST_FILE),`${JSON.stringify(manifest,null,1)}
|
|
34
37
|
`),await rm4(options.bundleDir,{recursive:!0,force:!0}),await rename(staging,options.bundleDir),manifest}async function copySidecars(sessionDir,sessionId,staging){let sources=[],extensions=join5(sessionDir,"extensions"),sidecarName=`${encodedSessionId(sessionId)}.json`;if(await pathExists(extensions))for(let extension of await readdir3(extensions,{withFileTypes:!0})){let file=join5(extensions,extension.name,sidecarName);extension.isDirectory()&&await pathExists(file)&&sources.push(file)}sources.push(...await filesUnder(join5(sessionDir,"resident-blobs",sessionId)));let files=[];for(let source of sources){let path=bundlePath("files",sessionDir,source);await mkdir2(dirname(join5(staging,path)),{recursive:!0}),await copyFile(source,join5(staging,path)),files.push({path,sha256:await sha256File(join5(staging,path))})}return files}async function copyExtensionState(dir,staging){if(dir===void 0)return[];let files=[];for(let source of await filesUnder(dir)){let path=bundlePath("state",dir,source);await mkdir2(dirname(join5(staging,path)),{recursive:!0}),await copyFile(source,join5(staging,path)),files.push({path,sha256:await sha256File(join5(staging,path))})}return files}function bundlePath(prefix,from,source){return posix.join(prefix,...relative(from,source).split(sep))}async function filesUnder(dir){if(!await pathExists(dir))return[];let files=[];for(let entry of await readdir3(dir,{withFileTypes:!0})){let path=join5(dir,entry.name);files.push(...entry.isDirectory()?await filesUnder(path):[path])}return files}import{rm as rm5}from"node:fs/promises";var hook;function moveStep(step){hook?.(step)}async function requeueInput(sessionFile,moveId,texts){if(texts.length===0)return;let sessionManager=await SessionManager.openAsync(sessionFile),next=0,inputs=new SessionPendingInputs({sessionManager,nextQueuedId:()=>`move-${moveId}-${next++}`});for(let[index,text2]of texts.entries())await inputs.admit({clientMessageId:`move:${moveId}:${index}`,text:text2,mode:"followUp"},()=>{})}var MoveMismatchError=class extends Error{constructor(expected,found,what){super(`The answer is about move ${expected}, but ${what} belongs to move ${found}; nothing was changed. Finish each move with its own answer and bundle.`),this.code="move_mismatch",this.name="MoveMismatchError"}},MoveAlreadyMovedError=class extends Error{constructor(moveId){super(`The receiver revoked its copy for move ${moveId}, but this session file was already marked moved by an earlier accepted answer; nothing was changed and no copy is writable. Copy the session to a new thread to keep working from it.`),this.code="move_already_moved",this.name="MoveAlreadyMovedError"}};function finishMove(options){return withSessionMoveLock2(options.sessionFile,()=>settleMove(options),options.guard)}async function settleMove(options){let{sessionFile,bundleDir,moveId,answer:answer3}=options;if(await pathExists(bundleDir)){let bundled=(await readManifest(bundleDir)).moveId;if(bundled!==moveId)throw new MoveMismatchError(moveId,bundled,"the kept bundle")}let entries=await loadEntriesFromFileAsync(sessionFile),ownership=sessionOwnership(entries);if(ownership.writable){reclaimed(entries,moveId)&&await requeueDroppedInput(sessionFile,bundleDir),await discardMoveFiles(sessionFile,bundleDir,moveId);return}if(ownership.moveId!==moveId)throw new MoveMismatchError(moveId,ownership.moveId,"the session file");if(ownership.state==="moved"){if("revoked"in answer3)throw new MoveAlreadyMovedError(moveId);await discardMoveFiles(sessionFile,bundleDir,moveId);return}let sessionId=headerSessionId(entries)??"";switch(answer3.state){case"receiving":return;case"accepted":if("revoked"in answer3){await takeBack(sessionFile,bundleDir,{move_id:moveId,session_id:sessionId,reason:"revoked"});break}(await SessionManager.openAsync(sessionFile)).appendCustomEntry(SESSION_MOVED,{move_id:moveId,session_id:sessionId,target:ownership.target,moved_at:new Date().toISOString()}),moveStep("finish:recorded");break;case"declined":case"failed":await takeBack(sessionFile,bundleDir,{move_id:moveId,session_id:sessionId,reason:answer3.state,detail:answer3.reason});break;default:{let unreachable=answer3;throw new Error(`Unknown move answer ${JSON.stringify(unreachable)}`)}}moveStep("finish:requeued"),await discardMoveFiles(sessionFile,bundleDir,moveId)}async function takeBack(sessionFile,bundleDir,data2){(await SessionManager.openAsync(sessionFile)).appendCustomEntry(SESSION_RECLAIMED,{...data2,reclaimed_at:new Date().toISOString()}),moveStep("finish:recorded"),await requeueDroppedInput(sessionFile,bundleDir)}async function discardMoveFiles(sessionFile,bundleDir,moveId){await rm5(bundleDir,{recursive:!0,force:!0}),await rm5(outgoingStateDir(sessionFile,moveId),{recursive:!0,force:!0})}function reclaimed(entries,moveId){return entries.some(entry=>entry.type==="custom"&&entry.customType===SESSION_RECLAIMED&&entry.data?.move_id===moveId)}async function requeueDroppedInput(sessionFile,bundleDir){if(!await pathExists(bundleDir))return;let manifest=await readManifest(bundleDir);await requeueInput(sessionFile,manifest.moveId,manifest.droppedUserMessages)}import{copyFile as copyFile2,mkdir as mkdir4,readdir as readdir4,rm as rm6}from"node:fs/promises";import{dirname as dirname2,join as join7}from"node:path";import{mkdir as mkdir3,readFile as readFile3,rename as renameFile,writeFile as writeFile4}from"node:fs/promises";import{join as join6}from"node:path";function parseLanding(value){if(typeof value!="object"||value===null)return{};let{target,committing}=value;return{...typeof target=="string"?{target}:{},...committing===!0?{committing:!0}:{}}}function settledLanding(record,committing,outcome){if(record?.state==="receiving"&&committing)return outcome==="absent"?{state:"failed",reason:"import_failed"}:outcome==="revoked"?{state:"accepted",revoked:!0}:{state:"accepted"};if(record?.state==="accepted"&&!("revoked"in record)&&outcome==="revoked")return{state:"accepted",revoked:!0}}function landsAt(record,landing,target){return record?.state==="receiving"&&landing.committing!==!0&&landing.target===target}function landedElsewhere(record,landing){let stored=landing.target;return record?.state==="accepted"&&"revoked"in record?"it was revoked here and never lands again":record?.state==="receiving"&&landing.committing===!0?"an import of it stopped mid-commit, and a move lands once; only the file it landed is accepted":record?.state==="accepted"?"it already landed here once, and a move lands once (a deleted copy is gone; copy the session to a new thread instead)":record?.state==="receiving"&&stored===void 0?"an older version started receiving it and where it landed is unknown; only its already landed file is accepted":stored===void 0?void 0:`it lands only as ${stored}`}var LOCK_OPTIONS={realpath:!1,stale:1e4,update:2e3,retries:0},LOCK_WAIT_MS=15e3,MoveRecordUnlockedError=class extends Error{constructor(file){super(`Move record ${file} was written outside its lock; the write was refused.`),this.code="move_record_unlocked",this.name="MoveRecordUnlockedError"}},MoveRecordLocks=class{#held=new Map;async hold(file,fn){let held=await acquireMoveRecordLock(file);this.#held.set(file,held);try{return await fn()}finally{this.#held.delete(file),await held.release().catch(()=>{})}}assertHeld(file){let held=this.#held.get(file);if(held===void 0)throw new MoveRecordUnlockedError(file);held.assertHeld()}};async function acquireMoveRecordLock(file){let startedAt=Date.now();for(let attempt=0;;attempt+=1)try{return await lockWithLossHandling(file,{...LOCK_OPTIONS,lockfilePath:`${file}.lock`})}catch(error2){if(!isLockError(error2))throw error2;let waited=Date.now()-startedAt;if(waited>=LOCK_WAIT_MS)throw new Error(`Move record ${file} stayed locked for ${waited}ms`,{cause:error2});let delay2=Math.min(FILE_STORAGE_LOCK_RETRY_MIN_DELAY_MS*2**attempt,FILE_STORAGE_LOCK_RETRY_MAX_DELAY_MS);await new Promise(resolve2=>setTimeout(resolve2,delay2))}}var READY_TTL_MS=10*6e4,FINAL_STATES=["accepted","declined","failed"],MoveFencedError=class extends Error{constructor(moveId,record,detail2){super(`Move ${moveId} can no longer be imported here: ${detail2??`it was already answered (${record?.state??"no record"})`}.`),this.code="move_fenced",this.name="MoveFencedError",this.record=record}},DECLINE_REASONS=["no_record","expired","cancelled","chunk_without_ready","repository"],FAIL_REASONS=["bundle_invalid","import_failed"];function parseMoveStatus(value){let record=parseRecord(value);return record?.state==="ready"?void 0:record}function parseRecord(value){if(typeof value!="object"||value===null)return;let{state,reason}=value;if(state==="accepted"&&value.revoked===!0)return{state,revoked:!0};if(state==="receiving")return{state};if(state==="accepted")return{state};let{expiresAt}=value;if(state==="ready"&&typeof expiresAt=="string"&&!Number.isNaN(Date.parse(expiresAt)))return{state,expiresAt};let decline=DECLINE_REASONS.find(known=>known===reason);if(state==="declined"&&decline!==void 0)return{state,reason:decline};let fail2=FAIL_REASONS.find(known=>known===reason);if(state==="failed"&&fail2!==void 0)return{state,reason:fail2}}var MoveLedger=class{#locks=new MoveRecordLocks;constructor(dir,options={}){this.dir=dir,this.now=options.now??Date.now}prepare(moveId){return this.locked(moveId,async()=>{let record=await this.current(moveId);if(record===void 0){let ready={state:"ready",expiresAt:new Date(this.now()+READY_TTL_MS).toISOString()};return await this.write(moveId,ready),ready}if(record.state==="ready"||record.state==="receiving"||record.state==="accepted")return record;throw new MoveFencedError(moveId,record)})}beginReceive(moveId,target){return this.locked(moveId,async()=>{let record=await this.current(moveId),landing=await this.landing(moveId);if(record?.state==="ready"){await this.write(moveId,{state:"receiving"},{target});return}if(landsAt(record,landing,target))return;if(record?.state==="receiving"||record?.state==="accepted")throw new MoveFencedError(moveId,record,landedElsewhere(record,landing));if(record!==void 0)throw new MoveFencedError(moveId,record);let declined={state:"declined",reason:"chunk_without_ready"};throw await this.write(moveId,declined),new MoveFencedError(moveId,declined)})}expire(moveId){return this.locked(moveId,()=>this.current(moveId))}answerStatus(moveId,here){return this.locked(moveId,async()=>{let record=await this.reconcile(moveId,await this.current(moveId),here.landed);if(here.revoked===!0)return{state:"accepted",revoked:!0};if(record?.state==="accepted")return record;if(here.movedIn)return{state:"accepted"};if(record?.state==="ready")return{state:"receiving"};if(record!==void 0)return record;let declined={state:"declined",reason:"no_record"};return await this.write(moveId,declined),declined})}decline(moveId,reason){return this.settle(moveId,{state:"declined",reason},["receiving"])}fail(moveId,reason,options={}){return this.locked(moveId,async()=>await options.unlessLanded?.()?this.current(moveId):this.settleLocked(moveId,{state:"failed",reason},[]))}commit(moveId,target,rename2,prepare){return this.locked(moveId,async()=>{let record=await this.read(moveId),landing=await this.landing(moveId);if(!landsAt(record,landing,target))throw new MoveFencedError(moveId,record,landedElsewhere(record,landing));await prepare?.(),await this.write(moveId,{state:"receiving"},{target,committing:!0}),moveStep("import:stamped");let result=await rename2();return moveStep("import:renamed"),await this.write(moveId,{state:"accepted"},{target}),result})}confirmLanded(moveId,target,revoked){return this.locked(moveId,async()=>{let record=await this.read(moveId),landing=await this.landing(moveId);if(!(record===void 0||record.state==="receiving"||record.state==="accepted")||landing.target!==void 0&&landing.target!==target)throw new MoveFencedError(moveId,record,landedElsewhere(record,landing));let marked=record?.state==="accepted"&&"revoked"in record;record?.state==="accepted"&&(marked||!revoked)||await this.write(moveId,revoked?{state:"accepted",revoked:!0}:{state:"accepted"},{target})})}async reconcile(moveId,record,landed){let{target,committing}=await this.landing(moveId);if(landed===void 0||target===void 0)return record;let next=settledLanding(record,committing===!0,await landed(target));return next===void 0?record:(await this.write(moveId,next,{target}),next)}markRevoked(moveId){return this.locked(moveId,async()=>{let record=await this.read(moveId);if(record!==void 0&&record.state!=="receiving"&&record.state!=="accepted"||record?.state==="accepted"&&"revoked"in record)return;let{target}=await this.landing(moveId);await this.write(moveId,{state:"accepted",revoked:!0},target===void 0?{}:{target})})}settle(moveId,next,keeps){return this.locked(moveId,()=>this.settleLocked(moveId,next,keeps))}async settleLocked(moveId,next,keeps){let record=await this.current(moveId);return record!==void 0&&(FINAL_STATES.includes(record.state)||keeps.includes(record.state))||record!==void 0&&(await this.landing(moveId)).committing===!0?record:(await this.write(moveId,next),next)}async current(moveId){let record=await this.read(moveId);if(record?.state!=="ready"||this.now()<Date.parse(record.expiresAt))return record;let expired={state:"declined",reason:"expired"};return await this.write(moveId,expired),expired}path(moveId){return join6(this.dir,`${parseMoveId(moveId)}.json`)}async raw(moveId){try{return JSON.parse(await readFile3(this.path(moveId),"utf8"))}catch(error2){if(error2.code==="ENOENT")return;throw error2}}async read(moveId){let value=await this.raw(moveId);if(value===void 0)return;let record=parseRecord(value);if(record===void 0)throw new Error(`Move record ${this.path(moveId)} is not a move record`);return record}async landing(moveId){return parseLanding(await this.raw(moveId))}async write(moveId,record,landing={}){let file=this.path(moveId),temp=`${file}.${process.pid}.tmp`;this.#locks.assertHeld(file),await writeFile4(temp,`${JSON.stringify({...record,...landing,at:new Date().toISOString()})}
|
|
35
|
-
`),this.#locks.assertHeld(file),await renameFile(temp,file)}locked(moveId,fn){let file=this.path(moveId);return serializeByKey(file,async()=>(await mkdir3(this.dir,{recursive:!0}),this.#locks.hold(file,fn)))}};var RevokeMismatchError=class extends Error{constructor(moveId){super(`This session file is not the copy this device imported for move ${moveId}; nothing was changed. Revoke only the copy that move brought in, with that move's id.`),this.code="move_mismatch",this.name="RevokeMismatchError"}},REVOKED="revoked";function revokeImportedMove(options){return withSessionMoveLock2(options.sessionFile,async()=>{await seal(options.sessionFile,options.moveId),moveStep("revoke:sealed"),await options.ledger.markRevoked(options.moveId),moveStep("revoke:marked")},options.guard)}async function seal(sessionFile,moveId){let entries=await loadEntriesFromFileAsync(sessionFile),sessionId=headerSessionId(entries),ownership={writable:!0},latest;for(let entry of entries){let step=ownershipStep(ownership,entry,sessionId);step.kind==="apply"&&(ownership=step.next,latest=entry)}let ofThisMove=latest!==void 0&&data(latest,"move_id")===moveId;if(!(ofThisMove&&latest?.customType===SESSION_MOVED&&data(latest,"reason")===REVOKED)){if(!(ownership.writable&&ofThisMove&&latest?.customType===SESSION_MOVED_IN))throw new RevokeMismatchError(moveId);(await SessionManager.openAsync(sessionFile)).appendCustomEntry(SESSION_MOVED,{move_id:moveId,session_id:sessionId??"",target:data(latest,"from")??"",reason:REVOKED,moved_at:new Date().toISOString()})}}function data(entry,key){if(typeof entry.data!="object"||entry.data===null)return;let value=entry.data[key];return typeof value=="string"?value:void 0}var MoveRefusedError=class extends Error{constructor(targetCwd,sourceCwd){super(`${targetCwd} is not the same repository the session was recorded in (${sourceCwd}). Pick a checkout of the same repository, or copy the session into this folder instead.`),this.name="MoveRefusedError",this.code="move_repository_mismatch"}},MoveTargetOccupiedError=class extends Error{constructor(target){super(`A session that can still be written already sits at ${target}; the moved session was not imported over it. Close or move that session first, then send it again.`),this.code="move_target_occupied",this.name="MoveTargetOccupiedError"}},movedInFor=async(file,moveId)=>(await loadEntriesFromFileAsync(file)).some(entry=>entry.type==="custom"&&entry.customType===SESSION_MOVED_IN&&entry.data?.move_id===moveId);async function importOutcome(file,moveId){let outcome="absent";for(let entry of await loadEntriesFromFileAsync(file)){if(entry.type!=="custom")continue;let data2=entry.data;data2?.move_id===moveId&&(entry.customType===SESSION_MOVED_IN?outcome="moved_in":outcome==="moved_in"&&entry.customType===SESSION_MOVED&&data2.reason===REVOKED&&(outcome="revoked"))}return outcome}var StatusPathMismatchError=class extends Error{constructor(moveId,sessionFile){super(`${sessionFile} is not the copy this device imported for move ${moveId}; nothing was answered. Pass the session_path import returned for this move, or leave sessionPath out to answer from this device's record.`),this.code="move_mismatch",this.name="StatusPathMismatchError"}};async function answerMoveStatus(ledger,moveId,sessionFile){let landed=async target=>await pathExists(target)?importOutcome(target,moveId):"absent";return sessionFile===void 0||!await pathExists(sessionFile)?ledger.answerStatus(moveId,{movedIn:!1,landed}):serializeByKey(await moveLockKey(sessionFile),async()=>{let outcome=await importOutcome(sessionFile,moveId);if(outcome==="absent")throw new StatusPathMismatchError(moveId,sessionFile);return ledger.answerStatus(moveId,{movedIn:!0,revoked:outcome==="revoked",landed})})}async function importMovedSession(options){let manifest=await readManifest(options.bundleDir),targetCwd=resolvePath(options.targetCwd),sessionDir=options.sessionDir?normalizePath(options.sessionDir):getDefaultSessionDir(targetCwd),target=join7(sessionDir,manifest.sessionFileName),landed=async()=>await pathExists(target)&&await movedInFor(target,manifest.moveId);if(await landed())return await options.ledger.confirmLanded(manifest.moveId,target,await importOutcome(target,manifest.moveId)==="revoked"),{sessionFile:target};try{await verifyBundle(options.bundleDir,manifest)}catch(error2){throw error2 instanceof MoveBundleInvalidError&&await options.ledger.fail(manifest.moveId,"bundle_invalid",{unlessLanded:landed}),error2}let read=options.readIdentity??readRepositoryIdentity;if(compareRepositoryIdentities(manifest.repository,await read(targetCwd))!=="same")throw await landed()||await options.ledger.decline(manifest.moveId,"repository"),new MoveRefusedError(targetCwd,manifest.sourceCwd);await options.ledger.beginReceive(manifest.moveId,target),moveStep("import:received");let staging=join7(sessionDir,".move-staging",encodeURIComponent(manifest.moveId));try{let staged=await stage(options.bundleDir,manifest,staging,options.from??""),sessionFile=await options.ledger.commit(manifest.moveId,target,()=>rebindSessionFile(staged,targetCwd,sessionDir),async()=>{await replacePredecessor(target,manifest.sessionId,sessionDir),await placeExtensionState(staging,manifest,movedStateDir(target,manifest.moveId))});return moveStep("import:accepted"),await rm6(staging,{recursive:!0,force:!0}),{sessionFile}}catch(error2){throw error2 instanceof MoveFencedError||await options.ledger.fail(manifest.moveId,error2 instanceof MoveBundleInvalidError?"bundle_invalid":"import_failed",{unlessLanded:landed}),error2}}async function replacePredecessor(target,sessionId,sessionDir){if(!await pathExists(target))return;let entries=await loadEntriesFromFileAsync(target);if(headerSessionId(entries)!==sessionId||sessionOwnership(entries).writable)throw new MoveTargetOccupiedError(target);let extensions=join7(sessionDir,"extensions");if(await pathExists(extensions))for(let extension of await readdir4(extensions,{withFileTypes:!0}))extension.isDirectory()&&await rm6(join7(extensions,extension.name,`${encodedSessionId(sessionId)}.json`),{force:!0});await rm6(join7(sessionDir,"resident-blobs",sessionId),{recursive:!0,force:!0}),await rm6(target,{force:!0})}var STAGED_PAYLOADS=".payloads",extensionStateFiles=manifest=>manifest.payloads.filter(payload=>payload.kind===EXTENSION_STATE_PAYLOAD).flatMap(p=>p.files);async function stagePayloads(bundleDir,manifest,staging){for(let file of manifest.payloads.flatMap(payload=>payload.files)){let to=join7(staging,STAGED_PAYLOADS,file.path);if(await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(bundleDir,file.path),to),await sha256File(to)!==file.sha256)throw new MoveBundleInvalidError(`${file.path} changed in transit`)}}async function placeExtensionState(staging,manifest,dir){let files=extensionStateFiles(manifest);if(files.length!==0){await rm6(dir,{recursive:!0,force:!0});for(let file of files){let to=join7(dir,file.path.slice(EXTENSION_STATE_PREFIX.length));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(staging,STAGED_PAYLOADS,file.path),to)}}}async function stage(bundleDir,manifest,staging,from){let file=join7(staging,manifest.sessionFileName);if(!(await pathExists(file)&&await movedInFor(file,manifest.moveId))){await rm6(staging,{recursive:!0,force:!0});for(let item of[manifest.session,...manifest.sidecars]){let to=item===manifest.session?file:join7(staging,item.path.replace(/^files\//,""));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(bundleDir,item.path),to)}await stagePayloads(bundleDir,manifest,staging),(await SessionManager.openAsync(file,staging)).appendCustomEntry(SESSION_MOVED_IN,{move_id:manifest.moveId,session_id:manifest.sessionId,from,bundle_sha256:manifest.session.sha256,moved_in_at:new Date().toISOString()})}return await requeueInput(file,manifest.moveId,manifest.droppedUserMessages),file}var MOVE_SESSION_CAPABILITY="move_session",MOVE_SESSION_REVOKE_CAPABILITY="move_session_revoke",MOVE_SESSION_COPY_CAPABILITY="move_session_copy",RPC_ERROR_INVALID_MOVE_REQUEST="invalid_move_request",RPC_ERROR_SESSION_OPEN_HERE="session_open_here",RPC_ERROR_MOVE_NOT_RELEASED="move_not_released",RPC_ERROR_MOVE_FAILED="move_failed";import{isAbsolute}from"node:path";function plainMoveId(value){try{return parseMoveId(value)}catch{return}}var text=value=>typeof value=="string"&&value.trim()!=="",PLAIN_ID_RULE="a letter or digit, then letters, digits, '.', '_' or '-', at most 128 characters";function parseCopy(raw){return text(raw.sessionPath)?isPlainId(raw.sessionId)?raw.sessionDir!==void 0&&(!text(raw.sessionDir)||!isAbsolute(raw.sessionDir))?"sessionDir must be an absolute path.":{op:"copy",sessionPath:raw.sessionPath,sessionId:raw.sessionId,sessionDir:raw.sessionDir}:`sessionId must be a plain id: ${PLAIN_ID_RULE}.`:"copy needs sessionPath, the session file to copy."}function parseMoveRequest(raw){let{op}=raw;if(op==="import"){if(!text(raw.bundleDir)||!text(raw.cwd)||!isAbsolute(raw.bundleDir)||!isAbsolute(raw.cwd))return"import needs bundleDir and cwd as absolute paths.";let from=typeof raw.from=="string"?raw.from:void 0;return raw.from!==void 0&&from===void 0?"from must be a string.":{op,bundleDir:raw.bundleDir,cwd:raw.cwd,from:from??""}}if(op==="copy")return parseCopy(raw);let id=plainMoveId(raw.moveId);if(id===void 0)return`moveId must be a plain id: ${PLAIN_ID_RULE}.`;switch(op){case"prepare":case"cancel":return{op,moveId:id};case"status":{let sessionPath=text(raw.sessionPath)?raw.sessionPath:void 0;return raw.sessionPath!==void 0&&sessionPath===void 0?"sessionPath must be a non-empty string.":{op,moveId:id,sessionPath}}case"export":{let dropped=raw.droppedUserMessages??[];return!text(raw.sessionPath)||!text(raw.target)?"export needs sessionPath and target.":!Array.isArray(dropped)||!dropped.every(item=>typeof item=="string")?"droppedUserMessages must be the dropped.user_messages strings release_session returned.":{op,sessionPath:raw.sessionPath,moveId:id,target:raw.target,dropped}}case"finish":{let answer3=parseMoveStatus(raw.answer);return!text(raw.sessionPath)||answer3===void 0?"finish needs sessionPath and the receiver's answer from status (receiving, accepted, declined or failed).":{op,sessionPath:raw.sessionPath,moveId:id,answer:answer3}}case"revoke":return text(raw.sessionPath)?{op,sessionPath:raw.sessionPath,moveId:id}:"revoke needs sessionPath, the copy this host imported for the move.";default:return'op must be one of "prepare", "cancel", "status", "export", "import", "finish", "revoke" or "copy".'}}var CORE_CODES=new Set(["move_fenced","move_bundle_invalid","move_repository_mismatch","move_target_occupied","move_mismatch","move_already_moved","session_moved_away","invalid_move_request"]),RENAMED_CODES={ESESSIONHELD:"session_held"},wireRecord=record=>record.state==="ready"?{state:"ready",expires_at:record.expiresAt}:record;async function moveSession(port,command){let raw={...command},parsed=parseMoveRequest(raw);if(typeof parsed=="string")return refusal(command.id,RPC_ERROR_INVALID_MOVE_REQUEST,parsed);let root=join8(port.agentDir,"session-moves"),ledger=new MoveLedger(join8(root,"ledger")),outgoing=moveId=>join8(root,"outgoing",moveId);try{return answer(command.id,await run(parsed,port,ledger,outgoing))}catch(cause){if(cause instanceof MoveRefusal)return refusal(command.id,cause.code,cause.message);let code2=typeof cause=="object"&&cause!==null&&"code"in cause?cause.code:void 0,detail2=cause instanceof Error?cause.message:String(cause);return refusal(command.id,typeof code2=="string"?RENAMED_CODES[code2]??(CORE_CODES.has(code2)?code2:RPC_ERROR_MOVE_FAILED):RPC_ERROR_MOVE_FAILED,detail2)}}async function run(parsed,port,ledger,outgoing){switch(parsed.op){case"prepare":return wireRecord(await ledger.prepare(parsed.moveId));case"cancel":return wireRecord(await ledger.decline(parsed.moveId,"cancelled"));case"status":return answerMoveStatus(ledger,parsed.moveId,parsed.sessionPath);case"export":{let sessionFile=await orderedRealPath(parsed.sessionPath),bundleDir=outgoing(parsed.moveId),manifest=await exportSessionForMove({sessionFile,moveId:parsed.moveId,target:parsed.target,droppedUserMessages:parsed.dropped,bundleDir,extensionStateDir:()=>sealedOutgoingStateDir(sessionFile,parsed.moveId),guard:async()=>{await refuseOpenHere(port,sessionFile,"This session is open on this host. Release it with release_session reason move and this moveId first."),await refuseUnlessSealedFor(sessionFile,parsed.moveId)},lockedGuard:()=>refuseUnlessSealedFor(sessionFile,parsed.moveId)});return{move_id:manifest.moveId,session_id:manifest.sessionId,bundle_dir:bundleDir,files:1+manifest.sidecars.length}}case"import":{let cwd=resolvePath(parsed.cwd),sessionDir=getDefaultSessionDir(cwd,port.agentDir),{sessionFile}=await importMovedSession({bundleDir:normalizePath(parsed.bundleDir),targetCwd:cwd,ledger,sessionDir,from:parsed.from}),sessionId=headerSessionId(await loadEntriesFromFileAsync(sessionFile));if(sessionId===void 0)throw new Error(`The imported session at ${sessionFile} has no id in its header.`);return{session_id:sessionId,session_path:sessionFile}}case"finish":{let sessionFile=await orderedRealPath(parsed.sessionPath);return await finishMove({sessionFile,bundleDir:outgoing(parsed.moveId),moveId:parsed.moveId,answer:parsed.answer,guard:()=>refuseOpenHere(port,sessionFile,"This session is open on this host, so its runtime would not see the move end. Close it here, then finish the move.")}),ownershipOf(sessionFile)}case"revoke":{let sessionFile=await orderedRealPath(parsed.sessionPath);return await revokeImportedMove({sessionFile,moveId:parsed.moveId,ledger,guard:()=>refuseOpenHere(port,sessionFile,"This session is open on this host, so its runtime would not see the revoke. Close it here, then revoke the move.")}),ownershipOf(sessionFile)}case"copy":return copySessionAs({sourceFile:await orderedRealPath(parsed.sessionPath),sessionId:parsed.sessionId,sessionDir:cwd=>parsed.sessionDir===void 0?getDefaultSessionDir(cwd,port.agentDir):normalizePath(parsed.sessionDir)})}}async function ownershipOf(sessionFile){let ownership=sessionOwnership(await loadEntriesFromFileAsync(sessionFile));return{ownership:ownership.writable?"writable":ownership.state}}var MoveRefusal=class extends Error{constructor(code2,detail2){super(detail2),this.name="MoveRefusal",this.code=code2}};async function refuseUnlessSealedFor(sessionFile,moveId){let ownership=sessionOwnership(await loadEntriesFromFileAsync(sessionFile));if(ownership.writable||ownership.state!=="moving"||ownership.moveId!==moveId)throw new MoveRefusal(RPC_ERROR_MOVE_NOT_RELEASED,"This session file is not sealed for this move. Release it with release_session reason move and this moveId first; that also hands back its queued input.")}async function refuseOpenHere(port,sessionFile,detail2){if((await Promise.all(port.hostedPaths().map(path=>realSessionPath(path)))).includes(sessionFile))throw new MoveRefusal(RPC_ERROR_SESSION_OPEN_HERE,detail2)}function answer(id,data2){return"refuse"in data2?refusal(id,data2.refuse,data2.detail):{id,type:"response",command:"move_session",success:!0,data:data2}}function refusal(id,code2,detail2){return{id,type:"response",command:"move_session",success:!1,error:code2,errorCode:code2,errorData:{detail:detail2}}}import{rm as rm7}from"node:fs/promises";var NOTHING_DROPPED={deliveries:[],user_messages:[]};function takeQueuedInput(session){let admittedBefore=session.externalAdmission.list().pending,cleared=session.clearQueue({abortWillFollow:!0}),stillAdmitted=new Set(session.externalAdmission.list().pending);return{deliveries:admittedBefore.filter(deliveryId=>!stillAdmitted.has(deliveryId)),user_messages:cleared.ordered.map(queued=>queued.text)}}async function abortAndSettle(port,sessionId,session){session.abortBash();let stopStarts=session.subscribe(event=>{event.type==="agent_start"&&session.abort()}),deadline,expired=new Promise(resolve2=>{deadline=setTimeout(resolve2,1e4)});try{await Promise.race([Promise.allSettled([session.abort().then(()=>session.waitForIdle()),port.otherRequestsSettled(sessionId),...port.pendingPrompts(sessionId)]),expired])}finally{clearTimeout(deadline),stopStarts()}}var SESSION_RELEASED_ENTRY_TYPE="session_released",RELEASED_ADMISSION_CLOSED="release_session handed this session to another runtime; deliver there instead (admission is closed here)",RELEASE_QUEUED_HINT="queued user input is still owed a turn; release with interrupt: true to take it out and receive it in dropped.user_messages";async function releaseSession(port,command){let validMove=command.reason==="move"&&isMoveId(command.moveId);if(command.reason!=="takeover"&&!validMove)return refusal2(command.id,RPC_ERROR_INVALID_RELEASE_REASON);if(port.draining())return refusal2(command.id,RPC_ERROR_HOST_DRAINING);let first=releasable(port,command,void 0);if(!("session"in first))return first;if(command.reason==="move"&&!isPlainId(first.session.sessionManager.getSessionId()))return refusal2(command.id,RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"session_id_not_plain"});let busy=busySignals(port,command.sessionId,first.session),interrupted=busy.length>0;if(interrupted&&command.interrupt!==!0)return refusal2(command.id,busyCode(busy),{attachments:first.attachments,...busyData(busy)});let admission=first.session.externalAdmission,dropped=NOTHING_DROPPED,answer3,stagedState,sealed=!1;try{interrupted&&(admission.close(RELEASED_ADMISSION_CLOSED),dropped=takeQueuedInput(first.session),await abortAndSettle(port,command.sessionId,first.session),await first.session.whenQueueClearRecorded());let manager=first.session.sessionManager;if(manager.isTranscriptFlushed()||await manager.persistHeaderNow(),command.reason==="move"){let moveId=parseMoveId(command.moveId);stagedState=await prepareOutgoingState(first.sessionPath,moveId);let[failed]=await first.session.extensionRunner.emitSessionMove({type:"session_move_export",moveId,dir:stagedState.dir});if(failed!==void 0)throw new Error(`${failed.extensionPath} could not write its state for the move: ${failed.error}`)}return answer3=await claimAndRelease(port,command,interrupted,dropped,stagedState?.attempt,()=>{sealed=!0}),answer3}catch(cause){return cause instanceof SessionMovedAwayError?(answer3=refusal2(command.id,cause.code,{detail:cause.message,...interrupted?{interrupted:!0,dropped}:{}}),answer3):(answer3=refusal2(command.id,RPC_ERROR_RELEASE_FAILED,{detail:cause instanceof Error?cause.message:String(cause),...interrupted?{interrupted:!0,dropped}:{}}),answer3)}finally{answer3?.success!==!0&&(admission.reopen(),stagedState!==void 0&&!sealed&&await rm7(stagedState.dir,{recursive:!0,force:!0}))}}async function claimAndRelease(port,command,interrupted,dropped,stateAttempt,onSealed){let taken=interrupted?{interrupted:!0,dropped}:void 0,ready=releasable(port,command,taken);if(!("session"in ready))return ready;let stillBusy=busySignals(port,command.sessionId,ready.session);if(stillBusy.length>0)return refusal2(command.id,busyCode(stillBusy),{attachments:ready.attachments,...busyData(stillBusy),interrupted,...taken});let admission=ready.session.externalAdmission;admission.close(RELEASED_ADMISSION_CLOSED);try{ready.session.sessionManager.appendCustomEntry(SESSION_RELEASED_ENTRY_TYPE,{reason:command.reason,...command.reason==="move"?{move_id:command.moveId,...stateAttempt===void 0?{}:{[STATE_ATTEMPT_FIELD]:stateAttempt},target:command.target??"",session_id:ready.session.sessionManager.getSessionId()}:{},interrupted,attachments:ready.attachments,host_instance:port.hostInstance??null,released_at:new Date().toISOString()})}catch(cause){throw admission.reopen(),cause}return onSealed(),await port.tearDown(command.sessionId,ready.sessionPath)?{id:command.id,type:"response",command:"release_session",success:!0,data:{released:!0,session_path:ready.sessionPath,attachments:ready.attachments,dropped}}:refusal2(command.id,RPC_ERROR_SESSION_CLOSING,taken)}function busySignals(port,sessionId,session){let activity=session.activitySnapshot,signals=[];return activity.isStreaming&&signals.push("turn"),port.pendingPrompts(sessionId).length>0&&signals.push("prompt"),session.pendingMessageCount>0&&signals.push("queued"),session.externalAdmission.list().pending.length>0&&signals.push("delivery"),activity.isBashRunning&&signals.push("bash"),activity.isCompacting&&signals.push("compaction"),activity.hasSessionWork&&signals.push("session_work"),signals.length===0&&isHandoffBusy(activity)&&signals.push("activity"),port.otherRequests(sessionId)>0&&signals.push("request"),signals}function busyData(signals){return signals.includes("queued")?{busy:signals,retry_with:{interrupt:!0},hint:RELEASE_QUEUED_HINT}:{busy:signals}}function busyCode(signals){return signals.some(signal=>signal==="turn"||signal==="prompt"||signal==="queued"||signal==="delivery")?RPC_ERROR_TURN_ACTIVE:RPC_ERROR_SESSION_BUSY}function releasable(port,command,taken){let refuse=(code2,data2)=>refusal2(command.id,code2,data2||taken?{...data2,...taken}:void 0),entry;try{entry=port.lookup(command.sessionId)}catch(cause){return refuse(port.code(cause))}if(entry.state!=="open")return refuse(RPC_ERROR_SESSION_CLOSING);let session=entry.runtime?.session;if(session===void 0)return refuse(RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"worker_runtime"});let sessionPath=entry.sessionPath??session.sessionFile;if(sessionPath===void 0)return refuse(RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"no_session_file"});let elsewhere=port.otherAttachments(command.sessionId);return elsewhere>0&&command.force!==!0?refuse(RPC_ERROR_ATTACHED,{attachments:elsewhere}):{session,sessionPath,attachments:entry.attachments}}function refusal2(id,code2,data2){return{id,type:"response",command:"release_session",success:!1,error:code2,...data2&&{errorCode:code2,errorData:data2}}}var UNLOAD_SESSION_CAPABILITY="unload_session",SUBSCRIPTION_LIMITS_CAPABILITY="subscription_limits",RESOLVE_PATH_CAPABILITY="resolve_path";function multiSessionHostCapabilities(options){return[...new Set(["multi_session","snapshot_cursor","ui_answer_ledger","secret_input_v1","dialog_observer",...options.mcpPresenters?["mcp_form_presenter_v1"]:[],"session_lifecycle","expected_host_instance","attach_session","release_attachment","release_caller_aware","reclaim_session",AUTO_TITLE_SESSIONS_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,DURABLE_CLIENT_MESSAGE_ID_CAPABILITY,EFFECT_LEDGER_CAPABILITY,SUBSCRIPTION_LIMITS_CAPABILITY,RESOLVE_PATH_CAPABILITY,STEER_WHEN_IDLE_CAPABILITY,CONTINUE_FROM_LEAF_CAPABILITY,EVAL_CELLS_CAPABILITY,AUTH_KEY_VERIFY_CAPABILITY,PROVIDER_ACCOUNT_TEST_CAPABILITY,ACCOUNT_RESET_CAPABILITY,QUEUED_MESSAGE_REVISION_CAPABILITY,TOOL_BARRIER_CAPABILITY,USER_ACTIVITY_CAPABILITY,SESSION_MODEL_SCOPE_CAPABILITY,SESSION_HELD_CAPABILITY,RESUME_SESSION_CAPABILITY,ATTENDED_CAPABILITY,OBSERVE_READS_CAPABILITY,ENTRIES_TAIL_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,DETACH_CONNECTION_CAPABILITY,DELEGATED_CONNECTION_CAPABILITY,DELEGATION_ROLES_CAPABILITY,UNLOAD_SESSION_CAPABILITY,MOVE_SESSION_CAPABILITY,MOVE_SESSION_REVOKE_CAPABILITY,MOVE_SESSION_COPY_CAPABILITY,SESSION_RELOCATION_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,SESSION_STATUS_CAPABILITY,AUTO_TITLE_PER_SESSION_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,MOVED_PATH_GUARD_CAPABILITY,PROMPT_SURFACE_CAPABILITY,PROMPT_SURFACE_CHAT_CAPABILITY,BROWSER_ENGINE_CAPABILITY,SESSION_ENV_CAPABILITY,RETRY_FALLBACK_PROFILE_CAPABILITY,ACCEPT_EDITS_PERMISSION_PRESET_CAPABILITY,AUTO_PERMISSION_PRESET_CAPABILITY,...options.warm?[WARM_CAPABILITY]:[],...toolRuntimeCapabilities(options.toolRuntime),...options.negotiated.filter(capability=>capability!=="mcp_form_presenter_v1"&&(!compactUpdatesEnabled()||capability!=="compact_message_updates_v1"&&capability!=="compact_events")&&!isHostOwnedToolRuntimeCapability(capability))])]}function sessionMemory(host,sessionId){let view=host.hostMemoryView;if(view===void 0)return{main_heap_bytes:0,kernel_heap_bytes:0,kernel_count:0};let kernels=view.kernels().filter(kernel=>kernel.sessionId===sessionId),kernelHeapBytes=0;for(let kernel of kernels)kernelHeapBytes+=kernel.liveBytes;return{main_heap_bytes:view.mainHeapBytes(),kernel_heap_bytes:kernelHeapBytes,kernel_count:kernels.length}}function acknowledgePrompt(host,id,sessionId){let connection=host.writer.currentConnection();if(id===void 0||connection===void 0)return;let inFlight=Math.max(0,(host.activeRequests.get(sessionId)??1)-1);host.writer.sendOpenQueued(connection,{type:"queued",for_request:id,position:inFlight+1,in_flight:inFlight})}function otherRequestsSettled(host,sessionId){return new Promise(resolve2=>{let listeners=host.requestSettledListeners.get(sessionId)??new Set,check=()=>{(host.activeRequests.get(sessionId)??0)>1||(listeners.delete(check),listeners.size===0&&host.requestSettledListeners.delete(sessionId),resolve2())};listeners.add(check),host.requestSettledListeners.set(sessionId,listeners),check()})}function answerProtocolInfo(host,command){let hostCapabilities=multiSessionHostCapabilities({warm:host.registry.warm!==void 0,toolRuntime:host.defaults.toolRuntime??"in-process",negotiated:host.connectionOptions?.capabilities??[],mcpPresenters:host.writer.mcpPresenters!==void 0}),capabilities=host.defaults.handSelection===void 0?hostCapabilities:[...hostCapabilities,HAND_SELECTION_CAPABILITY];return{id:command.id,type:"response",command:"get_protocol_info",success:!0,data:{protocolVersion:1,serverVersion:VERSION,capabilities:advertisedCompactCapabilities(capabilities,host.writer.currentConnection()!==void 0&&host.registry.supportsCompact?.()===!0),mode:"multi",...protocolIdentity(host.defaults.agentDir),memory_pressure:host.memoryPressure,path_identity_resolver:pathIdentityResolverStatus(sharedPathIdentityResolver())}}}function answerSubscriptionLimits(command){return{id:command.id,type:"response",command:"get_subscription_limits",success:!0,data:{accounts:subscriptionLimits.snapshot()}}}function answerListSessions(host,command){let rows=host.registry.list(),presence=host.defaults.sessionPresence,withMemory=rows.map(row=>({...row,memory:sessionMemory(host,row.sessionId),...presence&&row.durableSessionId!==void 0?{presence:presence.view(row.durableSessionId)}:{}})),sessions=command.include_workers===!0?withMemory:withMemory.filter(row=>row.kind!=="worker").map(({context:_context,...row})=>row);return{id:command.id,type:"response",command:"list_sessions",success:!0,data:{sessions}}}var CHILD_TASK_SOURCE=/^senpi-task/,ACTIONS={extension_work:"let the named work finish, or unload with force: true (it is stopped, not resumed on reopen)",turn_active:"wait for the turn to end, or unload with interrupt: true to stop it first",work_pending:"wait for the work to finish, or unload with interrupt: true",children_live:'wait for the child tasks, or unload with children: "detach" to leave them running',attached:"ask the other clients to detach, or unload with force: true (they receive session_parked)"};async function unloadSession(port,command){if(port.draining())return answer2(command,refused3({reason:"host_draining",detail:"this host is draining and parks every session itself"}));let first=loaded(port,command.sessionId);if("reason"in first)return answer2(command,refused3(first));let{effectId}=command;if(effectId!==void 0){let begun=await beginEffect({session:first.session,by:port.by,sessionId:command.sessionId},"unload",{...command,effectId});if(!isEffectBegin(begun))return begun;if("replay"in begun)return answer2(command,{outcome:begun.replay.state==="failed"?"refused":"unloaded",...refusalFields(begun.replay.outcome),...effectAnswer(begun.replay,command.sessionId,!0)})}let blocked=blockers(port,command,first.session,first.durableSessionId),standing=blocked.find(refusal3=>!interruptible(refusal3)||command.interrupt!==!0);return standing!==void 0?fail(command,first.session,standing):(blocked.length>0&&await abortAndSettle(port,command.sessionId,first.session),claimAndUnload(port,command))}async function claimAndUnload(port,command){let ready=loaded(port,command.sessionId);if("reason"in ready)return answer2(command,refused3(ready));let stillBlocked=blockers(port,command,ready.session,ready.durableSessionId);if(stillBlocked.length>0)return fail(command,ready.session,stillBlocked[0]);command.clearQueue===!0&&(ClientAdmissions.clearQueuedFor(ready.session),ready.session.clearQueue());let effect=command.effectId===void 0?void 0:EffectLedger.forSession(ready.session).transition(command.effectId,"done",{disposition:"unloaded"});return await port.tearDown(command.sessionId,ready.sessionPath)?answer2(command,{outcome:"unloaded",sessionPath:ready.sessionPath,...effect===void 0?{}:effectAnswer(effect,command.sessionId)}):answer2(command,{outcome:"refused",reason:"session_closing",detail:"another close of this session finished first"})}function interruptible(refusal3){return refusal3.reason==="turn_active"||refusal3.reason==="work_pending"}function blockers(port,command,session,durableSessionId){let found=[],activity=session.activitySnapshot,running=[activity.isStreaming&&"an agent run",port.pendingPrompts(command.sessionId).length>0&&"a prompt about to start",activity.isCompacting&&"compaction",activity.hasSessionWork&&"session work"].filter(label=>typeof label=="string");running.length>0&&found.push({reason:"turn_active",detail:running.join(", "),action:ACTIONS.turn_active});let pending=[activity.isBashRunning&&"a bash command",session.externalAdmission.list().pending.length>0&&"an admitted delivery not yet written",port.otherRequests(command.sessionId)>0&&"another request for this session"].filter(label=>typeof label=="string");pending.length>0&&found.push({reason:"work_pending",detail:pending.join(", "),action:ACTIONS.work_pending});let sources=session.activeWakeSources,childSources=sources.filter(source=>CHILD_TASK_SOURCE.test(source)),otherSources=sources.filter(source=>!CHILD_TASK_SOURCE.test(source));otherSources.length>0&&command.force!==!0&&found.push({reason:"extension_work",detail:`work published by ${otherSources.join(", ")}`,action:ACTIONS.extension_work});let childSessions=port.openChildSessions(durableSessionId);if(command.children!=="detach"&&(childSources.length>0||childSessions>0)){let what=childSessions>0?`${childSessions} child session(s) open on this host`:"child tasks still working";found.push({reason:"children_live",detail:what,action:ACTIONS.children_live})}let others=port.otherAttachments(command.sessionId);return others>0&&command.force!==!0&&found.push({reason:"attached",detail:`${others} other client(s) attached`,action:ACTIONS.attached}),found}function loaded(port,sessionId){let entry;try{entry=port.lookup(sessionId)}catch(cause){return{reason:"unsupported",detail:port.code(cause)}}if(entry.state!=="open")return{reason:"session_closing",detail:"the session is already closing"};let session=entry.runtime?.session;if(session===void 0)return{reason:"unsupported",detail:"a worker isolate owns this session's runtime"};let sessionPath=entry.sessionPath??session.sessionFile;return sessionPath===void 0?{reason:"unsupported",detail:"the session has no file to reopen it by",action:"send a prompt first so the session is written, or close it instead"}:{session,sessionPath,durableSessionId:session.sessionManager.getSessionId()}}function fail(command,session,refusal3){if(command.effectId===void 0)return answer2(command,refused3(refusal3));let status=EffectLedger.forSession(session).transition(command.effectId,"failed",{outcome:{kind:"refused",reason:refusal3.reason,detail:refusal3.detail,...refusal3.action===void 0?{}:{action:refusal3.action}}});return answer2(command,{...refused3(refusal3),...effectAnswer(status,command.sessionId)})}function refusalFields(outcome){return outcome?.reason===void 0?{}:{reason:outcome.reason,...outcome.detail===void 0?{}:{detail:outcome.detail},...outcome.action===void 0?{}:{action:outcome.action}}}function refused3(refusal3){return{outcome:"refused",reason:refusal3.reason,detail:refusal3.detail,...refusal3.action===void 0?{}:{action:refusal3.action}}}function answer2(command,data2){return{id:command.id,type:"response",command:"unload_session",success:!0,data:data2}}function handle(host,command){let malformed=invalidCompactAdmission(command);if(malformed)return Promise.resolve(malformed);let ownership=unknownCompactAdmission(host,command);return ownership instanceof Promise?ownership.then(refusal3=>refusal3??admitted(host,command)):ownership?Promise.resolve(ownership):admitted(host,command)}function admitted(host,command){let refusal3=attachmentGate(host,command)??compactAdmissionGate(host,command);if(refusal3)return Promise.resolve(refusal3);if(command.type==="set_client_info"&&compactUpdatesEnabled()){let reply=declareSocketClient(host,command);if(!reply.success)return Promise.resolve(reply);let peer=host.writer.currentConnection();if(command.capabilities!==void 0&&peer!==void 0&&(command={...command,capabilities:[...host.pendingCapabilities.get(peer)??[]]}),command.id===void 0&&command.capabilities===void 0)return Promise.resolve(void 0)}let sessionId="sessionId"in command?command.sessionId:void 0;return host.draining&&sessionId!==void 0&&host.handoffClosed.has(sessionId)?Promise.resolve(void 0):host.draining&&command.type==="open_session"?Promise.resolve(error(command.id,command.type,"host_draining")):command.type==="warm"?answerWarm(command,{draining:host.draining,warm:host.registry.warm,cwd:host.defaults.cwd,hostContext:host.defaults.hostContext}):(host.activeRequests.set(sessionId,(host.activeRequests.get(sessionId)??0)+1),withAdmissionRequest(command,host.writer.currentConnection(),()=>runWithSessionAttribution({sessionId},()=>dispatch(host,command)).finally(()=>{let remaining=(host.activeRequests.get(sessionId)??1)-1;if(remaining>0?host.activeRequests.set(sessionId,remaining):host.activeRequests.delete(sessionId),sessionId!==void 0)for(let listener of host.requestSettledListeners.get(sessionId)??[])listener();host.draining&&sweepDrain(host)})))}function otherAttachments(host,caller,sessionId){let own=caller===void 0?0:host.sessionsByConnection.get(caller)?.get(sessionId)??0;return Math.max(0,(host.registry.peek(sessionId)?.attachments??0)-own)}async function dispatch(host,command){if(command.type==="reset_stream"&&host.admissions)return resetStream(host,command);if(command.type==="cancel_attempt"&&host.admissions!==void 0){let peer=host.writer.currentConnection(),epoch=peer===void 0?void 0:host.writer.socketEpochOf(peer);if(epoch===void 0)return error(command.id,command.type,"unsupported_transport");let outcome=await host.admissions.cancel(epoch,command.admissionId);return{id:command.id,type:"response",command:"cancel_attempt",success:!0,data:{outcome}}}if((command.type==="reset_stream"||command.type==="cancel_attempt")&&host.admissions===void 0)return compactTransportDisabled(command);if(command.type==="get_protocol_info")return answerProtocolInfo(host,command);if(command.type==="get_subscription_limits")return answerSubscriptionLimits(command);if(command.type==="list_sessions")return answerListSessions(host,command);if(command.type==="list_hands")return answerListHands(host,command);if(command.type==="select_hand")return answerSelectHand(host,command);if(command.type==="detach_connection")return detachConnection(command,host.writer.currentConnection(),id=>releaseConnection(host,id));if(command.type==="open_session")return openWithBarrier(host,command);if(command.type==="attach_session")return attachSession(host,command);if(command.type==="release_attachment")return releaseAttachment(host,command);if(command.type==="reclaim_session")return reclaimSession(host,command);if(command.type==="close_session")return close(host,command);if(command.type==="release_session")return releaseSession({draining:()=>host.draining,hostInstance:host.defaults.hostContext?.host_instance,otherAttachments:sessionId2=>otherAttachments(host,host.writer.currentConnection(),sessionId2),lookup:sessionId2=>host.registry.getForCommand(sessionId2,"release_session"),code:cause=>code(cause),otherRequests:sessionId2=>Math.max(0,(host.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>otherRequestsSettled(host,sessionId2),pendingPrompts:sessionId2=>host.bindings.get(sessionId2)?.pendingPrompts?.()??[],tearDown:(sessionId2,sessionPath)=>host.releaseTeardown(sessionId2,sessionPath)},command);if(command.type==="move_session"){let agentDir=host.registry.agentDir;return agentDir===void 0?error(command.id,command.type,"move_unsupported: this host keeps no agent directory to move sessions in"):moveSession({agentDir,hostedPaths:()=>host.registry.list().flatMap(row=>row.sessionPath===void 0?[]:[row.sessionPath])},command)}if(command.type==="unload_session"){let caller=host.writer.currentConnection();return unloadSession({draining:()=>host.draining,by:{connectionId:caller??"host"},lookup:sessionId2=>host.registry.getForCommand(sessionId2,"unload_session"),code:cause=>code(cause),otherRequests:sessionId2=>Math.max(0,(host.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>otherRequestsSettled(host,sessionId2),pendingPrompts:sessionId2=>host.bindings.get(sessionId2)?.pendingPrompts?.()??[],otherAttachments:sessionId2=>otherAttachments(host,caller,sessionId2),openChildSessions:durableSessionId=>host.registry.list().filter(row=>row.durableSessionId!==durableSessionId&&(row.context?.parent_session_id===durableSessionId||row.context?.root_session_id===durableSessionId)).length,tearDown:(sessionId2,sessionPath)=>tearDownUnloaded(host,sessionId2,sessionPath)},command)}if(command.type==="set_client_info"&&!command.sessionId)return command.id===void 0&&compactUpdatesEnabled()?void 0:declareSocketClient(host,command);if(command.type==="subscribe_sessions"){if(host.admissions&&command.admissionId!==void 0)return compactSubscribe(host,command);let connection=host.writer.currentConnection(),{answer:answer3,activate}=answerSubscribeSessions(command,connection,host.writer.status);if(activate!==void 0&&connection!==void 0){(async()=>{await host.writer.enqueueControl(answer3,connection),await new Promise(resolve2=>queueMicrotask(resolve2));try{host.writer.hasConnection(connection)?host.writer.status.activate(activate):host.writer.status.unsubscribe(connection,activate)}catch(cause){process.stderr.write(`senpi rpc subscription activation failed: ${String(cause)}
|
|
38
|
+
`),this.#locks.assertHeld(file),await renameFile(temp,file)}locked(moveId,fn){let file=this.path(moveId);return serializeByKey(file,async()=>(await mkdir3(this.dir,{recursive:!0}),this.#locks.hold(file,fn)))}};var RevokeMismatchError=class extends Error{constructor(moveId){super(`This session file is not the copy this device imported for move ${moveId}; nothing was changed. Revoke only the copy that move brought in, with that move's id.`),this.code="move_mismatch",this.name="RevokeMismatchError"}},REVOKED="revoked";function revokeImportedMove(options){return withSessionMoveLock2(options.sessionFile,async()=>{await seal(options.sessionFile,options.moveId),moveStep("revoke:sealed"),await options.ledger.markRevoked(options.moveId),moveStep("revoke:marked")},options.guard)}async function seal(sessionFile,moveId){let entries=await loadEntriesFromFileAsync(sessionFile),sessionId=headerSessionId(entries),ownership={writable:!0},latest;for(let entry of entries){let step=ownershipStep(ownership,entry,sessionId);step.kind==="apply"&&(ownership=step.next,latest=entry)}let ofThisMove=latest!==void 0&&data(latest,"move_id")===moveId;if(!(ofThisMove&&latest?.customType===SESSION_MOVED&&data(latest,"reason")===REVOKED)){if(!(ownership.writable&&ofThisMove&&latest?.customType===SESSION_MOVED_IN))throw new RevokeMismatchError(moveId);(await SessionManager.openAsync(sessionFile)).appendCustomEntry(SESSION_MOVED,{move_id:moveId,session_id:sessionId??"",target:data(latest,"from")??"",reason:REVOKED,moved_at:new Date().toISOString()})}}function data(entry,key){if(typeof entry.data!="object"||entry.data===null)return;let value=entry.data[key];return typeof value=="string"?value:void 0}var MoveRefusedError=class extends Error{constructor(targetCwd,sourceCwd){super(`${targetCwd} is not the same repository the session was recorded in (${sourceCwd}). Pick a checkout of the same repository, or copy the session into this folder instead.`),this.name="MoveRefusedError",this.code="move_repository_mismatch"}},MoveTargetOccupiedError=class extends Error{constructor(target){super(`A session that can still be written already sits at ${target}; the moved session was not imported over it. Close or move that session first, then send it again.`),this.code="move_target_occupied",this.name="MoveTargetOccupiedError"}},movedInFor=async(file,moveId)=>(await loadEntriesFromFileAsync(file)).some(entry=>entry.type==="custom"&&entry.customType===SESSION_MOVED_IN&&entry.data?.move_id===moveId);async function importOutcome(file,moveId){let outcome="absent";for(let entry of await loadEntriesFromFileAsync(file)){if(entry.type!=="custom")continue;let data2=entry.data;data2?.move_id===moveId&&(entry.customType===SESSION_MOVED_IN?outcome="moved_in":outcome==="moved_in"&&entry.customType===SESSION_MOVED&&data2.reason===REVOKED&&(outcome="revoked"))}return outcome}var StatusPathMismatchError=class extends Error{constructor(moveId,sessionFile){super(`${sessionFile} is not the copy this device imported for move ${moveId}; nothing was answered. Pass the session_path import returned for this move, or leave sessionPath out to answer from this device's record.`),this.code="move_mismatch",this.name="StatusPathMismatchError"}};async function answerMoveStatus(ledger,moveId,sessionFile){let landed=async target=>await pathExists(target)?importOutcome(target,moveId):"absent";return sessionFile===void 0||!await pathExists(sessionFile)?ledger.answerStatus(moveId,{movedIn:!1,landed}):serializeByKey(await moveLockKey(sessionFile),async()=>{let outcome=await importOutcome(sessionFile,moveId);if(outcome==="absent")throw new StatusPathMismatchError(moveId,sessionFile);return ledger.answerStatus(moveId,{movedIn:!0,revoked:outcome==="revoked",landed})})}async function importMovedSession(options){let manifest=await readManifest(options.bundleDir),targetCwd=resolvePath(options.targetCwd),sessionDir=options.sessionDir?normalizePath(options.sessionDir):getDefaultSessionDir(targetCwd),target=join7(sessionDir,manifest.sessionFileName),landed=async()=>await pathExists(target)&&await movedInFor(target,manifest.moveId);if(await landed())return await options.ledger.confirmLanded(manifest.moveId,target,await importOutcome(target,manifest.moveId)==="revoked"),{sessionFile:target};try{await verifyBundle(options.bundleDir,manifest)}catch(error2){throw error2 instanceof MoveBundleInvalidError&&await options.ledger.fail(manifest.moveId,"bundle_invalid",{unlessLanded:landed}),error2}let read=options.readIdentity??readRepositoryIdentity;if(compareRepositoryIdentities(manifest.repository,await read(targetCwd))!=="same")throw await landed()||await options.ledger.decline(manifest.moveId,"repository"),new MoveRefusedError(targetCwd,manifest.sourceCwd);await options.ledger.beginReceive(manifest.moveId,target),moveStep("import:received");let staging=join7(sessionDir,".move-staging",encodeURIComponent(manifest.moveId));try{let staged=await stage(options.bundleDir,manifest,staging,options.from??""),sessionFile=await options.ledger.commit(manifest.moveId,target,()=>rebindSessionFile(staged,targetCwd,sessionDir),async()=>{await replacePredecessor(target,manifest.sessionId,sessionDir),await placeExtensionState(staging,manifest,movedStateDir(target,manifest.moveId))});return moveStep("import:accepted"),await rm6(staging,{recursive:!0,force:!0}),{sessionFile}}catch(error2){throw error2 instanceof MoveFencedError||await options.ledger.fail(manifest.moveId,error2 instanceof MoveBundleInvalidError?"bundle_invalid":"import_failed",{unlessLanded:landed}),error2}}async function replacePredecessor(target,sessionId,sessionDir){if(!await pathExists(target))return;let entries=await loadEntriesFromFileAsync(target);if(headerSessionId(entries)!==sessionId||sessionOwnership(entries).writable)throw new MoveTargetOccupiedError(target);let extensions=join7(sessionDir,"extensions");if(await pathExists(extensions))for(let extension of await readdir4(extensions,{withFileTypes:!0}))extension.isDirectory()&&await rm6(join7(extensions,extension.name,`${encodedSessionId(sessionId)}.json`),{force:!0});await rm6(join7(sessionDir,"resident-blobs",sessionId),{recursive:!0,force:!0}),await rm6(target,{force:!0})}var STAGED_PAYLOADS=".payloads",extensionStateFiles=manifest=>manifest.payloads.filter(payload=>payload.kind===EXTENSION_STATE_PAYLOAD).flatMap(p=>p.files);async function stagePayloads(bundleDir,manifest,staging){for(let file of manifest.payloads.flatMap(payload=>payload.files)){let to=join7(staging,STAGED_PAYLOADS,file.path);if(await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(bundleDir,file.path),to),await sha256File(to)!==file.sha256)throw new MoveBundleInvalidError(`${file.path} changed in transit`)}}async function placeExtensionState(staging,manifest,dir){let files=extensionStateFiles(manifest);if(files.length!==0){await rm6(dir,{recursive:!0,force:!0});for(let file of files){let to=join7(dir,file.path.slice(EXTENSION_STATE_PREFIX.length));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(staging,STAGED_PAYLOADS,file.path),to)}}}async function stage(bundleDir,manifest,staging,from){let file=join7(staging,manifest.sessionFileName);if(!(await pathExists(file)&&await movedInFor(file,manifest.moveId))){await rm6(staging,{recursive:!0,force:!0});for(let item of[manifest.session,...manifest.sidecars]){let to=item===manifest.session?file:join7(staging,item.path.replace(/^files\//,""));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join7(bundleDir,item.path),to)}await stagePayloads(bundleDir,manifest,staging),(await SessionManager.openAsync(file,staging)).appendCustomEntry(SESSION_MOVED_IN,{move_id:manifest.moveId,session_id:manifest.sessionId,from,bundle_sha256:manifest.session.sha256,moved_in_at:new Date().toISOString()})}return await requeueInput(file,manifest.moveId,manifest.droppedUserMessages),file}import{isAbsolute}from"node:path";function plainMoveId(value){try{return parseMoveId(value)}catch{return}}var text=value=>typeof value=="string"&&value.trim()!=="",PLAIN_ID_RULE="a letter or digit, then letters, digits, '.', '_' or '-', at most 128 characters";function parseCopy(raw){return text(raw.sessionPath)?isPlainId(raw.sessionId)?raw.sessionDir!==void 0&&(!text(raw.sessionDir)||!isAbsolute(raw.sessionDir))?"sessionDir must be an absolute path.":{op:"copy",sessionPath:raw.sessionPath,sessionId:raw.sessionId,sessionDir:raw.sessionDir}:`sessionId must be a plain id: ${PLAIN_ID_RULE}.`:"copy needs sessionPath, the session file to copy."}function parseMoveRequest(raw){let{op}=raw;if(op==="import"){if(!text(raw.bundleDir)||!text(raw.cwd)||!isAbsolute(raw.bundleDir)||!isAbsolute(raw.cwd))return"import needs bundleDir and cwd as absolute paths.";let from=typeof raw.from=="string"?raw.from:void 0;return raw.from!==void 0&&from===void 0?"from must be a string.":{op,bundleDir:raw.bundleDir,cwd:raw.cwd,from:from??""}}if(op==="copy")return parseCopy(raw);let id=plainMoveId(raw.moveId);if(id===void 0)return`moveId must be a plain id: ${PLAIN_ID_RULE}.`;switch(op){case"prepare":case"cancel":return{op,moveId:id};case"status":{let sessionPath=text(raw.sessionPath)?raw.sessionPath:void 0;return raw.sessionPath!==void 0&&sessionPath===void 0?"sessionPath must be a non-empty string.":{op,moveId:id,sessionPath}}case"export":{let dropped=raw.droppedUserMessages??[];return!text(raw.sessionPath)||!text(raw.target)?"export needs sessionPath and target.":!Array.isArray(dropped)||!dropped.every(item=>typeof item=="string")?"droppedUserMessages must be the dropped.user_messages strings release_session returned.":{op,sessionPath:raw.sessionPath,moveId:id,target:raw.target,dropped}}case"finish":{let answer3=parseMoveStatus(raw.answer);return!text(raw.sessionPath)||answer3===void 0?"finish needs sessionPath and the receiver's answer from status (receiving, accepted, declined or failed).":{op,sessionPath:raw.sessionPath,moveId:id,answer:answer3}}case"revoke":return text(raw.sessionPath)?{op,sessionPath:raw.sessionPath,moveId:id}:"revoke needs sessionPath, the copy this host imported for the move.";default:return'op must be one of "prepare", "cancel", "status", "export", "import", "finish", "revoke" or "copy".'}}var CORE_CODES=new Set(["move_fenced","move_bundle_invalid","move_repository_mismatch","move_target_occupied","move_mismatch","move_already_moved","session_moved_away","invalid_move_request"]),RENAMED_CODES={ESESSIONHELD:"session_held"},wireRecord=record=>record.state==="ready"?{state:"ready",expires_at:record.expiresAt}:record;async function moveSession(port,command){let raw={...command},parsed=parseMoveRequest(raw);if(typeof parsed=="string")return refusal(command.id,RPC_ERROR_INVALID_MOVE_REQUEST,parsed);let root=join8(port.agentDir,"session-moves"),ledger=new MoveLedger(join8(root,"ledger")),outgoing=moveId=>join8(root,"outgoing",moveId);try{return answer(command.id,await run(parsed,port,ledger,outgoing))}catch(cause){if(cause instanceof MoveRefusal)return refusal(command.id,cause.code,cause.message);let code2=typeof cause=="object"&&cause!==null&&"code"in cause?cause.code:void 0,detail2=cause instanceof Error?cause.message:String(cause);return refusal(command.id,typeof code2=="string"?RENAMED_CODES[code2]??(CORE_CODES.has(code2)?code2:RPC_ERROR_MOVE_FAILED):RPC_ERROR_MOVE_FAILED,detail2)}}async function run(parsed,port,ledger,outgoing){switch(parsed.op){case"prepare":return wireRecord(await ledger.prepare(parsed.moveId));case"cancel":return wireRecord(await ledger.decline(parsed.moveId,"cancelled"));case"status":return answerMoveStatus(ledger,parsed.moveId,parsed.sessionPath);case"export":{let sessionFile=await orderedRealPath(parsed.sessionPath),bundleDir=outgoing(parsed.moveId),manifest=await exportSessionForMove({sessionFile,moveId:parsed.moveId,target:parsed.target,droppedUserMessages:parsed.dropped,bundleDir,extensionStateDir:()=>sealedOutgoingStateDir(sessionFile,parsed.moveId),guard:async()=>{await refuseOpenHere(port,sessionFile,"This session is open on this host. Release it with release_session reason move and this moveId first."),await refuseUnlessSealedFor(sessionFile,parsed.moveId)},lockedGuard:()=>refuseUnlessSealedFor(sessionFile,parsed.moveId)});return{move_id:manifest.moveId,session_id:manifest.sessionId,bundle_dir:bundleDir,files:1+manifest.sidecars.length}}case"import":{let cwd=resolvePath(parsed.cwd),sessionDir=getDefaultSessionDir(cwd,port.agentDir),{sessionFile}=await importMovedSession({bundleDir:normalizePath(parsed.bundleDir),targetCwd:cwd,ledger,sessionDir,from:parsed.from}),sessionId=headerSessionId(await loadEntriesFromFileAsync(sessionFile));if(sessionId===void 0)throw new Error(`The imported session at ${sessionFile} has no id in its header.`);return{session_id:sessionId,session_path:sessionFile}}case"finish":{let sessionFile=await orderedRealPath(parsed.sessionPath);return await finishMove({sessionFile,bundleDir:outgoing(parsed.moveId),moveId:parsed.moveId,answer:parsed.answer,guard:()=>refuseOpenHere(port,sessionFile,"This session is open on this host, so its runtime would not see the move end. Close it here, then finish the move.")}),ownershipOf(sessionFile)}case"revoke":{let sessionFile=await orderedRealPath(parsed.sessionPath);return await revokeImportedMove({sessionFile,moveId:parsed.moveId,ledger,guard:()=>refuseOpenHere(port,sessionFile,"This session is open on this host, so its runtime would not see the revoke. Close it here, then revoke the move.")}),ownershipOf(sessionFile)}case"copy":return copySessionAs({sourceFile:await orderedRealPath(parsed.sessionPath),sessionId:parsed.sessionId,sessionDir:cwd=>parsed.sessionDir===void 0?getDefaultSessionDir(cwd,port.agentDir):normalizePath(parsed.sessionDir)})}}async function ownershipOf(sessionFile){let ownership=sessionOwnership(await loadEntriesFromFileAsync(sessionFile));return{ownership:ownership.writable?"writable":ownership.state}}var MoveRefusal=class extends Error{constructor(code2,detail2){super(detail2),this.name="MoveRefusal",this.code=code2}};async function refuseUnlessSealedFor(sessionFile,moveId){let ownership=sessionOwnership(await loadEntriesFromFileAsync(sessionFile));if(ownership.writable||ownership.state!=="moving"||ownership.moveId!==moveId)throw new MoveRefusal(RPC_ERROR_MOVE_NOT_RELEASED,"This session file is not sealed for this move. Release it with release_session reason move and this moveId first; that also hands back its queued input.")}async function refuseOpenHere(port,sessionFile,detail2){if((await Promise.all(port.hostedPaths().map(path=>realSessionPath(path)))).includes(sessionFile))throw new MoveRefusal(RPC_ERROR_SESSION_OPEN_HERE,detail2)}function answer(id,data2){return"refuse"in data2?refusal(id,data2.refuse,data2.detail):{id,type:"response",command:"move_session",success:!0,data:data2}}function refusal(id,code2,detail2){return{id,type:"response",command:"move_session",success:!1,error:code2,errorCode:code2,errorData:{detail:detail2}}}import{rm as rm7}from"node:fs/promises";var NOTHING_DROPPED={deliveries:[],user_messages:[]};function takeQueuedInput(session){let admittedBefore=session.externalAdmission.list().pending,cleared=session.clearQueue({abortWillFollow:!0}),stillAdmitted=new Set(session.externalAdmission.list().pending);return{deliveries:admittedBefore.filter(deliveryId=>!stillAdmitted.has(deliveryId)),user_messages:cleared.ordered.map(queued=>queued.text)}}async function abortAndSettle(port,sessionId,session){session.abortBash();let stopStarts=session.subscribe(event=>{event.type==="agent_start"&&session.abort()}),deadline,expired=new Promise(resolve2=>{deadline=setTimeout(resolve2,1e4)});try{await Promise.race([Promise.allSettled([session.abort().then(()=>session.waitForIdle()),port.otherRequestsSettled(sessionId),...port.pendingPrompts(sessionId)]),expired])}finally{clearTimeout(deadline),stopStarts()}}var SESSION_RELEASED_ENTRY_TYPE="session_released",RELEASED_ADMISSION_CLOSED="release_session handed this session to another runtime; deliver there instead (admission is closed here)",RELEASE_QUEUED_HINT="queued user input is still owed a turn; release with interrupt: true to take it out and receive it in dropped.user_messages";async function releaseSession(port,command){let validMove=command.reason==="move"&&isMoveId(command.moveId);if(command.reason!=="takeover"&&!validMove)return refusal2(command.id,RPC_ERROR_INVALID_RELEASE_REASON);if(port.draining())return refusal2(command.id,RPC_ERROR_HOST_DRAINING);let first=releasable(port,command,void 0);if(!("session"in first))return first;if(command.reason==="move"&&!isPlainId(first.session.sessionManager.getSessionId()))return refusal2(command.id,RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"session_id_not_plain"});let busy=busySignals(port,command.sessionId,first.session),interrupted=busy.length>0;if(interrupted&&command.interrupt!==!0)return refusal2(command.id,busyCode(busy),{attachments:first.attachments,...busyData(busy)});let admission=first.session.externalAdmission,dropped=NOTHING_DROPPED,answer3,stagedState,sealed=!1;try{interrupted&&(admission.close(RELEASED_ADMISSION_CLOSED),dropped=takeQueuedInput(first.session),await abortAndSettle(port,command.sessionId,first.session),await first.session.whenQueueClearRecorded());let manager=first.session.sessionManager;if(manager.isTranscriptFlushed()||await manager.persistHeaderNow(),command.reason==="move"){let moveId=parseMoveId(command.moveId);stagedState=await prepareOutgoingState(first.sessionPath,moveId);let[failed]=await first.session.extensionRunner.emitSessionMove({type:"session_move_export",moveId,dir:stagedState.dir});if(failed!==void 0)throw new Error(`${failed.extensionPath} could not write its state for the move: ${failed.error}`)}return answer3=await claimAndRelease(port,command,interrupted,dropped,stagedState?.attempt,()=>{sealed=!0}),answer3}catch(cause){return cause instanceof SessionMovedAwayError?(answer3=refusal2(command.id,cause.code,{detail:cause.message,...interrupted?{interrupted:!0,dropped}:{}}),answer3):(answer3=refusal2(command.id,RPC_ERROR_RELEASE_FAILED,{detail:cause instanceof Error?cause.message:String(cause),...interrupted?{interrupted:!0,dropped}:{}}),answer3)}finally{answer3?.success!==!0&&(admission.reopen(),stagedState!==void 0&&!sealed&&await rm7(stagedState.dir,{recursive:!0,force:!0}))}}async function claimAndRelease(port,command,interrupted,dropped,stateAttempt,onSealed){let taken=interrupted?{interrupted:!0,dropped}:void 0,ready=releasable(port,command,taken);if(!("session"in ready))return ready;let stillBusy=busySignals(port,command.sessionId,ready.session);if(stillBusy.length>0)return refusal2(command.id,busyCode(stillBusy),{attachments:ready.attachments,...busyData(stillBusy),interrupted,...taken});let admission=ready.session.externalAdmission;admission.close(RELEASED_ADMISSION_CLOSED);try{ready.session.sessionManager.appendCustomEntry(SESSION_RELEASED_ENTRY_TYPE,{reason:command.reason,...command.reason==="move"?{move_id:command.moveId,...stateAttempt===void 0?{}:{[STATE_ATTEMPT_FIELD]:stateAttempt},target:command.target??"",session_id:ready.session.sessionManager.getSessionId()}:{},interrupted,attachments:ready.attachments,host_instance:port.hostInstance??null,released_at:new Date().toISOString()})}catch(cause){throw admission.reopen(),cause}return onSealed(),await port.tearDown(command.sessionId,ready.sessionPath)?{id:command.id,type:"response",command:"release_session",success:!0,data:{released:!0,session_path:ready.sessionPath,attachments:ready.attachments,dropped}}:refusal2(command.id,RPC_ERROR_SESSION_CLOSING,taken)}function busySignals(port,sessionId,session){let activity=session.activitySnapshot,signals=[];return activity.isStreaming&&signals.push("turn"),port.pendingPrompts(sessionId).length>0&&signals.push("prompt"),session.pendingMessageCount>0&&signals.push("queued"),session.externalAdmission.list().pending.length>0&&signals.push("delivery"),activity.isBashRunning&&signals.push("bash"),activity.isCompacting&&signals.push("compaction"),activity.hasSessionWork&&signals.push("session_work"),signals.length===0&&isHandoffBusy(activity)&&signals.push("activity"),port.otherRequests(sessionId)>0&&signals.push("request"),signals}function busyData(signals){return signals.includes("queued")?{busy:signals,retry_with:{interrupt:!0},hint:RELEASE_QUEUED_HINT}:{busy:signals}}function busyCode(signals){return signals.some(signal=>signal==="turn"||signal==="prompt"||signal==="queued"||signal==="delivery")?RPC_ERROR_TURN_ACTIVE:RPC_ERROR_SESSION_BUSY}function releasable(port,command,taken){let refuse=(code2,data2)=>refusal2(command.id,code2,data2||taken?{...data2,...taken}:void 0),entry;try{entry=port.lookup(command.sessionId)}catch(cause){return refuse(port.code(cause))}if(entry.state!=="open")return refuse(RPC_ERROR_SESSION_CLOSING);let session=entry.runtime?.session;if(session===void 0)return refuse(RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"worker_runtime"});let sessionPath=entry.sessionPath??session.sessionFile;if(sessionPath===void 0)return refuse(RPC_ERROR_RELEASE_UNSUPPORTED,{detail:"no_session_file"});let elsewhere=port.otherAttachments(command.sessionId);return elsewhere>0&&command.force!==!0?refuse(RPC_ERROR_ATTACHED,{attachments:elsewhere}):{session,sessionPath,attachments:entry.attachments}}function refusal2(id,code2,data2){return{id,type:"response",command:"release_session",success:!1,error:code2,...data2&&{errorCode:code2,errorData:data2}}}function sessionMemory(host,sessionId){let view=host.hostMemoryView;if(view===void 0)return{main_heap_bytes:0,kernel_heap_bytes:0,kernel_count:0};let kernels=view.kernels().filter(kernel=>kernel.sessionId===sessionId),kernelHeapBytes=0;for(let kernel of kernels)kernelHeapBytes+=kernel.liveBytes;return{main_heap_bytes:view.mainHeapBytes(),kernel_heap_bytes:kernelHeapBytes,kernel_count:kernels.length}}function acknowledgePrompt(host,id,sessionId){let connection=host.writer.currentConnection();if(id===void 0||connection===void 0)return;let inFlight=Math.max(0,(host.activeRequests.get(sessionId)??1)-1);host.writer.sendOpenQueued(connection,{type:"queued",for_request:id,position:inFlight+1,in_flight:inFlight})}function otherRequestsSettled(host,sessionId){return new Promise(resolve2=>{let listeners=host.requestSettledListeners.get(sessionId)??new Set,check=()=>{(host.activeRequests.get(sessionId)??0)>1||(listeners.delete(check),listeners.size===0&&host.requestSettledListeners.delete(sessionId),resolve2())};listeners.add(check),host.requestSettledListeners.set(sessionId,listeners),check()})}function answerProtocolInfo(host,command){let hostCapabilities=multiSessionHostCapabilities({warm:host.registry.warm!==void 0,toolRuntime:host.defaults.toolRuntime??"in-process",negotiated:host.connectionOptions?.capabilities??[],mcpPresenters:host.writer.mcpPresenters!==void 0}),capabilities=host.defaults.handSelection===void 0?hostCapabilities:[...hostCapabilities,HAND_SELECTION_CAPABILITY];return{id:command.id,type:"response",command:"get_protocol_info",success:!0,data:{protocolVersion:1,serverVersion:VERSION,capabilities:advertisedCompactCapabilities(capabilities,host.writer.currentConnection()!==void 0&&host.registry.supportsCompact?.()===!0),mode:"multi",...protocolIdentity(host.defaults.agentDir),memory_pressure:host.memoryPressure,path_identity_resolver:pathIdentityResolverStatus(sharedPathIdentityResolver())}}}function answerSubscriptionLimits(command){return{id:command.id,type:"response",command:"get_subscription_limits",success:!0,data:{accounts:subscriptionLimits.snapshot()}}}function answerListSessions(host,command){let rows=host.registry.list(),presence=host.defaults.sessionPresence,withMemory=rows.map(row=>({...row,memory:sessionMemory(host,row.sessionId),...presence&&row.durableSessionId!==void 0?{presence:presence.view(row.durableSessionId)}:{}})),sessions=command.include_workers===!0?withMemory:withMemory.filter(row=>row.kind!=="worker").map(({context:_context,...row})=>row);return{id:command.id,type:"response",command:"list_sessions",success:!0,data:{sessions}}}var CHILD_TASK_SOURCE=/^senpi-task/,ACTIONS={extension_work:"let the named work finish, or unload with force: true (it is stopped, not resumed on reopen)",turn_active:"wait for the turn to end, or unload with interrupt: true to stop it first",work_pending:"wait for the work to finish, or unload with interrupt: true",children_live:'wait for the child tasks, or unload with children: "detach" to leave them running',attached:"ask the other clients to detach, or unload with force: true (they receive session_parked)"};async function unloadSession(port,command){if(port.draining())return answer2(command,refused3({reason:"host_draining",detail:"this host is draining and parks every session itself"}));let first=loaded(port,command.sessionId);if("reason"in first)return answer2(command,refused3(first));let{effectId}=command;if(effectId!==void 0){let begun=await beginEffect({session:first.session,by:port.by,sessionId:command.sessionId},"unload",{...command,effectId});if(!isEffectBegin(begun))return begun;if("replay"in begun)return answer2(command,{outcome:begun.replay.state==="failed"?"refused":"unloaded",...refusalFields(begun.replay.outcome),...effectAnswer(begun.replay,command.sessionId,!0)})}let blocked=blockers(port,command,first.session,first.durableSessionId),standing=blocked.find(refusal3=>!interruptible(refusal3)||command.interrupt!==!0);return standing!==void 0?fail(command,first.session,standing):(blocked.length>0&&await abortAndSettle(port,command.sessionId,first.session),claimAndUnload(port,command))}async function claimAndUnload(port,command){let ready=loaded(port,command.sessionId);if("reason"in ready)return answer2(command,refused3(ready));let stillBlocked=blockers(port,command,ready.session,ready.durableSessionId);if(stillBlocked.length>0)return fail(command,ready.session,stillBlocked[0]);command.clearQueue===!0&&(ClientAdmissions.clearQueuedFor(ready.session),ready.session.clearQueue());let effect=command.effectId===void 0?void 0:EffectLedger.forSession(ready.session).transition(command.effectId,"done",{disposition:"unloaded"});return await port.tearDown(command.sessionId,ready.sessionPath)?answer2(command,{outcome:"unloaded",sessionPath:ready.sessionPath,...effect===void 0?{}:effectAnswer(effect,command.sessionId)}):answer2(command,{outcome:"refused",reason:"session_closing",detail:"another close of this session finished first"})}function interruptible(refusal3){return refusal3.reason==="turn_active"||refusal3.reason==="work_pending"}function blockers(port,command,session,durableSessionId){let found=[],activity=session.activitySnapshot,running=[activity.isStreaming&&"an agent run",port.pendingPrompts(command.sessionId).length>0&&"a prompt about to start",activity.isCompacting&&"compaction",activity.hasSessionWork&&"session work"].filter(label=>typeof label=="string");running.length>0&&found.push({reason:"turn_active",detail:running.join(", "),action:ACTIONS.turn_active});let pending=[activity.isBashRunning&&"a bash command",session.externalAdmission.list().pending.length>0&&"an admitted delivery not yet written",port.otherRequests(command.sessionId)>0&&"another request for this session"].filter(label=>typeof label=="string");pending.length>0&&found.push({reason:"work_pending",detail:pending.join(", "),action:ACTIONS.work_pending});let sources=session.activeWakeSources,childSources=sources.filter(source=>CHILD_TASK_SOURCE.test(source)),otherSources=sources.filter(source=>!CHILD_TASK_SOURCE.test(source));otherSources.length>0&&command.force!==!0&&found.push({reason:"extension_work",detail:`work published by ${otherSources.join(", ")}`,action:ACTIONS.extension_work});let childSessions=port.openChildSessions(durableSessionId);if(command.children!=="detach"&&(childSources.length>0||childSessions>0)){let what=childSessions>0?`${childSessions} child session(s) open on this host`:"child tasks still working";found.push({reason:"children_live",detail:what,action:ACTIONS.children_live})}let others=port.otherAttachments(command.sessionId);return others>0&&command.force!==!0&&found.push({reason:"attached",detail:`${others} other client(s) attached`,action:ACTIONS.attached}),found}function loaded(port,sessionId){let entry;try{entry=port.lookup(sessionId)}catch(cause){return{reason:"unsupported",detail:port.code(cause)}}if(entry.state!=="open")return{reason:"session_closing",detail:"the session is already closing"};let session=entry.runtime?.session;if(session===void 0)return{reason:"unsupported",detail:"a worker isolate owns this session's runtime"};let sessionPath=entry.sessionPath??session.sessionFile;return sessionPath===void 0?{reason:"unsupported",detail:"the session has no file to reopen it by",action:"send a prompt first so the session is written, or close it instead"}:{session,sessionPath,durableSessionId:session.sessionManager.getSessionId()}}function fail(command,session,refusal3){if(command.effectId===void 0)return answer2(command,refused3(refusal3));let status=EffectLedger.forSession(session).transition(command.effectId,"failed",{outcome:{kind:"refused",reason:refusal3.reason,detail:refusal3.detail,...refusal3.action===void 0?{}:{action:refusal3.action}}});return answer2(command,{...refused3(refusal3),...effectAnswer(status,command.sessionId)})}function refusalFields(outcome){return outcome?.reason===void 0?{}:{reason:outcome.reason,...outcome.detail===void 0?{}:{detail:outcome.detail},...outcome.action===void 0?{}:{action:outcome.action}}}function refused3(refusal3){return{outcome:"refused",reason:refusal3.reason,detail:refusal3.detail,...refusal3.action===void 0?{}:{action:refusal3.action}}}function answer2(command,data2){return{id:command.id,type:"response",command:"unload_session",success:!0,data:data2}}function handle(host,command){let malformed=invalidCompactAdmission(command);if(malformed)return Promise.resolve(malformed);let ownership=unknownCompactAdmission(host,command);return ownership instanceof Promise?ownership.then(refusal3=>refusal3??admitted(host,command)):ownership?Promise.resolve(ownership):admitted(host,command)}function admitted(host,command){let refusal3=attachmentGate(host,command)??compactAdmissionGate(host,command);if(refusal3)return Promise.resolve(refusal3);if(command.type==="set_client_info"&&compactUpdatesEnabled()){let reply=declareSocketClient(host,command);if(!reply.success)return Promise.resolve(reply);let peer=host.writer.currentConnection();if(command.capabilities!==void 0&&peer!==void 0&&(command={...command,capabilities:[...host.pendingCapabilities.get(peer)??[]]}),command.id===void 0&&command.capabilities===void 0)return Promise.resolve(void 0)}let sessionId="sessionId"in command?command.sessionId:void 0;return host.draining&&sessionId!==void 0&&host.handoffClosed.has(sessionId)?Promise.resolve(void 0):host.draining&&command.type==="open_session"?Promise.resolve(error(command.id,command.type,"host_draining")):command.type==="warm"?answerWarm(command,{draining:host.draining,warm:host.registry.warm,cwd:host.defaults.cwd,hostContext:host.defaults.hostContext}):(host.activeRequests.set(sessionId,(host.activeRequests.get(sessionId)??0)+1),withAdmissionRequest(command,host.writer.currentConnection(),()=>runWithSessionAttribution({sessionId},()=>dispatch(host,command)).finally(()=>{let remaining=(host.activeRequests.get(sessionId)??1)-1;if(remaining>0?host.activeRequests.set(sessionId,remaining):host.activeRequests.delete(sessionId),sessionId!==void 0)for(let listener of host.requestSettledListeners.get(sessionId)??[])listener();host.draining&&sweepDrain(host)})))}function otherAttachments(host,caller,sessionId){let own=caller===void 0?0:host.sessionsByConnection.get(caller)?.get(sessionId)??0;return Math.max(0,(host.registry.peek(sessionId)?.attachments??0)-own)}async function dispatch(host,command){if(command.type==="reset_stream"&&host.admissions)return resetStream(host,command);if(command.type==="cancel_attempt"&&host.admissions!==void 0){let peer=host.writer.currentConnection(),epoch=peer===void 0?void 0:host.writer.socketEpochOf(peer);if(epoch===void 0)return error(command.id,command.type,"unsupported_transport");let outcome=await host.admissions.cancel(epoch,command.admissionId);return{id:command.id,type:"response",command:"cancel_attempt",success:!0,data:{outcome}}}if((command.type==="reset_stream"||command.type==="cancel_attempt")&&host.admissions===void 0)return compactTransportDisabled(command);if(command.type==="get_protocol_info")return answerProtocolInfo(host,command);if(command.type==="get_subscription_limits")return answerSubscriptionLimits(command);if(command.type==="list_sessions")return answerListSessions(host,command);if(command.type==="list_hands")return answerListHands(host,command);if(command.type==="select_hand")return answerSelectHand(host,command);if(command.type==="detach_connection")return detachConnection(command,host.writer.currentConnection(),id=>releaseConnection(host,id));if(command.type==="open_session")return openWithBarrier(host,command);if(command.type==="attach_session")return attachSession(host,command);if(command.type==="release_attachment")return releaseAttachment(host,command);if(command.type==="reclaim_session")return reclaimSession(host,command);if(command.type==="close_session")return close(host,command);if(command.type==="release_session")return releaseSession({draining:()=>host.draining,hostInstance:host.defaults.hostContext?.host_instance,otherAttachments:sessionId2=>otherAttachments(host,host.writer.currentConnection(),sessionId2),lookup:sessionId2=>host.registry.getForCommand(sessionId2,"release_session"),code:cause=>code(cause),otherRequests:sessionId2=>Math.max(0,(host.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>otherRequestsSettled(host,sessionId2),pendingPrompts:sessionId2=>host.bindings.get(sessionId2)?.pendingPrompts?.()??[],tearDown:(sessionId2,sessionPath)=>host.releaseTeardown(sessionId2,sessionPath)},command);if(command.type==="move_session"){let agentDir=host.registry.agentDir;return agentDir===void 0?error(command.id,command.type,"move_unsupported: this host keeps no agent directory to move sessions in"):moveSession({agentDir,hostedPaths:()=>host.registry.list().flatMap(row=>row.sessionPath===void 0?[]:[row.sessionPath])},command)}if(command.type==="unload_session"){let caller=host.writer.currentConnection();return unloadSession({draining:()=>host.draining,by:{connectionId:caller??"host"},lookup:sessionId2=>host.registry.getForCommand(sessionId2,"unload_session"),code:cause=>code(cause),otherRequests:sessionId2=>Math.max(0,(host.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>otherRequestsSettled(host,sessionId2),pendingPrompts:sessionId2=>host.bindings.get(sessionId2)?.pendingPrompts?.()??[],otherAttachments:sessionId2=>otherAttachments(host,caller,sessionId2),openChildSessions:durableSessionId=>host.registry.list().filter(row=>row.durableSessionId!==durableSessionId&&(row.context?.parent_session_id===durableSessionId||row.context?.root_session_id===durableSessionId)).length,tearDown:(sessionId2,sessionPath)=>tearDownUnloaded(host,sessionId2,sessionPath)},command)}if(command.type==="set_client_info"&&!command.sessionId)return command.id===void 0&&compactUpdatesEnabled()?void 0:declareSocketClient(host,command);if(command.type==="subscribe_sessions"){if(host.admissions&&command.admissionId!==void 0)return compactSubscribe(host,command);let connection=host.writer.currentConnection(),{answer:answer3,activate}=answerSubscribeSessions(command,connection,host.writer.status);if(activate!==void 0&&connection!==void 0){(async()=>{await host.writer.enqueueControl(answer3,connection),await new Promise(resolve2=>queueMicrotask(resolve2));try{host.writer.hasConnection(connection)?host.writer.status.activate(activate):host.writer.status.unsubscribe(connection,activate)}catch(cause){process.stderr.write(`senpi rpc subscription activation failed: ${String(cause)}
|
|
36
39
|
`)}})().catch(cause=>{host.writer.status.unsubscribe(connection,activate),process.stderr.write(`senpi rpc subscribe answer could not be delivered: ${String(cause)}
|
|
37
|
-
`)});return}return answer3}if(command.type==="unsubscribe_sessions"){let peer=host.writer.currentConnection(),answer3=answerUnsubscribeSessions(command,peer,host.writer.status);return answer3.success&&peer!==void 0&&host.writer.unregisterSubscription(peer,command.subscriptionId),answer3}if(command.type==="get_effect_status"&&!command.sessionId&&command.sessionPath!==void 0)return answerEffectFromTranscript(command.id,command.sessionPath,command.effectId);if(command.type==="get_recovery_page"&&host.writer.recoveryPages!==void 0)return answerRecoveryPage(host.writer.recoveryPages,host.writer,command);if(command.type==="release_recovery"&&host.writer.recoveryEvents!==void 0)return answerReleaseRecovery(host.writer.recoveryEvents,host.writer,command);if(command.type==="get_recovery_page"||command.type==="release_recovery")return compactTransportDisabled(command);if(!command.sessionId)return error(command.id,command.type,RPC_ERROR_MISSING_SESSION_ID);let sessionId=command.sessionId;if(host.writer.isSessionSealed(sessionId)&&host.registry.peek(sessionId)?.state==="open")return error(command.id,command.type,"session_output_overflow",{sessionId,action:"unload_and_reopen"});if(command.type==="set_session_context")return setSessionContext(host,command);try{let entry=host.registry.getForCommand(sessionId,command.type);await dispatchSessionBinding(command,entry,host.bindings.get(sessionId),()=>acknowledgePrompt(host,command.id,sessionId),observedStarts=>host.registry.holderPids?.(observedStarts)??Promise.resolve([]));return}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}}function setSessionContext(host,command){let owner=host.writer.currentConnection();if(owner!==void 0&&host.sessionsByConnection.get(owner)?.has(command.sessionId)!==!0)return notAttachedRefusal(command);try{let entry=host.registry.getForCommand(command.sessionId,command.type);return answerSetSessionContext(command,entry,host.writer.status)}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}}var SessionCommandRouter=class{constructor(...args){this.context=new RouterContext(...args),this.context.releaseTeardown=(sessionId,sessionPath)=>this.tearDownReleased(sessionId,sessionPath)}tearDownReleased(sessionId,sessionPath){return tearDownReleased(this.context,sessionId,sessionPath)}get sessionCount(){return this.context.registry.size}handle(command){return handle(this.context,command)}beginDrain(){beginDrain(this.context)}setMemoryPressure(pressure){this.context.memoryPressure=pressure}sweepIdleSessions(){sweepIdleSessions(this.context)}dispose(){return dispose(this.context)}reopenParked(entry){return reopenParked(this.context,entry)}releaseConnection(connectionId){return releaseConnection(this.context,connectionId)}setHostMemoryView(view){this.context.hostMemoryView=view}};var SESSION_WORKER_LIMITS={workers:20,requests:64,controlRequests:4,controlBytes:1024*1024,requestBytes:16*1024*1024,outputBytes:16*1024*1024,reservations:64,openMs:3e4,controlMs:5e3,secretFrameBytes:64*1024,secretInputs:64,secretIds:1088};var WORKER_CREDIT_CODES={granted:1,conflict:2,limit:3,stale:4};function typedWorkerRefusal(cause){let message=cause instanceof Error?cause.message:String(cause);throw message.startsWith("open_failed: ")?new RpcSessionRegistryError("open_failed",message.slice(13)):cause}function closedByWorkerDeath(cause){return cause instanceof RpcSessionRegistryError?cause.code==="session_closing":cause instanceof Error&&(cause.message==="session_closing"||cause.message==="session_worker_exited")}var RESERVATION_DENIAL_CODES={conflict:"session_path_in_use",limit:"session_reservation_limit"},SessionPathReservations=class{constructor(){this.owners=new Map}owner(path){return this.owners.get(path)}count(handle2){let count=0;for(let owner of this.owners.values())owner===handle2&&count++;return count}reserve(handle2,path,live){let owner=this.owners.get(path);return owner?owner===handle2?"granted":"conflict":this.count(handle2)>=SESSION_WORKER_LIMITS.reservations&&(!live||(this.reconcile(handle2,live),this.count(handle2)>=SESSION_WORKER_LIMITS.reservations))?"limit":(this.owners.set(path,handle2),"granted")}reconcile(handle2,live){for(let[path,owner]of this.owners)owner!==handle2||path===live.sessionPath||live.livePaths.includes(path)||this.owners.delete(path)}releaseAll(handle2){for(let[path,owner]of this.owners)owner===handle2&&this.owners.delete(path)}};function acknowledgeGrant(signal,grant){let state=new Int32Array(signal);Atomics.store(state,0,WORKER_CREDIT_CODES[grant]),Atomics.notify(state,0)}function acknowledge(signal,granted){acknowledgeGrant(signal,granted?"granted":"conflict")}function workerCapabilities(options,message,writer){let connection=roleConnection(message.connection);if(options.connectionRoles?.isStale(connection,message.incarnation)===!0)return acknowledgeGrant(message.signal,"stale"),options;let current=message.connection===void 0||!compactUpdatesEnabled()?void 0:writer?.compactSelection(message.connection);if(current&&(current.refused||message.capabilities.length!==current.capabilities.length||!message.capabilities.every(cap=>current.capabilities.includes(cap))))return acknowledge(message.signal,!1),options;let verdict=options.connectionRoles?.declare(connection,message.capabilities,message.incarnation);return verdict==="stale"?(acknowledgeGrant(message.signal,"stale"),options):verdict==="fixed"?(acknowledge(message.signal,!1),options):(message.connection===void 0&&(options={...options,capabilities:message.capabilities}),options.clientInfo?.setCapabilities(message.connection,message.capabilities),acknowledge(message.signal,!0),options)}var SessionWorkerRequests=class{constructor(send,timeout){this.pending=new Map,this.serial=0,this.closed=!1,this.send=send,this.timeout=timeout}remainingOpenMs(){let now=Date.now();return this.openingDeadline===void 0&&(this.openingDeadline=now+SESSION_WORKER_LIMITS.openMs),Math.max(0,this.openingDeadline-now)}get activeCount(){return this.pending.size}request(message){if(this.closed)return Promise.reject(new Error("session_closing"));let control=message.type==="secret_sealed_answer"||message.type==="command"&&"type"in message.command&&typeof message.command.type=="string"&&["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(message.command.type),bytes=Buffer.byteLength(JSON.stringify(message)),count=0,pendingBytes=0;for(let pending of this.pending.values())pending.control===control&&(count++,pendingBytes+=pending.bytes);let maxCount=control?SESSION_WORKER_LIMITS.controlRequests:SESSION_WORKER_LIMITS.requests,maxBytes=control?SESSION_WORKER_LIMITS.controlBytes:SESSION_WORKER_LIMITS.requestBytes;if(count>=maxCount||pendingBytes+bytes>maxBytes)return Promise.reject(new Error("session_worker_request_limit"));let request=++this.serial;return new Promise((resolve2,reject)=>{let timer=message.type==="command"&&!control?void 0:setTimeout(this.timeout,control?SESSION_WORKER_LIMITS.controlMs:this.remainingOpenMs());this.pending.set(request,{resolve:resolve2,reject,bytes,control,timer});try{this.send({...message,request})}catch(cause){this.pending.delete(request),clearTimeout(timer),reject(cause instanceof Error?cause:new Error(String(cause)))}})}receive(message){let pending=this.pending.get(message.request);pending&&(clearTimeout(pending.timer),this.pending.delete(message.request),message.type==="result"&&message.error?pending.reject(new Error(message.error)):pending.resolve(message))}close(error2){this.closed=!0;for(let pending of this.pending.values())clearTimeout(pending.timer),pending.reject(error2);this.pending.clear()}};var WORKER_PERMIT_BYTES=FRAGMENT_ENVELOPE_MAX_BYTES,WORKER_CONTROL_SLOTS=1,PERMIT_WORD={credit:0,host:1,worker:2,wake:3},PERMIT_BLOCK_BYTES=Object.keys(PERMIT_WORD).length*Int32Array.BYTES_PER_ELEMENT,PERMIT_TAG={idle:0,granted:1,denied:2,closed:3,waiting:4},WorkerPermitLedger=class{constructor(capacity=TRANSFER_STAGING_MAX_BYTES){this.granted=0,this.waiting=new Set,this.ceiling=Math.floor(capacity/WORKER_PERMIT_BYTES)-WORKER_CONTROL_SLOTS}request(grant){return this.granted>=this.ceiling?(this.waiting.add(grant),!1):(this.granted+=1,grant(),!0)}release(){this.granted-=1;let[next]=this.waiting;next&&(this.waiting.delete(next),this.granted+=1,next())}withdraw(grant){this.waiting.delete(grant)}status(){return{granted:this.granted,waiting:this.waiting.size,ceiling:this.ceiling}}},hostWorkerPermits=new WorkerPermitLedger,HostPermits=class{constructor(ledger){this.block=new SharedArrayBuffer(PERMIT_BLOCK_BYTES),this.state=new Int32Array(this.block),this.holding=!1,this.closed=!1,this.grant=()=>{this.holding=!0,Atomics.add(this.state,PERMIT_WORD.credit,WORKER_PERMIT_BYTES),this.signal(PERMIT_TAG.granted)},this.ledger=ledger,this.request()}returned(){this.closed||!this.holding||Atomics.load(this.state,PERMIT_WORD.credit)>=WORKER_PERMIT_BYTES||(this.holding=!1,this.ledger.release(),this.request())}close(){this.closed||(this.closed=!0,this.signal(PERMIT_TAG.closed),this.holding?this.ledger.release():this.ledger.withdraw(this.grant),this.holding=!1)}request(){this.ledger.request(this.grant)||this.signal(PERMIT_TAG.denied)}signal(tag){Atomics.store(this.state,PERMIT_WORD.host,tag),Atomics.add(this.state,PERMIT_WORD.wake,1),Atomics.notify(this.state,PERMIT_WORD.wake)}};var PAID=new Set(["ready","snapshot","output","canonical","canonical_unavailable","fragment"]),FRAGMENT_KIND=protocolId("worker_frame"),WorkerIntake=class{constructor(staging,fail2,ledger=hostWorkerPermits){this.expected=0,this.serial=0,this.assembled=new WeakSet,this.staging=staging,this.fail=fail2,this.permits=new HostPermits(ledger)}get nextOrdinal(){return this.expected}get refusal(){return this.refused}received(message){PAID.has(message.type)&&!this.assembled.delete(message)&&this.permits.returned()}inOrder(message){if(message.ordinal===this.expected)return this.expected+=1,!0;message.signal&&acknowledge(message.signal,!1);let kind=(message.ordinal??Number.POSITIVE_INFINITY)<this.expected?"duplicate":"gap";return this.fail(`session_worker_frame_${kind}`),!1}fragment(frame){let end=frame.offset+frame.text.length*2,final=end===frame.length;if(frame.ordinal!==void 0&&!final&&!this.inOrder(frame))return this.refuse(frame);let fed=this.open?.fed??0;if(frame.offset!==fed)return this.refuse(frame,`session_worker_frame_${frame.offset<fed?"duplicate":"gap"}`);try{this.open??={transfer:this.staging.begin(FRAGMENT_KIND,protocolId(`t${++this.serial}`),frame.length),fed},this.open.transfer.append(frame.text),this.open.fed=end}catch(error2){let cause=error2 instanceof TransferStagingError?error2.reason:"failed",ordinal=frame.ordinal===void 0?void 0:frame.ordinal+Math.ceil((frame.length-frame.offset)/FRAGMENT_MAX_BYTES)-1;this.refused={cause,event:{type:frame.of,...ordinal===void 0?{}:{ordinal},length:frame.length}};let at=ordinal===void 0?"":` ordinal ${ordinal}`;return this.refuse(frame,`session_worker_transfer_${cause}: ${frame.of}${at} (${frame.length} stored bytes)`)}if(!final)return;let content=this.open.transfer.commit();return this.open=void 0,this.whole(content,frame)}refuse(frame,error2){this.open?.transfer.abort(),this.open=void 0,error2!==void 0&&(frame.signal&&acknowledge(frame.signal,!1),this.fail(error2))}async whole(content,frame){try{let text2="";for await(let chunk of this.staging.chunks(content))text2+=chunk;let message=JSON.parse(text2);return this.assembled.add(message),Object.assign(message,frame.ordinal===void 0?{}:{ordinal:frame.ordinal},frame.firstOrdinal===void 0?{}:{firstOrdinal:frame.firstOrdinal},frame.signal?{signal:frame.signal}:{},frame.epochSignal&&"bootstrap"in message?{bootstrap:{...message.bootstrap,epochSignal:frame.epochSignal}}:{})}finally{this.staging.abandon(content)}}};import{randomUUID as randomUUID2}from"node:crypto";var WorkerOwnerGates=class{constructor(){this.generation=randomUUID2(),this.issued=new Map}capture(context,connection,command){let transport=context.transport;if(connection===void 0||transport===void 0||!carriesExtensionOwner(command))return;let owner=transport.capture(this.generation);owner.retired&&(this.generation=randomUUID2(),owner=transport.capture(this.generation));let owners=this.issued.get(connection)??new Set;return owners.add(owner),this.issued.set(connection,owners),owner.wire}detach(context,connection){let owners=this.issued.get(connection);if(!owners)return[];this.issued.delete(connection);let current=context.transportOf(connection),kept=new Set,retired=[];for(let owner of owners)current!==void 0&¤t.ownerId!==owner.wire.ownerId&&!owner.retired?kept.add(owner):(owner.retire(),retired.push({ownerId:owner.wire.ownerId,bindingGeneration:owner.wire.bindingGeneration}));return kept.size>0&&this.issued.set(connection,kept),retired}retireAll(){let retired=[];for(let owners of this.issued.values())for(let owner of owners)owner.retire(),retired.push({ownerId:owner.wire.ownerId,bindingGeneration:owner.wire.bindingGeneration});return this.issued.clear(),this.generation=randomUUID2(),retired}};var SECRET_FRAME_TYPES=["extension_ui_request","secret_input_settled","secret_sealed_offer"];function secretFrameType(record){let type="type"in record?record.type:void 0;return SECRET_FRAME_TYPES.find(known=>known===type)}function isSealedOffer(record){if(!("type"in record)||record.type!=="secret_sealed_offer")return!1;let offer=record;return typeof offer.hpkePk=="string"&&/^[A-Za-z0-9_-]{43}$/.test(offer.hpkePk)&&typeof offer.title=="string"&&(offer.placeholder===void 0||typeof offer.placeholder=="string")&&Number.isSafeInteger(offer.deadlineAtMs)}var WorkerSecretIds=class{constructor(){this.sent=new Map}has(id){return this.sent.has(id)}ids(){return this.sent.keys()}admitsNew(){if(this.sent.size>=SESSION_WORKER_LIMITS.secretIds)return!1;let open2=0;for(let sent of this.sent.values())sent.has("secret_input_settled")||open2++;return open2<SESSION_WORKER_LIMITS.secretInputs}add(id){this.sent.has(id)||this.sent.set(id,new Set)}admitFrame(id,record){let sent=this.sent.get(id),type=secretFrameType(record);return!sent||type===void 0||sent.has(type)||Buffer.byteLength(JSON.stringify(record))>SESSION_WORKER_LIMITS.secretFrameBytes?!1:(sent.add(type),!0)}forget(id){this.sent.delete(id)}clear(){this.sent.clear()}};var SEALED_ANSWERS_PER_ID=5,OUTCOMES=new Set(["answered","cancelled","timed_out","unavailable"]),REPLY_ERRORS=new Set(["already_answered","unknown_extension_ui_request","secret_stepup_refused","invalid_secret_response","secret_answer_refused"]),isReplyError=error2=>REPLY_ERRORS.has(error2);function isolateReply(value){if(typeof value!="object"||value===null)return{error:"secret_answer_refused"};let disposition="disposition"in value?value.disposition:void 0;if(disposition==="applied"||disposition==="replay")return{disposition};let error2="error"in value?value.error:void 0;return typeof error2=="string"&&isReplyError(error2)?{error:error2}:{error:"secret_answer_refused"}}var WorkerHostSecrets=class{constructor(deps){this.ids=new WorkerSecretIds,this.queue=new Map,this.forwarded=new Map,this.settledIds=new Set,this.deps=deps}bind(sessionId,writer){this.writer=writer,this.route=writer.secretInputRoute(sessionId,!0),this.route.bindSealedResponder?.({settled:()=>{},respond:(answer3,claim)=>this.forward(answer3,claim)})}refuses(uiRequestId){return this.ids.has(uiRequestId)&&this.route?.accepts(uiRequestId)!==!0}exited(){this.route?.bindSealedResponder?.(void 0);for(let id of this.ids.ids())this.settledIds.has(id)||(this.route?.sealedOutcome?.(id,"unavailable",void 0),this.route?.settled(id));for(let id of this.ids.ids())this.route?.forget(id);this.ids.clear(),this.forwarded.clear(),this.settledIds.clear()}receive(message){switch(message.type){case"secret_select":return this.select(message),!0;case"secret_frame":if("type"in message.record&&message.record.type==="secret_sealed_offer"&&!isSealedOffer(message.record)||!this.ids.admitFrame(message.id,message.record))return acknowledge(message.signal,!1),!0;if(isSealedOffer(message.record)){let{hpkePk,title,placeholder,deadlineAtMs}=message.record;this.route?.offerSealed?.(message.id,{hpkePk,title,placeholder,deadlineAtMs})}else this.route?.send(message.id,message.record);return acknowledge(message.signal,!0),!0;case"secret_settled":return this.admitsSettle(message)?(this.settledIds.add(message.id),message.outcome!==void 0&&this.route?.sealedOutcome?.(message.id,message.outcome,message.winnerGrant),this.route?.settled(message.id),acknowledge(message.signal,!0),!0):(acknowledge(message.signal,!1),!0);case"secret_forget":return this.ids.forget(message.id),this.forwarded.delete(message.id),this.settledIds.delete(message.id),this.route?.forget(message.id),acknowledge(message.signal,!0),!0;case"secret_handshake":return this.writer?.setSoleSecretCapabilities(message.capabilities),acknowledge(message.signal,!0),!0;default:return!1}}select(message){if(!this.ids.has(message.id)&&!this.ids.admitsNew()){acknowledge(message.signal,!1);return}let select=()=>{let route=this.route,reason=route?.select(message.id,()=>this.deps.post({type:"cancel_secret",id:message.id}))??(route?void 0:"no_presenter");reason===void 0&&this.ids.add(message.id);let result=reason===void 0?{accepted:!0,connection:route?.presenter(message.id),raiser:route?.raiser?.(message.id)??!0,sealed:route?.sealed?.(message.id)??!1}:{accepted:!1,reason},encoded=new TextEncoder().encode(JSON.stringify(result));new Uint8Array(message.decision,4).set(encoded),Atomics.store(new Int32Array(message.decision,0,1),0,encoded.length),acknowledge(message.signal,!0)};message.connection!==void 0&&this.writer?this.writer.withConnection(message.connection,select):select()}admitsSettle(message){let{id,outcome,winnerGrant}=message;return!this.ids.has(id)||this.settledIds.has(id)||outcome!==void 0&&!OUTCOMES.has(outcome)?!1:winnerGrant===void 0||(outcome==="answered"||outcome==="cancelled")&&this.forwarded.get(id)?.has(winnerGrant)===!0}forward(answer3,claim){let id=answer3.uiRequestId,queued=this.queue.get(id);if(!this.ids.has(id)||(queued?.depth??0)>=SEALED_ANSWERS_PER_ID)return Promise.resolve({error:"secret_answer_refused"});let run2=async()=>{if(!claim.current())return{error:"secret_answer_refused"};let forwarded=this.forwarded.get(id)??new Set;forwarded.add(answer3.grantId),this.forwarded.set(id,forwarded);let reply=await this.deps.request({type:"secret_sealed_answer",answer:answer3});return reply.type==="secret_sealed_result"?isolateReply(reply.reply):{error:"secret_answer_refused"}},result=(queued?.tail??Promise.resolve()).then(run2).catch(()=>({error:"secret_answer_refused"})),entry={tail:result.then(()=>{}),depth:(queued?.depth??0)+1};return this.queue.set(id,entry),result.finally(()=>{let current=this.queue.get(id);current===entry?this.queue.delete(id):current&¤t.depth--}),result}};import{randomUUID as randomUUID3}from"node:crypto";import{fileURLToPath}from"node:url";import{Worker}from"node:worker_threads";var compiledWorkerEntry=typeof SENPI_RPC_SESSION_WORKER_ENTRY=="string"?SENPI_RPC_SESSION_WORKER_ENTRY:"./src/modes/rpc/session-worker.ts";function startSessionWorker(webviewBroker){return sessionWorkerDataRegistry.spawn(issued=>new Worker(isBunBinary?fileURLToPath(new URL(compiledWorkerEntry,import.meta.url)).replaceAll("\\","/"):new URL(import.meta.url.endsWith(".ts")?"./session-worker.ts":"./session-worker.js",import.meta.url),{workerData:{hostProcessStartedAtMs:ownProcessStartedAtMs(),extensionData:issued.extensionData,...webviewBroker?{webviewBroker:webviewBroker.port}:{}},transferList:[...webviewBroker?[webviewBroker.port]:[],...issued.transfer]}))}async function reconcileWorkerReplacement(message,lane,callbacks){message.snapshot&&(message.bootstrap&&compactUpdatesEnabled()&&await lane?.generations.bind(message.snapshot.state.sessionId),await callbacks.reconcile(message.snapshot.liveSessionPaths))}var SessionWorkerClient=class{constructor(callbacks,agentDir=recoveryAgentDir){this.secrets=new WorkerHostSecrets({post:message=>this.post(message),request:message=>this.request(message)}),this.privateOperations=new Map,this.webviewBroker=createWebViewBroker(),this.bindingReady=!1,this.request=message=>this.requests.request(message),this.requests=new SessionWorkerRequests(message=>this.worker.postMessage(message),()=>this.fail("session_worker_request_timeout")),this.stopped=!1,this.options={},this.listeners=new Set,this.cancelUiPending=!1,this.stopLimitMirror=()=>{},this.owners=new WorkerOwnerGates,this.callbacks=callbacks,this.agentDir=agentDir,this.spawned=startSessionWorker(this.webviewBroker),this.worker=this.spawned.result,this.exited=new Promise((resolve2,reject)=>{this.worker.once("exit",()=>{this.intake?.permits.close(),this.secrets.exited(),this.stopPrivateBinding?.(),this.privateBinding?.dispose(),this.owners.retireAll(),this.spawned.issued.dispose();for(let operation of this.privateOperations.values())operation.operation.abort();this.privateOperations.clear(),!this.stopped&&!this.closeTimer&&this.fail("session_worker_exited"),this.stopped=!0,this.closeTimer&&clearTimeout(this.closeTimer),this.requests.close(new Error("session_worker_exited")),this.webviewBroker?.dispose(),this.stopLimitMirror(),this.listeners.clear();let released=callbacks.exit();released?released.then(()=>{this.publishTerminalFailure(),resolve2()},reject):(this.publishTerminalFailure(),resolve2())})}),this.worker.on("message",message=>this.receive(message)),this.worker.on("error",error2=>this.fail(error2 instanceof Error?error2.message:String(error2)))}async prepare(configuration,profile){this.stopLimitMirror(),this.stopLimitMirror=subscriptionLimits.subscribeMirror(limits=>this.post({type:"subscription_limits",accounts:[limits]}));let result=await this.request({type:"prepare",configuration,profile,subscriptionLimits:subscriptionLimits.mirrorSnapshot()});if(result.type!=="prepared")throw new Error("Invalid worker prepare response");return result.sessionPath}async setPromptSurface(surface){if((await this.request({type:"prompt_surface",surface})).type!=="result")throw new Error("Invalid worker prompt_surface response")}async setBrowserEngine(engine){if((await this.request({type:"browser_engine",engine})).type!=="result")throw new Error("Invalid worker browser_engine response")}async setPermissionPreset(preset){if((await this.request({type:"permission_preset",preset})).type!=="result")throw new Error("Invalid worker permission_preset response")}async commit(){if(!compactUpdatesEnabled()){let result=await this.request({type:"commit"});if(result.type!=="ready")throw new Error("Invalid worker commit response");return this.snapshot=result.snapshot,result.snapshot}let nonce=randomUUID3(),acceptance=new SessionAcceptanceLane(void 0,void 0,this.agentDir),intake=new WorkerIntake(acceptance.staging,error2=>this.fail(error2));this.acceptance=acceptance,this.intake=intake;let negotiated=!1;try{let result=await this.request({type:"commit",acceptance:!0,recoveryEpoch:nonce,permits:intake.permits.block});if(result.type!=="ready")throw new Error("Invalid worker commit response");if(!result.bootstrap)throw new StructuredLaneUnavailableError;return acceptance.bootstrap(result.bootstrap,nonce),negotiated=!0,this.snapshot=result.snapshot,result.snapshot}finally{negotiated||(intake.permits.close(),acceptance.retire("close"),this.acceptance=this.intake=void 0)}}async bind(sessionId,writer,requestClose,options){this.sessionId=sessionId,this.writer=writer,this.secrets.bind(sessionId,writer),this.acceptance&&writer.registerAcceptance(sessionId,this.acceptance),compactUpdatesEnabled()&&process.stderr.write(`senpi rpc worker ${sessionId}: bound mode=${this.acceptance?"acceptance":"legacy"}
|
|
40
|
+
`)});return}return answer3}if(command.type==="unsubscribe_sessions"){let peer=host.writer.currentConnection(),answer3=answerUnsubscribeSessions(command,peer,host.writer.status);return answer3.success&&peer!==void 0&&host.writer.unregisterSubscription(peer,command.subscriptionId),answer3}if(command.type==="get_effect_status"&&!command.sessionId&&command.sessionPath!==void 0)return answerEffectFromTranscript(command.id,command.sessionPath,command.effectId);if(command.type==="get_recovery_page"&&host.writer.recoveryPages!==void 0)return answerRecoveryPage(host.writer.recoveryPages,host.writer,command);if(command.type==="release_recovery"&&host.writer.recoveryEvents!==void 0)return answerReleaseRecovery(host.writer.recoveryEvents,host.writer,command);if(command.type==="get_recovery_page"||command.type==="release_recovery")return compactTransportDisabled(command);if(!command.sessionId)return error(command.id,command.type,RPC_ERROR_MISSING_SESSION_ID);let sessionId=command.sessionId;if(host.writer.isSessionSealed(sessionId)&&host.registry.peek(sessionId)?.state==="open")return error(command.id,command.type,"session_output_overflow",{sessionId,action:"unload_and_reopen"});if(command.type==="set_session_context")return setSessionContext(host,command);try{let entry=host.registry.getForCommand(sessionId,command.type);await dispatchSessionBinding(command,entry,host.bindings.get(sessionId),()=>acknowledgePrompt(host,command.id,sessionId),observedStarts=>host.registry.holderPids?.(observedStarts)??Promise.resolve([]));return}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}}function setSessionContext(host,command){let owner=host.writer.currentConnection();if(owner!==void 0&&host.sessionsByConnection.get(owner)?.has(command.sessionId)!==!0)return notAttachedRefusal(command);try{let entry=host.registry.getForCommand(command.sessionId,command.type),answered=answerSetSessionContext(command,entry,host.writer.status);return answered.success&&syncRetainedRecord(host,command.sessionId,void 0),answered}catch(cause){return error(command.id,command.type,code(cause),detail(cause))}}var SessionCommandRouter=class{constructor(...args){this.context=new RouterContext(...args),this.context.releaseTeardown=(sessionId,sessionPath)=>this.tearDownReleased(sessionId,sessionPath)}tearDownReleased(sessionId,sessionPath){return tearDownReleased(this.context,sessionId,sessionPath)}get sessionCount(){return this.context.registry.size}handle(command){return handle(this.context,command)}beginDrain(){beginDrain(this.context)}setMemoryPressure(pressure){this.context.memoryPressure=pressure}sweepIdleSessions(){sweepIdleSessions(this.context)}dispose(){return dispose(this.context)}reopenParked(entry){return reopenParked(this.context,entry)}releaseConnection(connectionId){return releaseConnection(this.context,connectionId)}setHostMemoryView(view){this.context.hostMemoryView=view}};var SESSION_WORKER_LIMITS={workers:20,requests:64,controlRequests:4,controlBytes:1024*1024,requestBytes:16*1024*1024,outputBytes:16*1024*1024,reservations:64,openMs:3e4,controlMs:5e3,secretFrameBytes:64*1024,secretInputs:64,secretIds:1088};var WORKER_CREDIT_CODES={granted:1,conflict:2,limit:3,stale:4};function typedWorkerRefusal(cause){let message=cause instanceof Error?cause.message:String(cause);throw message.startsWith("open_failed: ")?new RpcSessionRegistryError("open_failed",message.slice(13)):cause}function closedByWorkerDeath(cause){return cause instanceof RpcSessionRegistryError?cause.code==="session_closing":cause instanceof Error&&(cause.message==="session_closing"||cause.message==="session_worker_exited")}var RESERVATION_DENIAL_CODES={conflict:"session_path_in_use",limit:"session_reservation_limit"},SessionPathReservations=class{constructor(){this.owners=new Map}owner(path){return this.owners.get(path)}count(handle2){let count=0;for(let owner of this.owners.values())owner===handle2&&count++;return count}reserve(handle2,path,live){let owner=this.owners.get(path);return owner?owner===handle2?"granted":"conflict":this.count(handle2)>=SESSION_WORKER_LIMITS.reservations&&(!live||(this.reconcile(handle2,live),this.count(handle2)>=SESSION_WORKER_LIMITS.reservations))?"limit":(this.owners.set(path,handle2),"granted")}reconcile(handle2,live){for(let[path,owner]of this.owners)owner!==handle2||path===live.sessionPath||live.livePaths.includes(path)||this.owners.delete(path)}releaseAll(handle2){for(let[path,owner]of this.owners)owner===handle2&&this.owners.delete(path)}};function acknowledgeGrant(signal,grant){let state=new Int32Array(signal);Atomics.store(state,0,WORKER_CREDIT_CODES[grant]),Atomics.notify(state,0)}function acknowledge(signal,granted){acknowledgeGrant(signal,granted?"granted":"conflict")}function workerCapabilities(options,message,writer){let connection=roleConnection(message.connection);if(options.connectionRoles?.isStale(connection,message.incarnation)===!0)return acknowledgeGrant(message.signal,"stale"),options;let current=message.connection===void 0||!compactUpdatesEnabled()?void 0:writer?.compactSelection(message.connection);if(current&&(current.refused||message.capabilities.length!==current.capabilities.length||!message.capabilities.every(cap=>current.capabilities.includes(cap))))return acknowledge(message.signal,!1),options;let verdict=options.connectionRoles?.declare(connection,message.capabilities,message.incarnation);return verdict==="stale"?(acknowledgeGrant(message.signal,"stale"),options):verdict==="fixed"?(acknowledge(message.signal,!1),options):(message.connection===void 0&&(options={...options,capabilities:message.capabilities}),options.clientInfo?.setCapabilities(message.connection,message.capabilities),acknowledge(message.signal,!0),options)}var SessionWorkerRequests=class{constructor(send,timeout){this.pending=new Map,this.serial=0,this.closed=!1,this.send=send,this.timeout=timeout}remainingOpenMs(){let now=Date.now();return this.openingDeadline===void 0&&(this.openingDeadline=now+SESSION_WORKER_LIMITS.openMs),Math.max(0,this.openingDeadline-now)}get activeCount(){return this.pending.size}request(message){if(this.closed)return Promise.reject(new Error("session_closing"));let control=message.type==="secret_sealed_answer"||message.type==="command"&&"type"in message.command&&typeof message.command.type=="string"&&["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(message.command.type),bytes=Buffer.byteLength(JSON.stringify(message)),count=0,pendingBytes=0;for(let pending of this.pending.values())pending.control===control&&(count++,pendingBytes+=pending.bytes);let maxCount=control?SESSION_WORKER_LIMITS.controlRequests:SESSION_WORKER_LIMITS.requests,maxBytes=control?SESSION_WORKER_LIMITS.controlBytes:SESSION_WORKER_LIMITS.requestBytes;if(count>=maxCount||pendingBytes+bytes>maxBytes)return Promise.reject(new Error("session_worker_request_limit"));let request=++this.serial;return new Promise((resolve2,reject)=>{let timer=message.type==="command"&&!control?void 0:setTimeout(this.timeout,control?SESSION_WORKER_LIMITS.controlMs:this.remainingOpenMs());this.pending.set(request,{resolve:resolve2,reject,bytes,control,timer});try{this.send({...message,request})}catch(cause){this.pending.delete(request),clearTimeout(timer),reject(cause instanceof Error?cause:new Error(String(cause)))}})}receive(message){let pending=this.pending.get(message.request);pending&&(clearTimeout(pending.timer),this.pending.delete(message.request),message.type==="result"&&message.error?pending.reject(new Error(message.error)):pending.resolve(message))}close(error2){this.closed=!0;for(let pending of this.pending.values())clearTimeout(pending.timer),pending.reject(error2);this.pending.clear()}};var WORKER_PERMIT_BYTES=FRAGMENT_ENVELOPE_MAX_BYTES,WORKER_CONTROL_SLOTS=1,PERMIT_WORD={credit:0,host:1,worker:2,wake:3},PERMIT_BLOCK_BYTES=Object.keys(PERMIT_WORD).length*Int32Array.BYTES_PER_ELEMENT,PERMIT_TAG={idle:0,granted:1,denied:2,closed:3,waiting:4},WorkerPermitLedger=class{constructor(capacity=TRANSFER_STAGING_MAX_BYTES){this.granted=0,this.waiting=new Set,this.ceiling=Math.floor(capacity/WORKER_PERMIT_BYTES)-WORKER_CONTROL_SLOTS}request(grant){return this.granted>=this.ceiling?(this.waiting.add(grant),!1):(this.granted+=1,grant(),!0)}release(){this.granted-=1;let[next]=this.waiting;next&&(this.waiting.delete(next),this.granted+=1,next())}withdraw(grant){this.waiting.delete(grant)}status(){return{granted:this.granted,waiting:this.waiting.size,ceiling:this.ceiling}}},hostWorkerPermits=new WorkerPermitLedger,HostPermits=class{constructor(ledger){this.block=new SharedArrayBuffer(PERMIT_BLOCK_BYTES),this.state=new Int32Array(this.block),this.holding=!1,this.closed=!1,this.grant=()=>{this.holding=!0,Atomics.add(this.state,PERMIT_WORD.credit,WORKER_PERMIT_BYTES),this.signal(PERMIT_TAG.granted)},this.ledger=ledger,this.request()}returned(){this.closed||!this.holding||Atomics.load(this.state,PERMIT_WORD.credit)>=WORKER_PERMIT_BYTES||(this.holding=!1,this.ledger.release(),this.request())}close(){this.closed||(this.closed=!0,this.signal(PERMIT_TAG.closed),this.holding?this.ledger.release():this.ledger.withdraw(this.grant),this.holding=!1)}request(){this.ledger.request(this.grant)||this.signal(PERMIT_TAG.denied)}signal(tag){Atomics.store(this.state,PERMIT_WORD.host,tag),Atomics.add(this.state,PERMIT_WORD.wake,1),Atomics.notify(this.state,PERMIT_WORD.wake)}};var PAID=new Set(["ready","snapshot","output","canonical","canonical_unavailable","fragment"]),FRAGMENT_KIND=protocolId("worker_frame"),WorkerIntake=class{constructor(staging,fail2,ledger=hostWorkerPermits){this.expected=0,this.serial=0,this.assembled=new WeakSet,this.staging=staging,this.fail=fail2,this.permits=new HostPermits(ledger)}get nextOrdinal(){return this.expected}get refusal(){return this.refused}received(message){PAID.has(message.type)&&!this.assembled.delete(message)&&this.permits.returned()}inOrder(message){if(message.ordinal===this.expected)return this.expected+=1,!0;message.signal&&acknowledge(message.signal,!1);let kind=(message.ordinal??Number.POSITIVE_INFINITY)<this.expected?"duplicate":"gap";return this.fail(`session_worker_frame_${kind}`),!1}fragment(frame){let end=frame.offset+frame.text.length*2,final=end===frame.length;if(frame.ordinal!==void 0&&!final&&!this.inOrder(frame))return this.refuse(frame);let fed=this.open?.fed??0;if(frame.offset!==fed)return this.refuse(frame,`session_worker_frame_${frame.offset<fed?"duplicate":"gap"}`);try{this.open??={transfer:this.staging.begin(FRAGMENT_KIND,protocolId(`t${++this.serial}`),frame.length),fed},this.open.transfer.append(frame.text),this.open.fed=end}catch(error2){let cause=error2 instanceof TransferStagingError?error2.reason:"failed",ordinal=frame.ordinal===void 0?void 0:frame.ordinal+Math.ceil((frame.length-frame.offset)/FRAGMENT_MAX_BYTES)-1;this.refused={cause,event:{type:frame.of,...ordinal===void 0?{}:{ordinal},length:frame.length}};let at=ordinal===void 0?"":` ordinal ${ordinal}`;return this.refuse(frame,`session_worker_transfer_${cause}: ${frame.of}${at} (${frame.length} stored bytes)`)}if(!final)return;let content=this.open.transfer.commit();return this.open=void 0,this.whole(content,frame)}refuse(frame,error2){this.open?.transfer.abort(),this.open=void 0,error2!==void 0&&(frame.signal&&acknowledge(frame.signal,!1),this.fail(error2))}async whole(content,frame){try{let text2="";for await(let chunk of this.staging.chunks(content))text2+=chunk;let message=JSON.parse(text2);return this.assembled.add(message),Object.assign(message,frame.ordinal===void 0?{}:{ordinal:frame.ordinal},frame.firstOrdinal===void 0?{}:{firstOrdinal:frame.firstOrdinal},frame.signal?{signal:frame.signal}:{},frame.epochSignal&&"bootstrap"in message?{bootstrap:{...message.bootstrap,epochSignal:frame.epochSignal}}:{})}finally{this.staging.abandon(content)}}};import{randomUUID as randomUUID2}from"node:crypto";var WorkerOwnerGates=class{constructor(){this.generation=randomUUID2(),this.issued=new Map}capture(context,connection,command){let transport=context.transport;if(connection===void 0||transport===void 0||!carriesExtensionOwner(command))return;let owner=transport.capture(this.generation);owner.retired&&(this.generation=randomUUID2(),owner=transport.capture(this.generation));let owners=this.issued.get(connection)??new Set;return owners.add(owner),this.issued.set(connection,owners),owner.wire}detach(context,connection){let owners=this.issued.get(connection);if(!owners)return[];this.issued.delete(connection);let current=context.transportOf(connection),kept=new Set,retired=[];for(let owner of owners)current!==void 0&¤t.ownerId!==owner.wire.ownerId&&!owner.retired?kept.add(owner):(owner.retire(),retired.push({ownerId:owner.wire.ownerId,bindingGeneration:owner.wire.bindingGeneration}));return kept.size>0&&this.issued.set(connection,kept),retired}retireAll(){let retired=[];for(let owners of this.issued.values())for(let owner of owners)owner.retire(),retired.push({ownerId:owner.wire.ownerId,bindingGeneration:owner.wire.bindingGeneration});return this.issued.clear(),this.generation=randomUUID2(),retired}};var SECRET_FRAME_TYPES=["extension_ui_request","secret_input_settled","secret_sealed_offer"];function secretFrameType(record){let type="type"in record?record.type:void 0;return SECRET_FRAME_TYPES.find(known=>known===type)}function isSealedOffer(record){if(!("type"in record)||record.type!=="secret_sealed_offer")return!1;let offer=record;return typeof offer.hpkePk=="string"&&/^[A-Za-z0-9_-]{43}$/.test(offer.hpkePk)&&typeof offer.title=="string"&&(offer.placeholder===void 0||typeof offer.placeholder=="string")&&Number.isSafeInteger(offer.deadlineAtMs)}var WorkerSecretIds=class{constructor(){this.sent=new Map}has(id){return this.sent.has(id)}ids(){return this.sent.keys()}admitsNew(){if(this.sent.size>=SESSION_WORKER_LIMITS.secretIds)return!1;let open2=0;for(let sent of this.sent.values())sent.has("secret_input_settled")||open2++;return open2<SESSION_WORKER_LIMITS.secretInputs}add(id){this.sent.has(id)||this.sent.set(id,new Set)}admitFrame(id,record){let sent=this.sent.get(id),type=secretFrameType(record);return!sent||type===void 0||sent.has(type)||Buffer.byteLength(JSON.stringify(record))>SESSION_WORKER_LIMITS.secretFrameBytes?!1:(sent.add(type),!0)}forget(id){this.sent.delete(id)}clear(){this.sent.clear()}};var SEALED_ANSWERS_PER_ID=5,OUTCOMES=new Set(["answered","cancelled","timed_out","unavailable"]),REPLY_ERRORS=new Set(["already_answered","unknown_extension_ui_request","secret_stepup_refused","invalid_secret_response","secret_answer_refused"]),isReplyError=error2=>REPLY_ERRORS.has(error2);function isolateReply(value){if(typeof value!="object"||value===null)return{error:"secret_answer_refused"};let disposition="disposition"in value?value.disposition:void 0;if(disposition==="applied"||disposition==="replay")return{disposition};let error2="error"in value?value.error:void 0;return typeof error2=="string"&&isReplyError(error2)?{error:error2}:{error:"secret_answer_refused"}}var WorkerHostSecrets=class{constructor(deps){this.ids=new WorkerSecretIds,this.queue=new Map,this.forwarded=new Map,this.settledIds=new Set,this.deps=deps}bind(sessionId,writer){this.writer=writer,this.route=writer.secretInputRoute(sessionId,!0),this.route.bindSealedResponder?.({settled:()=>{},respond:(answer3,claim)=>this.forward(answer3,claim)})}refuses(uiRequestId){return this.ids.has(uiRequestId)&&this.route?.accepts(uiRequestId)!==!0}exited(){this.route?.bindSealedResponder?.(void 0);for(let id of this.ids.ids())this.settledIds.has(id)||(this.route?.sealedOutcome?.(id,"unavailable",void 0),this.route?.settled(id));for(let id of this.ids.ids())this.route?.forget(id);this.ids.clear(),this.forwarded.clear(),this.settledIds.clear()}receive(message){switch(message.type){case"secret_select":return this.select(message),!0;case"secret_frame":if("type"in message.record&&message.record.type==="secret_sealed_offer"&&!isSealedOffer(message.record)||!this.ids.admitFrame(message.id,message.record))return acknowledge(message.signal,!1),!0;if(isSealedOffer(message.record)){let{hpkePk,title,placeholder,deadlineAtMs}=message.record;this.route?.offerSealed?.(message.id,{hpkePk,title,placeholder,deadlineAtMs})}else this.route?.send(message.id,message.record);return acknowledge(message.signal,!0),!0;case"secret_settled":return this.admitsSettle(message)?(this.settledIds.add(message.id),message.outcome!==void 0&&this.route?.sealedOutcome?.(message.id,message.outcome,message.winnerGrant),this.route?.settled(message.id),acknowledge(message.signal,!0),!0):(acknowledge(message.signal,!1),!0);case"secret_forget":return this.ids.forget(message.id),this.forwarded.delete(message.id),this.settledIds.delete(message.id),this.route?.forget(message.id),acknowledge(message.signal,!0),!0;case"secret_handshake":return this.writer?.setSoleSecretCapabilities(message.capabilities),acknowledge(message.signal,!0),!0;default:return!1}}select(message){if(!this.ids.has(message.id)&&!this.ids.admitsNew()){acknowledge(message.signal,!1);return}let select=()=>{let route=this.route,reason=route?.select(message.id,()=>this.deps.post({type:"cancel_secret",id:message.id}))??(route?void 0:"no_presenter");reason===void 0&&this.ids.add(message.id);let result=reason===void 0?{accepted:!0,connection:route?.presenter(message.id),raiser:route?.raiser?.(message.id)??!0,sealed:route?.sealed?.(message.id)??!1}:{accepted:!1,reason},encoded=new TextEncoder().encode(JSON.stringify(result));new Uint8Array(message.decision,4).set(encoded),Atomics.store(new Int32Array(message.decision,0,1),0,encoded.length),acknowledge(message.signal,!0)};message.connection!==void 0&&this.writer?this.writer.withConnection(message.connection,select):select()}admitsSettle(message){let{id,outcome,winnerGrant}=message;return!this.ids.has(id)||this.settledIds.has(id)||outcome!==void 0&&!OUTCOMES.has(outcome)?!1:winnerGrant===void 0||(outcome==="answered"||outcome==="cancelled")&&this.forwarded.get(id)?.has(winnerGrant)===!0}forward(answer3,claim){let id=answer3.uiRequestId,queued=this.queue.get(id);if(!this.ids.has(id)||(queued?.depth??0)>=SEALED_ANSWERS_PER_ID)return Promise.resolve({error:"secret_answer_refused"});let run2=async()=>{if(!claim.current())return{error:"secret_answer_refused"};let forwarded=this.forwarded.get(id)??new Set;forwarded.add(answer3.grantId),this.forwarded.set(id,forwarded);let reply=await this.deps.request({type:"secret_sealed_answer",answer:answer3});return reply.type==="secret_sealed_result"?isolateReply(reply.reply):{error:"secret_answer_refused"}},result=(queued?.tail??Promise.resolve()).then(run2).catch(()=>({error:"secret_answer_refused"})),entry={tail:result.then(()=>{}),depth:(queued?.depth??0)+1};return this.queue.set(id,entry),result.finally(()=>{let current=this.queue.get(id);current===entry?this.queue.delete(id):current&¤t.depth--}),result}};import{randomUUID as randomUUID3}from"node:crypto";import{fileURLToPath}from"node:url";import{Worker}from"node:worker_threads";var compiledWorkerEntry=typeof SENPI_RPC_SESSION_WORKER_ENTRY=="string"?SENPI_RPC_SESSION_WORKER_ENTRY:"./src/modes/rpc/session-worker.ts";function startSessionWorker(webviewBroker){return sessionWorkerDataRegistry.spawn(issued=>new Worker(isBunBinary?fileURLToPath(new URL(compiledWorkerEntry,import.meta.url)).replaceAll("\\","/"):new URL(import.meta.url.endsWith(".ts")?"./session-worker.ts":"./session-worker.js",import.meta.url),{workerData:{hostProcessStartedAtMs:ownProcessStartedAtMs(),extensionData:issued.extensionData,...webviewBroker?{webviewBroker:webviewBroker.port}:{}},transferList:[...webviewBroker?[webviewBroker.port]:[],...issued.transfer]}))}async function reconcileWorkerReplacement(message,lane,callbacks){message.snapshot&&(message.bootstrap&&compactUpdatesEnabled()&&await lane?.generations.bind(message.snapshot.state.sessionId),await callbacks.reconcile(message.snapshot.liveSessionPaths))}var SessionWorkerClient=class{constructor(callbacks,agentDir=recoveryAgentDir){this.secrets=new WorkerHostSecrets({post:message=>this.post(message),request:message=>this.request(message)}),this.privateOperations=new Map,this.webviewBroker=createWebViewBroker(),this.bindingReady=!1,this.request=message=>this.requests.request(message),this.requests=new SessionWorkerRequests(message=>this.worker.postMessage(message),()=>this.fail("session_worker_request_timeout")),this.stopped=!1,this.options={},this.listeners=new Set,this.cancelUiPending=!1,this.stopLimitMirror=()=>{},this.owners=new WorkerOwnerGates,this.callbacks=callbacks,this.agentDir=agentDir,this.spawned=startSessionWorker(this.webviewBroker),this.worker=this.spawned.result,this.exited=new Promise((resolve2,reject)=>{this.worker.once("exit",()=>{this.intake?.permits.close(),this.secrets.exited(),this.stopPrivateBinding?.(),this.privateBinding?.dispose(),this.owners.retireAll(),this.spawned.issued.dispose();for(let operation of this.privateOperations.values())operation.operation.abort();this.privateOperations.clear(),!this.stopped&&!this.closeTimer&&this.fail("session_worker_exited"),this.stopped=!0,this.closeTimer&&clearTimeout(this.closeTimer),this.requests.close(new Error("session_worker_exited")),this.webviewBroker?.dispose(),this.stopLimitMirror(),this.listeners.clear();let released=callbacks.exit();released?released.then(()=>{this.publishTerminalFailure(),resolve2()},reject):(this.publishTerminalFailure(),resolve2())})}),this.worker.on("message",message=>this.receive(message)),this.worker.on("error",error2=>this.fail(error2 instanceof Error?error2.message:String(error2)))}async prepare(configuration,profile){this.stopLimitMirror(),this.stopLimitMirror=subscriptionLimits.subscribeMirror(limits=>this.post({type:"subscription_limits",accounts:[limits]}));let result=await this.request({type:"prepare",configuration,profile,subscriptionLimits:subscriptionLimits.mirrorSnapshot()});if(result.type!=="prepared")throw new Error("Invalid worker prepare response");return result.sessionPath}async setPromptSurface(surface){if((await this.request({type:"prompt_surface",surface})).type!=="result")throw new Error("Invalid worker prompt_surface response")}async setBrowserEngine(engine){if((await this.request({type:"browser_engine",engine})).type!=="result")throw new Error("Invalid worker browser_engine response")}async setPermissionPreset(preset){if((await this.request({type:"permission_preset",preset})).type!=="result")throw new Error("Invalid worker permission_preset response")}async commit(){if(!compactUpdatesEnabled()){let result=await this.request({type:"commit"});if(result.type!=="ready")throw new Error("Invalid worker commit response");return this.snapshot=result.snapshot,result.snapshot}let nonce=randomUUID3(),acceptance=new SessionAcceptanceLane(void 0,void 0,this.agentDir),intake=new WorkerIntake(acceptance.staging,error2=>this.fail(error2));this.acceptance=acceptance,this.intake=intake;let negotiated=!1;try{let result=await this.request({type:"commit",acceptance:!0,recoveryEpoch:nonce,permits:intake.permits.block});if(result.type!=="ready")throw new Error("Invalid worker commit response");if(!result.bootstrap)throw new StructuredLaneUnavailableError;return acceptance.bootstrap(result.bootstrap,nonce),negotiated=!0,this.snapshot=result.snapshot,result.snapshot}finally{negotiated||(intake.permits.close(),acceptance.retire("close"),this.acceptance=this.intake=void 0)}}async bind(sessionId,writer,requestClose,options){this.sessionId=sessionId,this.writer=writer,this.secrets.bind(sessionId,writer),this.acceptance&&writer.registerAcceptance(sessionId,this.acceptance),compactUpdatesEnabled()&&process.stderr.write(`senpi rpc worker ${sessionId}: bound mode=${this.acceptance?"acceptance":"legacy"}
|
|
38
41
|
`),this.requestClose=requestClose,this.options=options;let bound=writer.connectionContext.delegation;return await this.request({type:"bind",sessionId,capabilities:options.capabilities??[],connection:writer.currentConnection(),roles:options.connectionRoles?.rolesOf(roleConnection(writer.currentConnection()),bound?.incarnation),...bound===void 0?{}:{delegation:bound},mcpFormsEnforced:writer.mcpPresenters!==void 0}),{handle:async command=>{if(writer.handleMcpForm(command))return;let connection=writer.currentConnection(),owner=this.owners.capture(writer.connectionContext,connection,command),answered="type"in command&&command.type==="extension_ui_response"?answeredUiRequestId(command):void 0;if(answered!==void 0&&writer.acceptWorkerGrantResponse(sessionId,answered,connection)===!1)return;if(answered!==void 0&&this.secrets.refuses(answered)){let response=command;writer.enqueue(sessionId,refusedExtensionUiResponse(response.id,"secret_answer_refused"));return}let delegation=writer.connectionContext.delegation,exec=commandAuthority.getStore()?.exec;await this.request({type:"command",admissionReply:captureAdmissionReply(),command,connection,roles:options.connectionRoles?.rolesOf(roleConnection(connection),delegation?.incarnation),...originField(options.connectionRoles?.originOf(connection)),...owner===void 0?{}:{owner},...delegation===void 0?{}:{delegation},...exec===void 0?{}:{exec}})},cancelPendingExtensionUiRequests:()=>this.post({type:"cancel_ui"}),connectionDetached:connection=>this.postRetired(this.owners.detach(writer.connectionContext,connection)),dispose:async()=>{this.postRetired(this.owners.retireAll()),this.post({type:"cancel_ui"})}}}get busy(){return this.requests.activeCount>0||this.snapshot?.busy===!0}get handoffBusy(){return this.requests.activeCount>0||(this.snapshot?.handoffBusy??this.snapshot?.busy)===!0}subscribeSettled(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}close(graceMs){return this.stopped||this.closeTimer?this.exited:(this.post({type:"close"}),this.closeTimer=setTimeout(()=>this.quarantine(),graceMs),this.exited)}quarantine(){this.intake?.permits.close(),this.stopped=!0,this.requests.close(new Error("session_closing")),this.worker.terminate()}postRetired(owners){owners.length>0&&this.post({type:"owners_retired",owners})}post(message){if(!this.stopped){if(message.type==="cancel_ui"){if(this.cancelUiPending)return;this.cancelUiPending=!0}this.worker.postMessage(message)}}receive(message){if(this.stopped){"signal"in message&&message.signal&&acknowledge(message.signal,!1);return}if(this.intake?.received(message),!this.secrets.receive(message))switch(message.type){case"mcp_form_bind":{this.stopPrivateBinding?.(),this.privateBinding?.dispose();let writer=this.writer,sessionId=this.sessionId;if(!writer?.mcpPresenters||!sessionId){this.fail("private_form_unavailable");return}let bound=writer.bindMcpForms(sessionId,message.durableId,{},()=>{});if(bound instanceof Promise){this.fail("private_form_unavailable");return}this.privateBinding=writer.getMcpFormBinding(sessionId);let binding2=this.privateBinding;if(!binding2){this.fail("private_form_unavailable");return}let unsubscribe=binding2.subscribe?.(()=>this.post({type:"mcp_form_availability",epoch:binding2.epoch,version:binding2.version?.()}));this.stopPrivateBinding=()=>{unsubscribe?.(),bound?.()},this.post({type:"mcp_form_bound",id:message.id,epoch:binding2.epoch,version:binding2.version?.()});return}case"mcp_form_ready":{let binding2=this.privateBinding;this.post({type:"mcp_form_availability",id:message.id,epoch:message.epoch,version:binding2?.epoch===message.epoch?binding2.version?.():void 0});return}case"mcp_form_release":this.privateBinding?.epoch===message.epoch&&this.stopPrivateBinding?.();return;case"mcp_form_cancel":{let operation=this.privateOperations.get(message.id);operation?.epoch===message.epoch&&operation[message.lifetime].abort();return}case"mcp_form_create":{let binding2=this.privateBinding,presenter=binding2?.epoch===message.epoch&&binding2.version?.()===message.version?binding2.capture():void 0,operation=new AbortController,presentation=new AbortController;this.privateOperations.set(message.id,{operation,presentation,epoch:message.epoch});let fence=new Int32Array(message.operationFence),result=presenter?.present({...message.input,operationSignal:operation.signal,presentationSignal:presentation.signal,operationCurrent:()=>Atomics.load(fence,0)===0});Promise.resolve(result).then(outcome=>{this.privateOperations.delete(message.id),this.post({type:"mcp_form_settlement",id:message.id,epoch:message.epoch,settlementId:randomUUID3(),outcome:outcome??{kind:"processing_failure",source:"host_termination",humanAdmission:!1}})});return}case"secret_sealed_result":this.requests.receive(message);return;case"prepared":case"ready":case"result":{this.requests.receive(message),this.snapshot&&Promise.resolve(this.callbacks.reconcile(this.snapshot.liveSessionPaths)).catch(()=>this.fail("session_claim_reconcile_failed"));return}case"reserve":Promise.resolve(this.callbacks.reserve(message.path)).then(grant=>acknowledgeGrant(message.signal,this.stopped?"conflict":grant),()=>acknowledgeGrant(message.signal,"conflict"));return;case"snapshot":this.snapshot=message.snapshot,Promise.resolve(this.callbacks.reconcile(message.snapshot.liveSessionPaths)).then(()=>{if(acknowledge(message.signal,!this.stopped),message.settled)for(let listener of[...this.listeners])listener()},()=>{acknowledge(message.signal,!1),this.fail("session_claim_reconcile_failed")});return;case"control_done":this.cancelUiPending=!1;return;case"output":{let writer=this.writer,sessionId=this.sessionId;if(!writer||!sessionId||this.stopped){acknowledge(message.signal,!1);return}let lane=this.acceptance;if(this.intake?.inOrder(message)===!1)return;message.snapshot?this.snapshot=message.snapshot:this.snapshot&&(this.snapshot={...this.snapshot,...message.activity,state:{...this.snapshot.state,isStreaming:message.activity.streaming}});let record=message.recordText===void 0?message.record:JSON.parse(message.recordText);if("type"in record&&record.type==="security_grant_settled"&&"id"in record&&typeof record.id=="string"){writer.settleGrantDialog(sessionId,record.id),acknowledge(message.signal,!0);return}if("type"in record&&record.type==="security_notice_snapshot"){if(!("snapshot"in record)||!isSecurityNoticeState(record.snapshot)){acknowledge(message.signal,!1),this.fail("invalid_security_notice_snapshot");return}writer.acceptWorkerSecuritySnapshot(sessionId,record.snapshot),acknowledge(message.signal,!0);return}let outputConnection=message.connection;if(isGrantSelectRequest(record)){let title=Reflect.get(record,"title"),target=writer.routeWorkerGrant(sessionId,record.id,message.connection,this.options.capabilities??[],()=>this.post({type:"cancel_grant",id:record.id}),typeof title=="string"?title:void 0);if(!target.accepted){acknowledge(message.signal,!0);return}outputConnection=target.connection}let enqueue=()=>withAdmissionReply(message.admissionReply,()=>(message.bootstrap?lane?.bootstrap(message.bootstrap):(lane?.applyTranscript(message.transitions??[]),lane?.accept(record,message.recovery,frameUnit(message),message.canonicalRefused===!0,message.callKey)),enqueueLegacyRecord(writer,sessionId,record)?writer.waitForSessionBackpressure(sessionId):(acknowledge(message.signal,!1),this.fail("session_output_overflow_or_closed"),Promise.reject(new Error("session_output_overflow_or_closed")))));reconcileWorkerReplacement(message,lane,this.callbacks).then(()=>outputConnection===void 0?enqueue():message.owner===void 0||outputConnection!==message.connection?writer.withConnection(outputConnection,enqueue):writer.connectionContext.runCaptured(outputConnection,message.owner,enqueue)).then(()=>acknowledge(message.signal,!0),cause=>{acknowledge(message.signal,!1),this.fail(cause instanceof Error?cause.message:String(cause))});return}case"canonical":case"canonical_unavailable":if(!this.writer||!this.sessionId||this.stopped){acknowledge(message.signal,!1);return}if(this.intake?.inOrder(message)===!1)return;message.type==="canonical"?this.acceptance?.acceptControl(frameUnit({...message,canonical:message.record})):this.acceptance?.compactUnavailable(canonicalLoss(message)),acknowledge(message.signal,!0);return;case"capabilities":this.options=workerCapabilities(this.options,message,this.writer);return;case"loaded_surfaces":{let writer=this.writer,sessionId=this.sessionId;if(!writer||!sessionId||this.stopped){acknowledge(message.signal,!1);return}writer.publishLoadedSurfacesChanged(sessionId,message.previous,message.digest),acknowledge(message.signal,!0);return}case"fragment":this.intake?.fragment(message)?.then(whole=>this.receive(whole),()=>this.fail("session_worker_transfer_unreadable"));return;case"request_close":this.requestClose?.();return;case"subscription_limits":subscriptionLimits.adopt(message.limits);return;case"failure":this.fail(message.error);return}}fail(error2){this.stopped||(this.acceptance?.retire("worker_failed"),this.callbacks.failure(error2),this.terminalFailure=error2,this.writer&&this.sessionId&&this.writer.enqueue(this.sessionId,{type:"session_error",error:error2}),this.quarantine())}publishTerminalFailure(){let error2=this.terminalFailure,writer=this.writer,sessionId=this.sessionId;error2===void 0||!writer||!sessionId||(this.terminalFailure=void 0,writer.closeSession(sessionId,{type:"response",command:"close_session",success:!1,error:error2},"error"))}};import{isAbsolute as isAbsolute2}from"node:path";var WorkerSessionClaims=class{constructor(reservations){this.paths=new Map,this.releases=new Set,this.closed=!1,this.reservations=reservations}async claim(path,attached=!0){if(this.closed)throw new RpcSessionRegistryError("session_closing");if(!this.reservations)return;let previous=this.paths.get(path);if(previous)return previous.ownership;let record={ownership:this.reservations.claim(path,attached),attached};this.paths.set(path,record);let owner=await record.ownership;return owner&&this.paths.get(path)===record&&this.paths.delete(path),owner}setAttached(attached){for(let[path,record]of this.paths)record.attached!==attached&&(record.attached=attached,record.ownership.then(owner=>{!owner&&this.paths.get(path)===record&&this.reservations?.setAttached(path,record.attached)}))}reconcile(livePaths,attached){let live=new Set(livePaths);for(let path of this.paths.keys())live.has(path)||this.release(path);this.setAttached(attached)}release(path){let record=this.paths.get(path);if(!record)return Promise.resolve();this.paths.delete(path);let removal=record.ownership.then(async owner=>{owner||await this.reservations?.release(path)});return this.releases.add(removal),removal.then(()=>this.releases.delete(removal),()=>this.releases.delete(removal)),removal}async close(){this.closed=!0,await Promise.all([...this.paths.keys()].map(path=>this.release(path)).concat([...this.releases]))}};async function openWorkerSession(host,profile,options){if(!isAbsolute2(profile.cwd)||profile.sessionPath!==void 0&&!isAbsolute2(profile.sessionPath))throw new RpcSessionRegistryError("invalid_path");let requestedDurableId=profile.durableSessionId;if(requestedDurableId!==void 0){try{assertValidSessionId(requestedDurableId)}catch(cause){throw new RpcSessionRegistryError("invalid_session_id",String(cause))}let requestedKey=profile.sessionPath?host.knownReservationKey(profile.sessionPath):void 0;for(let entry2 of host.entries.values())if(entry2.state!=="closed"&&entry2.durableSessionId===requestedDurableId&&!(requestedKey!==void 0&&entry2.reservationKey===requestedKey))throw new RpcSessionRegistryError("session_id_in_use")}if(profile.sessionPath){let key=host.knownReservationKey(profile.sessionPath),owner=key?host.reservations.owner(key):void 0;if(key&&owner)return host.attach(owner,key,options,profile)}if(options?.attachOnly)throw new RpcSessionRegistryError("session_not_held",void 0,{reason:"session_not_held",action:"rediscover_holder"});if(host.size>=SESSION_WORKER_LIMITS.workers)throw new Error("too_many_sessions");let handle2=host.nextHandle(),claims=new WorkerSessionClaims(host.options.pathReservations);host.claims.set(handle2,claims);let storedProfile=frozenProfile(profile),entry={state:"opening",scope:new ProviderScope,profile:storedProfile,...sessionIdentity(storedProfile),cwd:profile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:host.now(),lifecycleMutex:Promise.resolve(),...requestedDurableId!==void 0?{durableSessionId:requestedDurableId}:{}},workerFailure,worker=host.createWorker({reserve:path=>host.reserve(handle2,path),reconcile:livePaths=>host.reconcile(handle2,livePaths),exit:()=>{if(host.entries.get(handle2)!==entry)return;let finish=()=>{host.entries.get(handle2)===entry&&(entry.state="closed",host.entries.delete(handle2),host.claims.delete(handle2),host.reservations.releaseAll(handle2),entry.closeResolve?.())};return releaseWithinGrace({closeGraceMs:host.closeGraceMs,releaseReservation:()=>claims.close()},handle2,entry.reservationKey??handle2).then(finish)},failure:error2=>{workerFailure=error2,entry.state="quarantined",process.stderr.write(`senpi rpc session ${handle2} quarantined: ${error2}
|
|
39
|
-
`)}});entry.worker=worker,host.entries.set(handle2,entry);let timer=startOpenTimer(`worker-open:${handle2}`);try{let path=await worker.prepare(host.options.configuration,profile).catch(typedWorkerRefusal);timer.mark("prepare");let owner=host.reservations.owner(path);if(owner){let attached=await host.attach(owner,path,options,profile);return entry.state="quarantined",worker.quarantine(),attached}let predecessor=await claims.claim(path);if(timer.mark("claim"),predecessor)throw new RpcSessionRegistryError("session_path_in_use",void 0,{owner:predecessor,retry_after_ms:SESSION_PATH_RETRY_AFTER_MS});let grant=await host.reserve(handle2,path);if(timer.mark("reserve"),grant!=="granted")throw new RpcSessionRegistryError(RESERVATION_DENIAL_CODES[grant]);entry.reservationKey=path,entry.requestedPathKey=profile.sessionPath?path:void 0,entry.sessionPath=path;let snapshot=await worker.commit();if(timer.mark("commit"),compactUpdatesEnabled()&&await worker.acceptance?.generations.bind(snapshot.state.sessionId),entry.state!=="opening")throw workerFailure===void 0?new RpcSessionRegistryError("session_closing"):new RpcSessionRegistryError("open_failed",workerFailure.replace(/^open_failed: /,""));return entry.durableSessionId=snapshot.state.sessionId,entry.cwd=snapshot.state.cwd,entry.state="open",host.openResult(handle2,entry)}catch(cause){throw entry.state="quarantined",worker.quarantine(),workerFailure!==void 0&&closedByWorkerDeath(cause)?new RpcSessionRegistryError("open_failed",workerFailure.replace(/^open_failed: /,"")):cause}}var WorkerSessionRegistry=class{constructor(options){this.supportsCompact=()=>!0,this.entries=new Map,this.reservations=new SessionPathReservations,this.claims=new Map,this.serial=0,this.options=options,this.closeGraceMs=options.closeGraceMs,this.now=options.now;let createWorker=options.createWorker??(callbacks=>new SessionWorkerClient(callbacks,options.configuration.agentDir));this.createWorker=callbacks=>outsideCommand(()=>createWorker(callbacks)),options.capacity?.track(()=>this.entries.size)}get size(){return this.entries.size}holderPids(observedStarts){return this.options.pathReservations?.holderPids?.(observedStarts)??Promise.resolve([])}openSession(profile,options){return openWorkerSession({entries:this.entries,reservations:this.reservations,claims:this.claims,options:this.options,closeGraceMs:this.closeGraceMs,size:this.options.capacity?.inUse()??this.size,now:this.now,nextHandle:()=>`rpc-${++this.serial}`,knownReservationKey:path=>this.knownReservationKey(path),attach:(owner,path,options2,requested)=>this.attach(owner,path,options2,requested),reserve:(handle2,path)=>this.reserve(handle2,path),reconcile:(handle2,paths)=>this.reconcile(handle2,paths),openResult:(handle2,entry)=>this.openResult(handle2,entry),createWorker:this.createWorker},profile,options)}peek(handle2){return this.entries.get(handle2)}attachSession(handle2){return attachLiveSession(this.entries.get(handle2),this.now(),()=>this.claims.get(handle2)?.setAttached(!0))}getForCommand(handle2,command){let entry=this.entries.get(handle2);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="quarantined"||entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return(entry.attachments>0||refreshesSessionActivity(command))&&(entry.lastCommandAt=this.now()),entry}beginClose(handle2,onRole,options){let entry=this.entries.get(handle2);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"||entry.state==="quarantined")return onRole?.(!1),entry;if(entry.state!=="open"&&entry.state!=="opening")throw new RpcSessionRegistryError("unknown_session");return entry.attachments--,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry.detachedAt??=this.now(),entry.worker?.busy||this.claims.get(handle2)?.setAttached(!1),entry):(entry.state="closing",entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),onRole?.(!0),entry)}close(handle2){return this.beginClose(handle2).state==="closing"?this.closeMarked(handle2):Promise.resolve()}async closeMarked(handle2){let entry=this.entries.get(handle2);if(entry?.state!=="closing"||!entry.worker)throw new RpcSessionRegistryError("unknown_session");if(entry.closeStarted)return entry.closeCompletion;entry.closeStarted=!0;let timer;await Promise.race([entry.worker.close(this.closeGraceMs),new Promise(resolve2=>{timer=setTimeout(()=>{entry.state!=="closed"&&(entry.state="quarantined"),resolve2()},this.closeGraceMs)})]),timer&&clearTimeout(timer)}list(){let now=this.now();return[...this.entries].map(([sessionId,entry])=>{let state=entry.worker?.snapshot?.state;return{sessionId,durableSessionId:state?.sessionId??entry.durableSessionId,sessionPath:state?.sessionFile??entry.sessionPath,cwd:state?.cwd??entry.cwd,name:state?.sessionName,kind:entry.kind,context:publishedSessionContext(entry.context,entry.contextOverlay),attachments:Math.max(0,entry.attachments),retain_on_disconnect:entry.retainOnDisconnect===!0,status:entry.state==="quarantined"?"closing":entry.state,idleMs:Math.max(0,now-entry.lastCommandAt),tool_child:{state:"none"}}})}knownReservationKey(path){if(this.reservations.owner(path))return path;for(let entry of this.entries.values()){if(entry.profile.sessionPath===path&&entry.requestedPathKey&&this.reservations.owner(entry.requestedPathKey))return entry.requestedPathKey;let snapshot=entry.worker?.snapshot;if(snapshot?.state.sessionFile===path)return snapshot.sessionPath}}async attach(owner,path,options,requested={cwd:""}){let{promptSurface,browserEngine,permissionPreset}=requested,entry=this.entries.get(owner);if(entry?.state!=="open"||!entry.worker?.bindingReady||entry.worker.snapshot?.sessionPath!==path)throw new RpcSessionRegistryError("session_path_in_use");promptSurface!==void 0&&promptSurface!==entry.profile.promptSurface&&(entry.profile=frozenProfile({...entry.profile,promptSurface}),await entry.worker.setPromptSurface(promptSurface)),browserEngine!==void 0&&browserEngine!==entry.profile.browserEngine&&(entry.profile=frozenProfile({...entry.profile,browserEngine}),await entry.worker.setBrowserEngine(browserEngine)),permissionPreset!==void 0&&(entry.profile=frozenProfile({...entry.profile,permissionPreset}),await entry.worker.setPermissionPreset(permissionPreset));let result=this.openResult(owner,entry);return entry.attachments++,this.claims.get(owner)?.setAttached(!0),options?.retainOnDisconnect&&(entry.retainOnDisconnect=!0),entry.lastCommandAt=this.now(),{...result,attached:!0}}reservationCount(handle2){return this.reservations.count(handle2)}async reserve(handle2,path){let entry=this.entries.get(handle2);if(!entry)return"conflict";if(this.reservations.owner(path)===handle2)return"granted";if(entry.state!=="opening"&&entry.state!=="open")return"conflict";let grant=this.reservations.reserve(handle2,path,this.liveWorkerPaths(entry));if(grant!=="granted")return grant;if(await this.claims.get(handle2)?.claim(path,entry.attachments>0||entry.worker?.busy===!0)||this.entries.get(handle2)!==entry||entry.state!=="opening"&&entry.state!=="open"){let live=this.liveWorkerPaths(entry);return this.reservations.reconcile(handle2,live??{livePaths:[],sessionPath:entry.reservationKey}),"conflict"}return"granted"}async reconcile(handle2,livePaths){let entry=this.entries.get(handle2);if(entry?.state!=="open")return;let sessionPath=entry.worker?.snapshot?.sessionPath,attached=entry.attachments>0||entry.worker?.busy===!0;if(sessionPath){if(await this.claims.get(handle2)?.claim(sessionPath,attached))throw new RpcSessionRegistryError("session_path_in_use");if(this.entries.get(handle2)!==entry||entry.state!=="open")return}this.reservations.reconcile(handle2,{livePaths,sessionPath}),this.claims.get(handle2)?.reconcile(sessionPath?[...livePaths,sessionPath]:livePaths,attached),sessionPath&&(entry.reservationKey=sessionPath,entry.sessionPath=sessionPath)}liveWorkerPaths(entry){let snapshot=entry.state==="open"?entry.worker?.snapshot:void 0;if(snapshot)return{livePaths:snapshot.liveSessionPaths,sessionPath:snapshot.sessionPath}}openResult(handle2,entry){let state=entry.worker?.snapshot?.state;if(!state)throw new RpcSessionRegistryError("open_failed");return{sessionId:handle2,durableSessionId:state.sessionId,sessionPath:state.sessionFile}}};var WINDOWS_SHUTDOWN_HARD_EXIT_MS=2e3,WINDOWS_SHUTDOWN_DISPOSE_BOUND_MS=1e4;async function runMultiSessionHost(options){return runAsHostGenerationProcess(()=>options.listen===void 0||options.listen==="stdio://"?runStdioHost(options):runSocketHost(options,resolveSocketPath(options.listen,options.agentDir)))}function createHostCore(options,writer,capabilities=parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")),idle={},hostContext,hooks={}){options.mcpPresenterEnforcement===!0&&writer.enableMcpPresenters();let machineOwned=options.sessionOwner==="machine",policy=resolveHostIdlePolicy(process.env,machineOwned?{...idle,emptyExitMs:Number.POSITIVE_INFINITY}:idle),endpointSocket=publicEndpointSocket(options),pathReservations=createEndpointReservations({agentDir:options.agentDir,socket:listenSocketPath(options),instanceId:hostInstanceId(),publicSocket:hostContext?.host_socket,onFailure:hostLog}),registry=options.workerConfiguration?new WorkerSessionRegistry({configuration:options.workerConfiguration,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4,pathReservations}):new RpcSessionRegistry({agentDir:options.agentDir,createRuntime:options.createRuntime,mcpRegistry:new HostMcpRegistry,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4,...hooks.onSessionCountChange?{onSizeChange:hooks.onSessionCountChange}:{},pathReservations}),router=new SessionCommandRouter(registry,writer,hostContext?{...options,hostContext}:options,options.createBinding,{capabilities},{now:policy.now,idleEvictionMs:policy.idleEvictionMs,emptyExitMs:policy.emptyExitMs,onEmptyExit:idle.onEmptyExit,onHandoffParked:idle.onHandoffParked,...endpointSocket===void 0?{}:{handoverParkedDir:createHostDaemonPaths({socket:endpointSocket,agentDir:options.agentDir}).dir},canExitWhenEmpty:idle.canExitWhenEmpty});endpointSocket!==void 0&&reopenHandoverParkedSessions(async entry=>{let refused4=await router.reopenParked(entry);if(refused4?.success!==!1)return;let detail2=typeof refused4.errorData=="object"&&refused4.errorData!==null&&!Array.isArray(refused4.errorData)?Object.fromEntries(Object.entries(refused4.errorData)):void 0;throw refused4.error==="session_path_in_use"?new RpcSessionRegistryError("session_path_in_use",void 0,detail2):new RpcSessionRegistryError("open_failed",refused4.error)},options.agentDir,endpointSocket,{hostInstance:hostInstanceId(),hostSocket:endpointSocket,...hooks.shouldReopenParked!==void 0?{shouldReopen:hooks.shouldReopenParked}:{}}).catch(cause=>{process.stderr.write(`senpi rpc successor reopen parked set failed: ${String(cause)}
|
|
42
|
+
`)}});entry.worker=worker,host.entries.set(handle2,entry);let timer=startOpenTimer(`worker-open:${handle2}`);try{let path=await worker.prepare(host.options.configuration,profile).catch(typedWorkerRefusal);timer.mark("prepare");let owner=host.reservations.owner(path);if(owner){let attached=await host.attach(owner,path,options,profile);return entry.state="quarantined",worker.quarantine(),attached}let predecessor=await claims.claim(path);if(timer.mark("claim"),predecessor)throw new RpcSessionRegistryError("session_path_in_use",void 0,{owner:predecessor,retry_after_ms:SESSION_PATH_RETRY_AFTER_MS});let grant=await host.reserve(handle2,path);if(timer.mark("reserve"),grant!=="granted")throw new RpcSessionRegistryError(RESERVATION_DENIAL_CODES[grant]);entry.reservationKey=path,entry.requestedPathKey=profile.sessionPath?path:void 0,entry.sessionPath=path;let snapshot=await worker.commit();if(timer.mark("commit"),compactUpdatesEnabled()&&await worker.acceptance?.generations.bind(snapshot.state.sessionId),entry.state!=="opening")throw workerFailure===void 0?new RpcSessionRegistryError("session_closing"):new RpcSessionRegistryError("open_failed",workerFailure.replace(/^open_failed: /,""));return entry.durableSessionId=snapshot.state.sessionId,entry.cwd=snapshot.state.cwd,entry.state="open",host.openResult(handle2,entry)}catch(cause){throw entry.state="quarantined",worker.quarantine(),workerFailure!==void 0&&closedByWorkerDeath(cause)?new RpcSessionRegistryError("open_failed",workerFailure.replace(/^open_failed: /,"")):cause}}var WorkerSessionRegistry=class{constructor(options){this.supportsCompact=()=>!0,this.entries=new Map,this.reservations=new SessionPathReservations,this.claims=new Map,this.serial=0,this.options=options,this.closeGraceMs=options.closeGraceMs,this.now=options.now;let createWorker=options.createWorker??(callbacks=>new SessionWorkerClient(callbacks,options.configuration.agentDir));this.createWorker=callbacks=>outsideCommand(()=>createWorker(callbacks)),options.capacity?.track(()=>this.entries.size)}get size(){return this.entries.size}holderPids(observedStarts){return this.options.pathReservations?.holderPids?.(observedStarts)??Promise.resolve([])}openSession(profile,options){return openWorkerSession({entries:this.entries,reservations:this.reservations,claims:this.claims,options:this.options,closeGraceMs:this.closeGraceMs,size:this.options.capacity?.inUse()??this.size,now:this.now,nextHandle:()=>`rpc-${++this.serial}`,knownReservationKey:path=>this.knownReservationKey(path),attach:(owner,path,options2,requested)=>this.attach(owner,path,options2,requested),reserve:(handle2,path)=>this.reserve(handle2,path),reconcile:(handle2,paths)=>this.reconcile(handle2,paths),openResult:(handle2,entry)=>this.openResult(handle2,entry),createWorker:this.createWorker},profile,options)}peek(handle2){return this.entries.get(handle2)}attachSession(handle2){return attachLiveSession(this.entries.get(handle2),this.now(),()=>this.claims.get(handle2)?.setAttached(!0))}getForCommand(handle2,command){let entry=this.entries.get(handle2);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="quarantined"||entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return(entry.attachments>0||refreshesSessionActivity(command))&&(entry.lastCommandAt=this.now()),entry}beginClose(handle2,onRole,options){let entry=this.entries.get(handle2);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"||entry.state==="quarantined")return onRole?.(!1),entry;if(entry.state!=="open"&&entry.state!=="opening")throw new RpcSessionRegistryError("unknown_session");return entry.attachments--,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry.detachedAt??=this.now(),entry.worker?.busy||this.claims.get(handle2)?.setAttached(!1),entry):(entry.state="closing",entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),onRole?.(!0),entry)}close(handle2){return this.beginClose(handle2).state==="closing"?this.closeMarked(handle2):Promise.resolve()}async closeMarked(handle2){let entry=this.entries.get(handle2);if(entry?.state!=="closing"||!entry.worker)throw new RpcSessionRegistryError("unknown_session");if(entry.closeStarted)return entry.closeCompletion;entry.closeStarted=!0;let timer;await Promise.race([entry.worker.close(this.closeGraceMs),new Promise(resolve2=>{timer=setTimeout(()=>{entry.state!=="closed"&&(entry.state="quarantined"),resolve2()},this.closeGraceMs)})]),timer&&clearTimeout(timer)}list(){let now=this.now();return[...this.entries].map(([sessionId,entry])=>{let state=entry.worker?.snapshot?.state;return{sessionId,durableSessionId:state?.sessionId??entry.durableSessionId,sessionPath:state?.sessionFile??entry.sessionPath,cwd:state?.cwd??entry.cwd,name:state?.sessionName,kind:entry.kind,context:publishedSessionContext(entry.context,entry.contextOverlay),attachments:Math.max(0,entry.attachments),retain_on_disconnect:entry.retainOnDisconnect===!0,status:entry.state==="quarantined"?"closing":entry.state,idleMs:Math.max(0,now-entry.lastCommandAt),tool_child:{state:"none"}}})}knownReservationKey(path){if(this.reservations.owner(path))return path;for(let entry of this.entries.values()){if(entry.profile.sessionPath===path&&entry.requestedPathKey&&this.reservations.owner(entry.requestedPathKey))return entry.requestedPathKey;let snapshot=entry.worker?.snapshot;if(snapshot?.state.sessionFile===path)return snapshot.sessionPath}}async attach(owner,path,options,requested={cwd:""}){let{promptSurface,browserEngine}=requested,permissionPreset=clientNamedPreset(requested),entry=this.entries.get(owner);if(entry?.state!=="open"||!entry.worker?.bindingReady||entry.worker.snapshot?.sessionPath!==path)throw new RpcSessionRegistryError("session_path_in_use");promptSurface!==void 0&&promptSurface!==entry.profile.promptSurface&&(entry.profile=frozenProfile({...entry.profile,promptSurface}),await entry.worker.setPromptSurface(promptSurface)),browserEngine!==void 0&&browserEngine!==entry.profile.browserEngine&&(entry.profile=frozenProfile({...entry.profile,browserEngine}),await entry.worker.setBrowserEngine(browserEngine)),permissionPreset!==void 0&&(entry.profile=frozenProfile(withClientPreset(entry.profile,permissionPreset)),await entry.worker.setPermissionPreset(permissionPreset));let result=this.openResult(owner,entry);return entry.attachments++,this.claims.get(owner)?.setAttached(!0),options?.retainOnDisconnect&&(entry.retainOnDisconnect=!0),entry.lastCommandAt=this.now(),{...result,attached:!0}}reservationCount(handle2){return this.reservations.count(handle2)}async reserve(handle2,path){let entry=this.entries.get(handle2);if(!entry)return"conflict";if(this.reservations.owner(path)===handle2)return"granted";if(entry.state!=="opening"&&entry.state!=="open")return"conflict";let grant=this.reservations.reserve(handle2,path,this.liveWorkerPaths(entry));if(grant!=="granted")return grant;if(await this.claims.get(handle2)?.claim(path,entry.attachments>0||entry.worker?.busy===!0)||this.entries.get(handle2)!==entry||entry.state!=="opening"&&entry.state!=="open"){let live=this.liveWorkerPaths(entry);return this.reservations.reconcile(handle2,live??{livePaths:[],sessionPath:entry.reservationKey}),"conflict"}return"granted"}async reconcile(handle2,livePaths){let entry=this.entries.get(handle2);if(entry?.state!=="open")return;let sessionPath=entry.worker?.snapshot?.sessionPath,attached=entry.attachments>0||entry.worker?.busy===!0;if(sessionPath){if(await this.claims.get(handle2)?.claim(sessionPath,attached))throw new RpcSessionRegistryError("session_path_in_use");if(this.entries.get(handle2)!==entry||entry.state!=="open")return}this.reservations.reconcile(handle2,{livePaths,sessionPath}),this.claims.get(handle2)?.reconcile(sessionPath?[...livePaths,sessionPath]:livePaths,attached),sessionPath&&(entry.reservationKey=sessionPath,entry.sessionPath=sessionPath)}liveWorkerPaths(entry){let snapshot=entry.state==="open"?entry.worker?.snapshot:void 0;if(snapshot)return{livePaths:snapshot.liveSessionPaths,sessionPath:snapshot.sessionPath}}openResult(handle2,entry){let state=entry.worker?.snapshot?.state;if(!state)throw new RpcSessionRegistryError("open_failed");return{sessionId:handle2,durableSessionId:state.sessionId,sessionPath:state.sessionFile}}};var WINDOWS_SHUTDOWN_HARD_EXIT_MS=2e3,WINDOWS_SHUTDOWN_DISPOSE_BOUND_MS=1e4;async function runMultiSessionHost(options){return runAsHostGenerationProcess(()=>options.listen===void 0||options.listen==="stdio://"?runStdioHost(options):runSocketHost(options,resolveSocketPath(options.listen,options.agentDir)))}function createHostCore(options,writer,capabilities=parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")),idle={},hostContext,hooks={}){options.mcpPresenterEnforcement===!0&&writer.enableMcpPresenters();let machineOwned=options.sessionOwner==="machine",policy=resolveHostIdlePolicy(process.env,machineOwned?{...idle,emptyExitMs:Number.POSITIVE_INFINITY}:idle),endpointSocket=publicEndpointSocket(options),pathReservations=createEndpointReservations({agentDir:options.agentDir,socket:listenSocketPath(options),instanceId:hostInstanceId(),publicSocket:hostContext?.host_socket,onFailure:hostLog}),registry=options.workerConfiguration?new WorkerSessionRegistry({configuration:options.workerConfiguration,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4,pathReservations}):new RpcSessionRegistry({agentDir:options.agentDir,createRuntime:options.createRuntime,mcpRegistry:new HostMcpRegistry,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4,...hooks.onSessionCountChange?{onSizeChange:hooks.onSessionCountChange}:{},pathReservations}),router=new SessionCommandRouter(registry,writer,hostContext?{...options,hostContext}:options,options.createBinding,{capabilities},{now:policy.now,idleEvictionMs:policy.idleEvictionMs,emptyExitMs:policy.emptyExitMs,onEmptyExit:idle.onEmptyExit,onHandoffParked:idle.onHandoffParked,...endpointSocket===void 0?{}:{handoverParkedDir:createHostDaemonPaths({socket:endpointSocket,agentDir:options.agentDir}).dir},canExitWhenEmpty:idle.canExitWhenEmpty});endpointSocket!==void 0&&reopenHandoverParkedSessions(async entry=>{let refused4=await router.reopenParked(entry);if(refused4?.success!==!1)return;let detail2=typeof refused4.errorData=="object"&&refused4.errorData!==null&&!Array.isArray(refused4.errorData)?Object.fromEntries(Object.entries(refused4.errorData)):void 0;throw refused4.error==="session_path_in_use"?new RpcSessionRegistryError("session_path_in_use",void 0,detail2):new RpcSessionRegistryError("open_failed",refused4.error)},options.agentDir,endpointSocket,{hostInstance:hostInstanceId(),hostSocket:endpointSocket,...hooks.shouldReopenParked!==void 0?{shouldReopen:hooks.shouldReopenParked}:{}}).catch(cause=>{process.stderr.write(`senpi rpc successor reopen parked set failed: ${String(cause)}
|
|
40
43
|
`)});let gate=new HostCoreGate(registry,command=>router.handle(command),hooks),handle2=async line=>{let connection=writer.currentConnection(),parsed;try{parsed=JSON.parse(line)}catch{await writer.enqueueControl(writer.delegations.unparsable(connection,"Failed to parse command: invalid JSON"));return}let delegation=writer.connectionContext.delegation;if(delegation?.mode!=="host")return handleParsed(connection,parsed);let exec=takeRelayExec(parsed);if(exec==="malformed"){await writer.enqueueControl(relayExecRefusal(parsed));return}return commandAuthority.run(new CommandAuthority(connection,delegation,exec),()=>handleParsed(connection,parsed))},handleParsed=async(connection,parsed)=>{let delegation=writer.delegations.inspect(connection,parsed);if(delegation.kind!=="pass"){await answerDelegation(writer,delegation,parsed);return}let delegated=writer.delegations.isDelegated(connection);if(writer.handleMcpForm(parsed)||await gate.intercept(parsed,answer3=>writer.enqueueControl(answer3)))return;let shapeError=rpcCommandShapeError(parsed);if(shapeError){await writer.enqueueControl(parseError(shapeError));return}let command=parsed,response=await gate.dispatch(command.type==="open_session"&&(delegated?command.retain_on_disconnect!==!0:machineOwned&&command.retain_on_disconnect===void 0)?{...command,retain_on_disconnect:!0}:command);response&&await writer.enqueueControl(response),writer.delegations.lineAnswered(connection)};return{router,handle:handle2,handover:gate.handover,handoverAnswered:()=>gate.answered(),warm:"warm"in registry?registry.warm:void 0,peekSession:sessionId=>registry.peek(sessionId)}}async function runStdioHost(options){takeOverStdout();let sink={writeRaw:writeRawStdout,waitForBackpressure:waitForRawStdoutBackpressure},writer=new SessionEventWriter(sink.writeRaw,sink.waitForBackpressure),runtimeBuildId=await startupRuntimeBuildId(),trim=createZeroSessionTrim(writer,()=>router.sessionCount),{router,handle:handle2,warm}=createHostCore(options,writer,void 0,{onEmptyExit:()=>{shutdown(0)}},void 0,{...runtimeBuildId===void 0?{}:{runtimeBuildId},onSessionCountChange:size=>trim.observe(size)}),observers=startHostObservers(router,writer,{trim}),shuttingDown=!1,shutdown=async(exitCode=0)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0,observers.stop(),detach(),await router.dispose(),await writer.flush(),await flushRawStdout(),process.exit(exitCode)},onEnd=()=>{shutdown()};process.stdin.on("end",onEnd);let reportInputFailure=cause=>{process.stderr.write(`senpi rpc stdio request failed: ${errorMessage(cause)}
|
|
41
44
|
`)},detachReader=attachJsonlLineReader(process.stdin,line=>{handle2(line).catch(reportInputFailure)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.enqueueControl(parseError(oversizedLineError())).catch(reportInputFailure)}}),detach=()=>{detachReader(),process.stdin.off("end",onEnd)};return registerShutdownSignals(shutdown),warmAtBootForPrivateFds(warm,{cwd:options.cwd},hostLog),new Promise(()=>{})}async function runSocketHost(options,socketPath){await prepareSocketPath(socketPath);let writer=new SessionEventWriter(()=>{}),connections=new Map,occupancy=new ClientOccupancy(()=>{},hostInstanceId()),draining=!1,handoffAnnounced=!1,handoff=new HandoffAnnouncement,hostContext=hostSessionContext(socketPath),runtimeBuildId=await startupRuntimeBuildId(),expected=process.env[EXPECTED_RUNTIME_BUILD_ID_ENV];expected!==void 0&&expected!==runtimeBuildId&&(hostLog(`runtime ${runtimeBuildId??"unreadable"} is not the handover target ${expected}; exiting`),process.exit(1));let canHandOver=runtimeBuildId!==void 0&&process.platform!=="win32",trim=createZeroSessionTrim(writer,()=>router.sessionCount),{router,handle:handle2,handover,handoverAnswered,warm}=createHostCore(options,writer,[...parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")),GENERATION_HANDOFF_CAPABILITY,ENDPOINT_OWNER_FENCE_CAPABILITY,...canHandOver?[RUNTIME_IDENTITY_HANDOVER_CAPABILITY]:[]],{onEmptyExit:()=>{shutdown(0)},canExitWhenEmpty:()=>draining||occupancy.attachedCount===0&&occupancy.unclassifiedCount===0,onHandoffParked:async ids=>{await Promise.all(ids.map(async id=>{await writer.flushConnection(id),await connections.get(id)?.close("host_handoff")}))}},hostContext,{onSessionCountChange:size=>trim.observe(size),shouldReopenParked:()=>!draining,...runtimeBuildId!==void 0&&{runtimeBuildId},...canHandOver&&{endpoint:{agentDir:options.agentDir,socket:hostWatchdogBinding()?.publicSocket??socketPath},handover:{identity:()=>({instanceId:hostInstanceId(),generation:hostGeneration(process.env),runtimeBuildId}),perform:async request=>performIdleHandover({presenterBootstrap:presenterControl?.successorBootstrapProvider(),request,socket:hostWatchdogBinding()?.publicSocket??socketPath,agentDir:options.agentDir}),log:hostLog}}}),presenter=await startMcpPresenterControl(writer,{enforcement:options.mcpPresenterEnforcement,bootstrap:options.presenterBootstrapFd===void 0?void 0:presenterBootstrapStream(options.presenterBootstrapFd),account:options.presenterAccountAuthority}),presenterControl=presenter?.control,presenterDir=presenter?.dir,observers=startHostObservers(router,writer,{trim,onIdlePressure:({footprintMb,measure,rssMb})=>{hostLog(`memory pressure with no sessions: footprintMb=${footprintMb} (${measure}) rssMb=${rssMb}`),endpointSuperseded().then(superseded=>{superseded&&drainForHandoff()},noop)}}),nextConnection=0,shuttingDown=!1;writer.endExhaustedConnections(id=>connections.get(id)?.sink);let secret=process.platform==="win32"?await ensureSocketSecret(process.env[SOCKET_SECRET_FILE_ENV]??socketSecretPath(socketPath)):void 0,transport=internalHostTransport(hostWatchdogBinding(),secret,{agentDir:options.agentDir,socket:socketPath,log:hostLog}),{watchdogConfig,admit}=transport,crashCleanupPaths=[...watchdogConfig?.cleanupPaths??[]],supervisorPublicSocketPath=process.platform==="win32"||socketPath.startsWith("\0")?void 0:watchdogConfig?.publicSocket,supervisorPublicOwnerFile=supervisorPublicSocketPath&&watchdogConfig?.scratchDir?join9(watchdogConfig.scratchDir,PUBLIC_SOCKET_IDENTITY_FILE):void 0,boundIdentity,supervisorPublicIdentity,server=createServer(rawSocket=>{let arrivedBeforeDrain=!draining&&!shuttingDown;admit(rawSocket,(socket=rawSocket,launchProof)=>{if(draining&&!shuttingDown&&handoff.deliverLate(socket,arrivedBeforeDrain))return;if(draining||shuttingDown){socket.destroy();return}let id=`socket-${++nextConnection}`,sink=socketSink(socket);writer.registerConnection(id,sink,launchProof===void 0?{}:{launchProof}),occupancy.admit(socket);let detachReader=attachJsonlLineReader(socket,line=>{writer.withConnection(id,()=>handle2(line)).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
|
|
42
45
|
`)})},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.withConnection(id,()=>writer.enqueueControl(parseError(oversizedLineError()))).catch(cause=>process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
|
|
43
46
|
`))}}),detached=!1,detach=()=>{detached||(detached=!0,detachReader(),writer.unregisterConnection(id),connections.delete(id),occupancy.release(socket),router.releaseConnection(id).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} release failed: ${errorMessage(cause)}
|
|
44
47
|
`)}))},close2=code2=>writer.closeConnection(id,code2,announced=>announced?sink.close?.():socket.destroy());connections.set(id,{id,sink,socket,detach,close:close2}),socket.once("close",detach),socket.once("error",()=>detach())})});server.on("error",cause=>{shuttingDown||process.stderr.write(`senpi rpc socket listener failed: ${errorMessage(cause)}
|
|
45
|
-
`)});let stopChildReaper=await startHostChildReaper(hostLog),shutdown=async(exitCode=0,watchdogCleanup)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0;let startedAt=Date.now();observers.stop(),handover?.dispose(),presenterControl?.dispose(),presenterDir&&await rm8(presenterDir,{recursive:!0,force:!0}),stopChildReaper(),await handoverAnswered();try{await(process.platform==="win32"?Promise.race([router.dispose(),delay(WINDOWS_SHUTDOWN_DISPOSE_BOUND_MS)]):router.dispose());let open2=[...connections.values()],cancelForce=await closeHostConnections(open2,id=>writer.flushConnection(id),startedAt,hostLog);await closeShieldedEndpoint(socketPath,()=>process.platform==="win32"?Promise.race([closeServer(server),delay(WINDOWS_SHUTDOWN_HARD_EXIT_MS)]):closeServer(server)),cancelForce(),await unlinkOwnedEndpoint(socketPath,boundIdentity,hostInstanceId(),hostLog),supervisorPublicSocketPath&&await unlinkOwnedEndpoint(supervisorPublicSocketPath,supervisorPublicIdentity,hostInstanceId(),hostLog),watchdogCleanup&&await watchdogCleanup}finally{await transport.dispose(),process.exit(exitCode)}},drainForHandoff=()=>{if(shuttingDown)return;if(draining){handoffAnnounced&&router.beginDrain();return}draining=!0,crashCleanupPaths.length=0,hostLog("draining for a generation handoff");let identity={instanceId:hostInstanceId(),generation:hostGeneration(process.env)};handoff.begin(endpointSuperseded(),identity,supervisorPublicSocketPath??socketPath,hostLog).then(announced=>announced&&writer.broadcastHostRecord(announced)).finally(()=>{handoffAnnounced=!0,router.beginDrain()})},endpointSuperseded=()=>supervisorPublicSocketPath===void 0?socketEntryReplaced(socketPath,boundIdentity):socketEntryReplaced(supervisorPublicSocketPath,supervisorPublicIdentity);registerShutdownSignals(shutdown),process.platform!=="win32"&&process.on("SIGUSR1",drainForHandoff);let drainRequestFile=hostChildDrainRequestFile();drainRequestFile!==void 0&&watchDrainRequest(drainRequestFile,drainForHandoff);let watchdog=watchdogConfig&&supervisorPublicOwnerFile?{...watchdogConfig,cleanupPaths:crashCleanupPaths,beforeCleanup:async()=>{supervisorPublicIdentity??=await readSocketIdentityFile(supervisorPublicOwnerFile)}}:watchdogConfig&&{...watchdogConfig,cleanupPaths:crashCleanupPaths};
|
|
46
|
-
`),shutdown(0,cleanup),setImmediate(killTrackedDetachedChildren)}),reportStartupMilestone("host_runtime"),boundIdentity=await
|
|
48
|
+
`)});let stopChildReaper=await startHostChildReaper(hostLog),shutdown=async(exitCode=0,watchdogCleanup)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0;let startedAt=Date.now();observers.stop(),handover?.dispose(),presenterControl?.dispose(),presenterDir&&await rm8(presenterDir,{recursive:!0,force:!0}),stopChildReaper(),await handoverAnswered();try{await(process.platform==="win32"?Promise.race([router.dispose(),delay(WINDOWS_SHUTDOWN_DISPOSE_BOUND_MS)]):router.dispose());let open2=[...connections.values()],cancelForce=await closeHostConnections(open2,id=>writer.flushConnection(id),startedAt,hostLog);await closeShieldedEndpoint(socketPath,()=>process.platform==="win32"?Promise.race([closeServer(server),delay(WINDOWS_SHUTDOWN_HARD_EXIT_MS)]):closeServer(server)),cancelForce(),await unlinkOwnedEndpoint(socketPath,boundIdentity,hostInstanceId(),hostLog),supervisorPublicSocketPath&&await unlinkOwnedEndpoint(supervisorPublicSocketPath,supervisorPublicIdentity,hostInstanceId(),hostLog),watchdogCleanup&&await watchdogCleanup}finally{await transport.dispose(),process.exit(exitCode)}},drainForHandoff=()=>{if(shuttingDown)return;if(draining){handoffAnnounced&&router.beginDrain();return}draining=!0,crashCleanupPaths.length=0,hostLog("draining for a generation handoff");let identity={instanceId:hostInstanceId(),generation:hostGeneration(process.env)};handoff.begin(endpointSuperseded(),identity,supervisorPublicSocketPath??socketPath,hostLog).then(announced=>announced&&writer.broadcastHostRecord(announced)).finally(()=>{handoffAnnounced=!0,router.beginDrain()})},endpointSuperseded=()=>supervisorPublicSocketPath===void 0?socketEntryReplaced(socketPath,boundIdentity):socketEntryReplaced(supervisorPublicSocketPath,supervisorPublicIdentity);registerShutdownSignals(shutdown),process.platform!=="win32"&&process.on("SIGUSR1",drainForHandoff);let drainRequestFile=hostChildDrainRequestFile();drainRequestFile!==void 0&&watchDrainRequest(drainRequestFile,drainForHandoff);let watchdog=watchdogConfig&&supervisorPublicOwnerFile?{...watchdogConfig,cleanupPaths:crashCleanupPaths,beforeCleanup:async()=>{supervisorPublicIdentity??=await readSocketIdentityFile(supervisorPublicOwnerFile)}}:watchdogConfig&&{...watchdogConfig,cleanupPaths:crashCleanupPaths};armHostWatchdog(watchdog,(reason,cleanup)=>{process.stderr.write(`senpi rpc host: ${reason}; shutting down
|
|
49
|
+
`),shutdown(0,cleanup),setImmediate(killTrackedDetachedChildren)}),reportStartupMilestone("host_runtime");let bind=()=>listen(server,socketPath,secret);return boundIdentity=await(hostWatchdogBinding()===void 0?bindRegisteredEndpoint({agentDir:options.agentDir,socket:socketPath,log:hostLog},bind):bind()),await transport.publish(()=>shutdown(1)),supervisorPublicOwnerFile&&(supervisorPublicIdentity=await waitForSocketIdentityFile(supervisorPublicOwnerFile)),process.stderr.write(`senpi rpc listening on ${formatSocketAddress(socketPath)}
|
|
47
50
|
`),warmAtBootForPrivateFds(warm,{cwd:options.cwd,sessionContext:hostContext},hostLog),new Promise(()=>{})}async function startupRuntimeBuildId(){try{return await computeRuntimeBuildId({profile:protocolIdentity().launch_profile.core})}catch(cause){hostLog(`runtime identity unreadable: ${errorMessage(cause)}`);return}}function delay(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}function noop(){}function parseError(error2){return{type:"response",command:"parse",success:!1,error:error2}}function oversizedLineError(){return`RPC input line exceeds ${MAX_RPC_LINE_CHARACTERS} characters.`}function errorMessage(cause){return cause instanceof Error?cause.message:String(cause)}function hostSessionContext(socketPath,supervised=hostWatchdogBinding()){let endpoint=supervised===void 0?socketPath:supervised.publicSocket;if(endpoint===void 0||endpoint.startsWith("\0"))return{host_instance:hostInstanceId()};let directory=canonicalSessionPath(dirname3(endpoint));return{host_socket:join9(directory,basename2(endpoint)),host_instance:hostInstanceId()}}function listenSocketPath(options){if(!(options.listen===void 0||options.listen==="stdio://"))return resolveSocketPath(options.listen,options.agentDir)}function publicEndpointSocket(options){let supervised=hostWatchdogBinding();return supervised!==void 0?supervised.publicSocket:listenSocketPath(options)}function closeServer(server){return new Promise((resolve2,reject)=>{server.close(cause=>cause?reject(cause):resolve2())})}function hostLog(message){process.stderr.write(`senpi rpc host: ${message}
|
|
48
51
|
`)}function registerShutdownSignals(shutdown){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{killTrackedDetachedChildren(),shutdown(signal==="SIGHUP"?129:143)})}export{DEFAULT_HOST_EMPTY_EXIT_MS,DEFAULT_SESSION_IDLE_EVICTION_MS,RPC_HOST_EMPTY_EXIT_MS_ENV,RPC_SESSION_IDLE_EVICTION_MS_ENV,createHostCore,hostSessionContext,presenterPipePath,resolveHostIdlePolicy,runMultiSessionHost};
|