@code-yeongyu/senpi 2026.10.18-1 → 2026.10.19

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 (154) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/bundle/chunks/{anthropic-messages-3CFTFCKV.js → anthropic-messages-EMTBHJMM.js} +2 -2
  3. package/dist/bundle/chunks/{args-SJWMIH2H.js → args-LWR7VFKS.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-IRKZ6FVC.js → chunk-35M5MVUZ.js} +149 -145
  5. package/dist/bundle/chunks/chunk-3DNYAO3P.js +2 -0
  6. package/dist/bundle/chunks/{chunk-T2BEB5SO.js → chunk-7QPFFAJT.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-4RUVN7K3.js → chunk-BOCN744P.js} +1 -1
  8. package/dist/bundle/chunks/{chunk-DDHBG2HU.js → chunk-FM7NDZR5.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-OMY4EC25.js → chunk-FSENE7JK.js} +2 -2
  10. package/dist/bundle/chunks/{chunk-Z2LCTXS2.js → chunk-G7LLAQXI.js} +3 -3
  11. package/dist/bundle/chunks/{chunk-NRHOGI4Z.js → chunk-IM6ZWYTW.js} +2 -2
  12. package/dist/bundle/chunks/{chunk-MLKYJIUK.js → chunk-KM4FMQII.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-OOWML2KE.js → chunk-PMGEQYEP.js} +2 -2
  14. package/dist/bundle/chunks/chunk-QGJLZ6BI.js +2 -0
  15. package/dist/bundle/chunks/{chunk-6EXDMO4S.js → chunk-QJ6MUFXY.js} +1 -1
  16. package/dist/bundle/chunks/{chunk-FZTO2ICI.js → chunk-QRGAMVEE.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-3QVP3ZVI.js → chunk-QXEWAKXA.js} +1 -1
  18. package/dist/bundle/chunks/{chunk-UUMKAA7S.js → chunk-RL5QMGQD.js} +9 -9
  19. package/dist/bundle/chunks/chunk-T36LJ6MW.js +3 -0
  20. package/dist/bundle/chunks/{chunk-GAHIHXVE.js → chunk-VEKNDMUA.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-TFXUF2IL.js → chunk-VPV7ADF3.js} +1 -1
  22. package/dist/bundle/chunks/{chunk-RELAITQ7.js → chunk-X6TWPBI6.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-PKDWFVE4.js → chunk-YUMRZIKJ.js} +6 -6
  24. package/dist/bundle/chunks/chunk-ZPSJQHDK.js +395 -0
  25. package/dist/bundle/chunks/{cli-main-JCSB54VT.js → cli-main-EABMHWFV.js} +1 -1
  26. package/dist/bundle/chunks/{help-fast-path-FVPGRSYA.js → help-fast-path-BYWJN6YX.js} +1 -1
  27. package/dist/bundle/chunks/{host-command-X2ZZFTME.js → host-command-5T34JLBP.js} +1 -1
  28. package/dist/bundle/chunks/{host-lifecycle-OKWTQFUJ.js → host-lifecycle-GSRIQP6Z.js} +1 -1
  29. package/dist/bundle/chunks/host-lifecycle.js +1 -1
  30. package/dist/bundle/chunks/{host-session-command-HKJKOAVS.js → host-session-command-LF6JODPX.js} +1 -1
  31. package/dist/bundle/chunks/{interactive-mode-GJERAFGV.js → interactive-mode-GMWHBIUC.js} +1 -1
  32. package/dist/bundle/chunks/{list-tips-AWDAUHF2.js → list-tips-VSWED3PT.js} +1 -1
  33. package/dist/bundle/chunks/{multi-session-host-JWMGLKAG.js → multi-session-host-3J7STKGD.js} +4 -4
  34. package/dist/bundle/chunks/{openai-codex-responses-RLYFSLK6.js → openai-codex-responses-7YOBPZ2N.js} +1 -1
  35. package/dist/bundle/chunks/{openai-completions-OWNSXMTD.js → openai-completions-HSZPYXEA.js} +1 -1
  36. package/dist/bundle/chunks/{package-manager-cli-FSVS2ND2.js → package-manager-cli-LWQZSWKL.js} +1 -1
  37. package/dist/bundle/chunks/{rotation-stream-M6QV2MMB.js → rotation-stream-QRRWL73X.js} +1 -1
  38. package/dist/bundle/chunks/{rpc-mode-TPG3J3ZJ.js → rpc-mode-6LSWRKXR.js} +1 -1
  39. package/dist/bundle/chunks/{schedule-command-PAVLVMWL.js → schedule-command-7CXMW4WK.js} +1 -1
  40. package/dist/bundle/chunks/{session-control-endpoint-NSMRMKKK.js → session-control-endpoint-E265WAIQ.js} +1 -1
  41. package/dist/bundle/chunks/{session-picker-UV6IVWJY.js → session-picker-XRB3LP5W.js} +1 -1
  42. package/dist/bundle/chunks/session-worker.js +298 -293
  43. package/dist/bundle/cli.js +2 -2
  44. package/dist/bundle/index.js +1 -1
  45. package/dist/bundle/rpc-entry.js +1 -1
  46. package/dist/bundle/runtime-manifest.json +1 -1
  47. package/dist/core/agent-run-continuation.d.ts +24 -0
  48. package/dist/core/agent-run-continuation.js +57 -0
  49. package/dist/core/agent-session.d.ts +38 -1
  50. package/dist/core/agent-session.js +122 -13
  51. package/dist/core/extension-handler-stall-report.d.ts +11 -0
  52. package/dist/core/extension-handler-stall-report.js +26 -0
  53. package/dist/core/extensions/builtin/anthropic-subscription/account-command.js +1 -0
  54. package/dist/core/extensions/builtin/anthropic-subscription/affinity.d.ts +13 -1
  55. package/dist/core/extensions/builtin/anthropic-subscription/affinity.js +15 -4
  56. package/dist/core/extensions/builtin/anthropic-subscription/auth-lane.js +2 -0
  57. package/dist/core/extensions/builtin/anthropic-subscription/failover.d.ts +2 -0
  58. package/dist/core/extensions/builtin/anthropic-subscription/failover.js +3 -2
  59. package/dist/core/extensions/builtin/anthropic-subscription/guidance.d.ts +8 -0
  60. package/dist/core/extensions/builtin/anthropic-subscription/guidance.js +29 -0
  61. package/dist/core/extensions/builtin/anthropic-subscription/settings.d.ts +2 -0
  62. package/dist/core/extensions/builtin/anthropic-subscription/settings.js +4 -0
  63. package/dist/core/extensions/builtin/anthropic-subscription/stream-guidance.js +4 -2
  64. package/dist/core/extensions/handler-budget.d.ts +84 -0
  65. package/dist/core/extensions/handler-budget.js +136 -0
  66. package/dist/core/extensions/runner.d.ts +23 -0
  67. package/dist/core/extensions/runner.js +184 -99
  68. package/dist/core/footer-data-provider.js +2 -1
  69. package/dist/core/keybindings.d.ts +1 -1
  70. package/dist/core/keybindings.js +3 -2
  71. package/dist/core/pending-input-journal.d.ts +6 -1
  72. package/dist/core/pending-input-journal.js +90 -34
  73. package/dist/core/pending-input-public.d.ts +11 -0
  74. package/dist/core/pending-input-public.js +10 -0
  75. package/dist/core/pending-input-session-port.d.ts +15 -0
  76. package/dist/core/pending-input-session-port.js +93 -0
  77. package/dist/core/pending-input-session.d.ts +108 -0
  78. package/dist/core/pending-input-session.js +220 -0
  79. package/dist/core/pending-input-store.d.ts +32 -1
  80. package/dist/core/pending-input-store.js +74 -26
  81. package/dist/core/pending-input-types.d.ts +25 -4
  82. package/dist/core/pending-input.js +36 -18
  83. package/dist/core/session-entry-file.js +1 -0
  84. package/dist/core/session-log.js +1 -1
  85. package/dist/core/session-manager.d.ts +1 -0
  86. package/dist/core/session-manager.js +5 -1
  87. package/dist/core/session-move/bundle.d.ts +39 -0
  88. package/dist/core/session-move/bundle.js +108 -0
  89. package/dist/core/session-move/export.d.ts +18 -0
  90. package/dist/core/session-move/export.js +83 -0
  91. package/dist/core/session-move/finish.d.ts +24 -0
  92. package/dist/core/session-move/finish.js +81 -0
  93. package/dist/core/session-move/import.d.ts +32 -0
  94. package/dist/core/session-move/import.js +124 -0
  95. package/dist/core/session-move/move-ledger.d.ts +47 -0
  96. package/dist/core/session-move/move-ledger.js +151 -0
  97. package/dist/core/session-move/ownership.d.ts +61 -0
  98. package/dist/core/session-move/ownership.js +89 -0
  99. package/dist/core/session-move/requeue.d.ts +8 -0
  100. package/dist/core/session-move/requeue.js +18 -0
  101. package/dist/core/session-move/write-guard.d.ts +22 -0
  102. package/dist/core/session-move/write-guard.js +44 -0
  103. package/dist/core/settings-manager.d.ts +13 -0
  104. package/dist/core/settings-manager.js +17 -0
  105. package/dist/core/turn-deadline.d.ts +2 -0
  106. package/dist/core/turn-deadline.js +10 -3
  107. package/dist/modes/interactive/components/ask-user-async-widget.d.ts +7 -0
  108. package/dist/modes/interactive/components/ask-user-async-widget.js +20 -6
  109. package/dist/modes/rpc/connection-handler.js +3 -0
  110. package/dist/modes/rpc/effect-commands.js +3 -4
  111. package/dist/modes/rpc/host-observe-request.js +1 -0
  112. package/dist/modes/rpc/rpc-client.d.ts +10 -0
  113. package/dist/modes/rpc/rpc-client.js +11 -0
  114. package/dist/modes/rpc/rpc-input-validation.js +8 -0
  115. package/dist/modes/rpc/rpc-types.d.ts +25 -1
  116. package/dist/modes/rpc/session-command-activity.js +1 -0
  117. package/dist/modes/rpc/session-control-actions-data.js +17 -8
  118. package/dist/modes/rpc/session-held.js +1 -0
  119. package/dist/modes/rpc/session-release.js +16 -1
  120. package/dist/modes/rpc/tool-child/admission.d.ts +42 -0
  121. package/dist/modes/rpc/tool-child/admission.js +81 -0
  122. package/dist/modes/rpc/tool-child/admission.test.d.ts +2 -0
  123. package/dist/modes/rpc/tool-child/admission.test.js +166 -0
  124. package/dist/modes/rpc/tool-child/codec.d.ts +21 -0
  125. package/dist/modes/rpc/tool-child/codec.js +137 -0
  126. package/dist/modes/rpc/tool-child/codec.test.d.ts +2 -0
  127. package/dist/modes/rpc/tool-child/codec.test.js +234 -0
  128. package/dist/modes/rpc/tool-child/context.d.ts +42 -0
  129. package/dist/modes/rpc/tool-child/context.js +23 -0
  130. package/dist/modes/rpc/tool-child/flow-control.d.ts +24 -0
  131. package/dist/modes/rpc/tool-child/flow-control.js +80 -0
  132. package/dist/modes/rpc/tool-child/payload-ref-paths.d.ts +9 -0
  133. package/dist/modes/rpc/tool-child/payload-ref-paths.js +45 -0
  134. package/dist/modes/rpc/tool-child/payload-ref.d.ts +58 -0
  135. package/dist/modes/rpc/tool-child/payload-ref.js +166 -0
  136. package/dist/modes/rpc/tool-child/payload-ref.test.d.ts +2 -0
  137. package/dist/modes/rpc/tool-child/payload-ref.test.js +254 -0
  138. package/dist/modes/rpc/tool-child/payload-wire.d.ts +13 -0
  139. package/dist/modes/rpc/tool-child/payload-wire.js +22 -0
  140. package/dist/modes/rpc/tool-child/protocol-guard.d.ts +9 -0
  141. package/dist/modes/rpc/tool-child/protocol-guard.js +128 -0
  142. package/dist/modes/rpc/tool-child/protocol.d.ts +192 -0
  143. package/dist/modes/rpc/tool-child/protocol.js +54 -0
  144. package/dist/utils/wsl.d.ts +2 -2
  145. package/dist/utils/wsl.js +4 -4
  146. package/docs/providers.md +2 -0
  147. package/docs/rpc.md +16 -2
  148. package/docs/settings.md +1 -0
  149. package/docs/terminal-setup.md +2 -0
  150. package/package.json +10 -6
  151. package/dist/bundle/chunks/chunk-COJK5FDH.js +0 -2
  152. package/dist/bundle/chunks/chunk-IDXW4FAO.js +0 -2
  153. package/dist/bundle/chunks/chunk-PFNBY43W.js +0 -2
  154. package/dist/bundle/chunks/chunk-QBD4LY7D.js +0 -395
@@ -1,3 +1,3 @@
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,answerSubscribeSessions,answerUnsubscribeSessions,refusal,sessionRuntimeView,socketSink}from"./chunk-6EXDMO4S.js";import{WakeScheduler,answeredUiRequestId,availableModelsData,buildRpcSessionState,interruptRunningTurn,onProcessContinue,rpcCommandShapeError,runGetEffectStatus,settledQuestionStatus,subscribeSessionRecords,unansweredQuestionIds,unsupportedThinkingLevel,watchInbox}from"./chunk-QBD4LY7D.js";import"./chunk-MF57DS3V.js";import"./chunk-FZTO2ICI.js";import"./chunk-PKDWFVE4.js";import"./chunk-4RSWXPUB.js";import"./chunk-OJPUDLM2.js";import"./chunk-UUMKAA7S.js";import{SESSION_STATUS_CAPABILITY,acquireHostEnsureLock,engineBuildIdentity,gcHostEndpoints}from"./chunk-GAHIHXVE.js";import"./chunk-QMRJYMNH.js";import{tuiSocketName}from"./chunk-36GE6JDV.js";import"./chunk-HB35RBP4.js";import"./chunk-GZVCRV7I.js";import"./chunk-KUPQO7MC.js";import"./chunk-GOKAWZUO.js";import"./chunk-26UBFF6N.js";import"./chunk-OOWML2KE.js";import{MAX_SOCKET_PATH_BYTES,thisProcessStartTime,writeHostRegistration}from"./chunk-TFXUF2IL.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,authenticateSocket,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,serializeJsonLine,socketSecretPath}from"./chunk-XC2CNM26.js";import"./chunk-7ASLQ243.js";import"./chunk-U3VOXCGP.js";import"./chunk-2VZJTDUX.js";import"./chunk-YU2P3CAR.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-AUZXSLZN.js";import{VERSION}from"./chunk-G3ZEPNGM.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-COJK5FDH.js";import"./chunk-WHPDEDCC.js";import"./chunk-RUGYFYH7.js";import"./chunk-PFNBY43W.js";import"./chunk-KRNXUTZJ.js";import"./chunk-UAQW2T7G.js";import"./chunk-HK46JMSC.js";import"./chunk-5ROMKDLK.js";import"./chunk-45SZOLCU.js";import"./chunk-3W47LTXQ.js";import"./chunk-WQLMQGOW.js";import"./chunk-WDTJ6JKE.js";import"./chunk-LAWS3FYQ.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{randomUUID as randomUUID2}from"node:crypto";import{rm as rm2}from"node:fs/promises";var ControlAttachments=class{constructor(session,pendingQuestions){this.writer=new SessionEventWriter(()=>{}),this.attached=new Set,this.session=session,this.writer.status.setSource({sessionIds:()=>[this.handle],entryView:id=>id===this.handle?this.entryView():void 0,view:id=>id===this.handle?{entry:this.entryView(),runtime:sessionRuntimeView(session,pendingQuestions())}:void 0}),this.writer.registerConnection(NULL_CONNECTION,{writeRaw:()=>{},waitForBackpressure:async()=>{}}),this.stopRecords=subscribeSessionRecords(session,record=>this.writer.enqueue(this.handle,record))}get handle(){return this.session.sessionId}opened(connection){this.writer.registerConnection(keyOf(connection),connection.transport)}closed(connection){let key=keyOf(connection);this.attached.delete(key)&&this.writer.status.publish(this.handle,"detach","client"),this.writer.unregisterConnection(key)}attach(connection){let key=keyOf(connection);return this.attached.has(key)?!1:(this.attached.add(key),this.writer.attachConnectionToSession(key,this.handle),this.writer.status.publish(this.handle,"attach","client"),!0)}isAttached(connection){return this.attached.has(keyOf(connection))}run(connection,task){return this.writer.withConnection(keyOf(connection),task)}respond(connection,answer2){this.writer.enqueueControl(answer2,keyOf(connection)).catch(()=>connection.transport.close?.())}dispose(){this.stopRecords()}entryView(){let manager=this.session.sessionManager,path=this.session.sessionFile,name=manager.getSessionName();return{state:"open",kind:"interactive",cwd:manager.getCwd(),attachments:1+this.attached.size,durableSessionId:this.session.sessionId,...path!==void 0?{sessionPath:path}:{},...name!==void 0?{name}:{},context:{}}}},NULL_CONNECTION="tui-null";function keyOf(connection){return`tui-${connection.id}`}import{randomUUID}from"node:crypto";import{realpathSync}from"node:fs";import{resolve}from"node:path";var TUI_RPC_COMMANDS=["open_session","subscribe_sessions","unsubscribe_sessions","steer","follow_up","prompt","get_effect_status"];async function runTuiRpcCommand(context,connection,command){switch(command.type){case"open_session":return openSession(context,connection,command);case"subscribe_sessions":return subscribe(context,connection,command);case"unsubscribe_sessions":return answerUnsubscribeSessions(command,keyOf(connection),context.attachments.writer.status);case"steer":case"follow_up":return admitInput(context,command,command.type==="steer"?"steer":"followUp",command.whenIdle);case"prompt":return admitPrompt(context,command);case"get_effect_status":return runGetEffectStatus({session:context.session,by:{connectionId:keyOf(connection)},sessionId:context.attachments.handle},command);default:return}}function idOf(command){return typeof command.id=="string"?command.id:void 0}function openSession(context,connection,command){let{session,attachments}=context,ownPath=typeof command.sessionPath=="string"&&samePath(command.sessionPath,session.sessionFile),ownId=command.sessionId!==void 0&&command.sessionId===session.sessionId;return!ownPath&&!ownId?refusal(idOf(command),"open_session","terminal_single_session",{reason:"this terminal hosts one session and the request names another",action:"open it by this terminal's sessionPath, or open the other session on a host"}):(attachments.run(connection,()=>{attachments.attach(connection),attachments.writer.enqueue(attachments.handle,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:attachments.handle,state:buildRpcSessionState(session),attached:!0}})}),null)}function subscribe(context,connection,command){let{writer}=context.attachments,key=keyOf(connection),{answer:answer2,activate}=answerSubscribeSessions(command,key,writer.status);return activate===void 0?answer2:(writer.enqueueControl(answer2,key).then(()=>{writer.hasConnection(key)?writer.status.activate(activate):writer.status.unsubscribe(key,activate)}).catch(()=>writer.status.unsubscribe(key,activate)),null)}function admitPrompt(context,command){let behavior=command.streamingBehavior;return behavior===void 0&&context.session.isStreaming?refusal(idOf(command),"prompt","session_busy",{reason:"a turn is running and the prompt names no streamingBehavior",action:'send it with streamingBehavior "steer" or "followUp", or as a steer/follow_up'}):admitInput(context,command,behavior==="followUp"?"followUp":"steer","start")}var UNSERVED_INPUT_FIELDS=["images","thinkingLevel","expandPromptTemplates","unknownCommandAsText","sessionTitlePrompt","enqueueOrder"];function samePath(requested,own){if(own===void 0)return!1;let canonical=path=>{try{return realpathSync(resolve(path))}catch{return resolve(path)}};return canonical(requested)===canonical(own)}function admitInput(context,command,deliverAs,whenIdle){let id=idOf(command),unserved=UNSERVED_INPUT_FIELDS.filter(field=>command[field]!==void 0);if(unserved.length>0)return refusal(id,command.type,"unsupported_field",{reason:`a terminal delivers input through its admission, which carries text only, not ${unserved.join(", ")}`,action:"send the message without those fields, or send it to a host session"});let message=command.message;if(typeof message!="string"||message.trim()==="")return refusal(id,command.type,"invalid_message",{reason:"message is empty",action:"send a non-empty message"});if(whenIdle!==void 0&&whenIdle!=="queue"&&whenIdle!=="start")return refusal(id,command.type,"invalid_when_idle",{reason:`whenIdle must be "queue" or "start", not ${JSON.stringify(whenIdle)}`,action:'send whenIdle: "queue" (the default) or "start"'});let admission=context.session.externalAdmission,clientMessageId=typeof command.clientMessageId=="string"?command.clientMessageId:void 0,expected=typeof command.expected_turn_id=="number"?command.expected_turn_id:admission.turnEpoch,result=admission.admit({delivery_id:clientMessageId??`tui-rpc-${randomUUID()}`,text:message,sender:{kind:"external",platform:"rpc"},deliverAs,expected_turn_id:expected,whenIdle:whenIdle==="start"?"start":"queue"}),identity=clientMessageId===void 0?{}:{clientMessageId};switch(result.kind){case"started":return answered(id,command.type,{disposition:"started",...identity});case"steered":case"queued":return answered(id,command.type,{disposition:"queued",...identity});case"already_admitted":return answered(id,command.type,{disposition:"queued",duplicate:!0,...identity});case"held_draft":return refusal(id,command.type,"held_draft",{reason:"the user is composing in this terminal, so nothing was delivered",action:"retry after the draft is sent or cleared"});case"turn_conflict":return refusal(id,command.type,"turn_conflict",{reason:`the turn moved on (now ${result.turn_epoch}); this steer named an earlier one`,action:"read get_state's turn_epoch and send it again"})}}function answered(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,data}}import{chmod}from"node:fs/promises";import{createServer}from"node:net";async function listenControlSocket(socketPath,secret,handlers){let clients=new Set,nextConnection=0,server=createServer(socket=>{clients.add(socket),socket.once("close",()=>clients.delete(socket)),socket.on("error",()=>socket.destroy()),authenticateSocket(socket,secret,()=>acceptConnection(socket,++nextConnection,handlers))});return await new Promise((resolve2,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve2()})}),server.on("error",error=>handlers.listenerError(error)),await chmod(socketPath,384),{close:()=>closeServer(server,clients)}}function acceptConnection(socket,id,handlers){let connection={id,send:record=>{handlers.respond!==void 0?handlers.respond(connection,record):socket.destroyed||socket.write(serializeJsonLine(record))},transport:socketSink(socket)};handlers.opened?.(connection);let detach=attachJsonlLineReader(socket,line=>{answer(connection,line,handlers)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>connection.send(failure(void 0,"parse","RPC line exceeds the size limit."))});socket.once("close",()=>{detach(),handlers.closed(connection)})}async function answer(connection,line,handlers){let parsed;try{parsed=JSON.parse(line)}catch{connection.send(failure(void 0,"parse","Invalid JSON."));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError!==void 0||!isCommand(parsed)){connection.send(failure(void 0,"parse",shapeError??"RPC command needs a string `type`."));return}let answer2=await handlers.command(connection,parsed);answer2!==null&&connection.send(answer2)}function isCommand(value){return typeof value=="object"&&value!==null&&"type"in value&&typeof value.type=="string"}function failure(id,command,error){return{...id===void 0?{}:{id},type:"response",command,success:!1,error}}function success(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,...data===void 0?{}:{data}}}function closeServer(server,clients){for(let client of clients)client.destroy();return new Promise(resolve2=>server.close(()=>resolve2()))}var SESSION_CONTROL_COMMANDS=["get_available_models","get_available_thinking_levels","set_model","set_thinking_level","interrupt"];async function runSessionControlCommand(session,controls,command){let{id,type}=command;switch(type){case"get_available_models":return success(id,type,await availableModelsData(session));case"get_available_thinking_levels":return success(id,type,{levels:session.getAvailableThinkingLevels()});case"set_model":return await setModel(session,controls,command);case"set_thinking_level":{let level=session.getAvailableThinkingLevels().find(candidate=>candidate===command.level);return level===void 0?failure(id,type,unsupportedThinkingLevel(command.level)):(controls.selectThinkingLevel(level,command.scope!=="turn"),success(id,type))}case"interrupt":return success(id,type,await interruptRunningTurn(session,command.turnId,()=>controls.interruptTurn()));default:return}}async function setModel(session,controls,command){let{id,type}=command,model=(await session.modelRegistry.getAvailable()).find(candidate=>candidate.provider===command.provider&&candidate.id===command.modelId);if(model===void 0)return failure(id,type,`Model not found: ${String(command.provider)}/${String(command.modelId)}`);try{let change=await controls.selectModel(model);return success(id,type,{...model,systemPromptName:change?.systemPromptName})}catch(error){return failure(id,type,error instanceof Error?error.message:String(error))}}var TUI_CONTROL_CAPABILITY="tui_control",TUI_CONTROL_COMMANDS=["get_protocol_info","list_sessions","get_state","get_messages","set_session_name","subscribe","wake","extension_ui_response",...SESSION_CONTROL_COMMANDS,...TUI_RPC_COMMANDS];async function runControlCommand(context,connection,command){let{id,type}=command,{session}=context;switch(type){case"get_protocol_info":{let build=engineBuildIdentity();return success(id,type,{protocolVersion:1,serverVersion:VERSION,capabilities:[TUI_CONTROL_CAPABILITY,SESSION_STATUS_CAPABILITY],mode:"tui",endpoint_kind:"tui",instanceId:context.instanceId,generation:0,engineVersion:build.text,engineOrdinal:build.ordinal,commands:TUI_CONTROL_COMMANDS})}case"list_sessions":return success(id,type,{sessions:[sessionRow(session)]});case"get_state":return success(id,type,{...buildRpcSessionState(session),turn_epoch:session.externalAdmission.turnEpoch,blocking_question:context.surface.blockingQuestion(),compacting:session.isCompacting,editor_has_draft:context.surface.draftHold()!==void 0,state_version:context.feed.stateVersion});case"get_messages":return success(id,type,{messages:session.messages});case"set_session_name":{let name=typeof command.name=="string"?command.name.trim():"";return name===""?failure(id,type,"Session name cannot be empty"):(session.setSessionName(name),success(id,type))}case"subscribe":{let cursor=typeof command.cursor=="number"?command.cursor:void 0;return success(id,type,{cursor:context.feed.subscribe(connection.id,cursor,connection.send)})}case"wake":{let ids=Array.isArray(command.delivery_ids)?command.delivery_ids.filter(entry=>typeof entry=="string"):void 0,result=await context.wake(ids);return success(id,type,{admitted:result.admitted??[]})}case"extension_ui_response":return answerQuestion(context.surface,command);default:{let rpc=await runTuiRpcCommand(context,connection,command);return rpc!==void 0?rpc:await runSessionControlCommand(session,context.surface,command)??failure(id,type,"unsupported")}}}function sessionRow(session){let manager=session.sessionManager,created=manager.getHeader()?.timestamp??null,last=manager.getEntries().at(-1);return{sessionId:session.sessionId,sessionPath:session.sessionFile??null,session_file:session.sessionFile??null,kind:"interactive",surface:"tui",cwd:manager.getCwd(),name:session.sessionName??null,created_at:created,updated_at:last?.timestamp??created,attachments:1}}function answerQuestion(surface,command){let frameId=command.id,requestId=answeredUiRequestId(command),request=requestId===void 0?void 0:surface.pendingQuestion(requestId);if(requestId===void 0||request===void 0)return failure(frameId,"extension_ui_response","unknown_request");let response=questionResponse(command,request.questions);return response==="question_incomplete"?failure(frameId,"extension_ui_response",response):response===void 0||!surface.answerQuestion(requestId,response)?failure(frameId,"extension_ui_response","invalid_response"):success(frameId,"extension_ui_response")}function questionResponse(command,questions){if(command.cancelled===!0)return{status:"cancelled",answers:{},unanswered:[]};let answers=command.answers;if(typeof answers!="object"||answers===null||Array.isArray(answers))return;let parsed={};for(let[question,value]of Object.entries(answers)){if(typeof value!="object"||value===null||!("selected"in value)||!Array.isArray(value.selected))return;let selected=value.selected.filter(entry=>typeof entry=="string"),text="text"in value&&typeof value.text=="string"?value.text:void 0;parsed[question]=text===void 0?{selected}:{selected,text}}let comment=typeof command.comment=="string"?command.comment:void 0,status=settledQuestionStatus(parsed,comment);if(status===void 0)return"question_incomplete";let unanswered=unansweredQuestionIds(questions,parsed);return{status,resolvedBy:"control_endpoint",answers:parsed,unanswered,...comment===void 0?{}:{comment}}}var ControlFeed=class{constructor(){this.seq=0,this.stateVersionValue=0,this.ring=[],this.subscribers=new Map}get stateVersion(){return this.stateVersionValue}publish(kind,data={}){kind==="state"&&(this.stateVersionValue+=1);let event={type:"session_control_event",seq:++this.seq,kind,data:kind==="state"?{...data,state_version:this.stateVersionValue}:data};this.ring.push(event),this.ring.length>256&&this.ring.shift();for(let send of this.subscribers.values())send(event)}subscribe(connection,cursor,send){if(this.subscribers.set(connection,send),cursor!==void 0)for(let event of this.ring)event.seq>cursor&&send(event);return this.seq}unsubscribe(connection){this.subscribers.delete(connection)}clear(){this.subscribers.clear()}};import{createHash}from"node:crypto";import{rmSync}from"node:fs";import{chmod as chmod2,lstat,mkdir,realpath,rm}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname,join}from"node:path";var PRIVATE_DIRECTORY_MODE=448,REGISTRY_LOCK_WAIT_MS=5e3;async function resolveTuiSocket(agentDir,instanceId){let name=tuiSocketName(instanceId),primary=join(agentDir,"rpc","tui",name);if(Buffer.byteLength(primary)<=MAX_SOCKET_PATH_BYTES)return await makePrivateDirectory(dirname(primary)),primary;let fallbackName=`senpi-rpc-${createHash("sha256").update(agentDir).digest("hex").slice(0,8)}`,scopedRoot=join(tmpdir(),fallbackName),root=Buffer.byteLength(join(scopedRoot,"tui",name))<=MAX_SOCKET_PATH_BYTES?scopedRoot:join("/tmp",fallbackName),tuiRoot=join(root,"tui");await makePrivateDirectory(tuiRoot);for(let directory of[root,tuiRoot])await assertPrivateDirectory(directory);let fallback=join(tuiRoot,name);if(Buffer.byteLength(fallback)>MAX_SOCKET_PATH_BYTES)throw new Error(`socket path ${fallback} exceeds ${MAX_SOCKET_PATH_BYTES} bytes`);return fallback}async function makePrivateDirectory(directory){await mkdir(directory,{recursive:!0,mode:PRIVATE_DIRECTORY_MODE}),await chmod2(directory,PRIVATE_DIRECTORY_MODE)}async function assertPrivateDirectory(directory){let stat=await lstat(await realpath(directory)),ownedByUs=process.getuid===void 0||stat.uid===process.getuid();if(!stat.isDirectory()||!ownedByUs||(stat.mode&63)!==0)throw new Error(`alt_root_unsafe: ${directory} is not a private directory of this user`)}async function registerTuiEndpoint(options){let paths=createHostDaemonPaths({socket:options.socket,agentDir:options.agentDir}),release=await acquireHostEnsureLock(options.socket,REGISTRY_LOCK_WAIT_MS);try{await writeHostRegistration(paths,{record:{pid:process.pid,processStartTime:await thisProcessStartTime()},socket:options.socket,instanceId:options.instanceId,generation:0,launchProfileId:"tui",build:engineBuildIdentity()},{fresh:!0}),await createDaemonDirectories(paths,{kind:"tui"})}finally{await release()}return{paths,socket:options.socket}}async function unregisterTuiEndpoint(entry){let release=await acquireHostEnsureLock(entry.socket,REGISTRY_LOCK_WAIT_MS).catch(()=>{});try{await rm(entry.socket,{force:!0}),await rm(socketSecretPath(entry.socket),{force:!0}),await rm(entry.paths.dir,{recursive:!0,force:!0})}finally{await release?.()}}function unregisterTuiEndpointSync(entry){rmSync(entry.socket,{force:!0}),rmSync(socketSecretPath(entry.socket),{force:!0}),rmSync(entry.paths.dir,{recursive:!0,force:!0})}var REPORT_TEXT_LIMIT=4e3;function activateControlEndpoint(parts){let{context,feed,wake}=parts,{session,surface}=context;session.externalAdmission.setEditorSource(()=>editorHold(context));let unsubscribeSession=session.subscribe(event=>{event.type==="agent_start"?feed.publish("state"):event.type==="agent_idle"?(feed.publish("completion",{turn_epoch:session.externalAdmission.turnEpoch}),feed.publish("state"),wake("idle")):event.type==="agent_end"||event.type==="queue_update"||event.type==="compaction_start"||event.type==="compaction_end"?feed.publish("state"):event.type==="message_end"&&event.message.role==="assistant"&&feed.publish("report",{text:assistantText(event.message).slice(0,REPORT_TEXT_LIMIT)})}),unsubscribeEmitted=session.externalAdmission.onEmitted(()=>{wake("emitted")}),unsubscribeInputs=session.externalAdmission.onInputsSettled(()=>queueMicrotask(()=>{wake("submission")})),stopContinue=onProcessContinue(()=>{wake("continue")}),exitCleanup=()=>unregisterTuiEndpointSync(parts.entry);process.once("exit",exitCleanup);let disposing,dispose=()=>(disposing??=(async()=>{process.removeListener("exit",exitCleanup),unsubscribeSession(),unsubscribeEmitted(),unsubscribeInputs(),stopContinue(),parts.stopInbox(),parts.scheduler.dispose(),feed.clear(),session.externalAdmission.setEditorSource(void 0),await parts.server.close(),await sessionReferenced(parts.options,surface)||await session.sessionManager.discardHeaderOnlyFile(),await unregisterTuiEndpoint(parts.entry)})(),disposing);return{socket:parts.entry.socket,wake:reason=>{wake(reason)},noteState:()=>feed.publish("state"),noteQuestions:()=>feed.publish("question",{pending:[...surface.pendingQuestionIds()]}),dispose}}function editorHold(context){let hold=context.surface.draftHold(),revision=context.editorRevision();return hold===void 0?{revision}:{hold_reason:hold,revision}}async function sessionReferenced(options,surface){if(options.isSessionReferenced===void 0)return!1;try{return await options.isSessionReferenced()}catch(error){return surface.notice(`control endpoint kept the session file: ${error instanceof Error?error.message:String(error)}`),!0}}function assistantText(message){return message.role!=="assistant"?"":message.content.flatMap(part=>part.type==="text"?[part.text]:[]).join(`
2
+ import{SessionEventWriter,answerSubscribeSessions,answerUnsubscribeSessions,refusal,sessionRuntimeView,socketSink}from"./chunk-QJ6MUFXY.js";import{WakeScheduler,answeredUiRequestId,availableModelsData,buildRpcSessionState,interruptRunningTurn,onProcessContinue,rpcCommandShapeError,runGetEffectStatus,settledQuestionStatus,subscribeSessionRecords,unansweredQuestionIds,unsupportedThinkingLevel,watchInbox}from"./chunk-ZPSJQHDK.js";import"./chunk-MF57DS3V.js";import"./chunk-QRGAMVEE.js";import"./chunk-YUMRZIKJ.js";import"./chunk-4RSWXPUB.js";import"./chunk-OJPUDLM2.js";import"./chunk-RL5QMGQD.js";import{SESSION_STATUS_CAPABILITY,acquireHostEnsureLock,engineBuildIdentity,gcHostEndpoints}from"./chunk-VEKNDMUA.js";import"./chunk-QMRJYMNH.js";import{tuiSocketName}from"./chunk-36GE6JDV.js";import"./chunk-HB35RBP4.js";import"./chunk-GZVCRV7I.js";import"./chunk-KUPQO7MC.js";import"./chunk-GOKAWZUO.js";import"./chunk-26UBFF6N.js";import"./chunk-PMGEQYEP.js";import{MAX_SOCKET_PATH_BYTES,thisProcessStartTime,writeHostRegistration}from"./chunk-VPV7ADF3.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,authenticateSocket,createDaemonDirectories,createHostDaemonPaths,createSocketSecret,serializeJsonLine,socketSecretPath}from"./chunk-XC2CNM26.js";import"./chunk-7ASLQ243.js";import"./chunk-U3VOXCGP.js";import"./chunk-2VZJTDUX.js";import"./chunk-YU2P3CAR.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-AUZXSLZN.js";import{VERSION}from"./chunk-G3ZEPNGM.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-T36LJ6MW.js";import"./chunk-WHPDEDCC.js";import"./chunk-RUGYFYH7.js";import"./chunk-QGJLZ6BI.js";import"./chunk-KRNXUTZJ.js";import"./chunk-UAQW2T7G.js";import"./chunk-HK46JMSC.js";import"./chunk-5ROMKDLK.js";import"./chunk-45SZOLCU.js";import"./chunk-3W47LTXQ.js";import"./chunk-WQLMQGOW.js";import"./chunk-WDTJ6JKE.js";import"./chunk-LAWS3FYQ.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";import{randomUUID as randomUUID2}from"node:crypto";import{rm as rm2}from"node:fs/promises";var ControlAttachments=class{constructor(session,pendingQuestions){this.writer=new SessionEventWriter(()=>{}),this.attached=new Set,this.session=session,this.writer.status.setSource({sessionIds:()=>[this.handle],entryView:id=>id===this.handle?this.entryView():void 0,view:id=>id===this.handle?{entry:this.entryView(),runtime:sessionRuntimeView(session,pendingQuestions())}:void 0}),this.writer.registerConnection(NULL_CONNECTION,{writeRaw:()=>{},waitForBackpressure:async()=>{}}),this.stopRecords=subscribeSessionRecords(session,record=>this.writer.enqueue(this.handle,record))}get handle(){return this.session.sessionId}opened(connection){this.writer.registerConnection(keyOf(connection),connection.transport)}closed(connection){let key=keyOf(connection);this.attached.delete(key)&&this.writer.status.publish(this.handle,"detach","client"),this.writer.unregisterConnection(key)}attach(connection){let key=keyOf(connection);return this.attached.has(key)?!1:(this.attached.add(key),this.writer.attachConnectionToSession(key,this.handle),this.writer.status.publish(this.handle,"attach","client"),!0)}isAttached(connection){return this.attached.has(keyOf(connection))}run(connection,task){return this.writer.withConnection(keyOf(connection),task)}respond(connection,answer2){this.writer.enqueueControl(answer2,keyOf(connection)).catch(()=>connection.transport.close?.())}dispose(){this.stopRecords()}entryView(){let manager=this.session.sessionManager,path=this.session.sessionFile,name=manager.getSessionName();return{state:"open",kind:"interactive",cwd:manager.getCwd(),attachments:1+this.attached.size,durableSessionId:this.session.sessionId,...path!==void 0?{sessionPath:path}:{},...name!==void 0?{name}:{},context:{}}}},NULL_CONNECTION="tui-null";function keyOf(connection){return`tui-${connection.id}`}import{randomUUID}from"node:crypto";import{realpathSync}from"node:fs";import{resolve}from"node:path";var TUI_RPC_COMMANDS=["open_session","subscribe_sessions","unsubscribe_sessions","steer","follow_up","prompt","get_effect_status"];async function runTuiRpcCommand(context,connection,command){switch(command.type){case"open_session":return openSession(context,connection,command);case"subscribe_sessions":return subscribe(context,connection,command);case"unsubscribe_sessions":return answerUnsubscribeSessions(command,keyOf(connection),context.attachments.writer.status);case"steer":case"follow_up":return admitInput(context,command,command.type==="steer"?"steer":"followUp",command.whenIdle);case"prompt":return admitPrompt(context,command);case"get_effect_status":return runGetEffectStatus({session:context.session,by:{connectionId:keyOf(connection)},sessionId:context.attachments.handle},command);default:return}}function idOf(command){return typeof command.id=="string"?command.id:void 0}function openSession(context,connection,command){let{session,attachments}=context,ownPath=typeof command.sessionPath=="string"&&samePath(command.sessionPath,session.sessionFile),ownId=command.sessionId!==void 0&&command.sessionId===session.sessionId;return!ownPath&&!ownId?refusal(idOf(command),"open_session","terminal_single_session",{reason:"this terminal hosts one session and the request names another",action:"open it by this terminal's sessionPath, or open the other session on a host"}):(attachments.run(connection,()=>{attachments.attach(connection),attachments.writer.enqueue(attachments.handle,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:attachments.handle,state:buildRpcSessionState(session),attached:!0}})}),null)}function subscribe(context,connection,command){let{writer}=context.attachments,key=keyOf(connection),{answer:answer2,activate}=answerSubscribeSessions(command,key,writer.status);return activate===void 0?answer2:(writer.enqueueControl(answer2,key).then(()=>{writer.hasConnection(key)?writer.status.activate(activate):writer.status.unsubscribe(key,activate)}).catch(()=>writer.status.unsubscribe(key,activate)),null)}function admitPrompt(context,command){let behavior=command.streamingBehavior;return behavior===void 0&&context.session.isStreaming?refusal(idOf(command),"prompt","session_busy",{reason:"a turn is running and the prompt names no streamingBehavior",action:'send it with streamingBehavior "steer" or "followUp", or as a steer/follow_up'}):admitInput(context,command,behavior==="followUp"?"followUp":"steer","start")}var UNSERVED_INPUT_FIELDS=["images","thinkingLevel","expandPromptTemplates","unknownCommandAsText","sessionTitlePrompt","enqueueOrder"];function samePath(requested,own){if(own===void 0)return!1;let canonical=path=>{try{return realpathSync(resolve(path))}catch{return resolve(path)}};return canonical(requested)===canonical(own)}function admitInput(context,command,deliverAs,whenIdle){let id=idOf(command),unserved=UNSERVED_INPUT_FIELDS.filter(field=>command[field]!==void 0);if(unserved.length>0)return refusal(id,command.type,"unsupported_field",{reason:`a terminal delivers input through its admission, which carries text only, not ${unserved.join(", ")}`,action:"send the message without those fields, or send it to a host session"});let message=command.message;if(typeof message!="string"||message.trim()==="")return refusal(id,command.type,"invalid_message",{reason:"message is empty",action:"send a non-empty message"});if(whenIdle!==void 0&&whenIdle!=="queue"&&whenIdle!=="start")return refusal(id,command.type,"invalid_when_idle",{reason:`whenIdle must be "queue" or "start", not ${JSON.stringify(whenIdle)}`,action:'send whenIdle: "queue" (the default) or "start"'});let admission=context.session.externalAdmission,clientMessageId=typeof command.clientMessageId=="string"?command.clientMessageId:void 0,expected=typeof command.expected_turn_id=="number"?command.expected_turn_id:admission.turnEpoch,result=admission.admit({delivery_id:clientMessageId??`tui-rpc-${randomUUID()}`,text:message,sender:{kind:"external",platform:"rpc"},deliverAs,expected_turn_id:expected,whenIdle:whenIdle==="start"?"start":"queue"}),identity=clientMessageId===void 0?{}:{clientMessageId};switch(result.kind){case"started":return answered(id,command.type,{disposition:"started",...identity});case"steered":case"queued":return answered(id,command.type,{disposition:"queued",...identity});case"already_admitted":return answered(id,command.type,{disposition:"queued",duplicate:!0,...identity});case"held_draft":return refusal(id,command.type,"held_draft",{reason:"the user is composing in this terminal, so nothing was delivered",action:"retry after the draft is sent or cleared"});case"turn_conflict":return refusal(id,command.type,"turn_conflict",{reason:`the turn moved on (now ${result.turn_epoch}); this steer named an earlier one`,action:"read get_state's turn_epoch and send it again"})}}function answered(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,data}}import{chmod}from"node:fs/promises";import{createServer}from"node:net";async function listenControlSocket(socketPath,secret,handlers){let clients=new Set,nextConnection=0,server=createServer(socket=>{clients.add(socket),socket.once("close",()=>clients.delete(socket)),socket.on("error",()=>socket.destroy()),authenticateSocket(socket,secret,()=>acceptConnection(socket,++nextConnection,handlers))});return await new Promise((resolve2,reject)=>{server.once("error",reject),server.listen(socketPath,()=>{server.off("error",reject),resolve2()})}),server.on("error",error=>handlers.listenerError(error)),await chmod(socketPath,384),{close:()=>closeServer(server,clients)}}function acceptConnection(socket,id,handlers){let connection={id,send:record=>{handlers.respond!==void 0?handlers.respond(connection,record):socket.destroyed||socket.write(serializeJsonLine(record))},transport:socketSink(socket)};handlers.opened?.(connection);let detach=attachJsonlLineReader(socket,line=>{answer(connection,line,handlers)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>connection.send(failure(void 0,"parse","RPC line exceeds the size limit."))});socket.once("close",()=>{detach(),handlers.closed(connection)})}async function answer(connection,line,handlers){let parsed;try{parsed=JSON.parse(line)}catch{connection.send(failure(void 0,"parse","Invalid JSON."));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError!==void 0||!isCommand(parsed)){connection.send(failure(void 0,"parse",shapeError??"RPC command needs a string `type`."));return}let answer2=await handlers.command(connection,parsed);answer2!==null&&connection.send(answer2)}function isCommand(value){return typeof value=="object"&&value!==null&&"type"in value&&typeof value.type=="string"}function failure(id,command,error){return{...id===void 0?{}:{id},type:"response",command,success:!1,error}}function success(id,command,data){return{...id===void 0?{}:{id},type:"response",command,success:!0,...data===void 0?{}:{data}}}function closeServer(server,clients){for(let client of clients)client.destroy();return new Promise(resolve2=>server.close(()=>resolve2()))}var SESSION_CONTROL_COMMANDS=["get_available_models","get_available_thinking_levels","set_model","set_thinking_level","interrupt"];async function runSessionControlCommand(session,controls,command){let{id,type}=command;switch(type){case"get_available_models":return success(id,type,await availableModelsData(session));case"get_available_thinking_levels":return success(id,type,{levels:session.getAvailableThinkingLevels()});case"set_model":return await setModel(session,controls,command);case"set_thinking_level":{let level=session.getAvailableThinkingLevels().find(candidate=>candidate===command.level);return level===void 0?failure(id,type,unsupportedThinkingLevel(command.level)):(controls.selectThinkingLevel(level,command.scope!=="turn"),success(id,type))}case"interrupt":return success(id,type,await interruptRunningTurn(session,command.turnId,()=>controls.interruptTurn()));default:return}}async function setModel(session,controls,command){let{id,type}=command,model=(await session.modelRegistry.getAvailable()).find(candidate=>candidate.provider===command.provider&&candidate.id===command.modelId);if(model===void 0)return failure(id,type,`Model not found: ${String(command.provider)}/${String(command.modelId)}`);try{let change=await controls.selectModel(model);return success(id,type,{...model,systemPromptName:change?.systemPromptName})}catch(error){return failure(id,type,error instanceof Error?error.message:String(error))}}var TUI_CONTROL_CAPABILITY="tui_control",TUI_CONTROL_COMMANDS=["get_protocol_info","list_sessions","get_state","get_messages","set_session_name","subscribe","wake","extension_ui_response",...SESSION_CONTROL_COMMANDS,...TUI_RPC_COMMANDS];async function runControlCommand(context,connection,command){let{id,type}=command,{session}=context;switch(type){case"get_protocol_info":{let build=engineBuildIdentity();return success(id,type,{protocolVersion:1,serverVersion:VERSION,capabilities:[TUI_CONTROL_CAPABILITY,SESSION_STATUS_CAPABILITY],mode:"tui",endpoint_kind:"tui",instanceId:context.instanceId,generation:0,engineVersion:build.text,engineOrdinal:build.ordinal,commands:TUI_CONTROL_COMMANDS})}case"list_sessions":return success(id,type,{sessions:[sessionRow(session)]});case"get_state":return success(id,type,{...buildRpcSessionState(session),turn_epoch:session.externalAdmission.turnEpoch,blocking_question:context.surface.blockingQuestion(),compacting:session.isCompacting,editor_has_draft:context.surface.draftHold()!==void 0,state_version:context.feed.stateVersion});case"get_messages":return success(id,type,{messages:session.messages});case"set_session_name":{let name=typeof command.name=="string"?command.name.trim():"";return name===""?failure(id,type,"Session name cannot be empty"):(session.setSessionName(name),success(id,type))}case"subscribe":{let cursor=typeof command.cursor=="number"?command.cursor:void 0;return success(id,type,{cursor:context.feed.subscribe(connection.id,cursor,connection.send)})}case"wake":{let ids=Array.isArray(command.delivery_ids)?command.delivery_ids.filter(entry=>typeof entry=="string"):void 0,result=await context.wake(ids);return success(id,type,{admitted:result.admitted??[]})}case"extension_ui_response":return answerQuestion(context.surface,command);default:{let rpc=await runTuiRpcCommand(context,connection,command);return rpc!==void 0?rpc:await runSessionControlCommand(session,context.surface,command)??failure(id,type,"unsupported")}}}function sessionRow(session){let manager=session.sessionManager,created=manager.getHeader()?.timestamp??null,last=manager.getEntries().at(-1);return{sessionId:session.sessionId,sessionPath:session.sessionFile??null,session_file:session.sessionFile??null,kind:"interactive",surface:"tui",cwd:manager.getCwd(),name:session.sessionName??null,created_at:created,updated_at:last?.timestamp??created,attachments:1}}function answerQuestion(surface,command){let frameId=command.id,requestId=answeredUiRequestId(command),request=requestId===void 0?void 0:surface.pendingQuestion(requestId);if(requestId===void 0||request===void 0)return failure(frameId,"extension_ui_response","unknown_request");let response=questionResponse(command,request.questions);return response==="question_incomplete"?failure(frameId,"extension_ui_response",response):response===void 0||!surface.answerQuestion(requestId,response)?failure(frameId,"extension_ui_response","invalid_response"):success(frameId,"extension_ui_response")}function questionResponse(command,questions){if(command.cancelled===!0)return{status:"cancelled",answers:{},unanswered:[]};let answers=command.answers;if(typeof answers!="object"||answers===null||Array.isArray(answers))return;let parsed={};for(let[question,value]of Object.entries(answers)){if(typeof value!="object"||value===null||!("selected"in value)||!Array.isArray(value.selected))return;let selected=value.selected.filter(entry=>typeof entry=="string"),text="text"in value&&typeof value.text=="string"?value.text:void 0;parsed[question]=text===void 0?{selected}:{selected,text}}let comment=typeof command.comment=="string"?command.comment:void 0,status=settledQuestionStatus(parsed,comment);if(status===void 0)return"question_incomplete";let unanswered=unansweredQuestionIds(questions,parsed);return{status,resolvedBy:"control_endpoint",answers:parsed,unanswered,...comment===void 0?{}:{comment}}}var ControlFeed=class{constructor(){this.seq=0,this.stateVersionValue=0,this.ring=[],this.subscribers=new Map}get stateVersion(){return this.stateVersionValue}publish(kind,data={}){kind==="state"&&(this.stateVersionValue+=1);let event={type:"session_control_event",seq:++this.seq,kind,data:kind==="state"?{...data,state_version:this.stateVersionValue}:data};this.ring.push(event),this.ring.length>256&&this.ring.shift();for(let send of this.subscribers.values())send(event)}subscribe(connection,cursor,send){if(this.subscribers.set(connection,send),cursor!==void 0)for(let event of this.ring)event.seq>cursor&&send(event);return this.seq}unsubscribe(connection){this.subscribers.delete(connection)}clear(){this.subscribers.clear()}};import{createHash}from"node:crypto";import{rmSync}from"node:fs";import{chmod as chmod2,lstat,mkdir,realpath,rm}from"node:fs/promises";import{tmpdir}from"node:os";import{dirname,join}from"node:path";var PRIVATE_DIRECTORY_MODE=448,REGISTRY_LOCK_WAIT_MS=5e3;async function resolveTuiSocket(agentDir,instanceId){let name=tuiSocketName(instanceId),primary=join(agentDir,"rpc","tui",name);if(Buffer.byteLength(primary)<=MAX_SOCKET_PATH_BYTES)return await makePrivateDirectory(dirname(primary)),primary;let fallbackName=`senpi-rpc-${createHash("sha256").update(agentDir).digest("hex").slice(0,8)}`,scopedRoot=join(tmpdir(),fallbackName),root=Buffer.byteLength(join(scopedRoot,"tui",name))<=MAX_SOCKET_PATH_BYTES?scopedRoot:join("/tmp",fallbackName),tuiRoot=join(root,"tui");await makePrivateDirectory(tuiRoot);for(let directory of[root,tuiRoot])await assertPrivateDirectory(directory);let fallback=join(tuiRoot,name);if(Buffer.byteLength(fallback)>MAX_SOCKET_PATH_BYTES)throw new Error(`socket path ${fallback} exceeds ${MAX_SOCKET_PATH_BYTES} bytes`);return fallback}async function makePrivateDirectory(directory){await mkdir(directory,{recursive:!0,mode:PRIVATE_DIRECTORY_MODE}),await chmod2(directory,PRIVATE_DIRECTORY_MODE)}async function assertPrivateDirectory(directory){let stat=await lstat(await realpath(directory)),ownedByUs=process.getuid===void 0||stat.uid===process.getuid();if(!stat.isDirectory()||!ownedByUs||(stat.mode&63)!==0)throw new Error(`alt_root_unsafe: ${directory} is not a private directory of this user`)}async function registerTuiEndpoint(options){let paths=createHostDaemonPaths({socket:options.socket,agentDir:options.agentDir}),release=await acquireHostEnsureLock(options.socket,REGISTRY_LOCK_WAIT_MS);try{await writeHostRegistration(paths,{record:{pid:process.pid,processStartTime:await thisProcessStartTime()},socket:options.socket,instanceId:options.instanceId,generation:0,launchProfileId:"tui",build:engineBuildIdentity()},{fresh:!0}),await createDaemonDirectories(paths,{kind:"tui"})}finally{await release()}return{paths,socket:options.socket}}async function unregisterTuiEndpoint(entry){let release=await acquireHostEnsureLock(entry.socket,REGISTRY_LOCK_WAIT_MS).catch(()=>{});try{await rm(entry.socket,{force:!0}),await rm(socketSecretPath(entry.socket),{force:!0}),await rm(entry.paths.dir,{recursive:!0,force:!0})}finally{await release?.()}}function unregisterTuiEndpointSync(entry){rmSync(entry.socket,{force:!0}),rmSync(socketSecretPath(entry.socket),{force:!0}),rmSync(entry.paths.dir,{recursive:!0,force:!0})}var REPORT_TEXT_LIMIT=4e3;function activateControlEndpoint(parts){let{context,feed,wake}=parts,{session,surface}=context;session.externalAdmission.setEditorSource(()=>editorHold(context));let unsubscribeSession=session.subscribe(event=>{event.type==="agent_start"?feed.publish("state"):event.type==="agent_idle"?(feed.publish("completion",{turn_epoch:session.externalAdmission.turnEpoch}),feed.publish("state"),wake("idle")):event.type==="agent_end"||event.type==="queue_update"||event.type==="compaction_start"||event.type==="compaction_end"?feed.publish("state"):event.type==="message_end"&&event.message.role==="assistant"&&feed.publish("report",{text:assistantText(event.message).slice(0,REPORT_TEXT_LIMIT)})}),unsubscribeEmitted=session.externalAdmission.onEmitted(()=>{wake("emitted")}),unsubscribeInputs=session.externalAdmission.onInputsSettled(()=>queueMicrotask(()=>{wake("submission")})),stopContinue=onProcessContinue(()=>{wake("continue")}),exitCleanup=()=>unregisterTuiEndpointSync(parts.entry);process.once("exit",exitCleanup);let disposing,dispose=()=>(disposing??=(async()=>{process.removeListener("exit",exitCleanup),unsubscribeSession(),unsubscribeEmitted(),unsubscribeInputs(),stopContinue(),parts.stopInbox(),parts.scheduler.dispose(),feed.clear(),session.externalAdmission.setEditorSource(void 0),await parts.server.close(),await sessionReferenced(parts.options,surface)||await session.sessionManager.discardHeaderOnlyFile(),await unregisterTuiEndpoint(parts.entry)})(),disposing);return{socket:parts.entry.socket,wake:reason=>{wake(reason)},noteState:()=>feed.publish("state"),noteQuestions:()=>feed.publish("question",{pending:[...surface.pendingQuestionIds()]}),dispose}}function editorHold(context){let hold=context.surface.draftHold(),revision=context.editorRevision();return hold===void 0?{revision}:{hold_reason:hold,revision}}async function sessionReferenced(options,surface){if(options.isSessionReferenced===void 0)return!1;try{return await options.isSessionReferenced()}catch(error){return surface.notice(`control endpoint kept the session file: ${error instanceof Error?error.message:String(error)}`),!0}}function assistantText(message){return message.role!=="assistant"?"":message.content.flatMap(part=>part.type==="text"?[part.text]:[]).join(`
3
3
  `)}async function registerSessionControlEndpoint(context,options){let cleanups=[];try{let endpoint=await openEndpoint(context,options,cleanups);return{registration:{status:"registered",socket:endpoint.socket,dispose:endpoint.dispose},endpoint}}catch(error){for(let cleanup of cleanups.reverse())await Promise.resolve(cleanup()).catch(()=>{});let reason=errorText(error);return context.surface.notice(`control endpoint unavailable: ${reason}`),{registration:{status:"failed",reason}}}}async function openEndpoint(context,options,cleanups){let{session,agentDir,surface}=context;thisProcessStartTime();let headerDurable=session.sessionManager.persistHeaderNow();headerDurable.catch(()=>{});let instanceId=randomUUID2(),socket=await resolveTuiSocket(agentDir,instanceId);cleanups.push(()=>rm2(socket,{force:!0}),()=>rm2(socketSecretPath(socket),{force:!0}));let secret=await createSocketSecret(socketSecretPath(socket)),feed=new ControlFeed,scheduler=new WakeScheduler(async event=>(await session.extensionRunner.emit(event),await options.drain(event)??{admitted:[]}),error=>surface.notice(`control endpoint drain failed: ${errorText(error)}`));cleanups.push(()=>scheduler.dispose());let wake=(reason,ids)=>scheduler.request(reason,ids),attachments=new ControlAttachments(session,()=>surface.pendingQuestionIds().length);cleanups.push(()=>attachments.dispose());let commandContext={instanceId,session,surface,feed,wake:ids=>wake("command",ids),attachments},server=await listenControlSocket(socket,secret,{command:(connection,command)=>runControlCommand(commandContext,connection,command),opened:connection=>attachments.opened(connection),respond:(connection,answer2)=>attachments.respond(connection,answer2),closed:connection=>{feed.unsubscribe(connection.id),attachments.closed(connection)},listenerError:error=>surface.notice(`control endpoint listener failed: ${error.message}`)});cleanups.push(()=>server.close()),await headerDurable;let entry=await registerTuiEndpoint({agentDir,socket,instanceId});cleanups.push(()=>unregisterTuiEndpoint(entry));let inbox=await watchInbox(options.inboxDir,()=>{wake("inbox")},error=>surface.notice(`control endpoint inbox watch failed: ${errorText(error)}`));cleanups.push(()=>inbox.stop());let endpoint=activateControlEndpoint({context,options,entry,server,scheduler,feed,stopInbox:inbox.stop,wake});return endpoint.wake("inbox"),inbox.armed.then(()=>endpoint.wake("inbox")),setImmediate(()=>{gcHostEndpoints(agentDir,{kinds:["tui"]}).catch(error=>surface.notice(`control endpoint gc of dead terminals failed: ${errorText(error)}`))}),endpoint}function errorText(error){return error instanceof Error?error.message:String(error)}export{registerSessionControlEndpoint};
@@ -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{SessionSelectorComponent,createStartupTui,startStartupTui}from"./chunk-Z2LCTXS2.js";import{KeybindingsManager}from"./chunk-IDXW4FAO.js";import"./chunk-FZTO2ICI.js";import"./chunk-PKDWFVE4.js";import"./chunk-4RSWXPUB.js";import"./chunk-OJPUDLM2.js";import{setKeybindings}from"./chunk-UUMKAA7S.js";import"./chunk-QMRJYMNH.js";import"./chunk-SMIIHUSE.js";import"./chunk-YU4AYH4C.js";import"./chunk-7X72IACK.js";import"./chunk-GZVCRV7I.js";import"./chunk-26UBFF6N.js";import"./chunk-OOWML2KE.js";import"./chunk-U3VOXCGP.js";import"./chunk-2VZJTDUX.js";import"./chunk-YU2P3CAR.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-AUZXSLZN.js";import"./chunk-ZOFZRJSL.js";import"./chunk-G3ZEPNGM.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-COJK5FDH.js";import"./chunk-WHPDEDCC.js";import"./chunk-PFNBY43W.js";import"./chunk-UAQW2T7G.js";import"./chunk-HK46JMSC.js";import"./chunk-5ROMKDLK.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-3W47LTXQ.js";import"./chunk-WQLMQGOW.js";import"./chunk-WDTJ6JKE.js";import"./chunk-LAWS3FYQ.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";async function selectSession(currentSessionsLoader,allSessionsLoader,settingsManager){let ui=await createStartupTui(settingsManager);return new Promise(resolve=>{let keybindings=KeybindingsManager.create();setKeybindings(keybindings);let resolved=!1,selector=new SessionSelectorComponent(currentSessionsLoader,allSessionsLoader,path=>{resolved||(resolved=!0,ui.stop(),resolve(path))},()=>{resolved||(resolved=!0,ui.stop(),resolve(null))},()=>{ui.stop(),process.exit(0)},()=>ui.requestRender(),{showRenameHint:!1,keybindings});ui.addChild(selector),ui.setFocus(selector.getSessionList()),startStartupTui(ui,settingsManager)})}export{selectSession};
2
+ import{SessionSelectorComponent,createStartupTui,startStartupTui}from"./chunk-G7LLAQXI.js";import{KeybindingsManager}from"./chunk-3DNYAO3P.js";import"./chunk-QRGAMVEE.js";import"./chunk-YUMRZIKJ.js";import"./chunk-4RSWXPUB.js";import"./chunk-OJPUDLM2.js";import{setKeybindings}from"./chunk-RL5QMGQD.js";import"./chunk-QMRJYMNH.js";import"./chunk-SMIIHUSE.js";import"./chunk-YU4AYH4C.js";import"./chunk-7X72IACK.js";import"./chunk-GZVCRV7I.js";import"./chunk-26UBFF6N.js";import"./chunk-PMGEQYEP.js";import"./chunk-U3VOXCGP.js";import"./chunk-2VZJTDUX.js";import"./chunk-YU2P3CAR.js";import"./chunk-COH5F7QV.js";import"./chunk-RFB5CBW7.js";import"./chunk-AUZXSLZN.js";import"./chunk-ZOFZRJSL.js";import"./chunk-G3ZEPNGM.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-T36LJ6MW.js";import"./chunk-WHPDEDCC.js";import"./chunk-QGJLZ6BI.js";import"./chunk-UAQW2T7G.js";import"./chunk-HK46JMSC.js";import"./chunk-5ROMKDLK.js";import"./chunk-45SZOLCU.js";import"./chunk-PELNNWGO.js";import"./chunk-3W47LTXQ.js";import"./chunk-WQLMQGOW.js";import"./chunk-WDTJ6JKE.js";import"./chunk-LAWS3FYQ.js";import"./chunk-DMI55M2N.js";import"./chunk-PJ34QVL5.js";import"./chunk-IKOFCODM.js";async function selectSession(currentSessionsLoader,allSessionsLoader,settingsManager){let ui=await createStartupTui(settingsManager);return new Promise(resolve=>{let keybindings=KeybindingsManager.create();setKeybindings(keybindings);let resolved=!1,selector=new SessionSelectorComponent(currentSessionsLoader,allSessionsLoader,path=>{resolved||(resolved=!0,ui.stop(),resolve(path))},()=>{resolved||(resolved=!0,ui.stop(),resolve(null))},()=>{ui.stop(),process.exit(0)},()=>ui.requestRender(),{showRenameHint:!1,keybindings});ui.addChild(selector),ui.setFocus(selector.getSessionList()),startStartupTui(ui,settingsManager)})}export{selectSession};