@code-yeongyu/senpi 2026.10.23-1 → 2026.10.24-1

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/dist/bundle/chunks/{chunk-TFFJEEHQ.js → chunk-3PTVLFBA.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-52DQGTJR.js → chunk-CXED7XG5.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-TCWZBUBG.js → chunk-FKXOOQMF.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-7R3FUPMO.js → chunk-OS42QW66.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-NYYDXANA.js → chunk-QEHPPMVF.js} +2 -2
  7. package/dist/bundle/chunks/{chunk-TFULKHNU.js → chunk-T75A2MVF.js} +2 -2
  8. package/dist/bundle/chunks/{chunk-E6IDMANN.js → chunk-XE753Y6U.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-RWRICRZB.js → chunk-ZSU4SPDQ.js} +80 -80
  10. package/dist/bundle/chunks/{cli-main-FVJRIDEL.js → cli-main-DQBJUCQS.js} +1 -1
  11. package/dist/bundle/chunks/{host-session-command-I7W5WSGN.js → host-session-command-MMYPIHCX.js} +1 -1
  12. package/dist/bundle/chunks/{interactive-mode-2GTQWY5I.js → interactive-mode-KIYNWS2N.js} +1 -1
  13. package/dist/bundle/chunks/{multi-session-host-4DDNG3S4.js → multi-session-host-X2XCJ7BZ.js} +4 -4
  14. package/dist/bundle/chunks/{package-manager-cli-VMY6B2WQ.js → package-manager-cli-UQMDWNHH.js} +1 -1
  15. package/dist/bundle/chunks/{rpc-mode-CN5HBSB3.js → rpc-mode-I7CRGV4X.js} +1 -1
  16. package/dist/bundle/chunks/{schedule-command-I3IYHTWW.js → schedule-command-6LF6KHSF.js} +1 -1
  17. package/dist/bundle/chunks/{session-control-endpoint-W3EL4JYJ.js → session-control-endpoint-VV6PUFSF.js} +1 -1
  18. package/dist/bundle/chunks/{session-picker-HES2YE6K.js → session-picker-QZZ3DJER.js} +1 -1
  19. package/dist/bundle/chunks/session-worker.js +143 -143
  20. package/dist/bundle/cli.js +2 -2
  21. package/dist/bundle/index.js +1 -1
  22. package/dist/bundle/rpc-entry.js +1 -1
  23. package/dist/bundle/runtime-manifest.json +1 -1
  24. package/dist/core/lifecycle-ledger.d.ts +3 -0
  25. package/dist/core/lifecycle-ledger.js +18 -1
  26. package/dist/core/lifecycle-session-binding.js +1 -0
  27. package/dist/core/session-holders.js +2 -1
  28. package/dist/core/session-lifecycle.d.ts +3 -0
  29. package/dist/core/session-lifecycle.js +11 -1
  30. package/dist/core/session-move/export.d.ts +3 -3
  31. package/dist/core/session-move/export.js +32 -27
  32. package/dist/core/session-move/extension-state.d.ts +5 -5
  33. package/dist/core/session-move/extension-state.js +25 -25
  34. package/dist/core/session-move/finish.d.ts +1 -1
  35. package/dist/core/session-move/finish.js +14 -13
  36. package/dist/core/session-move/import.js +37 -36
  37. package/dist/core/session-move/move-ledger.d.ts +3 -3
  38. package/dist/core/session-move/move-ledger.js +7 -6
  39. package/dist/core/session-move/requeue.js +1 -1
  40. package/dist/core/session-move/revoke.d.ts +1 -1
  41. package/dist/core/session-move/revoke.js +5 -5
  42. package/dist/core/session-move/session-lock.d.ts +4 -3
  43. package/dist/core/session-move/session-lock.js +23 -9
  44. package/dist/core/session-rebind.d.ts +1 -1
  45. package/dist/core/session-rebind.js +61 -31
  46. package/dist/modes/rpc/session-move-commands.js +16 -15
  47. package/dist/modes/rpc/session-release.js +3 -3
  48. package/docs/release-guide.md +1 -1
  49. package/package.json +6 -6
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  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 = () => {}; } }
3
- import{enableStartupCompileCache}from"./chunk-TCWZBUBG.js";import"./chunk-J6XY5DH5.js";import{installStaleExtensionContainment,main}from"./chunk-RWRICRZB.js";import"./chunk-MCUSE2TT.js";import"./chunk-NYYDXANA.js";import{configureHttpDispatcher}from"./chunk-52DQGTJR.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import"./chunk-TFULKHNU.js";import"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import"./chunk-7R3FUPMO.js";import"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import"./chunk-MTQQ2VQH.js";import"./chunk-L66F2AZM.js";import"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import{installEarlyInspectorVmImportRecovery}from"./chunk-E6IDMANN.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import{APP_NAME,scrubBrandFromEnvironment}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";await enableStartupCompileCache();installEarlyInspectorVmImportRecovery();installStaleExtensionContainment();process.title=APP_NAME;scrubBrandFromEnvironment();process.env.PI_CODING_AGENT="true";process.emitWarning=(()=>{});configureHttpDispatcher();await main(process.argv.slice(2));
3
+ import{enableStartupCompileCache}from"./chunk-FKXOOQMF.js";import"./chunk-J6XY5DH5.js";import{installStaleExtensionContainment,main}from"./chunk-ZSU4SPDQ.js";import"./chunk-MCUSE2TT.js";import"./chunk-QEHPPMVF.js";import{configureHttpDispatcher}from"./chunk-CXED7XG5.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import"./chunk-T75A2MVF.js";import"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import"./chunk-OS42QW66.js";import"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import"./chunk-MTQQ2VQH.js";import"./chunk-L66F2AZM.js";import"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import{installEarlyInspectorVmImportRecovery}from"./chunk-XE753Y6U.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import{APP_NAME,scrubBrandFromEnvironment}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";await enableStartupCompileCache();installEarlyInspectorVmImportRecovery();installStaleExtensionContainment();process.title=APP_NAME;scrubBrandFromEnvironment();process.env.PI_CODING_AGENT="true";process.emitWarning=(()=>{});configureHttpDispatcher();await main(process.argv.slice(2));
@@ -1,5 +1,5 @@
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{RpcClient,RpcCommandError,RpcRequestTimeoutError,RpcTransportGoneError,isTransportGoneError}from"./chunk-MCUSE2TT.js";import"./chunk-EV4TWAJI.js";import{SessionManager,assertValidSessionId}from"./chunk-7R3FUPMO.js";import"./chunk-CNPDUC4D.js";import"./chunk-KLAX467B.js";import"./chunk-SOMFLLPD.js";import{DEFAULT_HOST_LAUNCH_SPEC,HOST_EXIT_ERROR,HOST_EXIT_OK,HOST_EXIT_REFUSED,HOST_EXIT_USAGE,HostLaunchSpecError,STOP_WAIT_BUDGET_MS,daemonEnvKeys,daemonEnvOverrides,emit,ensureHost,loadHostLaunchSpec,refusal,resolveHostSocket,writeDaemonEnvKeys}from"./chunk-L66F2AZM.js";import{HostEnsureRefusedError}from"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import{endpointKindOfSocket}from"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import{canonicalSessionPath,createHostDaemonPaths}from"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-YJA2B7FQ.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import{APP_NAME,getAgentDir}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";import{readFileSync}from"node:fs";import{resolve}from"node:path";var DETACH_ACK_TIMEOUT_MS=5e3;async function detachBeforeClose(client,report,timeoutMs=DETACH_ACK_TIMEOUT_MS){let timer,late=new Promise(resolve2=>{timer=setTimeout(()=>resolve2("late"),timeoutMs)});try{await Promise.race([client.detachConnection(),late])==="late"&&report(`the host did not confirm the detach within ${timeoutMs} ms; closing the connection anyway`)}catch(error){if(error instanceof RpcTransportGoneError)return;report(`the host refused the detach (${error instanceof Error?error.message:String(error)}); closing the connection anyway`)}finally{clearTimeout(timer)}}var USAGE_CODES=new Set(["missing_session_id","invalid_path","invalid_session_context","invalid_session_kind","invalid_launch_profile","invalid_session_id","invalid_release_reason","empty","unknown_command"]),FAILURE_CODES=new Set(["open_failed","warm_failed","release_failed"]),REASON_FOR_CODE={streaming:"busy",not_found:"unknown_cursor"},BARE_CODE=/^[a-z][a-z0-9_]*$/;function mapError(error,socket){let detail=error instanceof Error?error.message:String(error);if(error instanceof RpcCommandError){let code=error.errorCode??(BARE_CODE.test(detail)?detail:void 0);if(code===void 0)return hostError(detail,socket);let exitCode=USAGE_CODES.has(code)?HOST_EXIT_USAGE:FAILURE_CODES.has(code)?HOST_EXIT_ERROR:HOST_EXIT_REFUSED;return{exitCode,payload:{action:exitCode===HOST_EXIT_REFUSED?"refuse":"error",reason:REASON_FOR_CODE[code]??code,detail,socket,...error.errorData!==void 0&&{data:error.errorData}}}}return isTransportGoneError(error)?{exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"transport_gone",detail,socket}}:hostError(detail,socket)}function hostError(detail,socket){return{exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"host_error",detail,socket}}}async function openHostSession(client,request,socket,ensured){let opened=await client.openSession({cwd:request.cwd,retain_on_disconnect:!0,...request.model&&{provider:request.model.provider,modelId:request.model.id}});ensured?.release();let{state}=opened,identity={sessionId:opened.sessionId,sessionPath:state.sessionFile,durableSessionId:state.sessionId};try{request.name!==void 0&&await client.setSessionName(request.name);let disposition=request.prompt===void 0?void 0:await client.prompt(request.prompt);return{exitCode:HOST_EXIT_OK,payload:{action:"open",socket,pid:ensured?.pid,reused:ensured?.reused,...identity,cwd:state.cwd,model:state.model?{provider:state.model.provider,id:state.model.id}:null,attached:opened.attached??!1,...disposition!==void 0&&{prompt:{disposition}}}}}catch(error){let outcome=mapError(error,socket),closed=await closeOpened(client,opened.sessionId);return{...outcome,payload:{...outcome.payload,...identity,closed}}}}async function closeOpened(client,sessionId){try{return await client.closeSession(sessionId),!(await client.listSessions()).some(row=>row.sessionId===sessionId)}catch{return!1}}import{existsSync}from"node:fs";import{readdir}from"node:fs/promises";import{dirname,join}from"node:path";async function resolveSessionRef(client,ref,agentDir){let rows=await client.listSessions(),handle=rows.find(row=>row.sessionId===ref);if(handle)return{kind:"live",row:handle};if(isSessionId(ref)){let byId=await resolveDurableId(ref,rows,agentDir);if(byId)return byId}let named=rows.filter(row=>row.name===ref);if(named.length>1)return{kind:"ambiguous",candidates:named.map(row=>row.sessionId)};let live=named[0]??rows.find(row=>row.sessionPath!==void 0&&samePath(row.sessionPath,ref));return live?{kind:"live",row:live}:looksLikePath(ref)?parkedByPath(ref):{kind:"unknown"}}async function resolveDurableId(id,rows,agentDir){let liveRows=rows.filter(row=>row.durableSessionId===id),transcripts=(await transcriptsUnder(agentDir)).filter(session=>session.id===id),files=new Set([...liveRows.map(row=>row.sessionPath===void 0?row.sessionId:canonicalSessionPath(row.sessionPath)),...transcripts.map(session=>canonicalSessionPath(session.path))]);return files.size>1?{kind:"ambiguous",candidates:[...files]}:liveRows[0]?{kind:"live",row:liveRows[0]}:transcripts[0]?parked(transcripts[0]):void 0}function isSessionId(ref){try{return assertValidSessionId(ref),!0}catch{return!1}}function looksLikePath(ref){return ref.includes("/")||ref.includes("\\")||ref.endsWith(".jsonl")}async function parkedByPath(ref){let path=canonicalSessionPath(ref);if(!existsSync(path))return{kind:"unknown"};let info=(await SessionManager.listAll(dirname(path))).find(session=>samePath(session.path,path));return info?parked(info):{kind:"unknown"}}async function transcriptsUnder(agentDir){let root=join(agentDir,"sessions");if(!existsSync(root))return[];let dirs=(await readdir(root,{withFileTypes:!0})).filter(entry=>entry.isDirectory());return(await Promise.all(dirs.map(entry=>SessionManager.listAll(join(root,entry.name))))).flat()}function parked(info){return{kind:"parked",sessionPath:info.path,cwd:info.cwd,durableSessionId:info.id}}function samePath(left,right){return canonicalSessionPath(left)===canonicalSessionPath(right)}function waitForHostSession(client,sessionId,request,onTransportLoss){let started=Date.now();return new Promise((resolveWait,reject)=>{let finished=!1,observed=!1,state,timer,cleanup=()=>{finished=!0,clearTimeout(timer),unsubscribe(),onTransportLoss(void 0)},fail=error=>{finished||(cleanup(),reject(error))},finish=outcome=>{finished||(cleanup(),resolveWait({exitCode:HOST_EXIT_OK,payload:{action:"wait",sessionId,until:request.until,outcome,waited_ms:Date.now()-started,state:{isStreaming:state?.isStreaming??!1,pendingMessageCount:state?.pendingMessageCount??0,lastAbortSource:state?.lastAbortSource??null}}}))},unsubscribe=client.onEvent(record=>{let event=record;if(event.type==="session_closed"||event.type==="session_parked"){finish(event.type);return}if(event.type==="agent_settled"&&"reason"in event&&event.reason==="session_closed"){finish("session_closed");return}event.type!=="agent_idle"&&!(request.until==="done"&&event.type==="agent_settled")||(observed=!0,client.getState().then(snapshot=>{state=snapshot,request.until==="done"?finish("done"):isDrained(snapshot)&&finish("idle")},fail))});onTransportLoss(fail),timer=setTimeout(()=>{finished||(cleanup(),resolveWait({exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"wait_timeout",sessionId,until:request.until,timeoutMs:request.timeoutMs}}))},request.timeoutMs),client.getState().then(snapshot=>{state=snapshot,!observed&&(request.until==="done"?!snapshot.isStreaming:isDrained(snapshot))&&finish("already_idle")},fail)})}function isDrained(state){return!state.isStreaming&&state.steering.length===0&&state.followUp.length===0&&state.ordered.length===0&&state.pendingMessageCount===0}async function runHostSessionRequest(request){let deadline=Date.now()+STOP_WAIT_BUDGET_MS;for(;;)try{return await runHostSessionRequestOnce(request,Math.max(0,deadline-Date.now()))}catch(error){if(request.action==="open"&&error instanceof RpcCommandError&&error.errorCode==="host_stopping"&&Date.now()<deadline)continue;return mapError(error,request.target.socket)}}async function runHostSessionRequestOnce(request,stoppingTimeoutMs){let{socket,agentDir}=request.target,client,ensured,disconnected,connectionUnusable=!1;try{if(await endpointKindOfSocket(socket,agentDir)==="tui")return refusal("refuse",void 0,{reason:"unsupported_endpoint_kind",socket,endpoint_kind:"tui"});request.action==="open"&&(ensured=await ensureHost({socket,agentDir,hostArgs:request.spec.hostArgs,env:daemonEnvOverrides(process.env,request.spec.env),policy:request.spec.policy,upgrade:"never",stoppingTimeoutMs}),ensured.reused||await writeDaemonEnvKeys(createHostDaemonPaths({socket,agentDir}),daemonEnvKeys(process.env,request.spec.env))),client=new RpcClient({socketPath:socket,onDisconnect:error=>{connectionUnusable=!0,disconnected?.(error)}});try{await client.start()}catch(error){if(error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ECONNREFUSED"))return refusal("refuse",void 0,{reason:"host_unavailable",socket,detail:error.message});throw error}let sessionId,durableSessionId;if("ref"in request){let found=await resolveSessionRef(client,request.ref,agentDir);if(found.kind==="unknown")return refusal("refuse",void 0,{reason:"unknown_session",ref:request.ref,socket});if(found.kind==="ambiguous"){let detail={reason:"ambiguous_session",ref:request.ref,candidates:found.candidates,socket};return refusal("refuse",void 0,detail)}let reopen=found.kind==="parked"?{sessionPath:found.sessionPath,cwd:found.cwd,retain_on_disconnect:!0,attended:!1}:{sessionPath:found.row.sessionPath,cwd:found.row.cwd};durableSessionId=found.kind==="parked"?found.durableSessionId:found.row.durableSessionId,sessionId=(await client.openSession(reopen)).sessionId}switch(request.action){case"open":return await openHostSession(client,request,socket,ensured);case"prompt":return{exitCode:HOST_EXIT_OK,payload:{action:"prompt",sessionId,disposition:await client.prompt(request.text)}};case"steer":{let streaming=(await client.getState()).isStreaming,disposition=await client.steer(request.text);return{exitCode:HOST_EXIT_OK,payload:{action:"steer",sessionId,disposition,streaming}}}case"abort":{let aborted=(await client.getState()).isStreaming;return await client.abortStrict(),{exitCode:HOST_EXIT_OK,payload:{action:"abort",sessionId,acknowledged:!0,aborted}}}case"model":{await client.setModel(request.model.provider,request.model.id);let state=await client.getState();return{exitCode:HOST_EXIT_OK,payload:{action:"model",sessionId,requested:request.model,model:state.model?{provider:state.model.provider,id:state.model.id}:null,pendingModelSwitch:state.pendingModelSwitch??null}}}case"list":return{exitCode:HOST_EXIT_OK,payload:{action:"list",socket,sessions:await client.listSessions({observe:!0})}};case"state":return{exitCode:HOST_EXIT_OK,payload:{action:"state",sessionId,durableSessionId,state:await client.getState()}};case"read":{if(request.messages){let all=await client.getMessages(),messages=request.tail===void 0?all:all.slice(-request.tail);return{exitCode:HOST_EXIT_OK,payload:{action:"read",sessionId,messages,count:messages.length}}}let{entries,leafId}=await client.getEntries(request.since),slice=request.tail===void 0?entries:entries.slice(-request.tail);return{exitCode:HOST_EXIT_OK,payload:{action:"read",sessionId,entries:slice,count:slice.length,total:entries.length,leafId,nextSince:slice.at(-1)?.id??request.since??null,...request.since!==void 0&&{since:request.since}}}}case"wait":return await waitForHostSession(client,sessionId,request,handler=>{disconnected=handler});case"unload":{let answer=await client.unloadSession({sessionId,interrupt:request.interrupt,force:request.force,clearQueue:request.clearQueue,children:request.children});return{exitCode:answer.outcome==="unloaded"?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{action:"unload",sessionId,...answer}}}case"close":{let reason,unsubscribe=client.onEvent(record=>{let event=record;event.type==="session_closed"&&(reason=event.reason)});try{await client.closeSession(sessionId);let remaining=(await client.listSessions()).find(row=>row.sessionId===sessionId);return{exitCode:HOST_EXIT_OK,payload:remaining?{action:"close",sessionId,closed:!1,attachments:remaining.attachments}:{action:"close",sessionId,closed:!0,reason:reason??"client_close"}}}finally{unsubscribe()}}default:return assertNever(request)}}catch(error){if((error instanceof RpcRequestTimeoutError||isTransportGoneError(error))&&(connectionUnusable=!0),request.action==="open"&&error instanceof RpcCommandError&&error.errorCode==="host_stopping")throw error;return error instanceof HostEnsureRefusedError?refusal("refuse",void 0,{reason:error.reason,socket,detail:error.detail}):mapError(error,socket)}finally{ensured?.release(),client&&!connectionUnusable&&await detachBeforeClose(client,line=>process.stderr.write(`senpi host session: ${line}
2
+ import{RpcClient,RpcCommandError,RpcRequestTimeoutError,RpcTransportGoneError,isTransportGoneError}from"./chunk-MCUSE2TT.js";import"./chunk-EV4TWAJI.js";import{SessionManager,assertValidSessionId}from"./chunk-OS42QW66.js";import"./chunk-CNPDUC4D.js";import"./chunk-KLAX467B.js";import"./chunk-SOMFLLPD.js";import{DEFAULT_HOST_LAUNCH_SPEC,HOST_EXIT_ERROR,HOST_EXIT_OK,HOST_EXIT_REFUSED,HOST_EXIT_USAGE,HostLaunchSpecError,STOP_WAIT_BUDGET_MS,daemonEnvKeys,daemonEnvOverrides,emit,ensureHost,loadHostLaunchSpec,refusal,resolveHostSocket,writeDaemonEnvKeys}from"./chunk-L66F2AZM.js";import{HostEnsureRefusedError}from"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import{endpointKindOfSocket}from"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import{canonicalSessionPath,createHostDaemonPaths}from"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-YJA2B7FQ.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import{APP_NAME,getAgentDir}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";import{readFileSync}from"node:fs";import{resolve}from"node:path";var DETACH_ACK_TIMEOUT_MS=5e3;async function detachBeforeClose(client,report,timeoutMs=DETACH_ACK_TIMEOUT_MS){let timer,late=new Promise(resolve2=>{timer=setTimeout(()=>resolve2("late"),timeoutMs)});try{await Promise.race([client.detachConnection(),late])==="late"&&report(`the host did not confirm the detach within ${timeoutMs} ms; closing the connection anyway`)}catch(error){if(error instanceof RpcTransportGoneError)return;report(`the host refused the detach (${error instanceof Error?error.message:String(error)}); closing the connection anyway`)}finally{clearTimeout(timer)}}var USAGE_CODES=new Set(["missing_session_id","invalid_path","invalid_session_context","invalid_session_kind","invalid_launch_profile","invalid_session_id","invalid_release_reason","empty","unknown_command"]),FAILURE_CODES=new Set(["open_failed","warm_failed","release_failed"]),REASON_FOR_CODE={streaming:"busy",not_found:"unknown_cursor"},BARE_CODE=/^[a-z][a-z0-9_]*$/;function mapError(error,socket){let detail=error instanceof Error?error.message:String(error);if(error instanceof RpcCommandError){let code=error.errorCode??(BARE_CODE.test(detail)?detail:void 0);if(code===void 0)return hostError(detail,socket);let exitCode=USAGE_CODES.has(code)?HOST_EXIT_USAGE:FAILURE_CODES.has(code)?HOST_EXIT_ERROR:HOST_EXIT_REFUSED;return{exitCode,payload:{action:exitCode===HOST_EXIT_REFUSED?"refuse":"error",reason:REASON_FOR_CODE[code]??code,detail,socket,...error.errorData!==void 0&&{data:error.errorData}}}}return isTransportGoneError(error)?{exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"transport_gone",detail,socket}}:hostError(detail,socket)}function hostError(detail,socket){return{exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"host_error",detail,socket}}}async function openHostSession(client,request,socket,ensured){let opened=await client.openSession({cwd:request.cwd,retain_on_disconnect:!0,...request.model&&{provider:request.model.provider,modelId:request.model.id}});ensured?.release();let{state}=opened,identity={sessionId:opened.sessionId,sessionPath:state.sessionFile,durableSessionId:state.sessionId};try{request.name!==void 0&&await client.setSessionName(request.name);let disposition=request.prompt===void 0?void 0:await client.prompt(request.prompt);return{exitCode:HOST_EXIT_OK,payload:{action:"open",socket,pid:ensured?.pid,reused:ensured?.reused,...identity,cwd:state.cwd,model:state.model?{provider:state.model.provider,id:state.model.id}:null,attached:opened.attached??!1,...disposition!==void 0&&{prompt:{disposition}}}}}catch(error){let outcome=mapError(error,socket),closed=await closeOpened(client,opened.sessionId);return{...outcome,payload:{...outcome.payload,...identity,closed}}}}async function closeOpened(client,sessionId){try{return await client.closeSession(sessionId),!(await client.listSessions()).some(row=>row.sessionId===sessionId)}catch{return!1}}import{existsSync}from"node:fs";import{readdir}from"node:fs/promises";import{dirname,join}from"node:path";async function resolveSessionRef(client,ref,agentDir){let rows=await client.listSessions(),handle=rows.find(row=>row.sessionId===ref);if(handle)return{kind:"live",row:handle};if(isSessionId(ref)){let byId=await resolveDurableId(ref,rows,agentDir);if(byId)return byId}let named=rows.filter(row=>row.name===ref);if(named.length>1)return{kind:"ambiguous",candidates:named.map(row=>row.sessionId)};let live=named[0]??rows.find(row=>row.sessionPath!==void 0&&samePath(row.sessionPath,ref));return live?{kind:"live",row:live}:looksLikePath(ref)?parkedByPath(ref):{kind:"unknown"}}async function resolveDurableId(id,rows,agentDir){let liveRows=rows.filter(row=>row.durableSessionId===id),transcripts=(await transcriptsUnder(agentDir)).filter(session=>session.id===id),files=new Set([...liveRows.map(row=>row.sessionPath===void 0?row.sessionId:canonicalSessionPath(row.sessionPath)),...transcripts.map(session=>canonicalSessionPath(session.path))]);return files.size>1?{kind:"ambiguous",candidates:[...files]}:liveRows[0]?{kind:"live",row:liveRows[0]}:transcripts[0]?parked(transcripts[0]):void 0}function isSessionId(ref){try{return assertValidSessionId(ref),!0}catch{return!1}}function looksLikePath(ref){return ref.includes("/")||ref.includes("\\")||ref.endsWith(".jsonl")}async function parkedByPath(ref){let path=canonicalSessionPath(ref);if(!existsSync(path))return{kind:"unknown"};let info=(await SessionManager.listAll(dirname(path))).find(session=>samePath(session.path,path));return info?parked(info):{kind:"unknown"}}async function transcriptsUnder(agentDir){let root=join(agentDir,"sessions");if(!existsSync(root))return[];let dirs=(await readdir(root,{withFileTypes:!0})).filter(entry=>entry.isDirectory());return(await Promise.all(dirs.map(entry=>SessionManager.listAll(join(root,entry.name))))).flat()}function parked(info){return{kind:"parked",sessionPath:info.path,cwd:info.cwd,durableSessionId:info.id}}function samePath(left,right){return canonicalSessionPath(left)===canonicalSessionPath(right)}function waitForHostSession(client,sessionId,request,onTransportLoss){let started=Date.now();return new Promise((resolveWait,reject)=>{let finished=!1,observed=!1,state,timer,cleanup=()=>{finished=!0,clearTimeout(timer),unsubscribe(),onTransportLoss(void 0)},fail=error=>{finished||(cleanup(),reject(error))},finish=outcome=>{finished||(cleanup(),resolveWait({exitCode:HOST_EXIT_OK,payload:{action:"wait",sessionId,until:request.until,outcome,waited_ms:Date.now()-started,state:{isStreaming:state?.isStreaming??!1,pendingMessageCount:state?.pendingMessageCount??0,lastAbortSource:state?.lastAbortSource??null}}}))},unsubscribe=client.onEvent(record=>{let event=record;if(event.type==="session_closed"||event.type==="session_parked"){finish(event.type);return}if(event.type==="agent_settled"&&"reason"in event&&event.reason==="session_closed"){finish("session_closed");return}event.type!=="agent_idle"&&!(request.until==="done"&&event.type==="agent_settled")||(observed=!0,client.getState().then(snapshot=>{state=snapshot,request.until==="done"?finish("done"):isDrained(snapshot)&&finish("idle")},fail))});onTransportLoss(fail),timer=setTimeout(()=>{finished||(cleanup(),resolveWait({exitCode:HOST_EXIT_ERROR,payload:{action:"error",reason:"wait_timeout",sessionId,until:request.until,timeoutMs:request.timeoutMs}}))},request.timeoutMs),client.getState().then(snapshot=>{state=snapshot,!observed&&(request.until==="done"?!snapshot.isStreaming:isDrained(snapshot))&&finish("already_idle")},fail)})}function isDrained(state){return!state.isStreaming&&state.steering.length===0&&state.followUp.length===0&&state.ordered.length===0&&state.pendingMessageCount===0}async function runHostSessionRequest(request){let deadline=Date.now()+STOP_WAIT_BUDGET_MS;for(;;)try{return await runHostSessionRequestOnce(request,Math.max(0,deadline-Date.now()))}catch(error){if(request.action==="open"&&error instanceof RpcCommandError&&error.errorCode==="host_stopping"&&Date.now()<deadline)continue;return mapError(error,request.target.socket)}}async function runHostSessionRequestOnce(request,stoppingTimeoutMs){let{socket,agentDir}=request.target,client,ensured,disconnected,connectionUnusable=!1;try{if(await endpointKindOfSocket(socket,agentDir)==="tui")return refusal("refuse",void 0,{reason:"unsupported_endpoint_kind",socket,endpoint_kind:"tui"});request.action==="open"&&(ensured=await ensureHost({socket,agentDir,hostArgs:request.spec.hostArgs,env:daemonEnvOverrides(process.env,request.spec.env),policy:request.spec.policy,upgrade:"never",stoppingTimeoutMs}),ensured.reused||await writeDaemonEnvKeys(createHostDaemonPaths({socket,agentDir}),daemonEnvKeys(process.env,request.spec.env))),client=new RpcClient({socketPath:socket,onDisconnect:error=>{connectionUnusable=!0,disconnected?.(error)}});try{await client.start()}catch(error){if(error instanceof Error&&"code"in error&&(error.code==="ENOENT"||error.code==="ECONNREFUSED"))return refusal("refuse",void 0,{reason:"host_unavailable",socket,detail:error.message});throw error}let sessionId,durableSessionId;if("ref"in request){let found=await resolveSessionRef(client,request.ref,agentDir);if(found.kind==="unknown")return refusal("refuse",void 0,{reason:"unknown_session",ref:request.ref,socket});if(found.kind==="ambiguous"){let detail={reason:"ambiguous_session",ref:request.ref,candidates:found.candidates,socket};return refusal("refuse",void 0,detail)}let reopen=found.kind==="parked"?{sessionPath:found.sessionPath,cwd:found.cwd,retain_on_disconnect:!0,attended:!1}:{sessionPath:found.row.sessionPath,cwd:found.row.cwd};durableSessionId=found.kind==="parked"?found.durableSessionId:found.row.durableSessionId,sessionId=(await client.openSession(reopen)).sessionId}switch(request.action){case"open":return await openHostSession(client,request,socket,ensured);case"prompt":return{exitCode:HOST_EXIT_OK,payload:{action:"prompt",sessionId,disposition:await client.prompt(request.text)}};case"steer":{let streaming=(await client.getState()).isStreaming,disposition=await client.steer(request.text);return{exitCode:HOST_EXIT_OK,payload:{action:"steer",sessionId,disposition,streaming}}}case"abort":{let aborted=(await client.getState()).isStreaming;return await client.abortStrict(),{exitCode:HOST_EXIT_OK,payload:{action:"abort",sessionId,acknowledged:!0,aborted}}}case"model":{await client.setModel(request.model.provider,request.model.id);let state=await client.getState();return{exitCode:HOST_EXIT_OK,payload:{action:"model",sessionId,requested:request.model,model:state.model?{provider:state.model.provider,id:state.model.id}:null,pendingModelSwitch:state.pendingModelSwitch??null}}}case"list":return{exitCode:HOST_EXIT_OK,payload:{action:"list",socket,sessions:await client.listSessions({observe:!0})}};case"state":return{exitCode:HOST_EXIT_OK,payload:{action:"state",sessionId,durableSessionId,state:await client.getState()}};case"read":{if(request.messages){let all=await client.getMessages(),messages=request.tail===void 0?all:all.slice(-request.tail);return{exitCode:HOST_EXIT_OK,payload:{action:"read",sessionId,messages,count:messages.length}}}let{entries,leafId}=await client.getEntries(request.since),slice=request.tail===void 0?entries:entries.slice(-request.tail);return{exitCode:HOST_EXIT_OK,payload:{action:"read",sessionId,entries:slice,count:slice.length,total:entries.length,leafId,nextSince:slice.at(-1)?.id??request.since??null,...request.since!==void 0&&{since:request.since}}}}case"wait":return await waitForHostSession(client,sessionId,request,handler=>{disconnected=handler});case"unload":{let answer=await client.unloadSession({sessionId,interrupt:request.interrupt,force:request.force,clearQueue:request.clearQueue,children:request.children});return{exitCode:answer.outcome==="unloaded"?HOST_EXIT_OK:HOST_EXIT_REFUSED,payload:{action:"unload",sessionId,...answer}}}case"close":{let reason,unsubscribe=client.onEvent(record=>{let event=record;event.type==="session_closed"&&(reason=event.reason)});try{await client.closeSession(sessionId);let remaining=(await client.listSessions()).find(row=>row.sessionId===sessionId);return{exitCode:HOST_EXIT_OK,payload:remaining?{action:"close",sessionId,closed:!1,attachments:remaining.attachments}:{action:"close",sessionId,closed:!0,reason:reason??"client_close"}}}finally{unsubscribe()}}default:return assertNever(request)}}catch(error){if((error instanceof RpcRequestTimeoutError||isTransportGoneError(error))&&(connectionUnusable=!0),request.action==="open"&&error instanceof RpcCommandError&&error.errorCode==="host_stopping")throw error;return error instanceof HostEnsureRefusedError?refusal("refuse",void 0,{reason:error.reason,socket,detail:error.detail}):mapError(error,socket)}finally{ensured?.release(),client&&!connectionUnusable&&await detachBeforeClose(client,line=>process.stderr.write(`senpi host session: ${line}
3
3
  `)),await client?.stop()}}function assertNever(value){throw new Error(`unreachable host session request: ${JSON.stringify(value)}`)}var USAGE=`usage: ${APP_NAME} host session <command> [--socket <path>] [--json]
4
4
 
5
5
  open --cwd <dir> [--model <provider/id>] [--name <text>] [--prompt <text|@file>] [--launch-spec <file>]
@@ -1,2 +1,2 @@
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{InteractiveMode,OptimisticUserEchoController,createInteractiveTui,createInteractiveTuiReference,formatCrashExtensionHint,formatResumeCommand,isApiKeyLoginProvider,shouldShowRetryIndicator,showsStartupDetails,showsStartupHeader}from"./chunk-RWRICRZB.js";import"./chunk-MCUSE2TT.js";import"./chunk-NYYDXANA.js";import"./chunk-52DQGTJR.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import"./chunk-TFULKHNU.js";import"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import"./chunk-7R3FUPMO.js";import"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import"./chunk-MTQQ2VQH.js";import"./chunk-L66F2AZM.js";import"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import"./chunk-E6IDMANN.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";export{InteractiveMode,OptimisticUserEchoController,createInteractiveTui,createInteractiveTuiReference,formatCrashExtensionHint,formatResumeCommand,isApiKeyLoginProvider,shouldShowRetryIndicator,showsStartupDetails,showsStartupHeader};
2
+ import{InteractiveMode,OptimisticUserEchoController,createInteractiveTui,createInteractiveTuiReference,formatCrashExtensionHint,formatResumeCommand,isApiKeyLoginProvider,shouldShowRetryIndicator,showsStartupDetails,showsStartupHeader}from"./chunk-ZSU4SPDQ.js";import"./chunk-MCUSE2TT.js";import"./chunk-QEHPPMVF.js";import"./chunk-CXED7XG5.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import"./chunk-T75A2MVF.js";import"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import"./chunk-OS42QW66.js";import"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import"./chunk-MTQQ2VQH.js";import"./chunk-L66F2AZM.js";import"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import"./chunk-VP7SFZIM.js";import"./chunk-OUPD5LWY.js";import"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import"./chunk-XE753Y6U.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import"./chunk-HRPMLI7O.js";import"./chunk-QEQG42HL.js";import"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";export{InteractiveMode,OptimisticUserEchoController,createInteractiveTui,createInteractiveTuiReference,formatCrashExtensionHint,formatResumeCommand,isApiKeyLoginProvider,shouldShowRetryIndicator,showsStartupDetails,showsStartupHeader};
@@ -1,5 +1,5 @@
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{SessionEventWriter,answerSetSessionContext,answerSubscribeSessions,answerUnsubscribeSessions,applyContextPatch,notAttachedRefusal,publishedSessionContext,recordLoopBlockedMs,registryStatusSource,socketSink}from"./chunk-TFFJEEHQ.js";import{ACCEPT_EDITS_PERMISSION_PRESET_CAPABILITY,AUTO_PERMISSION_PRESET_CAPABILITY,AgentSessionRuntime,CONNECTION_ROLE_FIXED,ConnectionRoles,EXTENSION_STATE_PAYLOAD,EXTENSION_STATE_PREFIX,HostMcpRegistry,MANIFEST_FILE,MOVE_BUNDLE_FORMAT,MoveBundleInvalidError,ProviderScope,SESSION_BUNDLE_PATH,STATE_ATTEMPT_FIELD,SessionPendingInputs,bindToProviderScope,createAgentSessionRuntime,createRpcConnectionHandler,createWebViewBroker,foreignSessionHolders,isMoveId,isPlainId,isSecurityNoticeState,movedStateDir,outgoingStateDir,parseMoveId,parsePermissionPresetName,parsePlainId,prepareOutgoingState,readCodemodeKernelRows,readMainThreadHeapBytes,readManifest,readRecordedRepositoryIdentity,readSessionCwd,rebindSessionFile,roleConnection,runWithProviderScope,sealedOutgoingStateDir,sha256File,startHostChildReaper,subscriptionLimits,verifyBundle}from"./chunk-RWRICRZB.js";import"./chunk-MCUSE2TT.js";import{SessionHeldError,encodedSessionId,liveSessionHolders,readProcessStartMs,serializeByKey,withSessionMoveLock}from"./chunk-NYYDXANA.js";import{flushRawStdout,liveToolMediaScope,takeOverStdout,toolMediaPersister,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-52DQGTJR.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import{ClientAdmissions,DURABLE_CLIENT_MESSAGE_ID_CAPABILITY,EFFECT_LEDGER_CAPABILITY,EMPTY_SESSION_CONTEXT,EffectLedger,answerEffectFromTranscript,beginEffect,buildRpcSessionState,drainSessionEffects,effectAnswer,installSessionEffectSink,isEffectBegin,latestSessionEffect,rpcCommandShapeError,sessionAutoTitleError,sessionBrowserEngineError,sessionContextError,sessionKindError,sessionPromptSurfaceError,sessionRetryFallbackError}from"./chunk-TFULKHNU.js";import{RPC_ERROR_ATTACHED,RPC_ERROR_HOST_DRAINING,RPC_ERROR_INVALID_LAUNCH_PROFILE,RPC_ERROR_INVALID_PATH,RPC_ERROR_INVALID_RELEASE_REASON,RPC_ERROR_INVALID_SESSION_CONTEXT,RPC_ERROR_INVALID_SESSION_KIND,RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OPEN_FAILED,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_WARM_FAILED,STEER_WHEN_IDLE_CAPABILITY,USER_ACTIVITY_CAPABILITY}from"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import{SESSION_MOVED,SESSION_MOVED_IN,SESSION_RECLAIMED,SESSION_RELEASED,SessionManager,SessionMovedAwayError,assertValidSessionId,compareRepositoryIdentities,getDefaultSessionDir,headerSessionId,loadEntriesFromFile,ownershipStep,readRepositoryIdentity,sessionOwnership}from"./chunk-7R3FUPMO.js";import{resolveMovedPath}from"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import{lockWithLossHandling}from"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import{readOwnFootprint}from"./chunk-MTQQ2VQH.js";import{BEGIN_HANDOVER_COMMAND,EXPECTED_RUNTIME_BUILD_ID_ENV,HostIdleHandover,beginHandoverResponse,handoverRefusal,isHandoffBusy,isHostIdle,parseBeginHandover,performIdleHandover,readDrainVerdicts,runAsHostGenerationProcess,withHostIdentity}from"./chunk-L66F2AZM.js";import{ATTENDED_CAPABILITY,AUTH_KEY_VERIFY_CAPABILITY,AUTO_TITLE_PER_SESSION_CAPABILITY,AUTO_TITLE_SESSIONS_CAPABILITY,BROWSER_ENGINE_CAPABILITY,CONTINUE_FROM_LEAF_CAPABILITY,DETACH_CONNECTION_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,EVAL_CELLS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,MOVED_PATH_GUARD_CAPABILITY,PROMPT_SURFACE_CAPABILITY,PROMPT_SURFACE_CHAT_CAPABILITY,QUEUED_MESSAGE_REVISION_CAPABILITY,RESUME_SESSION_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,RETRY_FALLBACK_PROFILE_CAPABILITY,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_HELD_CAPABILITY,SESSION_KIND_CAPABILITY,SESSION_RELOCATION_CAPABILITY,SESSION_STATUS_CAPABILITY,TOOL_BARRIER_CAPABILITY,WARM_CAPABILITY,computeRuntimeBuildId,hostGeneration,hostInstanceId,parseClientCapabilities,protocolIdentity}from"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import{isHostOwnedToolRuntimeCapability,toolRuntimeCapabilities}from"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import{ClientOccupancy,armHostWatchdog,loopLagErrorMs,prepareSocketPath,readHostWatchdogConfigFromBrandEnv}from"./chunk-VP7SFZIM.js";import{SESSION_PATH_RETRY_AFTER_MS,createEndpointReservations,holderGenerationEnded,hostChildDrainRequestFile,ownGenerationDir,parseIdleExitMs,watchDrainRequest,writeHeartbeat,writeStallEvidence}from"./chunk-OUPD5LWY.js";import{HOST_DAEMON_DIR_ENV,MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,canonicalSessionPath,createHostDaemonPaths,sessionDirectoryRemoved}from"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import{FILE_STORAGE_LOCK_RETRY_MAX_DELAY_MS,FILE_STORAGE_LOCK_RETRY_MIN_DELAY_MS,isLockError}from"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import{killTrackedDetachedChildren}from"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import"./chunk-E6IDMANN.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import{PUBLIC_SOCKET_IDENTITY_FILE,readSocketIdentityFile,shieldSocketDuringClose,socketEntryReplaced,statSocketIdentity,unlinkOwnedSocket,waitForSocketIdentityFile}from"./chunk-HRPMLI7O.js";import{SOCKET_SECRET_FILE_ENV,authenticateSocket,ensureSocketSecret,resolveSocketTransportAddress,socketSecretPath}from"./chunk-QEQG42HL.js";import{VERSION,envValue,isBunBinary,normalizePath,resolvePath}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import{ownProcessStartedAtMs}from"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import{processStartTimeMs}from"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";import{chmod}from"node:fs/promises";import{createServer}from"node:net";import{basename as basename2,dirname as dirname3,join as join6}from"node:path";var HostCoreGate=class{constructor(registry,route,hooks){this.inFlight=new Map,this.answering=new Set,this.route=route,this.runtimeBuildId=hooks.runtimeBuildId,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);return beginHandoverResponse(parsed.id,typeof request=="string"?request:await this.handover.begin(request))}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)}import{existsSync as existsSync4}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 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&&(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{SessionEventWriter,answerSetSessionContext,answerSubscribeSessions,answerUnsubscribeSessions,applyContextPatch,notAttachedRefusal,publishedSessionContext,recordLoopBlockedMs,registryStatusSource,socketSink}from"./chunk-3PTVLFBA.js";import{ACCEPT_EDITS_PERMISSION_PRESET_CAPABILITY,AUTO_PERMISSION_PRESET_CAPABILITY,AgentSessionRuntime,CONNECTION_ROLE_FIXED,ConnectionRoles,EXTENSION_STATE_PAYLOAD,EXTENSION_STATE_PREFIX,HostMcpRegistry,MANIFEST_FILE,MOVE_BUNDLE_FORMAT,MoveBundleInvalidError,ProviderScope,SESSION_BUNDLE_PATH,STATE_ATTEMPT_FIELD,SessionPendingInputs,bindToProviderScope,createAgentSessionRuntime,createRpcConnectionHandler,createWebViewBroker,foreignSessionHolders,isMoveId,isPlainId,isSecurityNoticeState,movedStateDir,outgoingStateDir,parseMoveId,parsePermissionPresetName,parsePlainId,pathExists,prepareOutgoingState,readCodemodeKernelRows,readMainThreadHeapBytes,readManifest,readRecordedRepositoryIdentity,readSessionCwd,rebindSessionFile,roleConnection,runWithProviderScope,sealedOutgoingStateDir,sha256File,startHostChildReaper,subscriptionLimits,verifyBundle}from"./chunk-ZSU4SPDQ.js";import"./chunk-MCUSE2TT.js";import{SessionHeldError,encodedSessionId,liveSessionHolders,readProcessStartMs,serializeByKey,withSessionMoveLock}from"./chunk-QEHPPMVF.js";import{flushRawStdout,liveToolMediaScope,takeOverStdout,toolMediaPersister,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-CXED7XG5.js";import"./chunk-DXJJP6RP.js";import"./chunk-HCF5M6NA.js";import{ClientAdmissions,DURABLE_CLIENT_MESSAGE_ID_CAPABILITY,EFFECT_LEDGER_CAPABILITY,EMPTY_SESSION_CONTEXT,EffectLedger,answerEffectFromTranscript,beginEffect,buildRpcSessionState,drainSessionEffects,effectAnswer,installSessionEffectSink,isEffectBegin,latestSessionEffect,rpcCommandShapeError,sessionAutoTitleError,sessionBrowserEngineError,sessionContextError,sessionKindError,sessionPromptSurfaceError,sessionRetryFallbackError}from"./chunk-T75A2MVF.js";import{RPC_ERROR_ATTACHED,RPC_ERROR_HOST_DRAINING,RPC_ERROR_INVALID_LAUNCH_PROFILE,RPC_ERROR_INVALID_PATH,RPC_ERROR_INVALID_RELEASE_REASON,RPC_ERROR_INVALID_SESSION_CONTEXT,RPC_ERROR_INVALID_SESSION_KIND,RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OPEN_FAILED,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_WARM_FAILED,STEER_WHEN_IDLE_CAPABILITY,USER_ACTIVITY_CAPABILITY}from"./chunk-EV4TWAJI.js";import"./chunk-PFI5TUMF.js";import{SESSION_MOVED,SESSION_MOVED_IN,SESSION_RECLAIMED,SESSION_RELEASED,SessionManager,SessionMovedAwayError,assertValidSessionId,compareRepositoryIdentities,getDefaultSessionDir,headerSessionId,loadEntriesFromFileAsync,ownershipStep,readRepositoryIdentity,sessionOwnership}from"./chunk-OS42QW66.js";import{resolveMovedPath}from"./chunk-CNPDUC4D.js";import"./chunk-566CWG3K.js";import"./chunk-FIBIVBQK.js";import"./chunk-VYZPP6NK.js";import"./chunk-MLVIYDHK.js";import"./chunk-TIVW4P37.js";import"./chunk-H4QOEVS5.js";import"./chunk-2PDVQXYC.js";import"./chunk-MSQCTH6V.js";import"./chunk-KLAX467B.js";import"./chunk-MNTI56WQ.js";import{lockWithLossHandling}from"./chunk-GQ5KSAFE.js";import"./chunk-GZVCRV7I.js";import"./chunk-SOMFLLPD.js";import{readOwnFootprint}from"./chunk-MTQQ2VQH.js";import{BEGIN_HANDOVER_COMMAND,EXPECTED_RUNTIME_BUILD_ID_ENV,HostIdleHandover,beginHandoverResponse,handoverRefusal,isHandoffBusy,isHostIdle,parseBeginHandover,performIdleHandover,readDrainVerdicts,runAsHostGenerationProcess,withHostIdentity}from"./chunk-L66F2AZM.js";import{ATTENDED_CAPABILITY,AUTH_KEY_VERIFY_CAPABILITY,AUTO_TITLE_PER_SESSION_CAPABILITY,AUTO_TITLE_SESSIONS_CAPABILITY,BROWSER_ENGINE_CAPABILITY,CONTINUE_FROM_LEAF_CAPABILITY,DETACH_CONNECTION_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,EVAL_CELLS_CAPABILITY,GENERATION_HANDOFF_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,MOVED_PATH_GUARD_CAPABILITY,PROMPT_SURFACE_CAPABILITY,PROMPT_SURFACE_CHAT_CAPABILITY,QUEUED_MESSAGE_REVISION_CAPABILITY,RESUME_SESSION_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,RETRY_FALLBACK_PROFILE_CAPABILITY,RUNTIME_IDENTITY_HANDOVER_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_HELD_CAPABILITY,SESSION_KIND_CAPABILITY,SESSION_RELOCATION_CAPABILITY,SESSION_STATUS_CAPABILITY,TOOL_BARRIER_CAPABILITY,WARM_CAPABILITY,computeRuntimeBuildId,hostGeneration,hostInstanceId,parseClientCapabilities,protocolIdentity}from"./chunk-X6JGA6GH.js";import"./chunk-QMRJYMNH.js";import"./chunk-RQHK4QZ5.js";import"./chunk-UXUJW7IU.js";import"./chunk-KUPQO7MC.js";import{isHostOwnedToolRuntimeCapability,toolRuntimeCapabilities}from"./chunk-XUYQ57MN.js";import"./chunk-26UBFF6N.js";import"./chunk-IBDADH5Z.js";import"./chunk-3474DPZK.js";import{ClientOccupancy,armHostWatchdog,loopLagErrorMs,prepareSocketPath,readHostWatchdogConfigFromBrandEnv}from"./chunk-VP7SFZIM.js";import{SESSION_PATH_RETRY_AFTER_MS,createEndpointReservations,holderGenerationEnded,hostChildDrainRequestFile,ownGenerationDir,parseIdleExitMs,watchDrainRequest,writeHeartbeat,writeStallEvidence}from"./chunk-OUPD5LWY.js";import{HOST_DAEMON_DIR_ENV,MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,canonicalSessionPath,createHostDaemonPaths,sessionDirectoryRemoved}from"./chunk-QQSCUEYJ.js";import"./chunk-U3VOXCGP.js";import"./chunk-HB35RBP4.js";import{FILE_STORAGE_LOCK_RETRY_MAX_DELAY_MS,FILE_STORAGE_LOCK_RETRY_MIN_DELAY_MS,isLockError}from"./chunk-BAOO4VSL.js";import"./chunk-2PYD62SK.js";import"./chunk-QXREUA5F.js";import"./chunk-RUGYFYH7.js";import"./chunk-OEFCY46F.js";import"./chunk-KRNXUTZJ.js";import"./chunk-TAV6QZFM.js";import"./chunk-PELNNWGO.js";import"./chunk-ZIUQ5TZR.js";import"./chunk-YJA2B7FQ.js";import{killTrackedDetachedChildren}from"./chunk-E735MHAK.js";import"./chunk-YU4AYH4C.js";import"./chunk-SPMDDXTO.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-TR4ULWEJ.js";import"./chunk-GVSBCJFI.js";import"./chunk-WASCMT6Y.js";import"./chunk-T36LJ6MW.js";import"./chunk-QGJLZ6BI.js";import"./chunk-WHPDEDCC.js";import"./chunk-AA2L2RHH.js";import"./chunk-HK46JMSC.js";import"./chunk-764SKI4R.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-QG4SIVZW.js";import"./chunk-45SZOLCU.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-BMX2U22F.js";import"./chunk-YU2P3CAR.js";import"./chunk-XE753Y6U.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import"./chunk-RAIZG6HA.js";import{PUBLIC_SOCKET_IDENTITY_FILE,readSocketIdentityFile,shieldSocketDuringClose,socketEntryReplaced,statSocketIdentity,unlinkOwnedSocket,waitForSocketIdentityFile}from"./chunk-HRPMLI7O.js";import{SOCKET_SECRET_FILE_ENV,authenticateSocket,ensureSocketSecret,resolveSocketTransportAddress,socketSecretPath}from"./chunk-QEQG42HL.js";import{VERSION,envValue,isBunBinary,normalizePath,resolvePath}from"./chunk-7YO7VQZW.js";import"./chunk-ATQFN5HI.js";import"./chunk-MIENF2YK.js";import"./chunk-OXNWERO4.js";import{ownProcessStartedAtMs}from"./chunk-QN2BHP3M.js";import"./chunk-NTK2MHJ5.js";import{processStartTimeMs}from"./chunk-7ASLQ243.js";import"./chunk-IKOFCODM.js";import{chmod}from"node:fs/promises";import{createServer}from"node:net";import{basename as basename2,dirname as dirname3,join as join6}from"node:path";var HostCoreGate=class{constructor(registry,route,hooks){this.inFlight=new Map,this.answering=new Set,this.route=route,this.runtimeBuildId=hooks.runtimeBuildId,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);return beginHandoverResponse(parsed.id,typeof request=="string"?request:await this.handover.begin(request))}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)}import{existsSync as existsSync4}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 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&&(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)}
3
3
  `,{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
4
4
  `),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)}import{isAbsolute as isAbsolute2}from"node:path";import{access}from"node:fs/promises";import{isAbsolute}from"node:path";var MAX_WARM_PROFILES=64;function profileKey(profile){let context=Object.entries(profile.sessionContext??{}).sort(([a],[b])=>a<b?-1:a>b?1:0);return JSON.stringify([profile.cwd,profile.sessionKind??"interactive",context])}var HostWarmer=class{constructor(load){this.warm=new Set,this.loading=new Map,this.load=load}async run(profile){let key=profileKey(profile);if(this.warm.has(key))return"already_warm";let pending=this.loading.get(key);return pending===void 0&&(pending=this.loadOnce(key,profile),this.loading.set(key,pending)),await pending,"warmed"}async loadOnce(key,profile){try{if(await this.load(profile),this.warm.add(key),this.warm.size>MAX_WARM_PROFILES){let oldest=this.warm.values().next().value;oldest!==void 0&&this.warm.delete(oldest)}}finally{this.loading.delete(key)}}};function createRegistryWarm(prepare,host){let warmer=new HostWarmer(async profile=>{await access(profile.cwd);let launchProfile={cwd:profile.cwd,...profile.sessionKind!==void 0?{sessionKind:profile.sessionKind}:{},...profile.sessionContext!==void 0?{sessionContext:Object.freeze({...profile.sessionContext})}:{}},scope=new ProviderScope;try{await runWithProviderScope(scope,()=>prepare({cwd:profile.cwd,agentDir:host.agentDir,launchProfile:Object.freeze(launchProfile),...host.mcpRegistry!==void 0?{mcpRegistry:host.mcpRegistry}:{}}))}finally{scope.close()}});return profile=>warmer.run(profile)}function refusal(command,code){return{id:command.id,type:"response",command:"warm",success:!1,error:code}}async function answerWarm(command,host){if(host.draining)return refusal(command,"host_draining");let kindError=sessionKindError(command.kind);if(kindError)return refusal(command,`${RPC_ERROR_INVALID_SESSION_KIND}: ${kindError}`);let contextError=sessionContextError(command.context);if(contextError)return refusal(command,`${RPC_ERROR_INVALID_SESSION_CONTEXT}: ${contextError}`);if(host.warm===void 0)return{id:command.id,type:"response",command:"warm",success:!0,data:{state:"unsupported"}};let sessionContext=host.hostContext?{...command.context,...host.hostContext}:command.context,cwd=command.cwd??host.cwd;if(!isAbsolute(cwd))return refusal(command,RPC_ERROR_INVALID_PATH);try{let state=await host.warm({cwd,...command.kind!==void 0?{sessionKind:command.kind}:{},...sessionContext!==void 0?{sessionContext}:{}});return{id:command.id,type:"response",command:"warm",success:!0,data:{state}}}catch(cause){return refusal(command,`${RPC_ERROR_WARM_FAILED}: ${cause instanceof Error?cause.message:String(cause)}`)}}var RpcSessionRegistryError=class extends Error{constructor(code,reason,detail){super(code==="open_failed"&&reason?`${code}: ${reason}`:code),this.code=code,this.name="RpcSessionRegistryError",detail&&(this.detail=detail)}};function frozenProfile(profile){return Object.freeze({...profile,...profile.holderEndpoint?{holderEndpoint:Object.freeze({...profile.holderEndpoint})}:{},...profile.creationModel?{creationModel:Object.freeze({...profile.creationModel})}:{},...profile.sessionContext?{sessionContext:Object.freeze({...profile.sessionContext})}:{},...profile.retryFallback?{retryFallback:Object.freeze({modelFallback:profile.retryFallback.modelFallback,fallbackChains:Object.freeze(Object.fromEntries(Object.entries(profile.retryFallback.fallbackChains).map(([key,entries])=>[key,Object.freeze([...entries])])))})}:{}})}function sessionIdentity(profile){return{kind:profile.sessionKind??"interactive",context:profile.sessionContext??EMPTY_SESSION_CONTEXT}}function assertRequestedModelResolved(profile,diagnostics){let requested=profile.creationModel;if(requested===void 0)return;let unresolved=diagnostics.find(diagnostic=>diagnostic.code==="model_unresolved");if(unresolved!==void 0)throw new RpcSessionRegistryError("open_failed",`model_unavailable: ${unresolved.message}`,{reason:"model_unavailable",requestedModel:`${requested.provider}/${requested.modelId}`})}var observations=new Set(["get_state","get_effect_status","get_pending_inputs","get_messages","get_entries","get_tree","get_fork_messages","get_last_assistant_text","get_session_stats","resolve_path","get_steering_messages","get_follow_up_messages","get_available_models","get_available_thinking_levels","get_model_thinking_level","get_fast_mode","get_commands","get_loaded_surfaces","get_media","get_auth_providers","get_provider_accounts","memory_report","eval_cells.list","eval_cells.peek"]);function refreshesSessionActivity(command){return!observations.has(command)}var DEFAULT_OPEN_IN_PROGRESS_WAIT_MS=45e3,OPEN_IN_PROGRESS_WAIT_RETRY_MS=2e3;function openInProgressWaitMs(){let override=Number(process.env.SENPI_OPEN_IN_PROGRESS_WAIT_MS);return Number.isFinite(override)&&override>0?override:DEFAULT_OPEN_IN_PROGRESS_WAIT_MS}var OpenInProgressWaitError=class extends Error{};function openingOwner(sessionPath){return{instanceId:hostInstanceId(),pid:process.pid,processStartTime:null,sessionPath,attached:!0,current:!0}}function waitWithDeadline(openCompletion,waitMs){let timer;return Promise.race([openCompletion,new Promise((_resolve,reject)=>{timer=setTimeout(()=>reject(new OpenInProgressWaitError),waitMs)})]).finally(()=>{timer!==void 0&&clearTimeout(timer)})}async function attachToOpenSession(entries,sessionPath,profile,options,pathReservations,now){let existing=[...entries].find(([,entry2])=>entry2.reservationKey===sessionPath&&entry2.state==="open");if(!existing){let inFlight=[...entries].find(([,entry2])=>entry2.reservationKey===sessionPath&&entry2.state==="opening");if(inFlight?.[1].openCompletion!==void 0){try{await waitWithDeadline(inFlight[1].openCompletion,openInProgressWaitMs())}catch(cause){throw cause instanceof OpenInProgressWaitError?new RpcSessionRegistryError("session_path_in_use","the session is still opening",{reason:"open_in_progress",retry_after_ms:OPEN_IN_PROGRESS_WAIT_RETRY_MS,owner:openingOwner(sessionPath)}):new RpcSessionRegistryError("session_path_in_use","the in-flight open failed",{reason:"open_failed",retry_after_ms:OPEN_IN_PROGRESS_WAIT_RETRY_MS})}return attachToOpenSession(entries,sessionPath,profile,options,pathReservations,now)}throw new RpcSessionRegistryError("session_path_in_use","the session is still being released",{reason:"path_still_held",retry_after_ms:OPEN_IN_PROGRESS_WAIT_RETRY_MS})}let[handle,entry]=existing,wasParked=entry.retainOnDisconnect===!0&&entry.attachments===0;if(entry.attachments+=1,entry.detachedAt=void 0,pathReservations?.setAttached(sessionPath,!0),options?.retainOnDisconnect&&(entry.retainOnDisconnect=!0),!entry.durableSessionId)throw new RpcSessionRegistryError("session_path_in_use");return profile.promptSurface!==void 0&&profile.promptSurface!==entry.profile.promptSurface&&(entry.profile=frozenProfile({...entry.profile,promptSurface:profile.promptSurface}),entry.runtime?.setPromptSurface(profile.promptSurface)),profile.browserEngine!==void 0&&profile.browserEngine!==entry.profile.browserEngine&&(entry.profile=frozenProfile({...entry.profile,browserEngine:profile.browserEngine}),entry.runtime?.setBrowserEngine(profile.browserEngine)),profile.permissionPreset!==void 0&&(entry.profile=frozenProfile({...entry.profile,permissionPreset:profile.permissionPreset}),entry.runtime?.setPermissionPreset(profile.permissionPreset)),entry.lastCommandAt=now,wasParked&&(entry.lifecycleMutex=entry.lifecycleMutex.then(()=>entry.runtime?.emitAttachmentEvent("session_resumed")),await entry.lifecycleMutex),{sessionId:handle,durableSessionId:entry.durableSessionId,sessionPath:entry.sessionPath,attached:!0}}function beginPendingClaim(pending,sessionPath){let settled=Promise.withResolvers();return pending.set(sessionPath,settled.promise),()=>{pending.get(sessionPath)===settled.promise&&pending.delete(sessionPath),settled.resolve()}}async function takeCrossGenerationClaim(reservations,pending,pathReservations,sessionPath){let settle=beginPendingClaim(pending,sessionPath),holder;try{holder=await pathReservations.claim(sessionPath)}catch(cause){throw reservations.delete(sessionPath),settle(),cause}if(holder===void 0)return settle;throw reservations.delete(sessionPath),settle(),new RpcSessionRegistryError("session_path_in_use",void 0,{owner:holder,retry_after_ms:SESSION_PATH_RETRY_AFTER_MS})}async function settlePendingClaim(pending,sessionPath,graceMs){let timer,late=new Promise(resolve2=>{timer=setTimeout(()=>resolve2("late"),graceMs)});try{for(let claim=pending.get(sessionPath);claim!==void 0;claim=pending.get(sessionPath))if(await Promise.race([claim.then(()=>"settled"),late])==="late")throw new RpcSessionRegistryError("session_path_in_use","another open of this path is still taking its claim",{reason:"claim_in_progress",retry_after_ms:SESSION_PATH_RETRY_AFTER_MS})}finally{clearTimeout(timer)}}function syncRuntimeMetadata(entries,reservations,pathReservations){for(let entry of entries){let manager=entry.runtime?.session.sessionManager;if(!manager)continue;let currentPath=manager.getSessionFile(),currentKey=currentPath?canonicalSessionPath(currentPath):void 0;(currentPath!==entry.sessionPath||currentKey!==entry.reservationKey)&&(entry.reservationKey&&(reservations.delete(entry.reservationKey),pathReservations?.release(entry.reservationKey)),currentKey&&(reservations.add(currentKey),pathReservations?.claim(currentKey,entry.attachments>0)),entry.reservationKey=currentKey,entry.sessionPath=currentPath),entry.durableSessionId=manager.getSessionId(),entry.cwd=manager.getCwd()}}async function settleClosingReservation(entries,sessionPath,closeGraceMs){let closing=[...entries].find(entry=>entry.reservationKey===sessionPath&&entry.state==="closing");if(!closing?.closeCompletion)return;let deadline;try{await Promise.race([closing.closeCompletion,new Promise(resolve2=>{deadline=setTimeout(resolve2,closeGraceMs)})])}finally{deadline&&clearTimeout(deadline)}}import{existsSync as existsSync2}from"node:fs";function resolveMovedProfile(requested){let profile={...requested,cwd:resolveMovedPath(requested.cwd),...requested.sessionPath?{sessionPath:resolveMovedPath(requested.sessionPath)}:{}};if(profile.sessionPath!==requested.sessionPath&&profile.sessionPath&&!existsSync2(profile.sessionPath))throw new RpcSessionRegistryError("open_failed",`moved session file does not exist: ${profile.sessionPath}`);return profile}import{existsSync as existsSync3}from"node:fs";function createEntrySwitchSession(entry,createRuntime,syncRuntimeMetadata2){return(sessionPath,options)=>{let operation=entry.lifecycleMutex.then(async()=>{if(entry.state!=="open"||!entry.runtime)throw new RpcSessionRegistryError("unknown_session");let runtime=entry.runtime,cwdOverride=options?.cwdOverride,cwdChanged=cwdOverride!==void 0&&runtime.session.sessionManager.getCwd()!==cwdOverride,result=await runtime.switchSession(sessionPath,options);if(result.cancelled||!cwdChanged)return result;let replacement=new AgentSessionRuntime(runtime.session,runtime.services,createRuntime,[...runtime.diagnostics],runtime.modelFallbackMessage,runtime.launchProfile);return replacement.setRebindSession(entry.rebindSession),ClientAdmissions.sealQueuedOnReplace(replacement),EffectLedger.sealOnReplace(replacement),runtime.releaseSessionHold(),entry.runtime=replacement,syncRuntimeMetadata2(),result});return entry.lifecycleMutex=operation.then(()=>{},()=>{}),operation}}function buildOpeningEntry(input){let{profile,sessionPath,requestedDurableId,options}=input,isResume=sessionPath!==void 0&&existsSync3(sessionPath),sessionStartEvent=isResume||profile.attended===!1?{type:"session_start",reason:isResume?"resume":"startup",...profile.attended===!1?{attended:!1}:{}}:void 0,storedProfile=frozenProfile({...profile,...sessionPath?{sessionPath}:{}}),runtimeProfile=isResume?frozenProfile({...storedProfile,creationModel:void 0,initialThinkingLevel:void 0}):storedProfile,settleOpen,openCompletion=new Promise((resolve2,reject)=>{settleOpen={resolve:resolve2,reject}});openCompletion.catch(()=>{});let entry={state:"opening",scope:new ProviderScope,profile:storedProfile,...sessionIdentity(storedProfile),sessionPath,reservationKey:sessionPath,cwd:storedProfile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:input.now,lifecycleMutex:Promise.resolve(),openCompletion};return entry.switchSession=createEntrySwitchSession(entry,input.createRuntime,input.sync),requestedDurableId!==void 0&&(entry.durableSessionId=requestedDurableId),{entry,storedProfile,runtimeProfile,sessionStartEvent,settleOpen}}function sessionIsWriting(entry){return entry.worker?.busy===!0||entry.runtime?.session.isSessionBusy===!0}function reportDetachedFailure(handle,cause){process.stderr.write(`senpi rpc session ${handle} teardown failed: ${String(cause)}
5
5
  `)}function beginSessionClose(host,handle,onRole,options){let entry=host.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing")return onRole?.(!1),entry;if(entry.state!=="open")throw new RpcSessionRegistryError("unknown_session");return entry.attachments-=1,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry.detachedAt??=host.now(),entry.reservationKey&&!sessionIsWriting(entry)&&host.markDetached(entry.reservationKey),entry):(entry.state="closing",onRole?.(!0),entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),entry)}async function releaseWithinGrace(host,handle,key){let timer,late=new Promise(resolve2=>{timer=setTimeout(()=>resolve2("late"),host.closeGraceMs)}),removal=host.releaseReservation(key).then(()=>"removed",cause=>(reportDetachedFailure(handle,cause),"failed")),outcome=await Promise.race([removal,late]);clearTimeout(timer),outcome==="late"&&reportDetachedFailure(handle,new Error(`session path reservation was not removed within ${host.closeGraceMs} ms; closing anyway`))}function closeSession(host,handle){return beginSessionClose(host,handle).state!=="closing"?Promise.resolve():closeMarkedSession(host,handle)}function closeMarkedSession(host,handle){host.sync();let entry=host.get(handle);if(entry?.state!=="closing")throw new RpcSessionRegistryError("unknown_session");let completion=entry.closeCompletion;if(!completion)return Promise.resolve();if(entry.closeStarted)return completion;entry.closeStarted=!0;let previousLifecycle=entry.lifecycleMutex,releaseTimer,released=!1,disposePromise,scopeClosed=!1,disposeOnce=()=>disposePromise||(disposePromise=Promise.resolve(entry.runtime?.dispose()),disposePromise),closeScopeOnce=async()=>{scopeClosed||(scopeClosed=!0,await disposeOnce().catch(()=>{}),await entry.scope.close?.())},release=async()=>{released||(released=!0,releaseTimer&&clearTimeout(releaseTimer),entry.reservationKey&&await releaseWithinGrace(host,handle,entry.reservationKey),entry.state="closed",host.delete(handle))},graceful=(async()=>{await previousLifecycle;try{await entry.runtime?.session.abort()}catch(cause){reportDetachedFailure(handle,cause)}try{await entry.runtime?.session.waitForIdle()}catch(cause){reportDetachedFailure(handle,cause)}try{await disposeOnce()}catch(cause){reportDetachedFailure(handle,cause)}try{await closeScopeOnce()}catch(cause){reportDetachedFailure(handle,cause)}})(),settled=!1,finish=async()=>{settled||(settled=!0,await release(),entry.closeResolve?.())};return releaseTimer=setTimeout(()=>{disposeOnce().catch(cause=>reportDetachedFailure(handle,cause)),closeScopeOnce().catch(cause=>reportDetachedFailure(handle,cause)),graceful.catch(cause=>reportDetachedFailure(handle,cause)),finish()},host.closeGraceMs),graceful.then(finish,cause=>(reportDetachedFailure(handle,cause),finish())),completion}var RpcSessionRegistry=class{get agentDir(){return this.options.agentDir}constructor(options){this.entries=new Map,this.reservations=new Set,this.pendingClaims=new Map,this.nextHandle=0,options.createRuntime.prepare&&(this.warm=createRegistryWarm(options.createRuntime.prepare,{agentDir:options.agentDir,...options.mcpRegistry!==void 0?{mcpRegistry:options.mcpRegistry}:{}})),this.options=options.mcpRegistry===void 0?options:{...options,createRuntime:runtimeOptions=>options.createRuntime({...runtimeOptions,mcpRegistry:options.mcpRegistry})},this.now=options.now??Date.now,this.closeGraceMs=options.closeGraceMs??1e4,this.teardownHost={closeGraceMs:this.closeGraceMs,get:handle=>this.entries.get(handle),delete:handle=>{let deleted=this.entries.delete(handle);return this.options.onSizeChange?.(this.entries.size),deleted},releaseReservation:async key=>{await this.options.pathReservations?.release(key),this.reservations.delete(key)},markDetached:key=>this.options.pathReservations?.setAttached(key,!1),now:()=>this.now(),sync:()=>this.syncRuntimeMetadata()}}get size(){return this.entries.size}holderPids(observedStarts){return this.options.pathReservations?.holderPids?.(observedStarts)??Promise.resolve([])}async openSession(requested,options){this.validateProfile(requested);let profile=resolveMovedProfile(requested);this.syncRuntimeMetadata();let sessionPath=profile.sessionPath?canonicalSessionPath(profile.sessionPath):void 0,requestedDurableId=profile.durableSessionId;if(requestedDurableId!==void 0){for(let entry2 of this.entries.values())if(entry2.state!=="closed"&&entry2.durableSessionId===requestedDurableId&&!(sessionPath!==void 0&&entry2.reservationKey===sessionPath))throw new RpcSessionRegistryError("session_id_in_use")}if(sessionPath){await settleClosingReservation(this.entries.values(),sessionPath,this.closeGraceMs);let deadline=Date.now()+this.closeGraceMs;for(;this.pendingClaims.has(sessionPath);)await settlePendingClaim(this.pendingClaims,sessionPath,Math.max(0,deadline-Date.now()))}if(sessionPath&&this.reservations.has(sessionPath))return attachToOpenSession(this.entries,sessionPath,profile,options,this.options.pathReservations,this.now());if(options?.attachOnly)throw new RpcSessionRegistryError("session_not_held",void 0,{reason:"session_not_held",action:"rediscover_holder"});let claimSettled;sessionPath&&(this.reservations.add(sessionPath),this.options.pathReservations&&(claimSettled=await takeCrossGenerationClaim(this.reservations,this.pendingClaims,this.options.pathReservations,sessionPath)));let handle=`rpc-${++this.nextHandle}`,opening;try{opening=buildOpeningEntry({profile,sessionPath,requestedDurableId,options,now:this.now(),createRuntime:this.options.createRuntime,sync:()=>this.syncRuntimeMetadata()})}catch(cause){try{sessionPath&&(this.reservations.delete(sessionPath),await this.options.pathReservations?.release(sessionPath))}catch(releaseCause){process.stderr.write(`senpi rpc open of ${sessionPath} could not release its claim: ${String(releaseCause)}
@@ -15,9 +15,9 @@ import{SessionEventWriter,answerSetSessionContext,answerSubscribeSessions,answer
15
15
  `),{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}:{},retain_on_disconnect:entry.retainOnDisconnect}}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)}};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 toolSpans=createToolAttributionSpans(sessionId),enqueueRecords=chunk=>{for(let line of chunk.split(`
16
16
  `)){if(!line)continue;let record=JSON.parse(line);toolSpans.observe(record),writer.enqueue(sessionId,record)}},runtimeHost=new Proxy({},{get(_target,property){if(property==="switchSession"&&entry.switchSession)return entry.switchSession;if(property==="setRebindSession")return callback=>{entry.rebindSession=callback,entry.runtime?.setRebindSession(callback)};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(enqueueRecords),taggedSink={writeRaw:chunk=>{if(entry.scope.state==="closed"){droppedAfterClose||process.stderr.write(`senpi rpc host: dropped a record for closed session ${sessionId} at ${new Date().toISOString()}
17
17
  `),droppedAfterClose=!0;return}writeInScope(chunk)},waitForBackpressure:bindToProviderScope(async()=>{})};return createRpcConnectionHandler(runtimeHost,taggedSink,{sessionId,shutdownHandler:bindToProviderScope(requestClose),disposeRuntime:!1,eventFlushScheduler:flush=>flush(),publishLoadedSurfacesChanged:(previous,digest)=>{entry.scope.state!=="closed"&&writer.publishLoadedSurfacesChanged(sessionId,previous,digest)},...options,workerSecurityBridge:writer.workerSecurityBridge,grantDialogSettled:id=>writer.settleGrantDialog(sessionId,id),bindSecurityPresentation:(session,ui)=>writer.bindSecurityPresentations(sessionId,session.sessionId,session.securityNotices,ui),clientInfo:options.clientInfo===void 0?void 0:{...options.clientInfo,hasCapability:(connection,capability)=>writer.getConnectionCapabilities(connection)?.includes(capability)===!0}})});return await handler.ready,{handle:command=>runWithProviderScope(entry.scope,()=>handler.handleInputLine(JSON.stringify(command))),cancelPendingExtensionUiRequests:()=>runWithProviderScope(entry.scope,()=>handler.cancelPendingExtensionUiRequests()),pendingPrompts:()=>handler.pendingPrompts(),connectionDetached:connectionId=>runWithProviderScope(entry.scope,()=>handler.connectionDetached(connectionId)),dispose:()=>(toolSpans.closeAll(),runWithProviderScope(entry.scope,()=>handler.dispose()))}}import{execFile}from"node:child_process";var READ_ONLY_OR_CONTROL=new Set(["get_state","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(`
18
- `)){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,binding,acknowledgePrompt,daemonPids){if(!binding)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"&&acknowledgePrompt(),await binding.handle(command)}import{isAbsolute as isAbsolute3,join as join5}from"node:path";import{copyFileSync,existsSync as existsSync5,mkdirSync,readdirSync,renameSync as renameSync2,rmSync}from"node:fs";import{writeFile as writeFile2}from"node:fs/promises";import{basename,dirname,join as join2,posix,relative,sep}from"node:path";import{realpathSync}from"node:fs";import{resolve}from"node:path";function realSessionPath(path){let absolute=resolve(path);try{return realpathSync(absolute)}catch{return absolute}}var lockKey=resolvedPath=>`session-move:${resolvedPath}`,moveLockKey=sessionFile=>lockKey(realSessionPath(sessionFile));function withSessionMoveLock2(sessionFile,step,guard){let path=realSessionPath(sessionFile);return serializeByKey(lockKey(path),async()=>{guard?.();let sessionId=headerSessionId(loadEntriesFromFile(path));return sessionId===void 0?step():withSessionMoveLock(path,sessionId,step)})}function exportSessionForMove(options){return withSessionMoveLock2(options.sessionFile,()=>(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=loadEntriesFromFile(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&&SessionManager.open(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"?options.extensionStateDir():options.extensionStateDir;if(stateDir!==void 0&&!existsSync5(stateDir))throw new MovedStateMissingError(stateDir);let staging=`${options.bundleDir}.partial-${process.pid}`;rmSync(staging,{recursive:!0,force:!0}),mkdirSync(join2(staging,dirname(SESSION_BUNDLE_PATH)),{recursive:!0}),copyFileSync(sessionFile,join2(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:readRecordedRepositoryIdentity(sessionFile),session:{path:SESSION_BUNDLE_PATH,sha256:await sha256File(join2(staging,SESSION_BUNDLE_PATH))},sidecars,droppedUserMessages:[...options.droppedUserMessages],payloads:stateFiles.length>0?[{kind:EXTENSION_STATE_PAYLOAD,files:stateFiles}]:[]};return await writeFile2(join2(staging,MANIFEST_FILE),`${JSON.stringify(manifest,null,1)}
19
- `),rmSync(options.bundleDir,{recursive:!0,force:!0}),renameSync2(staging,options.bundleDir),manifest}async function copySidecars(sessionDir,sessionId,staging){let sources=[],extensions=join2(sessionDir,"extensions"),sidecarName=`${encodedSessionId(sessionId)}.json`;if(existsSync5(extensions))for(let extension of readdirSync(extensions,{withFileTypes:!0})){let file=join2(extensions,extension.name,sidecarName);extension.isDirectory()&&existsSync5(file)&&sources.push(file)}sources.push(...filesUnder(join2(sessionDir,"resident-blobs",sessionId)));let files=[];for(let source of sources){let path=bundlePath("files",sessionDir,source);mkdirSync(dirname(join2(staging,path)),{recursive:!0}),copyFileSync(source,join2(staging,path)),files.push({path,sha256:await sha256File(join2(staging,path))})}return files}async function copyExtensionState(dir,staging){if(dir===void 0)return[];let files=[];for(let source of filesUnder(dir)){let path=bundlePath("state",dir,source);mkdirSync(dirname(join2(staging,path)),{recursive:!0}),copyFileSync(source,join2(staging,path)),files.push({path,sha256:await sha256File(join2(staging,path))})}return files}function bundlePath(prefix,from,source){return posix.join(prefix,...relative(from,source).split(sep))}function filesUnder(dir){return existsSync5(dir)?readdirSync(dir,{withFileTypes:!0}).flatMap(entry=>entry.isDirectory()?filesUnder(join2(dir,entry.name)):[join2(dir,entry.name)]):[]}import{existsSync as existsSync6,rmSync as rmSync2}from"node:fs";var hook;function moveStep(step){hook?.(step)}async function requeueInput(sessionFile,moveId,texts){if(texts.length===0)return;let sessionManager=SessionManager.open(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(existsSync6(bundleDir)){let bundled=(await readManifest(bundleDir)).moveId;if(bundled!==moveId)throw new MoveMismatchError(moveId,bundled,"the kept bundle")}let entries=loadEntriesFromFile(sessionFile),ownership=sessionOwnership(entries);if(ownership.writable){reclaimed(entries,moveId)&&await requeueDroppedInput(sessionFile,bundleDir),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);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}SessionManager.open(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"),discardMoveFiles(sessionFile,bundleDir,moveId)}async function takeBack(sessionFile,bundleDir,data2){SessionManager.open(sessionFile).appendCustomEntry(SESSION_RECLAIMED,{...data2,reclaimed_at:new Date().toISOString()}),moveStep("finish:recorded"),await requeueDroppedInput(sessionFile,bundleDir)}function discardMoveFiles(sessionFile,bundleDir,moveId){rmSync2(bundleDir,{recursive:!0,force:!0}),rmSync2(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(!existsSync6(bundleDir))return;let manifest=await readManifest(bundleDir);await requeueInput(sessionFile,manifest.moveId,manifest.droppedUserMessages)}import{copyFileSync as copyFileSync2,existsSync as existsSync7,mkdirSync as mkdirSync3,readdirSync as readdirSync2,rmSync as rmSync3}from"node:fs";import{dirname as dirname2,join as join4}from"node:path";import{mkdirSync as mkdirSync2}from"node:fs";import{readFile as readFile2,rename as renameFile,writeFile as writeFile3}from"node:fs/promises";import{join as join3}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,detail){super(`Move ${moveId} can no longer be imported here: ${detail??`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,()=>options.unlessLanded?.()?this.current(moveId):this.settleLocked(moveId,{state:"failed",reason},[]))}commit(moveId,target,rename,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));prepare?.(),await this.write(moveId,{state:"receiving"},{target,committing:!0}),moveStep("import:stamped");let result=await rename();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,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 join3(this.dir,`${parseMoveId(moveId)}.json`)}async raw(moveId){try{return JSON.parse(await readFile2(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 writeFile3(temp,`${JSON.stringify({...record,...landing,at:new Date().toISOString()})}
20
- `),this.#locks.assertHeld(file),await renameFile(temp,file)}locked(moveId,fn){let file=this.path(moveId);return serializeByKey(file,async()=>(mkdirSync2(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()=>{seal(options.sessionFile,options.moveId),moveStep("revoke:sealed"),await options.ledger.markRevoked(options.moveId),moveStep("revoke:marked")},options.guard)}function seal(sessionFile,moveId){let entries=loadEntriesFromFile(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);SessionManager.open(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=(file,moveId)=>loadEntriesFromFile(file).some(entry=>entry.type==="custom"&&entry.customType===SESSION_MOVED_IN&&entry.data?.move_id===moveId);function importOutcome(file,moveId){let outcome="absent";for(let entry of loadEntriesFromFile(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=target=>existsSync7(target)?importOutcome(target,moveId):"absent";return sessionFile===void 0||!existsSync7(sessionFile)?ledger.answerStatus(moveId,{movedIn:!1,landed}):serializeByKey(moveLockKey(sessionFile),async()=>{let outcome=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=join4(sessionDir,manifest.sessionFileName),landed=()=>existsSync7(target)&&movedInFor(target,manifest.moveId);if(landed())return await options.ledger.confirmLanded(manifest.moveId,target,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 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=join4(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),()=>{replacePredecessor(target,manifest.sessionId,sessionDir),placeExtensionState(staging,manifest,movedStateDir(target,manifest.moveId))});return moveStep("import:accepted"),rmSync3(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}}function replacePredecessor(target,sessionId,sessionDir){if(!existsSync7(target))return;let entries=loadEntriesFromFile(target);if(headerSessionId(entries)!==sessionId||sessionOwnership(entries).writable)throw new MoveTargetOccupiedError(target);let extensions=join4(sessionDir,"extensions");if(existsSync7(extensions))for(let extension of readdirSync2(extensions,{withFileTypes:!0}))extension.isDirectory()&&rmSync3(join4(extensions,extension.name,`${encodedSessionId(sessionId)}.json`),{force:!0});rmSync3(join4(sessionDir,"resident-blobs",sessionId),{recursive:!0,force:!0}),rmSync3(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=join4(staging,STAGED_PAYLOADS,file.path);if(mkdirSync3(dirname2(to),{recursive:!0}),copyFileSync2(join4(bundleDir,file.path),to),await sha256File(to)!==file.sha256)throw new MoveBundleInvalidError(`${file.path} changed in transit`)}}function placeExtensionState(staging,manifest,dir){let files=extensionStateFiles(manifest);if(files.length!==0){rmSync3(dir,{recursive:!0,force:!0});for(let file of files){let to=join4(dir,file.path.slice(EXTENSION_STATE_PREFIX.length));mkdirSync3(dirname2(to),{recursive:!0}),copyFileSync2(join4(staging,STAGED_PAYLOADS,file.path),to)}}}async function stage(bundleDir,manifest,staging,from){let file=join4(staging,manifest.sessionFileName);if(!(existsSync7(file)&&movedInFor(file,manifest.moveId))){rmSync3(staging,{recursive:!0,force:!0});for(let item of[manifest.session,...manifest.sidecars]){let to=item===manifest.session?file:join4(staging,item.path.replace(/^files\//,""));mkdirSync3(dirname2(to),{recursive:!0}),copyFileSync2(join4(bundleDir,item.path),to)}await stagePayloads(bundleDir,manifest,staging),SessionManager.open(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 CORE_CODES=new Set(["move_fenced","move_bundle_invalid","move_repository_mismatch","move_target_occupied","move_mismatch","move_already_moved","session_moved_away"]),RENAMED_CODES={ESESSIONHELD:"session_held"};function plainMoveId(value){try{return parseMoveId(value)}catch{return}}var text=value=>typeof value=="string"&&value.trim()!=="";function parse(raw){let{op}=raw;if(op==="import"){if(!text(raw.bundleDir)||!text(raw.cwd)||!isAbsolute3(raw.bundleDir)||!isAbsolute3(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??""}}let id=plainMoveId(raw.moveId);if(id===void 0)return"moveId must be a plain id: a letter or digit, then letters, digits, '.', '_' or '-', at most 128 characters.";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" or "revoke".'}}var wireRecord=record=>record.state==="ready"?{state:"ready",expires_at:record.expiresAt}:record;async function moveSession(port,command){let raw={...command},parsed=parse(raw);if(typeof parsed=="string")return refusal2(command.id,RPC_ERROR_INVALID_MOVE_REQUEST,parsed);let root=join5(port.agentDir,"session-moves"),ledger=new MoveLedger(join5(root,"ledger")),outgoing=moveId=>join5(root,"outgoing",moveId);try{return answer(command.id,await run(parsed,port,ledger,outgoing))}catch(cause){if(cause instanceof MoveRefusal)return refusal2(command.id,cause.code,cause.message);let code=typeof cause=="object"&&cause!==null&&"code"in cause?cause.code:void 0,detail=cause instanceof Error?cause.message:String(cause);return refusal2(command.id,typeof code=="string"?RENAMED_CODES[code]??(CORE_CODES.has(code)?code:RPC_ERROR_MOVE_FAILED):RPC_ERROR_MOVE_FAILED,detail)}}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=realSessionPath(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:()=>{refuseOpenHere(port,sessionFile,"This session is open on this host. Release it with release_session reason move and this moveId first."),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(loadEntriesFromFile(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=realSessionPath(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=realSessionPath(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)}}}function ownershipOf(sessionFile){let ownership=sessionOwnership(loadEntriesFromFile(sessionFile));return{ownership:ownership.writable?"writable":ownership.state}}var MoveRefusal=class extends Error{constructor(code,detail){super(detail),this.name="MoveRefusal",this.code=code}};function refuseUnlessSealedFor(sessionFile,moveId){let ownership=sessionOwnership(loadEntriesFromFile(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.")}function refuseOpenHere(port,sessionFile,detail){if(port.hostedPaths().some(path=>realSessionPath(path)===sessionFile))throw new MoveRefusal(RPC_ERROR_SESSION_OPEN_HERE,detail)}function answer(id,data2){return"refuse"in data2?refusal2(id,data2.refuse,data2.detail):{id,type:"response",command:"move_session",success:!0,data:data2}}function refusal2(id,code,detail){return{id,type:"response",command:"move_session",success:!1,error:code,errorCode:code,errorData:{detail}}}import{rmSync as rmSync4}from"node:fs";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 refusal3(command.id,RPC_ERROR_INVALID_RELEASE_REASON);if(port.draining())return refusal3(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 refusal3(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 refusal3(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=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=refusal3(command.id,cause.code,{detail:cause.message,...interrupted?{interrupted:!0,dropped}:{}}),answer3):(answer3=refusal3(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&&rmSync4(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 refusal3(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}}:refusal3(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=(code,data2)=>refusal3(command.id,code,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 others=port.otherAttachments(command.sessionId);return others>0&&command.force!==!0?refuse(RPC_ERROR_ATTACHED,{attachments:others}):{session,sessionPath,attachments:entry.attachments}}function refusal3(id,code,data2){return{id,type:"response",command:"release_session",success:!1,error:code,...data2&&{errorCode:code,errorData:data2}}}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 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,refused({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,refused(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(refusal4=>!interruptible(refusal4)||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,refused(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(refusal4){return refusal4.reason==="turn_active"||refusal4.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,refusal4){if(command.effectId===void 0)return answer2(command,refused(refusal4));let status=EffectLedger.forSession(session).transition(command.effectId,"failed",{outcome:{kind:"refused",reason:refusal4.reason,detail:refusal4.detail,...refusal4.action===void 0?{}:{action:refusal4.action}}});return answer2(command,{...refused(refusal4),...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 refused(refusal4){return{outcome:"refused",reason:refusal4.reason,detail:refusal4.detail,...refusal4.action===void 0?{}:{action:refusal4.action}}}function answer2(command,data2){return{id:command.id,type:"response",command:"unload_session",success:!0,data:data2}}var DRAIN_SWEEP_MS=50;function error(id,command,code,data2){return{id,type:"response",command,success:!1,error:code,...data2&&{errorCode:code,errorData:data2}}}var SessionCommandRouter=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(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.activeRequests=new Map,this.requestSettledListeners=new Map,this.memoryPressure=!1,this.stopLimitBroadcast=subscriptionLimits.subscribe(limits=>writer.broadcastHostRecord({type:"subscription_limits",...limits})),this.registry=registry,this.writer=writer,this.defaults=defaults,this.createBinding=createBinding,this.connectionOptions=connectionOptions,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=>this.routingIdOf(session)!==void 0,flush:(session,statuses)=>{let sessionId=this.routingIdOf(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(()=>this.sweepIdleSessions(),tickMs),this.sweepTimer.unref?.()}}get sessionCount(){return this.registry.size}setHostMemoryView(view){this.hostMemoryView=view}sessionMemory(sessionId){let view=this.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}}beginDrain(){this.draining=!0,this.stopSweep(),this.drainTimer===void 0&&!this.drainExitRequested&&(this.drainTimer=setInterval(()=>this.sweepDrain(),DRAIN_SWEEP_MS),this.drainTimer.unref?.()),this.sweepDrain()}sweepDrain(){if(this.activeRequests.has(void 0))return;let verdicts=readDrainVerdicts(this.registry,sessionId=>this.activeRequests.has(sessionId));if(verdicts){for(let sessionId of verdicts.gone)this.parkForHandoff(sessionId,"session_dir_removed");for(let sessionId of verdicts.park)this.parkForHandoff(sessionId,"handoff_parked");this.registry.size>0||this.handoffParks>0||this.finalizations.size>0||(this.drainTimer!==void 0&&(clearInterval(this.drainTimer),this.drainTimer=void 0),this.stopSweep(),!this.drainExitRequested&&(this.drainExitRequested=!0,this.onEmptyExit?.()))}}parkForHandoff(sessionId,reason){this.handoffClosed.add(sessionId),this.handoffParks++,this.evictIdleSession(sessionId,reason).catch(cause=>{process.stderr.write(`senpi rpc handoff park ${sessionId} failed: ${String(cause)}
18
+ `)){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,binding,acknowledgePrompt,daemonPids){if(!binding)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"&&acknowledgePrompt(),await binding.handle(command)}import{isAbsolute as isAbsolute3,join as join5}from"node:path";import{copyFile,mkdir as mkdir2,readdir as readdir2,rename,rm as rm2,writeFile as writeFile2}from"node:fs/promises";import{basename,dirname,join as join2,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 rm2(staging,{recursive:!0,force:!0}),await mkdir2(join2(staging,dirname(SESSION_BUNDLE_PATH)),{recursive:!0}),await copyFile(sessionFile,join2(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(join2(staging,SESSION_BUNDLE_PATH))},sidecars,droppedUserMessages:[...options.droppedUserMessages],payloads:stateFiles.length>0?[{kind:EXTENSION_STATE_PAYLOAD,files:stateFiles}]:[]};return await writeFile2(join2(staging,MANIFEST_FILE),`${JSON.stringify(manifest,null,1)}
19
+ `),await rm2(options.bundleDir,{recursive:!0,force:!0}),await rename(staging,options.bundleDir),manifest}async function copySidecars(sessionDir,sessionId,staging){let sources=[],extensions=join2(sessionDir,"extensions"),sidecarName=`${encodedSessionId(sessionId)}.json`;if(await pathExists(extensions))for(let extension of await readdir2(extensions,{withFileTypes:!0})){let file=join2(extensions,extension.name,sidecarName);extension.isDirectory()&&await pathExists(file)&&sources.push(file)}sources.push(...await filesUnder(join2(sessionDir,"resident-blobs",sessionId)));let files=[];for(let source of sources){let path=bundlePath("files",sessionDir,source);await mkdir2(dirname(join2(staging,path)),{recursive:!0}),await copyFile(source,join2(staging,path)),files.push({path,sha256:await sha256File(join2(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(join2(staging,path)),{recursive:!0}),await copyFile(source,join2(staging,path)),files.push({path,sha256:await sha256File(join2(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 readdir2(dir,{withFileTypes:!0})){let path=join2(dir,entry.name);files.push(...entry.isDirectory()?await filesUnder(path):[path])}return files}import{rm as rm3}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 rm3(bundleDir,{recursive:!0,force:!0}),await rm3(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 readdir3,rm as rm4}from"node:fs/promises";import{dirname as dirname2,join as join4}from"node:path";import{mkdir as mkdir3,readFile as readFile2,rename as renameFile,writeFile as writeFile3}from"node:fs/promises";import{join as join3}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,detail){super(`Move ${moveId} can no longer be imported here: ${detail??`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 join3(this.dir,`${parseMoveId(moveId)}.json`)}async raw(moveId){try{return JSON.parse(await readFile2(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 writeFile3(temp,`${JSON.stringify({...record,...landing,at:new Date().toISOString()})}
20
+ `),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=join4(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=join4(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 rm4(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=join4(sessionDir,"extensions");if(await pathExists(extensions))for(let extension of await readdir3(extensions,{withFileTypes:!0}))extension.isDirectory()&&await rm4(join4(extensions,extension.name,`${encodedSessionId(sessionId)}.json`),{force:!0});await rm4(join4(sessionDir,"resident-blobs",sessionId),{recursive:!0,force:!0}),await rm4(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=join4(staging,STAGED_PAYLOADS,file.path);if(await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join4(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 rm4(dir,{recursive:!0,force:!0});for(let file of files){let to=join4(dir,file.path.slice(EXTENSION_STATE_PREFIX.length));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join4(staging,STAGED_PAYLOADS,file.path),to)}}}async function stage(bundleDir,manifest,staging,from){let file=join4(staging,manifest.sessionFileName);if(!(await pathExists(file)&&await movedInFor(file,manifest.moveId))){await rm4(staging,{recursive:!0,force:!0});for(let item of[manifest.session,...manifest.sidecars]){let to=item===manifest.session?file:join4(staging,item.path.replace(/^files\//,""));await mkdir4(dirname2(to),{recursive:!0}),await copyFile2(join4(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 CORE_CODES=new Set(["move_fenced","move_bundle_invalid","move_repository_mismatch","move_target_occupied","move_mismatch","move_already_moved","session_moved_away"]),RENAMED_CODES={ESESSIONHELD:"session_held"};function plainMoveId(value){try{return parseMoveId(value)}catch{return}}var text=value=>typeof value=="string"&&value.trim()!=="";function parse(raw){let{op}=raw;if(op==="import"){if(!text(raw.bundleDir)||!text(raw.cwd)||!isAbsolute3(raw.bundleDir)||!isAbsolute3(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??""}}let id=plainMoveId(raw.moveId);if(id===void 0)return"moveId must be a plain id: a letter or digit, then letters, digits, '.', '_' or '-', at most 128 characters.";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" or "revoke".'}}var wireRecord=record=>record.state==="ready"?{state:"ready",expires_at:record.expiresAt}:record;async function moveSession(port,command){let raw={...command},parsed=parse(raw);if(typeof parsed=="string")return refusal2(command.id,RPC_ERROR_INVALID_MOVE_REQUEST,parsed);let root=join5(port.agentDir,"session-moves"),ledger=new MoveLedger(join5(root,"ledger")),outgoing=moveId=>join5(root,"outgoing",moveId);try{return answer(command.id,await run(parsed,port,ledger,outgoing))}catch(cause){if(cause instanceof MoveRefusal)return refusal2(command.id,cause.code,cause.message);let code=typeof cause=="object"&&cause!==null&&"code"in cause?cause.code:void 0,detail=cause instanceof Error?cause.message:String(cause);return refusal2(command.id,typeof code=="string"?RENAMED_CODES[code]??(CORE_CODES.has(code)?code:RPC_ERROR_MOVE_FAILED):RPC_ERROR_MOVE_FAILED,detail)}}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)}}}async function ownershipOf(sessionFile){let ownership=sessionOwnership(await loadEntriesFromFileAsync(sessionFile));return{ownership:ownership.writable?"writable":ownership.state}}var MoveRefusal=class extends Error{constructor(code,detail){super(detail),this.name="MoveRefusal",this.code=code}};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,detail){if((await Promise.all(port.hostedPaths().map(path=>realSessionPath(path)))).includes(sessionFile))throw new MoveRefusal(RPC_ERROR_SESSION_OPEN_HERE,detail)}function answer(id,data2){return"refuse"in data2?refusal2(id,data2.refuse,data2.detail):{id,type:"response",command:"move_session",success:!0,data:data2}}function refusal2(id,code,detail){return{id,type:"response",command:"move_session",success:!1,error:code,errorCode:code,errorData:{detail}}}import{rm as rm5}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 refusal3(command.id,RPC_ERROR_INVALID_RELEASE_REASON);if(port.draining())return refusal3(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 refusal3(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 refusal3(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=refusal3(command.id,cause.code,{detail:cause.message,...interrupted?{interrupted:!0,dropped}:{}}),answer3):(answer3=refusal3(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 rm5(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 refusal3(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}}:refusal3(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=(code,data2)=>refusal3(command.id,code,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 others=port.otherAttachments(command.sessionId);return others>0&&command.force!==!0?refuse(RPC_ERROR_ATTACHED,{attachments:others}):{session,sessionPath,attachments:entry.attachments}}function refusal3(id,code,data2){return{id,type:"response",command:"release_session",success:!1,error:code,...data2&&{errorCode:code,errorData:data2}}}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 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,refused({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,refused(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(refusal4=>!interruptible(refusal4)||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,refused(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(refusal4){return refusal4.reason==="turn_active"||refusal4.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,refusal4){if(command.effectId===void 0)return answer2(command,refused(refusal4));let status=EffectLedger.forSession(session).transition(command.effectId,"failed",{outcome:{kind:"refused",reason:refusal4.reason,detail:refusal4.detail,...refusal4.action===void 0?{}:{action:refusal4.action}}});return answer2(command,{...refused(refusal4),...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 refused(refusal4){return{outcome:"refused",reason:refusal4.reason,detail:refusal4.detail,...refusal4.action===void 0?{}:{action:refusal4.action}}}function answer2(command,data2){return{id:command.id,type:"response",command:"unload_session",success:!0,data:data2}}var DRAIN_SWEEP_MS=50;function error(id,command,code,data2){return{id,type:"response",command,success:!1,error:code,...data2&&{errorCode:code,errorData:data2}}}var SessionCommandRouter=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(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.activeRequests=new Map,this.requestSettledListeners=new Map,this.memoryPressure=!1,this.stopLimitBroadcast=subscriptionLimits.subscribe(limits=>writer.broadcastHostRecord({type:"subscription_limits",...limits})),this.registry=registry,this.writer=writer,this.defaults=defaults,this.createBinding=createBinding,this.connectionOptions=connectionOptions,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=>this.routingIdOf(session)!==void 0,flush:(session,statuses)=>{let sessionId=this.routingIdOf(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(()=>this.sweepIdleSessions(),tickMs),this.sweepTimer.unref?.()}}get sessionCount(){return this.registry.size}setHostMemoryView(view){this.hostMemoryView=view}sessionMemory(sessionId){let view=this.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}}beginDrain(){this.draining=!0,this.stopSweep(),this.drainTimer===void 0&&!this.drainExitRequested&&(this.drainTimer=setInterval(()=>this.sweepDrain(),DRAIN_SWEEP_MS),this.drainTimer.unref?.()),this.sweepDrain()}sweepDrain(){if(this.activeRequests.has(void 0))return;let verdicts=readDrainVerdicts(this.registry,sessionId=>this.activeRequests.has(sessionId));if(verdicts){for(let sessionId of verdicts.gone)this.parkForHandoff(sessionId,"session_dir_removed");for(let sessionId of verdicts.park)this.parkForHandoff(sessionId,"handoff_parked");this.registry.size>0||this.handoffParks>0||this.finalizations.size>0||(this.drainTimer!==void 0&&(clearInterval(this.drainTimer),this.drainTimer=void 0),this.stopSweep(),!this.drainExitRequested&&(this.drainExitRequested=!0,this.onEmptyExit?.()))}}parkForHandoff(sessionId,reason){this.handoffClosed.add(sessionId),this.handoffParks++,this.evictIdleSession(sessionId,reason).catch(cause=>{process.stderr.write(`senpi rpc handoff park ${sessionId} failed: ${String(cause)}
21
21
  `)}).finally(()=>{this.handoffParks--,this.sweepDrain()})}setMemoryPressure(pressure){this.memoryPressure=pressure}handle(command){let sessionId="sessionId"in command?command.sessionId:void 0;return this.draining&&sessionId!==void 0&&this.handoffClosed.has(sessionId)?Promise.resolve(void 0):this.draining&&command.type==="open_session"?Promise.resolve(error(command.id,command.type,"host_draining")):command.type==="warm"?answerWarm(command,{draining:this.draining,warm:this.registry.warm,cwd:this.defaults.cwd,hostContext:this.defaults.hostContext}):(this.activeRequests.set(sessionId,(this.activeRequests.get(sessionId)??0)+1),runWithSessionAttribution({sessionId},()=>this.dispatch(command)).finally(()=>{let remaining=(this.activeRequests.get(sessionId)??1)-1;if(remaining>0?this.activeRequests.set(sessionId,remaining):this.activeRequests.delete(sessionId),sessionId!==void 0)for(let listener of this.requestSettledListeners.get(sessionId)??[])listener();this.draining&&this.sweepDrain()}))}async dispatch(command){if(command.type==="get_protocol_info"){let capabilities=multiSessionHostCapabilities({warm:this.registry.warm!==void 0,toolRuntime:this.defaults.toolRuntime??"in-process",negotiated:this.connectionOptions?.capabilities??[]});return{id:command.id,type:"response",command:"get_protocol_info",success:!0,data:{protocolVersion:1,serverVersion:VERSION,capabilities,mode:"multi",...protocolIdentity(),memory_pressure:this.memoryPressure}}}if(command.type==="get_subscription_limits")return{id:command.id,type:"response",command:"get_subscription_limits",success:!0,data:{accounts:subscriptionLimits.snapshot()}};if(command.type==="list_sessions"){let withMemory=this.registry.list().map(row=>({...row,memory:this.sessionMemory(row.sessionId)})),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}}}if(command.type==="detach_connection")return detachConnection(command,this.writer.currentConnection(),id=>this.releaseConnection(id));if(command.type==="open_session")return this.openWithBarrier(command);if(command.type==="close_session")return this.close(command);if(command.type==="release_session"){let caller=this.writer.currentConnection();return releaseSession({draining:()=>this.draining,hostInstance:this.defaults.hostContext?.host_instance,lookup:sessionId2=>this.registry.getForCommand(sessionId2,"release_session"),code:cause=>this.code(cause),otherRequests:sessionId2=>Math.max(0,(this.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>this.otherRequestsSettled(sessionId2),pendingPrompts:sessionId2=>this.bindings.get(sessionId2)?.pendingPrompts?.()??[],otherAttachments:sessionId2=>this.otherAttachments(sessionId2,caller),tearDown:(sessionId2,sessionPath)=>this.tearDownReleased(sessionId2,sessionPath)},command)}if(command.type==="move_session"){let agentDir=this.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:()=>this.registry.list().flatMap(row=>row.sessionPath===void 0?[]:[row.sessionPath])},command)}if(command.type==="unload_session"){let caller=this.writer.currentConnection();return unloadSession({draining:()=>this.draining,by:{connectionId:caller??"host"},lookup:sessionId2=>this.registry.getForCommand(sessionId2,"unload_session"),code:cause=>this.code(cause),otherRequests:sessionId2=>Math.max(0,(this.activeRequests.get(sessionId2)??1)-1),otherRequestsSettled:sessionId2=>this.otherRequestsSettled(sessionId2),pendingPrompts:sessionId2=>this.bindings.get(sessionId2)?.pendingPrompts?.()??[],otherAttachments:sessionId2=>this.otherAttachments(sessionId2,caller),openChildSessions:durableSessionId=>this.registry.list().filter(row=>row.durableSessionId!==durableSessionId&&(row.context?.parent_session_id===durableSessionId||row.context?.root_session_id===durableSessionId)).length,tearDown:(sessionId2,sessionPath)=>this.tearDownUnloaded(sessionId2,sessionPath)},command)}if(command.type==="set_client_info"&&!command.sessionId){let connection=this.writer.currentConnection();return command.capabilities!==void 0&&!this.connectionRoles.declare(roleConnection(connection),command.capabilities)?{id:command.id,type:"response",command:"set_client_info",success:!1,error:CONNECTION_ROLE_FIXED}:(connection!==void 0&&(this.pendingCapabilities.set(connection,command.capabilities??[]),this.writer.setConnectionCapabilities(connection,command.capabilities??[])),{id:command.id,type:"response",command:"set_client_info",success:!0})}if(command.type==="subscribe_sessions"){let connection=this.writer.currentConnection(),{answer:answer3,activate}=answerSubscribeSessions(command,connection,this.writer.status);if(activate!==void 0&&connection!==void 0){(async()=>{await this.writer.enqueueControl(answer3,connection),await new Promise(resolve2=>queueMicrotask(resolve2));try{this.writer.hasConnection(connection)?this.writer.status.activate(activate):this.writer.status.unsubscribe(connection,activate)}catch(cause){process.stderr.write(`senpi rpc subscription activation failed: ${String(cause)}
22
22
  `)}})().catch(cause=>{this.writer.status.unsubscribe(connection,activate),process.stderr.write(`senpi rpc subscribe answer could not be delivered: ${String(cause)}
23
23
  `)});return}return answer3}if(command.type==="unsubscribe_sessions")return answerUnsubscribeSessions(command,this.writer.currentConnection(),this.writer.status);if(command.type==="get_effect_status"&&!command.sessionId&&command.sessionPath!==void 0)return answerEffectFromTranscript(command.id,command.sessionPath,command.effectId);if(!command.sessionId)return error(command.id,command.type,RPC_ERROR_MISSING_SESSION_ID);let sessionId=command.sessionId;if(command.type==="set_session_context")return this.setSessionContext(command);try{let entry=this.registry.getForCommand(sessionId,command.type);await dispatchSessionBinding(command,entry,this.bindings.get(sessionId),()=>this.acknowledgePrompt(command.id,sessionId),observedStarts=>this.registry.holderPids?.(observedStarts)??Promise.resolve([]));return}catch(cause){return error(command.id,command.type,this.code(cause),this.detail(cause))}}setSessionContext(command){let owner=this.writer.currentConnection();if(owner!==void 0&&this.sessionsByConnection.get(owner)?.has(command.sessionId)!==!0)return notAttachedRefusal(command);try{let entry=this.registry.getForCommand(command.sessionId,command.type);return answerSetSessionContext(command,entry,this.writer.status)}catch(cause){return error(command.id,command.type,this.code(cause),this.detail(cause))}}async dispose(){this.stopLimitBroadcast(),this.drainExitRequested=!0,this.stopSweep(),this.drainTimer!==void 0&&clearInterval(this.drainTimer),await Promise.all([...this.bindings.entries()].map(async([sessionId,binding])=>{let claim=this.tryClaimClose(sessionId,{drainAttachments:!0});claim&&(claim.finalizer?await this.finalizeClose(sessionId,binding,()=>this.writer.closeSession(sessionId,{type:"response",command:"close_session",success:!0,data:{}},"host_shutdown")):await this.finalizations.get(sessionId)?.promise,this.writer.forgetSession(sessionId))})),this.bindings.clear(),this.uninstallEffectSink?.(),this.uninstallEffectSink=void 0}sweepIdleSessions(){let now=this.idleNow(),idleEvictionMs=this.memoryPressure?this.idleEvictionMs/2:this.idleEvictionMs,verdicts=selectSweepEvictions(this.registry,now,idleEvictionMs,sessionId=>this.activeRequests.has(sessionId)||(this.bindings.get(sessionId)?.pendingPrompts?.().length??0)>0);for(let sessionId of verdicts.orphaned)this.evictIdleSession(sessionId,"session_dir_removed");for(let sessionId of verdicts.idle)this.evictIdleSession(sessionId);Number.isFinite(this.emptyExitMs)&&(this.registry.size===0&&(this.canExitWhenEmpty?.()??!0)?this.emptySince===void 0?this.emptySince=now:now-this.emptySince>=this.emptyExitMs&&(this.stopSweep(),this.onEmptyExit?.()):this.emptySince=void 0)}async evictIdleSession(sessionId,reason){let retained=this.registry.peek(sessionId),parkedPath=retained?.retainOnDisconnect===!0||reason==="handoff_parked"?retained?.sessionPath:void 0,handoff=reason==="handoff_parked"||reason==="session_dir_removed"&&this.draining,owners=handoff?[...this.sessionsByConnection].filter(([,owned])=>owned.has(sessionId)).map(([connection])=>connection):[],claim=this.tryClaimClose(sessionId,{drainAttachments:!0});if(!claim)return;this.handoverParkedDir!==void 0&&parkedPath!==void 0&&retained?.retainOnDisconnect===!0&&retained.sessionPath!==void 0&&await recordHandoverParkedSession(this.handoverParkedDir,{...parkedEntryFromProfile({sessionPath:retained.sessionPath,contextOverlay:retained.contextOverlay,...retained.durableSessionId!==void 0?{durableSessionId:retained.durableSessionId}:{}},retained.profile,Object.keys(this.defaults.hostContext??{})),parkedBy:this.defaults.hostContext?.host_instance??hostInstanceId()}).catch(cause=>{process.stderr.write(`senpi rpc handover park record ${sessionId} failed: ${String(cause)}