@code-yeongyu/senpi 2026.9.27-4 → 2026.9.28-2

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 (294) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/dist/bundle/chunks/{app-server-command-3GVJZFFH.js → app-server-command-H6LFICZ2.js} +1 -1
  3. package/dist/bundle/chunks/{azure-openai-responses-4SUOOZZ4.js → azure-openai-responses-FCZNBRWE.js} +1 -1
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  5. package/dist/bundle/chunks/{chunk-PSCNHY7D.js → chunk-3GMFUEU7.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-HBG6SQU5.js → chunk-62XHQXCZ.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-EJKCBRYK.js → chunk-6BWCPOCV.js} +4 -4
  8. package/dist/bundle/chunks/{chunk-SLL375O7.js → chunk-6VD3EBQE.js} +1 -1
  9. package/dist/bundle/chunks/chunk-7YUGCTEV.js +15 -0
  10. package/dist/bundle/chunks/{chunk-FWBSGMAE.js → chunk-A4UMPXQF.js} +1 -1
  11. package/dist/bundle/chunks/chunk-BBK6SSYT.js +2 -0
  12. package/dist/bundle/chunks/{chunk-C2425O2Q.js → chunk-CNQ4JB45.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-27IFXX3B.js → chunk-DRN4FQCE.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-22MGY5JQ.js → chunk-EHSZ7UCW.js} +1 -1
  15. package/dist/bundle/chunks/chunk-FHJYIU3U.js +5 -0
  16. package/dist/bundle/chunks/chunk-GJUCSTAG.js +19 -0
  17. package/dist/bundle/chunks/chunk-KOPTADA3.js +8 -0
  18. package/dist/bundle/chunks/{chunk-VMKAYXHL.js → chunk-LSW7QSLV.js} +31 -26
  19. package/dist/bundle/chunks/{chunk-2BMD37YV.js → chunk-LUPPSEQW.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-NRGMT74E.js → chunk-QOVUQZO4.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-IKXPBYSO.js → chunk-SICBVLRH.js} +1 -1
  22. package/dist/bundle/chunks/chunk-SN4ZHPMN.js +135 -0
  23. package/dist/bundle/chunks/{chunk-MUTD2NOH.js → chunk-TFA3YAJK.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-4T4GFAGK.js → chunk-VFSXUT7K.js} +1 -1
  25. package/dist/bundle/chunks/{cli-main-66NFBKVH.js → cli-main-GYRTYPMG.js} +1 -1
  26. package/dist/bundle/chunks/{google-generative-ai-ZTGKZTGU.js → google-generative-ai-LFCBHG3Y.js} +1 -1
  27. package/dist/bundle/chunks/{google-vertex-CCZ376YK.js → google-vertex-C474FXU7.js} +1 -1
  28. package/dist/bundle/chunks/{help-fast-path-NZ3I2UEN.js → help-fast-path-3U3YDEZ6.js} +1 -1
  29. package/dist/bundle/chunks/{host-command-RORPAC5X.js → host-command-6CJ7YM6W.js} +1 -1
  30. package/dist/bundle/chunks/{host-lifecycle-UDMJGLOR.js → host-lifecycle-RZIMOFDM.js} +1 -1
  31. package/dist/bundle/chunks/host-lifecycle.js +6 -6
  32. package/dist/bundle/chunks/interactive-host-runtime-A3GEIFTU.js +4 -0
  33. package/dist/bundle/chunks/{interactive-mode-LOAADKLH.js → interactive-mode-LX665HTP.js} +1 -1
  34. package/dist/bundle/chunks/{list-tips-S5CANO5W.js → list-tips-S4U7TKER.js} +1 -1
  35. package/dist/bundle/chunks/multi-session-host-MFTUM6XQ.js +21 -0
  36. package/dist/bundle/chunks/{openai-codex-responses-YSGZZDD5.js → openai-codex-responses-2LDIFL6Z.js} +1 -1
  37. package/dist/bundle/chunks/{openai-completions-KWHRWCBN.js → openai-completions-7KZLPKYP.js} +1 -1
  38. package/dist/bundle/chunks/{openai-images-6U5FCN5S.js → openai-images-I7DR7ERP.js} +1 -1
  39. package/dist/bundle/chunks/{openai-responses-7PWMBGYX.js → openai-responses-LCHS3AF3.js} +1 -1
  40. package/dist/bundle/chunks/{openrouter-images-QIKWQZUD.js → openrouter-images-IPNDRK6C.js} +1 -1
  41. package/dist/bundle/chunks/{package-manager-cli-5EEDA35I.js → package-manager-cli-6IAE5WG3.js} +1 -1
  42. package/dist/bundle/chunks/{rotation-stream-KZG4OVR7.js → rotation-stream-ZVJEGA2G.js} +1 -1
  43. package/dist/bundle/chunks/{rpc-mode-HOEA5NGQ.js → rpc-mode-XN3HNZMH.js} +1 -1
  44. package/dist/bundle/chunks/session-picker-FPKB4DAC.js +2 -0
  45. package/dist/bundle/chunks/session-worker.js +318 -309
  46. package/dist/bundle/cli.js +1 -1
  47. package/dist/bundle/index.js +1 -1
  48. package/dist/bundle/rpc-entry.js +1 -1
  49. package/dist/cli/args.js +1 -1
  50. package/dist/cli/args.js.map +1 -1
  51. package/dist/cli/host-command.d.ts +8 -1
  52. package/dist/cli/host-command.d.ts.map +1 -1
  53. package/dist/cli/host-command.js +66 -14
  54. package/dist/cli/host-command.js.map +1 -1
  55. package/dist/core/agent-session.d.ts +18 -1
  56. package/dist/core/agent-session.d.ts.map +1 -1
  57. package/dist/core/agent-session.js +119 -3
  58. package/dist/core/agent-session.js.map +1 -1
  59. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +2 -2
  60. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
  61. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +13 -5
  62. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
  63. package/dist/core/extensions/builtin/tool-search/native-search.d.ts.map +1 -1
  64. package/dist/core/extensions/builtin/tool-search/native-search.js +13 -1
  65. package/dist/core/extensions/builtin/tool-search/native-search.js.map +1 -1
  66. package/dist/core/retry-fallback/candidates.d.ts +26 -0
  67. package/dist/core/retry-fallback/candidates.d.ts.map +1 -0
  68. package/dist/core/retry-fallback/candidates.js +41 -0
  69. package/dist/core/retry-fallback/candidates.js.map +1 -0
  70. package/dist/core/retry-fallback/circuit-probes.d.ts +30 -0
  71. package/dist/core/retry-fallback/circuit-probes.d.ts.map +1 -0
  72. package/dist/core/retry-fallback/circuit-probes.js +60 -0
  73. package/dist/core/retry-fallback/circuit-probes.js.map +1 -0
  74. package/dist/core/retry-fallback/circuit.d.ts +101 -0
  75. package/dist/core/retry-fallback/circuit.d.ts.map +1 -0
  76. package/dist/core/retry-fallback/circuit.js +175 -0
  77. package/dist/core/retry-fallback/circuit.js.map +1 -0
  78. package/dist/core/retry-fallback/controller-types.d.ts +58 -0
  79. package/dist/core/retry-fallback/controller-types.d.ts.map +1 -0
  80. package/dist/core/retry-fallback/controller-types.js +2 -0
  81. package/dist/core/retry-fallback/controller-types.js.map +1 -0
  82. package/dist/core/retry-fallback/controller.d.ts +21 -49
  83. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  84. package/dist/core/retry-fallback/controller.js +88 -42
  85. package/dist/core/retry-fallback/controller.js.map +1 -1
  86. package/dist/core/sdk.d.ts.map +1 -1
  87. package/dist/core/sdk.js +25 -17
  88. package/dist/core/sdk.js.map +1 -1
  89. package/dist/core/session-failure-report.d.ts +33 -0
  90. package/dist/core/session-failure-report.d.ts.map +1 -0
  91. package/dist/core/session-failure-report.js +62 -0
  92. package/dist/core/session-failure-report.js.map +1 -0
  93. package/dist/core/settings-manager.d.ts +3 -0
  94. package/dist/core/settings-manager.d.ts.map +1 -1
  95. package/dist/core/settings-manager.js +4 -0
  96. package/dist/core/settings-manager.js.map +1 -1
  97. package/dist/core/slash-commands.d.ts.map +1 -1
  98. package/dist/core/slash-commands.js +1 -0
  99. package/dist/core/slash-commands.js.map +1 -1
  100. package/dist/index.d.ts +1 -1
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +1 -1
  103. package/dist/index.js.map +1 -1
  104. package/dist/modes/index.d.ts +1 -0
  105. package/dist/modes/index.d.ts.map +1 -1
  106. package/dist/modes/index.js +2 -0
  107. package/dist/modes/index.js.map +1 -1
  108. package/dist/modes/interactive/help-content.d.ts.map +1 -1
  109. package/dist/modes/interactive/help-content.js +3 -0
  110. package/dist/modes/interactive/help-content.js.map +1 -1
  111. package/dist/modes/interactive/interactive-host-attach.d.ts +10 -0
  112. package/dist/modes/interactive/interactive-host-attach.d.ts.map +1 -0
  113. package/dist/modes/interactive/interactive-host-attach.js +14 -0
  114. package/dist/modes/interactive/interactive-host-attach.js.map +1 -0
  115. package/dist/modes/interactive/interactive-host-runtime.d.ts.map +1 -1
  116. package/dist/modes/interactive/interactive-host-runtime.js +3 -6
  117. package/dist/modes/interactive/interactive-host-runtime.js.map +1 -1
  118. package/dist/modes/interactive/interactive-mode.d.ts +12 -0
  119. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  120. package/dist/modes/interactive/interactive-mode.js +95 -1
  121. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  122. package/dist/modes/interactive/session-failure-info.d.ts +3 -0
  123. package/dist/modes/interactive/session-failure-info.d.ts.map +1 -0
  124. package/dist/modes/interactive/session-failure-info.js +21 -0
  125. package/dist/modes/interactive/session-failure-info.js.map +1 -0
  126. package/dist/modes/interactive/tips/catalog/model-tips.d.ts +7 -7
  127. package/dist/modes/interactive/tips/catalog/model-tips.d.ts.map +1 -1
  128. package/dist/modes/interactive/tips/catalog/model-tips.js +7 -1
  129. package/dist/modes/interactive/tips/catalog/model-tips.js.map +1 -1
  130. package/dist/modes/interactive/tips/catalog/session-tips.d.ts.map +1 -1
  131. package/dist/modes/interactive/tips/catalog/session-tips.js +1 -1
  132. package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
  133. package/dist/modes/rpc/host-attach-hold.d.ts +16 -0
  134. package/dist/modes/rpc/host-attach-hold.d.ts.map +1 -0
  135. package/dist/modes/rpc/host-attach-hold.js +9 -0
  136. package/dist/modes/rpc/host-attach-hold.js.map +1 -0
  137. package/dist/modes/rpc/host-cleanup-paths.d.ts +20 -0
  138. package/dist/modes/rpc/host-cleanup-paths.d.ts.map +1 -0
  139. package/dist/modes/rpc/host-cleanup-paths.js +13 -0
  140. package/dist/modes/rpc/host-cleanup-paths.js.map +1 -0
  141. package/dist/modes/rpc/host-client-occupancy.d.ts +24 -0
  142. package/dist/modes/rpc/host-client-occupancy.d.ts.map +1 -0
  143. package/dist/modes/rpc/host-client-occupancy.js +53 -0
  144. package/dist/modes/rpc/host-client-occupancy.js.map +1 -0
  145. package/dist/modes/rpc/host-daemon-paths.d.ts +61 -8
  146. package/dist/modes/rpc/host-daemon-paths.d.ts.map +1 -1
  147. package/dist/modes/rpc/host-daemon-paths.js +128 -11
  148. package/dist/modes/rpc/host-daemon-paths.js.map +1 -1
  149. package/dist/modes/rpc/host-daemon-registration.d.ts +11 -1
  150. package/dist/modes/rpc/host-daemon-registration.d.ts.map +1 -1
  151. package/dist/modes/rpc/host-daemon-registration.js +28 -15
  152. package/dist/modes/rpc/host-daemon-registration.js.map +1 -1
  153. package/dist/modes/rpc/host-endpoints.d.ts +12 -0
  154. package/dist/modes/rpc/host-endpoints.d.ts.map +1 -0
  155. package/dist/modes/rpc/host-endpoints.js +59 -0
  156. package/dist/modes/rpc/host-endpoints.js.map +1 -0
  157. package/dist/modes/rpc/host-ensure-lock.d.ts +11 -0
  158. package/dist/modes/rpc/host-ensure-lock.d.ts.map +1 -0
  159. package/dist/modes/rpc/host-ensure-lock.js +49 -0
  160. package/dist/modes/rpc/host-ensure-lock.js.map +1 -0
  161. package/dist/modes/rpc/host-ensure.d.ts +7 -0
  162. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  163. package/dist/modes/rpc/host-ensure.js +42 -65
  164. package/dist/modes/rpc/host-ensure.js.map +1 -1
  165. package/dist/modes/rpc/host-gc-evidence.d.ts +18 -0
  166. package/dist/modes/rpc/host-gc-evidence.d.ts.map +1 -0
  167. package/dist/modes/rpc/host-gc-evidence.js +128 -0
  168. package/dist/modes/rpc/host-gc-evidence.js.map +1 -0
  169. package/dist/modes/rpc/host-gc.d.ts +28 -0
  170. package/dist/modes/rpc/host-gc.d.ts.map +1 -0
  171. package/dist/modes/rpc/host-gc.js +110 -0
  172. package/dist/modes/rpc/host-gc.js.map +1 -0
  173. package/dist/modes/rpc/host-generations.d.ts +10 -2
  174. package/dist/modes/rpc/host-generations.d.ts.map +1 -1
  175. package/dist/modes/rpc/host-generations.js +12 -7
  176. package/dist/modes/rpc/host-generations.js.map +1 -1
  177. package/dist/modes/rpc/host-handoff.d.ts +6 -0
  178. package/dist/modes/rpc/host-handoff.d.ts.map +1 -1
  179. package/dist/modes/rpc/host-handoff.js +31 -4
  180. package/dist/modes/rpc/host-handoff.js.map +1 -1
  181. package/dist/modes/rpc/host-lifecycle-policy.d.ts +53 -0
  182. package/dist/modes/rpc/host-lifecycle-policy.d.ts.map +1 -0
  183. package/dist/modes/rpc/host-lifecycle-policy.js +64 -0
  184. package/dist/modes/rpc/host-lifecycle-policy.js.map +1 -0
  185. package/dist/modes/rpc/host-lifecycle.d.ts +1 -44
  186. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  187. package/dist/modes/rpc/host-lifecycle.js +23 -85
  188. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  189. package/dist/modes/rpc/host-observe-request.d.ts +17 -0
  190. package/dist/modes/rpc/host-observe-request.d.ts.map +1 -0
  191. package/dist/modes/rpc/host-observe-request.js +30 -0
  192. package/dist/modes/rpc/host-observe-request.js.map +1 -0
  193. package/dist/modes/rpc/host-probe.d.ts +12 -0
  194. package/dist/modes/rpc/host-probe.d.ts.map +1 -1
  195. package/dist/modes/rpc/host-probe.js +28 -1
  196. package/dist/modes/rpc/host-probe.js.map +1 -1
  197. package/dist/modes/rpc/host-protocol-info.d.ts +2 -0
  198. package/dist/modes/rpc/host-protocol-info.d.ts.map +1 -1
  199. package/dist/modes/rpc/host-protocol-info.js +1 -0
  200. package/dist/modes/rpc/host-protocol-info.js.map +1 -1
  201. package/dist/modes/rpc/host-readiness.d.ts +22 -0
  202. package/dist/modes/rpc/host-readiness.d.ts.map +1 -0
  203. package/dist/modes/rpc/host-readiness.js +44 -0
  204. package/dist/modes/rpc/host-readiness.js.map +1 -0
  205. package/dist/modes/rpc/host-runner.d.ts +13 -0
  206. package/dist/modes/rpc/host-runner.d.ts.map +1 -1
  207. package/dist/modes/rpc/host-runner.js +23 -4
  208. package/dist/modes/rpc/host-runner.js.map +1 -1
  209. package/dist/modes/rpc/host-status-all.d.ts +31 -0
  210. package/dist/modes/rpc/host-status-all.d.ts.map +1 -0
  211. package/dist/modes/rpc/host-status-all.js +78 -0
  212. package/dist/modes/rpc/host-status-all.js.map +1 -0
  213. package/dist/modes/rpc/host-status-rows.d.ts +35 -0
  214. package/dist/modes/rpc/host-status-rows.d.ts.map +1 -0
  215. package/dist/modes/rpc/host-status-rows.js +42 -0
  216. package/dist/modes/rpc/host-status-rows.js.map +1 -0
  217. package/dist/modes/rpc/host-status.d.ts +32 -1
  218. package/dist/modes/rpc/host-status.d.ts.map +1 -1
  219. package/dist/modes/rpc/host-status.js +33 -27
  220. package/dist/modes/rpc/host-status.js.map +1 -1
  221. package/dist/modes/rpc/host-successor.d.ts +3 -1
  222. package/dist/modes/rpc/host-successor.d.ts.map +1 -1
  223. package/dist/modes/rpc/host-successor.js +105 -42
  224. package/dist/modes/rpc/host-successor.js.map +1 -1
  225. package/dist/modes/rpc/host-watchdog.d.ts +6 -0
  226. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
  227. package/dist/modes/rpc/host-watchdog.js +12 -13
  228. package/dist/modes/rpc/host-watchdog.js.map +1 -1
  229. package/dist/modes/rpc/loop-lag-watchdog.d.ts +16 -0
  230. package/dist/modes/rpc/loop-lag-watchdog.d.ts.map +1 -1
  231. package/dist/modes/rpc/loop-lag-watchdog.js +34 -2
  232. package/dist/modes/rpc/loop-lag-watchdog.js.map +1 -1
  233. package/dist/modes/rpc/multi-session-host.d.ts +2 -1
  234. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  235. package/dist/modes/rpc/multi-session-host.js +33 -6
  236. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  237. package/dist/modes/rpc/rpc-mode.d.ts +2 -2
  238. package/dist/modes/rpc/rpc-mode.js +2 -2
  239. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  240. package/dist/modes/rpc/rpc-types.d.ts +16 -0
  241. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  242. package/dist/modes/rpc/rpc-types.js.map +1 -1
  243. package/dist/modes/rpc/session-command-router.d.ts +9 -1
  244. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  245. package/dist/modes/rpc/session-command-router.js +4 -1
  246. package/dist/modes/rpc/session-command-router.js.map +1 -1
  247. package/dist/modes/rpc/session-path-key.d.ts +3 -1
  248. package/dist/modes/rpc/session-path-key.d.ts.map +1 -1
  249. package/dist/modes/rpc/session-path-key.js +3 -1
  250. package/dist/modes/rpc/session-path-key.js.map +1 -1
  251. package/docs/rpc.md +186 -19
  252. package/docs/settings.md +25 -1
  253. package/docs/usage.md +5 -2
  254. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +24 -0
  255. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  256. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  257. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +6 -0
  260. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -1
  261. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +36 -0
  262. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +1 -0
  264. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  265. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +14 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  268. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  269. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  270. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.d.ts.map +1 -1
  271. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +6 -4
  272. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js.map +1 -1
  273. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +3 -0
  274. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  275. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +20 -0
  276. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  277. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +2 -0
  278. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +1 -1
  279. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +1 -1
  280. package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.d.ts +5 -0
  281. package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.d.ts.map +1 -1
  282. package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.js +7 -0
  283. package/node_modules/@earendil-works/pi-tui/dist/slash-command-autocomplete.js.map +1 -1
  284. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  285. package/package.json +7 -7
  286. package/dist/bundle/chunks/chunk-3DEXCYNN.js +0 -135
  287. package/dist/bundle/chunks/chunk-5X4KSPK5.js +0 -12
  288. package/dist/bundle/chunks/chunk-KMD5ZONU.js +0 -5
  289. package/dist/bundle/chunks/chunk-PEHZYGYA.js +0 -8
  290. package/dist/bundle/chunks/chunk-PRC5XIIH.js +0 -2
  291. package/dist/bundle/chunks/chunk-QKY33652.js +0 -18
  292. package/dist/bundle/chunks/interactive-host-runtime-TIFT2SKR.js +0 -4
  293. package/dist/bundle/chunks/multi-session-host-GRHKB7Q2.js +0 -21
  294. package/dist/bundle/chunks/session-picker-FTFCQYHH.js +0 -2
@@ -1,2 +0,0 @@
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
- function normalizeProviderError(error){if(!(error instanceof Error))return{message:safeJsonStringify(error),messageCarriesBody:!1};let sdkError=error,status=extractStatus(sdkError),body=extractBody(sdkError),messageCarriesBody=body===void 0||error.message.includes(body);return{status,body,message:error.message,messageCarriesBody}}function extractStatus(error){if(typeof error.statusCode=="number")return error.statusCode;if(typeof error.status=="number")return error.status;if(typeof error.$metadata?.httpStatusCode=="number")return error.$metadata.httpStatusCode;if(typeof error.$response?.statusCode=="number")return error.$response.statusCode}function extractBody(error){let bodyText=pickBodyText(error);if(bodyText===void 0)return;let trimmed=bodyText.trim();if(trimmed.length!==0)return truncateErrorText(trimmed,4e3)}function pickBodyText(error){if(typeof error.body=="string")return error.body;if(isPlainNonEmptyObject(error.error))return safeJsonStringify(error.error);let responseBody=error.$response?.body;if(typeof responseBody=="string")return responseBody;if(!isReadableStreamLike(responseBody)&&isPlainNonEmptyObject(responseBody))return safeJsonStringify(responseBody)}function isReadableStreamLike(value){return typeof value=="object"&&value!==null&&"pipe"in value&&typeof value.pipe=="function"}function isPlainNonEmptyObject(value){if(typeof value!="object"||value===null)return!1;let proto=Object.getPrototypeOf(value);return proto!==Object.prototype&&proto!==null?!1:Object.keys(value).length>0}function formatProviderError(norm,prefix){return norm.messageCarriesBody||norm.status===void 0||norm.body===void 0?prefix!==void 0&&norm.status!==void 0?`${prefix} (${norm.status}): ${norm.message}`:norm.message:prefix!==void 0?`${prefix} (${norm.status}): ${norm.body}`:`${norm.status}: ${norm.body}`}function truncateErrorText(text,maxChars){return text.length<=maxChars?text:`${text.slice(0,maxChars)}... [truncated ${text.length-maxChars} chars]`}function safeJsonStringify(value){try{let serialized=JSON.stringify(value);return serialized===void 0?String(value):serialized}catch{return String(value)}}export{normalizeProviderError,formatProviderError};
@@ -1,18 +0,0 @@
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{HOST_INSTANCE_ID_ENV,MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,engineBuildIdentity}from"./chunk-NRGMT74E.js";import{require_signal_exit}from"./chunk-U3VOXCGP.js";import{DISPLAY_VERSION,VERSION,envValue,getAgentDir,isBunBinary,isBundledNode}from"./chunk-PBWQK23Z.js";import{__toESM}from"./chunk-IKOFCODM.js";import{spawn}from"node:child_process";import{randomUUID}from"node:crypto";import{existsSync,readFileSync as readFileSync4,realpathSync,writeSync}from"node:fs";import{access,chmod as chmod3,mkdir as mkdir5,readFile as readFile5,rename as rename4,rm as rm5,unlink as unlink2,writeFile as writeFile6}from"node:fs/promises";import{createConnection,createServer}from"node:net";import{tmpdir}from"node:os";import{dirname as dirname3,extname,join as join5,resolve}from"node:path";import{fileURLToPath}from"node:url";import{execFile}from"node:child_process";function parseDaemonPidFile(text){let parsed;try{parsed=JSON.parse(text)}catch(error){if(error instanceof SyntaxError)return;throw error}let unguarded=parsed!==null&&isRecord(parsed)&&parsed.processStartTime===null;if(!(!isRecord(parsed)||typeof parsed.pid!="number"||!unguarded&&typeof parsed.processStartTime!="string")&&!(!Number.isInteger(parsed.pid)||parsed.pid<=0)){if(unguarded)return{pid:parsed.pid,processStartTime:null};if(!(typeof parsed.processStartTime!="string"||parsed.processStartTime.trim()===""))return{pid:parsed.pid,processStartTime:parsed.processStartTime}}}var ProcessIdentityUnreadableError=class extends Error{constructor(pid,attempts,cause){super(`process identity for live pid ${pid} stayed unreadable after ${attempts} probe attempt(s): ${cause instanceof Error?cause.message:String(cause)}`),this.name="ProcessIdentityUnreadableError",this.pid=pid,this.attempts=attempts,this.cause=cause}};async function processMatchesPidFile(pidFile,readStartTime=readProcessStartTime,isLive=processIsLive,retry={}){if(pidFile.processStartTime===null){if(!isLive(pidFile.pid))return!1;throw new ProcessIdentityUnreadableError(pidFile.pid,0,new Error("pidfile carries no process identity guard"))}let attempts=Math.max(1,retry.attempts??5),delayMs=retry.delayMs??200,lastError;for(let attempt=1;attempt<=attempts;attempt++)try{let current=await readStartTime(pidFile.pid);if(current!==void 0)return current===pidFile.processStartTime;if(!isLive(pidFile.pid))return!1;lastError=new Error("process identity probe returned no identity for a live process"),attempt<attempts&&await new Promise(resolve2=>setTimeout(resolve2,delayMs))}catch(error){if(!isLive(pidFile.pid))return!1;lastError=error,attempt<attempts&&await new Promise(resolve2=>setTimeout(resolve2,delayMs))}throw new ProcessIdentityUnreadableError(pidFile.pid,attempts,lastError)}async function readProcessIdentity(pid,platform=process.platform,timeoutMs,isLive=processIsLive){let command=platform==="win32"?{executable:"powershell.exe",args:["-NoProfile","-NonInteractive","-Command",`$process = Get-CimInstance Win32_Process -Filter "ProcessId=${String(pid)}" -ErrorAction Stop; if ($null -eq $process) { Write-Output '__SENPI_ABSENT__'; exit 0 }; $process.CreationDate.ToFileTimeUtc().ToString("D", [Globalization.CultureInfo]::InvariantCulture)`]}:{executable:"ps",args:["-o","lstart=","-p",String(pid)]};return new Promise(resolve2=>{let effectiveTimeoutMs=timeoutMs??(platform==="win32"?1e3:void 0);execFile(command.executable,command.args,{windowsHide:!0,...effectiveTimeoutMs===void 0?{}:{timeout:effectiveTimeoutMs}},(error,stdout)=>{if(error){let code="code"in error?error.code:void 0;if(platform!=="win32"&&code===1||!isLive(pid)){resolve2({kind:"absent"});return}resolve2({kind:"error",error});return}let output=stdout.trim();if(output==="__SENPI_ABSENT__")return resolve2({kind:"absent"});if(!output||platform==="win32"&&!/^\d+$/.test(output))return resolve2({kind:"error",error:new Error("invalid process identity output")});resolve2({kind:"present",identity:output})}).once("error",error=>resolve2({kind:"error",error}))})}async function stopValidatedPid(pidFile,signal){if(await processMatchesPidFile(pidFile)){try{process.kill(pidFile.pid,signal)}catch(error){if(!isNodeErrorCode(error,"ESRCH"))throw error}signal==="SIGTERM"&&await waitForGone(pidFile,1e4),signal==="SIGKILL"&&await waitForGone(pidFile,2e3)}}async function waitForGone(pidFile,timeoutMs){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(!await processMatchesPidFile(pidFile))return!0;await delay(100)}return!await processMatchesPidFile(pidFile)}async function readProcessStartTime(pid,platform=process.platform,timeoutMs){return readProcessIdentity(pid,platform,timeoutMs).then(result=>{if(result.kind==="error")throw result.error;return result.kind==="present"?result.identity:void 0})}function processIsLive(pid){try{return process.kill(pid,0),!0}catch(error){if(isNodeErrorCode(error,"ESRCH"))return!1;if(isNodeErrorCode(error,"EPERM"))return!0;throw error}}async function waitForStartTime(pid,timeoutMs,readStartTime=readProcessStartTime,isLive=processIsLive){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){let startTime;try{startTime=await readStartTime(pid)}catch{}if(startTime)return startTime;await delay(20)}if(!isLive(pid))throw new Error(`spawned daemon pid ${pid} had no process start time`)}function delay(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isNodeErrorCode(error,code){return error instanceof Error&&"code"in error&&error.code===code}var import_signal_exit=__toESM(require_signal_exit(),1);import{appendFileSync,mkdirSync,readdirSync,readFileSync,renameSync,rmSync,statSync,utimesSync,writeFileSync}from"node:fs";import{join}from"node:path";var PROCESS_CRASH_RECORD_LIMIT=50,PROCESS_MARKER_HEARTBEAT_MS=6e4,FILE_MODE=384,DIR_MODE=448,MARKER_SUFFIX=".json";function processCrashPaths(agentDir){let dir=join(agentDir,"process-crashes");return{dir,liveDir:join(dir,"live"),recordsFile:join(dir,"crashes.jsonl")}}function crashingRuntimeVersions(){return{...process.versions.bun===void 0?{}:{bunVersion:process.versions.bun},senpiVersion:VERSION,...DISPLAY_VERSION===VERSION?{}:{productVersion:DISPLAY_VERSION}}}function recordProcessLifetime(agentDir,kind,options){return sweepDeadProcessMarkers(agentDir,options),options.supervised?()=>{}:installProcessLifetimeMarker(agentDir,kind,options)}function installProcessLifetimeMarker(agentDir,kind,options={}){let pid=options.pid??process.pid,now=options.now??Date.now,file=join(processCrashPaths(agentDir).liveDir,`${pid}${MARKER_SUFFIX}`),marker={kind,pid,startedAt:now(),...crashingRuntimeVersions()};try{mkdirSync(processCrashPaths(agentDir).liveDir,{recursive:!0,mode:DIR_MODE}),writeFileSync(file,`${JSON.stringify(marker)}
3
- `,{mode:FILE_MODE})}catch{return()=>{}}let heartbeat=setInterval(()=>{try{let at=new Date(now());utimesSync(file,at,at)}catch{}},options.heartbeatMs??PROCESS_MARKER_HEARTBEAT_MS);heartbeat.unref();let disposed=!1,dispose=()=>{disposed||(disposed=!0,clearInterval(heartbeat),process.off("exit",onProcessExit),removeSignalHook(),rmSync(file,{force:!0}))},onProcessExit=()=>{try{dispose()}catch{}};process.on("exit",onProcessExit);let removeSignalHook=(0,import_signal_exit.default)(onProcessExit);return dispose}function sweepDeadProcessMarkers(agentDir,options={}){let paths=processCrashPaths(agentDir),selfPid=options.pid??process.pid,isAlive=options.isAlive??isProcessAlive,names;try{names=readdirSync(paths.liveDir)}catch{return 0}let recorded=0;for(let name of names){if(!name.endsWith(MARKER_SUFFIX))continue;let pid=Number(name.slice(0,-MARKER_SUFFIX.length));if(!Number.isSafeInteger(pid)||pid<=0||pid===selfPid||isAlive(pid))continue;let claimed=join(paths.liveDir,`${name}.${selfPid}.sweep`);try{renameSync(join(paths.liveDir,name),claimed)}catch{continue}try{let record=crashRecordFromMarker(readFileSync(claimed,"utf8"),statSync(claimed).mtimeMs);record!==void 0&&(appendProcessCrashRecord(paths,record),recorded+=1)}catch{}finally{rmSync(claimed,{force:!0})}}return recorded}function isProcessAlive(pid){try{return process.kill(pid,0),!0}catch(error){return error.code==="EPERM"}}function crashRecordFromMarker(raw,lastHeartbeatMs){let value=JSON.parse(raw);if(typeof value!="object"||value===null)return;let kind=Reflect.get(value,"kind"),startedAt=Reflect.get(value,"startedAt"),senpiVersion=Reflect.get(value,"senpiVersion"),bunVersion=Reflect.get(value,"bunVersion"),productVersion=Reflect.get(value,"productVersion");if(!(typeof kind!="string"||typeof startedAt!="number"||typeof senpiVersion!="string"))return{at:new Date(lastHeartbeatMs).toISOString(),kind,detection:"unclean_exit",uptimeMs:Math.max(0,Math.round(lastHeartbeatMs-startedAt)),...typeof bunVersion=="string"?{bunVersion}:{},senpiVersion,...typeof productVersion=="string"?{productVersion}:{}}}function appendProcessCrashRecord(paths,record){mkdirSync(paths.dir,{recursive:!0,mode:DIR_MODE}),appendFileSync(paths.recordsFile,`${JSON.stringify(record)}
4
- `,{mode:FILE_MODE});let records=readProcessCrashRecordsFrom(paths.recordsFile);if(records.length<=PROCESS_CRASH_RECORD_LIMIT)return;let kept=records.slice(records.length-PROCESS_CRASH_RECORD_LIMIT);writeFileSync(paths.recordsFile,`${kept.join(`
5
- `)}
6
- `,{mode:FILE_MODE})}function readProcessCrashRecordsFrom(file){return readFileSync(file,"utf8").split(`
7
- `).filter(line=>line.trim()!=="")}import{appendFileSync as appendFileSync2,mkdirSync as mkdirSync2,readFileSync as readFileSync2,writeFileSync as writeFileSync2}from"node:fs";import{join as join2}from"node:path";var HOST_CRASH_RECORD_LIMIT=50,CRASH_RECORD_FILE_MODE=384;function hostCrashRecordFile(daemonDir){return join2(daemonDir,"crashes.jsonl")}function recordHostCrash(daemonDir,record){try{mkdirSync2(daemonDir,{recursive:!0,mode:448}),appendFileSync2(hostCrashRecordFile(daemonDir),`${JSON.stringify(record)}
8
- `,{mode:CRASH_RECORD_FILE_MODE}),pruneHostCrashRecords(daemonDir)}catch{}}function readHostCrashRecords(daemonDir){let raw;try{raw=readFileSync2(hostCrashRecordFile(daemonDir),"utf8")}catch{return[]}let records=[];for(let line of raw.split(`
9
- `))if(line.trim()!=="")try{let value=JSON.parse(line);typeof value=="object"&&value!==null&&typeof Reflect.get(value,"at")=="string"&&records.push(value)}catch{}return records}function pruneHostCrashRecords(daemonDir){let records=readHostCrashRecords(daemonDir);if(records.length<=HOST_CRASH_RECORD_LIMIT)return;let kept=records.slice(records.length-HOST_CRASH_RECORD_LIMIT);writeFileSync2(hostCrashRecordFile(daemonDir),`${kept.map(r=>JSON.stringify(r)).join(`
10
- `)}
11
- `,{mode:CRASH_RECORD_FILE_MODE})}function classifyChildExit(code,signal){return code===0&&signal===null?{reason:"rpc host exited on its own idle policy",exitCode:0}:{reason:`rpc host process exited unexpectedly (${code??signal})`,exitCode:1}}function noteChildExit(daemonDir,code,signal,childStartedAt,now=Date.now()){classifyChildExit(code,signal).exitCode!==0&&recordHostCrash(daemonDir,{at:new Date(now).toISOString(),...signal===null?{code:code??void 0}:{signal},uptimeMs:Math.max(0,now-childStartedAt),kind:"rpc-host",detection:"supervisor",...crashingRuntimeVersions()})}import{createHash}from"node:crypto";import{chmod,mkdir,writeFile}from"node:fs/promises";import{basename,join as join3,win32}from"node:path";var HOST_DAEMON_LAYOUT=2,HOST_DAEMON_DIR_ENV="SENPI_RPC_HOST_DAEMON_DIR",DIRECTORY_MODE=448,HOST_STATE_FILE_MODE=384;function daemonDirectoryName(socket,platform=process.platform){let canonical=platform==="win32"?win32.normalize(socket).toLowerCase():socket;return createHash("sha256").update(canonical,"utf8").digest("hex").slice(0,16)}function createHostDaemonPaths(target){let flatDir=join3(target.agentDir??getAgentDir(),"rpc-host-daemon");return{flatDir,layoutMarker:join3(flatDir,"layout.json"),legacyPidFile:join3(flatDir,"host.pid"),...hostDaemonDirectoryPaths(join3(flatDir,daemonDirectoryName(target.socket)))}}function hostDaemonDirectoryPaths(dir){return{dir,pointerFile:join3(dir,"host.pid"),lockFile:join3(dir,"daemon.lock"),settingsFile:join3(dir,"settings.json"),stderrLog:join3(dir,"stderr.log"),generationsDir:join3(dir,"generations"),reservationsDir:join3(dir,"reservations")}}function generationPaths(paths,instanceId){let dir=join3(paths.generationsDir,instanceId);return{dir,relativeDir:`generations/${instanceId}`,pidFile:join3(dir,"host.pid"),settingsFile:join3(dir,"settings.json"),scratchDir:join3(dir,"scratch")}}var HostDaemonStateError=class extends Error{constructor(path,cause){super(`RPC daemon state directory ${path} is not usable: ${cause instanceof Error?cause.message:cause}`,{cause}),this.name="HostDaemonStateError",this.path=path}};async function createDaemonDirectories(paths){try{await mkdir(paths.flatDir,{recursive:!0,mode:DIRECTORY_MODE});for(let directory of[paths.dir,paths.generationsDir,paths.reservationsDir])await mkdir(directory,{recursive:!0,mode:DIRECTORY_MODE}),await chmod(directory,DIRECTORY_MODE);await writeFile(paths.layoutMarker,`${JSON.stringify({layout:HOST_DAEMON_LAYOUT,dir:basename(paths.dir)})}
12
- `,{mode:HOST_STATE_FILE_MODE})}catch(cause){throw new HostDaemonStateError(paths.dir,cause)}}async function createGenerationDirectory(generation){try{await mkdir(generation.scratchDir,{recursive:!0,mode:DIRECTORY_MODE}),await chmod(generation.dir,DIRECTORY_MODE)}catch(cause){throw new HostDaemonStateError(generation.dir,cause)}}import{rename as rename2,rm as rm3}from"node:fs/promises";import{readFile,writeFile as writeFile2}from"node:fs/promises";async function writeHostSettings(paths,settings){let generation=generationPaths(paths,settings.instanceId);await createGenerationDirectory(generation),await writeStateFile(paths.settingsFile,settings),await writeStateFile(generation.settingsFile,settings)}async function readHostSettings(paths){let parsed=parseJson(await readFileOrUndefined(paths.settingsFile));if(parsed)return{...typeof parsed.coldStart=="string"&&{coldStart:parsed.coldStart},...typeof parsed.idleExitMs=="number"&&{idleExitMs:parsed.idleExitMs}}}async function writeStateFile(path,content){try{await writeFile2(path,`${JSON.stringify(content)}
13
- `,{mode:HOST_STATE_FILE_MODE})}catch(cause){throw new HostDaemonStateError(path,cause)}}async function readFileOrUndefined(path){try{return await readFile(path,"utf8")}catch(error){if(isNodeErrorCode2(error,"ENOENT")||isNodeErrorCode2(error,"ENOTDIR"))return;throw error}}function parseJson(text){if(text!==void 0)try{let parsed=JSON.parse(text);return isRecord2(parsed)?parsed:void 0}catch{return}}function isRecord2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isNodeErrorCode2(error,code){return error instanceof Error&&"code"in error&&error.code===code}import{readdir as readdir3,rm as rm2}from"node:fs/promises";import{readdir}from"node:fs/promises";import{readdirSync as readdirSync2,readFileSync as readFileSync3}from"node:fs";function supportedPlatform(platform){return platform==="darwin"||platform==="linux"?platform:void 0}async function loadProcessTableReader(platform=process.platform,options={}){let supported=supportedPlatform(platform);return supported===void 0||typeof globalThis.Bun>"u"?void 0:supported==="darwin"?await darwinReader(options):linuxReader}var KINFO_PROC_STRIDE=648,KINFO_PID_OFFSET=40,KINFO_PPID_OFFSET=560,KINFO_STAT_OFFSET=36,SZOMB=5,PROC_PIDTASKINFO=4,TASKINFO_RESIDENT_OFFSET=8,TABLE_START_BYTES=1<<20,TABLE_MAX_BYTES=32<<20;function parseKernelProcessTable(table,rowCount,residentKb){if(rowCount<=0||table.byteLength<rowCount*KINFO_PROC_STRIDE)return;let view=new DataView(table.buffer,table.byteOffset,table.byteLength),rows=[],selfSeen=!1;for(let index=0;index<rowCount;index++){let base=index*KINFO_PROC_STRIDE,pid=view.getUint32(base+KINFO_PID_OFFSET,!0);if(!Number.isInteger(pid)||pid<=0)continue;let ppid=view.getUint32(base+KINFO_PPID_OFFSET,!0),zombie=table[base+KINFO_STAT_OFFSET]===SZOMB;if(pid===process.pid){if(ppid!==process.ppid||zombie)return;selfSeen=!0}rows.push({pid,ppid,state:zombie?"Z":"U",rssKb:residentKb(pid)})}return selfSeen?rows:void 0}async function darwinReader(options){let{dlopen,FFIType,ptr}=await import("bun:ffi"),library=dlopen("libSystem.B.dylib",{sysctl:{args:[FFIType.ptr,FFIType.u32,FFIType.ptr,FFIType.ptr,FFIType.ptr,FFIType.i32],returns:FFIType.i32},proc_pidinfo:{args:[FFIType.i32,FFIType.i32,FFIType.u32,FFIType.ptr,FFIType.i32],returns:FFIType.i32}}),mib=new Int32Array([1,14,0]),none=new Uint8Array(1),requested=options.initialTableBytes,table=new Uint8Array(Number.isFinite(requested)&&requested!==void 0&&requested>0?Math.min(Math.floor(requested),TABLE_MAX_BYTES):TABLE_START_BYTES),length=new Uint32Array(1),taskInfo=new Uint8Array(256),taskView=new DataView(taskInfo.buffer),residentKb=pid=>(taskInfo.fill(0),library.symbols.proc_pidinfo(pid,PROC_PIDTASKINFO,0,ptr(taskInfo),taskInfo.byteLength)>0?Math.round(Number(taskView.getBigUint64(TASKINFO_RESIDENT_OFFSET,!0))/1024):0);return()=>{for(;;){if(length[0]=table.byteLength,library.symbols.sysctl(ptr(mib),mib.length,ptr(table),ptr(length),ptr(none),0)!==0){if(table.byteLength>=TABLE_MAX_BYTES)return;let reported=length[0]>table.byteLength?length[0]:0;table=new Uint8Array(Math.min(TABLE_MAX_BYTES,Math.max(table.byteLength*2,reported)));continue}return parseKernelProcessTable(table,Math.floor(length[0]/KINFO_PROC_STRIDE),residentKb)}}}function linuxReader(){let rows=[];for(let entry of readdirSync2("/proc")){let pid=Number(entry);if(!Number.isInteger(pid)||pid<=0)continue;let stat2;try{stat2=readFileSync3(`/proc/${pid}/stat`,"utf8")}catch{continue}let tail=stat2.slice(stat2.lastIndexOf(")")+2).split(" "),state=tail[0],ppid=Number(tail[1]);if(state===void 0||!Number.isInteger(ppid))continue;let rssPages=Number(tail[21]);rows.push({pid,ppid,state,rssKb:Number.isFinite(rssPages)?Math.round(rssPages*4):0})}return rows}var UNOBSERVED={rss_mb:null,host_rss_mb:null,open_fds:null,zombies:null},readers=new Map;function tableReader(platform){let cached=readers.get(platform);if(cached!==void 0)return cached;let loading=loadProcessTableReader(platform);return readers.set(platform,loading),loading}async function readHostProcessMetrics(pid,platform=process.platform){if(platform==="win32")return UNOBSERVED;let read=await tableReader(platform);if(read===void 0)return UNOBSERVED;let rows=read();if(rows===void 0)return UNOBSERVED;let tree=descendants(rows,pid);return tree.length===0?UNOBSERVED:{rss_mb:residentMegabytes(tree),host_rss_mb:residentMegabytes(tree.filter(row=>row.pid===pid||row.ppid===pid)),open_fds:platform==="linux"?await openDescriptors(tree):null,zombies:tree.filter(row=>row.state.startsWith("Z")).length}}function residentMegabytes(rows){return Math.round(rows.reduce((total,row)=>total+row.rssKb,0)/KILOBYTES_PER_MEGABYTE)}function descendants(rows,root){let tree=rows.filter(row=>row.pid===root);if(tree.length===0)return tree;for(let index=0;index<tree.length;index++){let parent=tree[index].pid;for(let row of rows)row.ppid===parent&&!tree.includes(row)&&tree.push(row)}return tree}var KILOBYTES_PER_MEGABYTE=1024;async function openDescriptors(tree){let total=0,counted=!1;for(let row of tree){let entries=await readdir(`/proc/${row.pid}/fd`).catch(()=>{});entries!==void 0&&(counted=!0,total+=entries.length)}return counted?total:null}import{createHash as createHash2}from"node:crypto";import{mkdir as mkdir2,readdir as readdir2,readFile as readFile2,rename,rm,writeFile as writeFile3}from"node:fs/promises";import{join as join4}from"node:path";var SESSION_PATH_RETRY_AFTER_MS=2e3;function reservationFile(dir,sessionPath){return join4(dir,`${createHash2("sha256").update(sessionPath,"utf8").digest("hex").slice(0,16)}.json`)}function createEndpointReservations(host){let told=process.env[HOST_DAEMON_DIR_ENV],dir=told!==void 0&&told.trim()!==""?told:host.socket===void 0?void 0:createHostDaemonPaths({socket:host.socket,agentDir:host.agentDir}).dir;if(dir!==void 0)return createSessionPathReservations({daemonDir:dir,instanceId:host.instanceId,...host.onFailure?{onFailure:host.onFailure}:{}})}function createSessionPathReservations(options){let paths=hostDaemonDirectoryPaths(options.daemonDir),dir=paths.reservationsDir,pid=options.pid??process.pid,startTime=readProcessStartTime(pid).then(value=>value??null,()=>null),held=new Set,report=message=>options.onFailure?.(message),publish=async(sessionPath,attached,stillHeld)=>{let owner={instanceId:options.instanceId,pid,processStartTime:await startTime,sessionPath,attached},file=reservationFile(dir,sessionPath);await mkdir2(dir,{recursive:!0,mode:448});let staging=`${file}.${pid}.tmp`;if(await writeFile3(staging,`${JSON.stringify(owner)}
14
- `,{mode:384}),stillHeld?.()===!1){await rm(staging,{force:!0});return}await rename(staging,file)};return{async claim(sessionPath,attached=!0){let existing=await readOwner(reservationFile(dir,sessionPath));if(existing&&existing.pid!==pid){let standing=await standingOwner(existing,paths.pointerFile);if(standing)return standing}try{await publish(sessionPath,attached),held.add(sessionPath)}catch(cause){report(`session path reservation for ${sessionPath} could not be written (${errorMessage(cause)})`)}},release(sessionPath){held.delete(sessionPath)&&rm(reservationFile(dir,sessionPath),{force:!0}).catch(cause=>{report(`session path reservation for ${sessionPath} could not be removed (${errorMessage(cause)})`)})},setAttached(sessionPath,attached){held.has(sessionPath)&&publish(sessionPath,attached,()=>held.has(sessionPath)).catch(cause=>{report(`session path reservation for ${sessionPath} could not be updated (${errorMessage(cause)})`)})}}}async function readSessionPathClaims(dir){let entries=await readdir2(dir).catch(()=>[]),claims=[];for(let entry of entries){if(!entry.endsWith(".json"))continue;let file=join4(dir,entry),owner=await readOwner(file);owner&&claims.push({file,owner})}return claims}async function standingOwner(owner,pointerFile){if(!await claimOwnerIsLive(owner))return;let current=await currentInstanceId(pointerFile)===owner.instanceId;return current||owner.attached!==!1?{...owner,current}:void 0}async function currentInstanceId(pointerFile){let pointer=parseJson(await readFileOrUndefined(pointerFile).catch(()=>{}));return typeof pointer?.instance_id=="string"?pointer.instance_id:void 0}async function readOwner(file){let parsed;try{parsed=JSON.parse(await readFile2(file,"utf8"))}catch{return}if(typeof parsed!="object"||parsed===null)return;let{instanceId,pid,processStartTime,sessionPath,attached}=parsed;if(!(typeof instanceId!="string"||typeof pid!="number"||typeof sessionPath!="string"))return{instanceId,pid,processStartTime:typeof processStartTime=="string"?processStartTime:null,sessionPath,...typeof attached=="boolean"?{attached}:{}}}async function claimOwnerIsLive(owner){if(!processIsLive(owner.pid))return!1;if(owner.processStartTime===null)return!0;let current=await readProcessStartTime(owner.pid).catch(()=>{});return current===void 0||current===owner.processStartTime}function errorMessage(cause){return cause instanceof Error?cause.message:String(cause)}async function pruneDeadGenerations(paths){let pointer=parseJson(await readFileOrUndefined(paths.pointerFile).catch(()=>{})),pointedAt=typeof pointer?.instance_id=="string"?pointer.instance_id:void 0,generations=[];for(let instanceId of await readdir3(paths.generationsDir).catch(()=>[])){let record=parseJson(await readFileOrUndefined(generationPaths(paths,instanceId).pidFile));typeof record?.pid!="number"||processIsLive(record.pid)||(await rm2(generationPaths(paths,instanceId).dir,{recursive:!0,force:!0}).catch(()=>{}),generations.push(instanceId))}let pointerRemoved=pointedAt!==void 0&&generations.includes(pointedAt);pointerRemoved&&await rm2(paths.pointerFile,{force:!0}).catch(()=>{});let claims=[];for(let claim of await readSessionPathClaims(paths.reservationsDir))await claimOwnerIsLive(claim.owner)||(await rm2(claim.file,{force:!0}).catch(()=>{}),claims.push(claim.owner.sessionPath));return{generations,claims,pointer:pointerRemoved}}function memoryOf(metrics){return{rss_mb:metrics.rss_mb,host_rss_mb:metrics.host_rss_mb}}async function readGenerationRows(paths){let pointer=parseJson(await readFileOrUndefined(paths.pointerFile).catch(()=>{})),currentId=typeof pointer?.instance_id=="string"?pointer.instance_id:void 0,claims=await readSessionPathClaims(paths.reservationsDir),rows=[];for(let instanceId of await readdir3(paths.generationsDir).catch(()=>[])){let record=parseJson(await readFileOrUndefined(generationPaths(paths,instanceId).pidFile));typeof record?.pid!="number"||!processIsLive(record.pid)||rows.push({instanceId,generation:typeof record.generation=="number"?record.generation:0,pid:record.pid,engineVersion:typeof record.engineVersion=="string"?record.engineVersion:null,...memoryOf(await readHostProcessMetrics(record.pid)),sessions:claims.filter(claim=>claim.owner.instanceId===instanceId).length,current:instanceId===currentId,alive:!0})}return rows.sort((left,right)=>left.generation-right.generation)}async function readHostRegistration(paths){let pointer=parseJson(await readFileOrUndefined(paths.pointerFile));if(!pointer||typeof pointer.instance_id!="string")return;let text=await readFileOrUndefined(generationPaths(paths,pointer.instance_id).pidFile),record=text===void 0?void 0:parseDaemonPidFile(text);if(record===void 0)return;let parsed=parseJson(text)??{},writer=parseWriter(parsed);return{record,...writer&&{writer},...typeof parsed.socket=="string"&&{socket:parsed.socket},instanceId:pointer.instance_id,generation:typeof parsed.generation=="number"?parsed.generation:0}}async function writeHostRegistration(paths,registration){await pruneDeadGenerations(paths);let generation=generationPaths(paths,registration.instanceId),writer={pid:process.pid,startTime:await thisProcessStartTime()},build=engineBuildIdentity();await createGenerationDirectory(generation),await writeStateFile(generation.pidFile,{...registration.record,instance_id:registration.instanceId,generation:registration.generation,engineVersion:build.text,engineOrdinal:build.ordinal,launchProfileId:registration.launchProfileId,socket:registration.socket,writer}),await writeStateFile(`${paths.pointerFile}.${process.pid}.tmp`,{layout:HOST_DAEMON_LAYOUT,instance_id:registration.instanceId,generation_dir:generation.relativeDir,writer}),await rename2(`${paths.pointerFile}.${process.pid}.tmp`,paths.pointerFile)}async function clearHostRegistration(paths){let pointer=parseJson(await readFileOrUndefined(paths.pointerFile));typeof pointer?.instance_id=="string"&&await rm3(generationPaths(paths,pointer.instance_id).dir,{recursive:!0,force:!0}),await rm3(paths.pointerFile,{force:!0}),await rm3(paths.settingsFile,{force:!0})}async function releaseGeneration(paths,owner){let generation=generationPaths(paths,owner.instanceId),record=parseDaemonPidFile(await readFileOrUndefined(generation.pidFile)??"");if(record!==void 0&&record.pid!==owner.pid)return;parseJson(await readFileOrUndefined(paths.pointerFile))?.instance_id===owner.instanceId&&(await rm3(paths.pointerFile,{force:!0}),await rm3(paths.settingsFile,{force:!0})),await rm3(generation.dir,{recursive:!0,force:!0})}async function readLegacyHostRecord(paths){let text=await readFileOrUndefined(paths.legacyPidFile);return text===void 0?void 0:parseDaemonPidFile(text)}async function provenOwner(registered,socket){let record=registered?.record;if(!record||record.processStartTime===null||registered?.socket!==void 0&&registered.socket!==socket)return;let identity={pid:record.pid,processStartTime:record.processStartTime};return await processMatchesPidFile(identity,readProcessStartTime).catch(()=>!1)?{...identity,instanceId:registered.instanceId}:void 0}async function legacyHostIsLive(paths,probe){let record=await readLegacyHostRecord(paths);if(record===void 0)return!1;try{return await processMatchesPidFile(record,probe)}catch(error){if(error instanceof ProcessIdentityUnreadableError)return!0;throw error}}async function writtenByThisProcess(writer){return writer===void 0||writer.pid!==process.pid||writer.startTime===null?!1:writer.startTime===await thisProcessStartTime()}var selfStartTime;function thisProcessStartTime(){return selfStartTime??=readProcessStartTime(process.pid).then(value=>value??null,()=>null),selfStartTime}function parseWriter(parsed){if(!isRecord2(parsed.writer)||typeof parsed.writer.pid!="number")return;let{pid,startTime}=parsed.writer;return{pid,startTime:typeof startTime=="string"?startTime:null}}import{mkdir as mkdir3,readFile as readFile3,rename as rename3,stat,unlink,writeFile as writeFile4}from"node:fs/promises";import{dirname}from"node:path";var PUBLIC_SOCKET_IDENTITY_FILE="public-socket.owner",SOCKET_IDENTITY_WAIT_MS=3e4,MAX_SOCKET_PATH_BYTES=103;function generationBindPath(publicSocket,generation){return`${publicSocket}.next-${generation}`}function sameSocketIdentity(a,b){return a.dev===b.dev&&a.ino===b.ino}async function statSocketIdentity(socketPath){try{let{dev,ino}=await stat(socketPath);return{dev,ino}}catch(cause){if(isNodeErrorCode3(cause,"ENOENT"))return;throw cause}}async function classifyEndpointOwnership(socketPath,identity){if(identity===void 0||process.platform==="win32"||socketPath.startsWith("\0"))return"unknown";let current;try{current=await statSocketIdentity(socketPath)}catch{return"unknown"}return current===void 0?"absent":sameSocketIdentity(current,identity)?"held":"replaced"}async function socketEntryReplaced(socketPath,identity){return await classifyEndpointOwnership(socketPath,identity)==="replaced"}async function writeSocketIdentityFile(path,identity){await mkdir3(dirname(path),{recursive:!0,mode:448});let tmpPath=`${path}.${process.pid}.tmp`;await writeFile4(tmpPath,`${JSON.stringify(identity)}
15
- `,{mode:384}),await rename3(tmpPath,path)}async function readSocketIdentityFile(path){let raw;try{raw=await readFile3(path,"utf8")}catch(cause){if(isNodeErrorCode3(cause,"ENOENT"))return;throw cause}let parsed;try{parsed=JSON.parse(raw)}catch{return}if(!(typeof parsed!="object"||parsed===null||typeof parsed.dev!="number"||typeof parsed.ino!="number"))return{dev:parsed.dev,ino:parsed.ino}}async function waitForSocketIdentityFile(path,timeoutMs=SOCKET_IDENTITY_WAIT_MS,intervalMs=25){let deadline=Date.now()+timeoutMs;for(;;){let identity=await readSocketIdentityFile(path);if(identity!==void 0)return identity;if(Date.now()>=deadline)return;await delayUnrefed(intervalMs)}}async function unlinkOwnedSocket(socketPath,identity,log){if(process.platform==="win32"||socketPath.startsWith("\0"))return;let current;try{current=await statSocketIdentity(socketPath)}catch(cause){log(`socket ${socketPath} ownership could not be verified (${errorMessage2(cause)}); leaving it`);return}if(current!==void 0){if(identity===void 0){log(`socket path ${socketPath} ownership unknown; leaving it`);return}if(!sameSocketIdentity(current,identity)){log(`socket path ${socketPath} now owned by another host; leaving it`);return}try{await unlink(socketPath)}catch(cause){isNodeErrorCode3(cause,"ENOENT")||log(`socket ${socketPath} removal failed (${errorMessage2(cause)})`)}}}async function shieldSocketDuringClose(socketPath,close){if(process.platform==="win32"||socketPath.startsWith("\0"))return close();let shieldPath=`${socketPath}.shield-${process.pid}`,shielded=!1;try{await statSocketIdentity(socketPath)!==void 0&&(await rename3(socketPath,shieldPath),shielded=!0)}catch{}try{await close()}finally{if(shielded)try{await rename3(shieldPath,socketPath)}catch{}}}function delayUnrefed(ms){return new Promise(resolve2=>{setTimeout(resolve2,ms).unref?.()})}function errorMessage2(cause){return cause instanceof Error?cause.message:String(cause)}function isNodeErrorCode3(cause,code){return cause instanceof Error&&"code"in cause&&cause.code===code}var SUPERSESSION_POLL_MS=1e3,ABSENT_CONFIRMATIONS=3;function watchForSupersession(endpoint,onLost){if(endpoint.identity===void 0||process.platform==="win32")return()=>{};let absentPolls=0,lost=!1,lose=loss=>{lost||(lost=!0,stop(),onLost(loss))},timer=setInterval(()=>{endpoint.settled?.()!==!0&&classifyEndpointOwnership(endpoint.path,endpoint.identity).then(ownership=>{if(endpoint.settled?.()!==!0)switch(ownership){case"replaced":lose("replaced");return;case"absent":if(absentPolls+=1,absentPolls<ABSENT_CONFIRMATIONS)return;lose("absent");return;case"held":case"unknown":absentPolls=0;return}},ignore)},SUPERSESSION_POLL_MS);timer.unref?.();let stop=()=>clearInterval(timer);return stop}function ignore(){}import{rmSync as rmSync2}from"node:fs";import{rm as rm4}from"node:fs/promises";import{Socket}from"node:net";var HOST_WATCH_FD_ENV="SENPI_RPC_HOST_WATCH_FD",HOST_SCRATCH_DIR_ENV="SENPI_RPC_HOST_SCRATCH_DIR",HOST_PUBLIC_SOCKET_ENV="SENPI_RPC_HOST_PUBLIC_SOCKET",HOST_WATCH_PPID_ENV="SENPI_RPC_HOST_WATCH_PPID",HOST_WATCH_PPID_INTERVAL_MS=250,HOST_CLEANUP_PATHS_ENV="SENPI_RPC_HOST_CLEANUP_PATHS";function parsePositiveInteger(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isSafeInteger(parsed)&&parsed>0?parsed:void 0}function readHostWatchdogConfig(env=process.env){let fd=parsePositiveInteger(env[HOST_WATCH_FD_ENV]),ppid=parsePositiveInteger(env[HOST_WATCH_PPID_ENV]);if(fd===void 0&&ppid===void 0)return;let scratchDir=env[HOST_SCRATCH_DIR_ENV],cleanupPaths=env[HOST_CLEANUP_PATHS_ENV]?.split(`
16
- `).filter(Boolean),publicSocket=env[HOST_PUBLIC_SOCKET_ENV];return{fd,ppid,scratchDir:scratchDir===void 0||scratchDir===""?void 0:scratchDir,cleanupPaths,publicSocket:publicSocket===""?void 0:publicSocket}}function readHostWatchdogConfigFromBrandEnv(){return readHostWatchdogConfig({[HOST_WATCH_FD_ENV]:process.env[HOST_WATCH_FD_ENV]??envValue("RPC_HOST_WATCH_FD"),[HOST_WATCH_PPID_ENV]:process.env[HOST_WATCH_PPID_ENV]??envValue("RPC_HOST_WATCH_PPID"),[HOST_SCRATCH_DIR_ENV]:process.env[HOST_SCRATCH_DIR_ENV]??envValue("RPC_HOST_SCRATCH_DIR"),[HOST_PUBLIC_SOCKET_ENV]:process.env[HOST_PUBLIC_SOCKET_ENV]??envValue("RPC_HOST_PUBLIC_SOCKET"),[HOST_CLEANUP_PATHS_ENV]:process.env[HOST_CLEANUP_PATHS_ENV]??envValue("RPC_HOST_CLEANUP_PATHS")})}function armHostWatchdog(config,onSupervisorGone){if(!config)return()=>{};let fire=reason=>{disarm();let captured=captureBeforeCleanup(config);if(process.platform==="win32"){let cleanup=captured.then(()=>cleanupWatchdogPaths(config));onSupervisorGone(reason,cleanup)}else captured.then(()=>cleanupWatchdogPaths(config)).finally(()=>onSupervisorGone(reason))},disarmers=[],disarm=()=>{for(let stop of disarmers.splice(0))stop()};return config.fd!==void 0&&disarmers.push(watchFdForEof(config.fd,fire)),config.ppid!==void 0&&disarmers.push(watchPpid(config.ppid,fire)),disarm}function watchFdForEof(fd,fire){let stream,streamFailed=!1,fired=!1,fireOnce=reason=>{fired||(fired=!0,fire(reason))};try{stream=new Socket({fd,readable:!0,writable:!1})}catch{return()=>{}}stream.resume();let onEnd=()=>fireOnce(`supervisor pipe fd ${fd} closed`),onClose=()=>{streamFailed||onEnd()},onError=()=>{streamFailed=!0};return stream.once("end",onEnd),process.platform==="win32"&&stream.once("close",onClose),stream.once("error",onError),()=>{stream.off("end",onEnd),stream.off("close",onClose),stream.off("error",onError),stream.destroy()}}function watchPpid(supervisorPid,fire){if(supervisorPid===process.pid)return()=>{};let timer=setInterval(()=>{if(!processAlive(supervisorPid)){fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`);return}process.ppid!==supervisorPid&&fire(`supervisor pid ${supervisorPid} is gone (ppid=${process.ppid})`)},HOST_WATCH_PPID_INTERVAL_MS);return timer.unref?.(),()=>clearInterval(timer)}function processAlive(pid){try{return process.kill(pid,0),!0}catch(cause){return cause instanceof Error&&"code"in cause&&cause.code!=="ESRCH"}}function captureBeforeCleanup(config){return config.beforeCleanup===void 0?Promise.resolve():Promise.resolve().then(config.beforeCleanup).catch(()=>{})}async function cleanupWatchdogPaths(config){let paths=[...config.cleanupPaths??[],...config.scratchDir?[config.scratchDir]:[]];if(process.platform==="win32"){for(let path of paths)try{rmSync2(path,{recursive:!0,force:!0,maxRetries:10,retryDelay:100})}catch{}return}await Promise.all(paths.map(async path=>{try{await rm4(path,{recursive:!0,force:!0})}catch{}}))}function activeTurnsForIdleDecision(input){return input.healthy?input.observedBusy:input.unhealthySince===void 0||input.now-input.unhealthySince<input.unknownGraceMs?1:0}function createObserverLink(options){let current,healthy=!1,unhealthySince,retry,armRetry=()=>{retry!==void 0||options.settled()||(retry=options.setTimer(()=>{retry=void 0,open().catch(armRetry)},options.retryDelayMs))};async function open(){let socket=await options.open();current=socket,healthy=!0,unhealthySince=void 0,socket.onLost(()=>{current!==socket||options.settled()||(healthy=!1,unhealthySince??=options.now(),current=void 0,armRetry())})}return{open,healthy:()=>healthy,unhealthySince:()=>unhealthySince,stop:()=>{retry?.cancel(),retry=void 0,current=void 0}}}import{createHash as createHash3,randomBytes,timingSafeEqual}from"node:crypto";import{chmod as chmod2,mkdir as mkdir4,readFile as readFile4,writeFile as writeFile5}from"node:fs/promises";import{dirname as dirname2,win32 as win322}from"node:path";var WINDOWS_PIPE_PREFIX="\\\\.\\pipe\\senpi-rpc-",SOCKET_SECRET_BYTES=32,SOCKET_SECRET_SUFFIX=".secret",SOCKET_SECRET_FILE_ENV="SENPI_RPC_SOCKET_SECRET_FILE",SOCKET_HANDSHAKE_TIMEOUT_MS=2e3;function socketSecretPath(logicalPath){if(logicalPath.toLowerCase().startsWith("\\\\.\\pipe\\"))throw new Error(`Windows RPC named-pipe addresses need a logical filesystem path for their secret: ${logicalPath}`);return`${logicalPath}${SOCKET_SECRET_SUFFIX}`}async function ensureSocketSecret(path){try{let existing=await readFile4(path);if(existing.length===SOCKET_SECRET_BYTES)return existing}catch(error){if(!isNodeErrorCode4(error,"ENOENT"))throw error}return createSocketSecret(path)}async function createSocketSecret(path){await mkdir4(dirname2(path),{recursive:!0});let secret=randomBytes(SOCKET_SECRET_BYTES);return await writeFile5(path,secret,{mode:384}),await chmod2(path,384),secret}async function readSocketSecret(path){let secret=await readFile4(path);if(secret.length!==SOCKET_SECRET_BYTES)throw new Error(`invalid RPC socket secret: ${path}`);return secret}function resolveSocketTransportAddress(socketPath,platform,secret){if(platform!=="win32"||socketPath.toLowerCase().startsWith("\\\\.\\pipe\\"))return socketPath;if(!/^[a-zA-Z]:[\\/]/.test(socketPath)&&!/^\\\\[^/]/.test(socketPath))throw new Error(`Windows RPC socket path must be drive-qualified or UNC: ${socketPath}`);let canonical=win322.normalize(socketPath).toLowerCase(),identity=Buffer.concat([Buffer.from(canonical,"utf8"),Buffer.from(secret??[])]),name=createHash3("sha256").update(identity).digest("hex").slice(0,32);return`${WINDOWS_PIPE_PREFIX}${name}`}function authenticateSocket(socket,secret,onAuthenticated){let received=Buffer.alloc(0),finish=()=>{clearTimeout(timer),socket.off("data",onData),socket.off("error",onError)},onError=()=>{finish(),socket.destroy()},timer=setTimeout(()=>{finish(),socket.destroy()},SOCKET_HANDSHAKE_TIMEOUT_MS),onData=chunk=>{if(received=Buffer.concat([received,chunk]),received.length<secret.length)return;if(finish(),!timingSafeEqual(received.subarray(0,secret.length),Buffer.from(secret))){socket.destroy();return}let remainder=received.subarray(secret.length);remainder.length>0&&socket.unshift(remainder),onAuthenticated()};socket.on("data",onData),socket.once("error",onError),socket.once("close",finish)}function sendSocketHandshake(socket,secret){socket.write(Buffer.from(secret))}function isNodeErrorCode4(error,code){return error instanceof Error&&"code"in error&&error.code===code}var HOST_COLD_START_ENV="SENPI_RPC_HOST_COLD_START",HOST_IDLE_EXIT_MS_ENV="SENPI_RPC_HOST_IDLE_EXIT_MS",DEFAULT_HOST_IDLE_EXIT_MS=15*6e4,HANDOFF_GRACE_MS_ENV="SENPI_RPC_HANDOFF_GRACE_MS",DEFAULT_HANDOFF_GRACE_MS=10*6e4,CHILD_STOP_TIMEOUT_MS=5e3,WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS=2e3,CHILD_WATCH_FD=3;async function createInternalSocketPath(baseDir=tmpdir(),platform=process.platform){if(platform==="win32"){let dir2=join5(baseDir,`internal-${randomUUID()}`);return await mkdir5(dir2,{recursive:!0,mode:448}),{socket:`\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,dir:dir2,secretPath:join5(dir2,"secret")}}let dir=join5(tmpdir(),`senpi-rpc-host-internal-${randomUUID().slice(0,8)}`);return await mkdir5(dir,{recursive:!1,mode:448}),await writeFile6(join5(dir,".owner"),JSON.stringify({pid:process.pid,processStartTime:await readProcessStartTime(process.pid),createdAt:Date.now()}),{mode:384}),{socket:join5(dir,"host.sock"),dir,secretPath:join5(dir,".secret")}}function parseColdStart(value){return value==="transient"||value==="persistent"?value:void 0}function parseIdleExitMs(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isFinite(parsed)&&parsed>0?parsed:void 0}function resolveHostPolicy(settings,env){let record=isRecord3(settings)?settings:{},coldStart=parseColdStart(env[HOST_COLD_START_ENV])??parseColdStart(asOptionalString(record.coldStart))??"transient",idleExitMs=parseIdleExitMs(env[HOST_IDLE_EXIT_MS_ENV])??parseIdleExitMs(asOptionalString(record.idleExitMs))??DEFAULT_HOST_IDLE_EXIT_MS;return{coldStart,idleExitMs}}var IdleExitDecider=class{constructor(idleExitMs,now=Date.now){this.idleExitMs=idleExitMs,this.now=now}update(activity){return activity.connections>0||activity.activeTurns>0?(this.idleSince=void 0,"active"):this.idleExitMs===Number.POSITIVE_INFINITY?"idle":this.idleSince===void 0?(this.idleSince=this.now(),"idle"):this.now()-this.idleSince>=this.idleExitMs?"exit":"idle"}},INTERNAL_SUPERVISOR_FLAG="--internal-rpc-host-supervisor",INJECTABLE_PREFIX_FLAGS=new Set(["--extension"]);function findInternalSupervisorArgs(argv){for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg===INTERNAL_SUPERVISOR_FLAG)return argv.slice(index+1);if(!INJECTABLE_PREFIX_FLAGS.has(arg)||index+1>=argv.length)return;index++}}function parseSupervisorArgs(argv){let hostArgs=[],socket,childCommand,childArgs,agentDir,bindSocket,replaceIdentity;for(let index=0;index<argv.length;index++){let arg=argv[index];if(arg==="--socket"&&index+1<argv.length){socket=argv[++index];continue}if(arg==="--child-command"&&index+1<argv.length){childCommand=argv[++index];continue}if(arg==="--child-args"&&index+1<argv.length){try{let parsed=JSON.parse(argv[++index]);Array.isArray(parsed)&&parsed.every(value=>typeof value=="string")&&(childArgs=parsed)}catch{return}continue}if(arg==="--agent-dir"&&index+1<argv.length){agentDir=argv[++index];continue}if(arg==="--bind"&&index+1<argv.length){bindSocket=argv[++index];continue}if(arg==="--replace"&&index+1<argv.length){replaceIdentity=parseSocketIdentity(argv[++index]);continue}hostArgs.push(arg)}return socket===void 0?void 0:{socket,hostArgs,childCommand,childArgs,agentDir,bindSocket,replaceIdentity}}function parseSocketIdentity(value){let match=/^(\d+):(\d+)$/.exec(value);return match?{dev:Number(match[1]),ino:Number(match[2])}:void 0}function resolveCliMainPath(){let modulePath=fileURLToPath(import.meta.url),extension=modulePath.endsWith(".ts")?".ts":".js",unbundled=resolve(dirname3(modulePath),"..","..",`cli-main${extension}`);return existsSync(unbundled)?unbundled:resolveDeclaredCliEntry(modulePath)??unbundled}function resolveDeclaredCliEntry(modulePath){let dir=dirname3(modulePath);for(let depth=0;depth<8;depth+=1){let manifestPath=resolve(dir,"package.json");if(existsSync(manifestPath)){try{let declared=JSON.parse(readFileSync4(manifestPath,"utf8")).bin,candidates=typeof declared=="string"?[declared]:Object.values(declared??{});for(let candidate of candidates){let entry=resolve(dir,candidate);if(existsSync(entry))return entry}}catch{}return}let parent=dirname3(dir);if(parent===dir)return;dir=parent}}function resolveHostChildLaunch(launch,internalSocket,compiled=isBunBinary){return launch.childCommand?{command:launch.childCommand,args:[...launch.childArgs??[],"--listen",`unix://${internalSocket}`]}:{command:process.execPath,args:[...compiled?[]:[...process.execArgv,resolveCliMainPath()],"--mode","rpc","--multi-session","--listen",`unix://${internalSocket}`,...launch.hostArgs]}}function quoteWindowsShellArg(value){return`"${value.replace(/(\\*)"/g,'$1$1\\"').replace(/(\\*)$/,"$1$1").replace(/([()%!^"<>&|;,])/g,"^$1")}"`}function spawnableChildLaunch(launch,platform=process.platform){let extension=extname(launch.command).toLowerCase();return platform!=="win32"||extension!==".cmd"&&extension!==".bat"?{...launch,shell:!1}:{command:quoteWindowsShellArg(launch.command),args:launch.args.map(quoteWindowsShellArg),shell:!0}}async function runHostSupervisor(launch){let paths=createHostDaemonPaths({socket:launch.socket,agentDir:launch.agentDir??getAgentDir()}),told=process.env[HOST_INSTANCE_ID_ENV],instanceId=told!==void 0&&told.trim()!==""?told:randomUUID(),generation=generationPaths(paths,instanceId),policy=resolveHostPolicy(await readSettingsFile(paths.settingsFile),process.env),publicSocket=launch.socket,bindSocket=launch.bindSocket??publicSocket,successor=launch.bindSocket!==void 0,publicSecret=process.platform==="win32"?await ensurePublicSocketSecret(publicSocket):void 0,internal=await createInternalSocketPath(paths.dir),internalSocket=internal.socket,internalSecretPath=internal.secretPath??socketSecretPath(internalSocket),internalSecret=process.platform==="win32"?await createSocketSecret(internalSecretPath):void 0,clientSockets=new Set,busySessions=new Map,observerSocket,observerLink=createObserverLink({open:async()=>{let secret=internalSecret,next=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,secret));return secret&&sendSocketHandshake(next,secret),await waitForConnect(next,5e3),observerSocket=next,attachJsonlLineReader(next,observeHostEvent,{maxLineLength:MAX_RPC_LINE_CHARACTERS}),{onLost:handler=>{next.once("close",handler),next.once("error",handler)}}},settled:()=>shuttingDown,retryDelayMs:250,now:Date.now,setTimer:(run,ms)=>{let timer=setTimeout(run,ms);return timer.unref?.(),{cancel:()=>clearTimeout(timer)}}}),childExitWatchTimer,stopSupersessionWatch,shuttingDown=!1,draining=!1,handoffGraceTimer,shutdownPromise,childLaunch=spawnableChildLaunch(resolveHostChildLaunch(launch,internalSocket)),child=spawn(childLaunch.command,childLaunch.args,{env:{...process.env,...launch.agentDir?{SENPI_CODING_AGENT_DIR:launch.agentDir}:{},[HOST_DAEMON_DIR_ENV]:paths.dir,[HOST_INSTANCE_ID_ENV]:instanceId,[HOST_WATCH_FD_ENV]:String(CHILD_WATCH_FD),[HOST_WATCH_PPID_ENV]:String(process.pid),...internal.dir?{[HOST_SCRATCH_DIR_ENV]:internal.dir}:{},...internalSecret?{[SOCKET_SECRET_FILE_ENV]:internalSecretPath}:{},[HOST_CLEANUP_PATHS_ENV]:[...successor?[]:[paths.pointerFile,generation.pidFile,paths.settingsFile],...process.platform==="win32"?[publicSocket]:[]].join(`
17
- `),...process.platform==="win32"?{}:{[HOST_PUBLIC_SOCKET_ENV]:publicSocket}},shell:childLaunch.shell,stdio:["ignore","ignore","inherit","pipe"],windowsHide:!0}),childStartedAt=Date.now();child.stdio[CHILD_WATCH_FD]?.on("error",()=>{}),child.once("exit",(code,signal)=>{if(shuttingDown)return;let{reason,exitCode}=classifyChildExit(code,signal);noteChildExit(paths.dir,code,signal,childStartedAt),shutdown(reason,exitCode)});let server=createServer(client=>{let accept=()=>{if(shuttingDown||draining){client.destroy();return}let internal2=createConnection(resolveSocketTransportAddress(internalSocket,process.platform,internalSecret));internalSecret&&sendSocketHandshake(internal2,internalSecret),clientSockets.add(client),decider.update(currentActivity());let detach=()=>{clientSockets.delete(client),decider.update(currentActivity()),internal2.destroy(),client.destroy()};client.pipe(internal2),internal2.pipe(client),client.once("close",detach),client.once("error",detach),internal2.once("end",()=>client.end(()=>client.destroy())),internal2.once("close",()=>{internal2.readableEnded||detach()}),internal2.once("error",detach)};publicSecret?authenticateSocket(client,publicSecret,accept):accept()});server.once("error",cause=>{shuttingDown||shutdown(`public socket listener failed: ${errorMessage3(cause)}`,1)});let decider=new IdleExitDecider(policy.coldStart==="persistent"?Number.POSITIVE_INFINITY:policy.idleExitMs),tickIntervalMs=Math.max(20,Math.min(1e3,policy.idleExitMs/4)),ticker=setInterval(()=>{!draining&&decider.update(currentActivity())==="exit"&&shutdown("idle",0)},tickIntervalMs);function currentActivity(){return{connections:clientSockets.size,activeTurns:activeTurnsForIdleDecision({healthy:observerLink.healthy(),unhealthySince:observerLink.unhealthySince(),now:Date.now(),unknownGraceMs:decider.idleExitMs,observedBusy:countBusySessions()})}}function countBusySessions(){let busy=0;for(let count of busySessions.values())count>0&&busy++;return busy}function observeHostEvent(line){let event;try{event=JSON.parse(line)}catch{return}if(typeof event!="object"||event===null)return;let{type,sessionId}=event;if(typeof sessionId=="string"){if(type==="agent_start")busySessions.set(sessionId,(busySessions.get(sessionId)??0)+1);else if(type==="agent_settled")busySessions.set(sessionId,Math.max(0,(busySessions.get(sessionId)??1)-1));else return;decider.update(currentActivity())}}async function shutdown(reason,exitCode){return shutdownPromise??=performShutdown(reason,exitCode),shutdownPromise}async function performShutdown(reason,exitCode){shuttingDown&&process.exit(exitCode),shuttingDown=!0,clearInterval(ticker),handoffGraceTimer&&clearTimeout(handoffGraceTimer),childExitWatchTimer&&clearInterval(childExitWatchTimer),stopSupersessionWatch?.();let hardExit=process.platform==="win32"?setTimeout(()=>process.exit(exitCode),WINDOWS_SUPERVISOR_SHUTDOWN_HARD_EXIT_MS):void 0;try{writeStderrLine(`senpi rpc host supervisor: ${reason} shutdown`);for(let client of clientSockets)client.destroy();draining||await shieldSocketDuringClose(publicSocket,()=>closeServer(server)),internal.dir&&await rm5(internal.dir,{recursive:!0,force:!0}),await stopChild(child),observerLink.stop(),observerSocket?.destroy(),publicSocketOwned&&process.platform!=="win32"&&await unlinkOwnedSocket(publicSocket,publicSocketIdentity,supervisorLog),await releaseGeneration(paths,{instanceId,pid:process.pid})}finally{hardExit&&clearTimeout(hardExit),process.exit(exitCode)}}let publicSocketOwned=!1,publicSocketIdentity;function supervisorLog(message){writeStderrLine(`senpi rpc host supervisor: ${message}`)}function drainForHandoff(){if(draining||shuttingDown)return;draining=!0,supervisorLog("draining into the next generation");let graceMs=parseIdleExitMs(process.env[HANDOFF_GRACE_MS_ENV])??DEFAULT_HANDOFF_GRACE_MS;handoffGraceTimer=setTimeout(()=>{supervisorLog(JSON.stringify({event:"handoff_grace_expired",graceMs})),requestChildDrain()},graceMs),handoffGraceTimer.unref(),requestChildDrain()}function requestChildDrain(){if(child.pid!==void 0&&child.exitCode===null&&child.signalCode===null)try{process.kill(child.pid,"SIGUSR1")}catch(cause){supervisorLog(`could not ask the host to drain: ${errorMessage3(cause)}`)}}registerSupervisorSignals(shutdown,drainForHandoff);try{await waitForListener(internalSocket,3e4,internalSecret),await observerLink.open(),await prepareSocketPath(bindSocket),await listen(server,bindSocket,publicSecret),publicSocketOwned=!0,successor&&await adoptPublicSocket(bindSocket,publicSocket,launch.replaceIdentity),publicSocketIdentity=await statSocketIdentity(publicSocket),publicSocketIdentity&&internal.dir&&await writeSocketIdentityFile(join5(internal.dir,PUBLIC_SOCKET_IDENTITY_FILE),publicSocketIdentity),stopSupersessionWatch=watchForSupersession({path:publicSocket,identity:publicSocketIdentity,settled:()=>shuttingDown||draining},loss=>{supervisorLog(loss==="absent"?"the public socket entry is gone; nothing can reach this generation; draining":"another generation owns the public socket; draining this one"),drainForHandoff()})}catch(cause){await shutdown(`startup failed: ${errorMessage3(cause)}`,1)}if(process.platform==="win32"&&child.pid!==void 0){let childStartTime=await readProcessStartTime(child.pid,process.platform,1e3).catch(()=>{}),missingIdentityChecks=0,checkingChildIdentity=!1;childExitWatchTimer=setInterval(()=>{shuttingDown||checkingChildIdentity||child.exitCode!==null||child.signalCode!==null||(checkingChildIdentity=!0,readProcessStartTime(child.pid,process.platform,1e3).then(currentStartTime=>{currentStartTime===void 0&&!processIsLive(child.pid)?missingIdentityChecks++:currentStartTime!==void 0&&(missingIdentityChecks=0),(childStartTime!==void 0&&currentStartTime!==void 0&&currentStartTime!==childStartTime||missingIdentityChecks>=2)&&shutdown("rpc host child exit observed by identity watchdog",0)}).catch(()=>{}).finally(()=>{checkingChildIdentity=!1}))},500),childExitWatchTimer.unref?.()}writeStderrLine(`senpi rpc host ready on unix://${publicSocket} (coldStart=${policy.coldStart}, idleExitMs=${policy.coldStart==="persistent"?"never":String(policy.idleExitMs)})`),await new Promise(()=>{})}function registerSupervisorSignals(shutdown,drain){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{shutdown(`signal:${signal}`,signal==="SIGHUP"?129:143)});process.platform!=="win32"&&process.on("SIGUSR1",drain)}async function adoptPublicSocket(bindSocket,publicSocket,expected){if(expected===void 0)throw new Error(`${publicSocket}: a generation launch must name the entry it replaces`);let current=await statSocketIdentity(publicSocket);if(current===void 0||current.dev!==expected.dev||current.ino!==expected.ino)throw new Error(`${publicSocket}: owned by another socket entry now; refusing to replace it`);await rename4(bindSocket,publicSocket)}async function ensurePublicSocketSecret(publicSocket){let secretPath=socketSecretPath(publicSocket);try{return await ensureSocketSecret(secretPath)}catch(cause){throw new Error(`senpi rpc host supervisor: cannot provision public socket secret ${secretPath}`,{cause})}}async function readSettingsFile(settingsFile){try{return JSON.parse(await readFile5(settingsFile,"utf8"))}catch{return}}async function stopChild(child){if(!(child.exitCode!==null||child.signalCode!==null)){try{child.kill("SIGTERM")}catch{return}if(!await waitForChildExit(child,CHILD_STOP_TIMEOUT_MS)){try{child.kill("SIGKILL")}catch{return}await waitForChildExit(child,2e3)}}}function waitForChildExit(child,timeoutMs){return child.exitCode!==null||child.signalCode!==null?Promise.resolve(!0):new Promise(resolve2=>{let timer=setTimeout(()=>{child.off("exit",onExit2),resolve2(!1)},timeoutMs),onExit2=()=>{clearTimeout(timer),resolve2(!0)};child.once("exit",onExit2)})}async function waitForListener(socketPath,timeoutMs,secret){let deadline=Date.now()+timeoutMs;for(;Date.now()<=deadline;){if(await canConnect(socketPath,secret))return;await delay2(50)}throw new Error(`${socketPath}: host did not start listening within ${timeoutMs}ms`)}function canConnect(socketPath,secret){return new Promise(resolve2=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform,secret));secret&&sendSocketHandshake(socket,secret);let settle=value=>{socket.destroy(),resolve2(value)};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1))})}function waitForConnect(socket,timeoutMs){return new Promise((resolve2,reject)=>{let timer=setTimeout(()=>{cleanup(),reject(new Error(`observer connection to internal host timed out after ${timeoutMs}ms`))},timeoutMs),onConnect=()=>{cleanup(),resolve2()},onError=cause=>{cleanup(),reject(cause)},cleanup=()=>{clearTimeout(timer),socket.off("connect",onConnect),socket.off("error",onError)};socket.once("connect",onConnect),socket.once("error",onError)})}async function prepareSocketPath(socketPath){if(process.platform!=="win32"){if(Buffer.byteLength(socketPath)>MAX_SOCKET_PATH_BYTES)throw new Error(`${socketPath}: socket path is ${Buffer.byteLength(socketPath)} bytes, over the ${MAX_SOCKET_PATH_BYTES}-byte limit.`);await mkdir5(dirname3(socketPath),{recursive:!0,mode:448});try{await access(socketPath)}catch(cause){if(isNodeErrorCode5(cause,"ENOENT"))return;throw cause}if(await canConnect(socketPath))throw new Error(`${socketPath}: address already in use by a live server.`);await unlink2(socketPath)}}function listen(server,socketPath,secret){return new Promise((resolve2,reject)=>{server.once("error",reject),server.listen({path:resolveSocketTransportAddress(socketPath,process.platform,secret),readableAll:!1,writableAll:!1},async()=>{server.off("error",reject);try{process.platform!=="win32"&&!socketPath.startsWith("\0")&&await chmod3(socketPath,384),resolve2()}catch(cause){reject(cause)}})})}function closeServer(server){return new Promise(resolve2=>{server.close(()=>resolve2())})}function writeStderrLine(text){try{writeSync(2,`${text}
18
- `)}catch{}}function delay2(ms){return new Promise(resolveDelay=>setTimeout(resolveDelay,ms))}function errorMessage3(cause){return cause instanceof Error?cause.message:String(cause)}function isNodeErrorCode5(cause,code){return cause instanceof Error&&"code"in cause&&cause.code===code}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function asOptionalString(value){return typeof value=="string"?value:typeof value=="number"?String(value):void 0}function isEntryScript(){let entry=process.argv[1];if(!entry)return!1;try{return fileURLToPath(import.meta.url)===realpathSync(entry)}catch{return!1}}if(!isBundledNode&&isEntryScript()){let launch=parseSupervisorArgs(process.argv.slice(2));launch||(writeStderrLine("usage: host-lifecycle.ts --socket <path> [host cli args...]"),process.exit(2)),runHostSupervisor(launch)}export{HOST_DAEMON_DIR_ENV,createHostDaemonPaths,createDaemonDirectories,writeHostSettings,readHostSettings,writeStateFile,readFileOrUndefined,parseJson,parseDaemonPidFile,ProcessIdentityUnreadableError,processMatchesPidFile,stopValidatedPid,waitForGone,readProcessStartTime,processIsLive,waitForStartTime,readHostProcessMetrics,SESSION_PATH_RETRY_AFTER_MS,createEndpointReservations,pruneDeadGenerations,readGenerationRows,readHostRegistration,writeHostRegistration,clearHostRegistration,releaseGeneration,provenOwner,legacyHostIsLive,writtenByThisProcess,SOCKET_SECRET_FILE_ENV,socketSecretPath,ensureSocketSecret,createSocketSecret,readSocketSecret,resolveSocketTransportAddress,authenticateSocket,sendSocketHandshake,recordProcessLifetime,classifyChildExit,PUBLIC_SOCKET_IDENTITY_FILE,MAX_SOCKET_PATH_BYTES,generationBindPath,statSocketIdentity,socketEntryReplaced,readSocketIdentityFile,waitForSocketIdentityFile,unlinkOwnedSocket,shieldSocketDuringClose,readHostWatchdogConfigFromBrandEnv,armHostWatchdog,HOST_COLD_START_ENV,HOST_IDLE_EXIT_MS_ENV,DEFAULT_HOST_IDLE_EXIT_MS,HANDOFF_GRACE_MS_ENV,DEFAULT_HANDOFF_GRACE_MS,createInternalSocketPath,parseColdStart,parseIdleExitMs,resolveHostPolicy,IdleExitDecider,INTERNAL_SUPERVISOR_FLAG,findInternalSupervisorArgs,parseSupervisorArgs,resolveCliMainPath,resolveHostChildLaunch,spawnableChildLaunch,runHostSupervisor};
@@ -1,4 +0,0 @@
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,SessionManager,executeBashWithOperations,isTransportGoneError}from"./chunk-27IFXX3B.js";import{SessionStreamingError,UserEditError}from"./chunk-C2425O2Q.js";import{SettingsManager}from"./chunk-3DEXCYNN.js";import{ensureHost}from"./chunk-KMD5ZONU.js";import{QUESTION_CAPABILITY,RENDERED_COMPONENTS_CAPABILITY}from"./chunk-HH3KJDWA.js";import"./chunk-QKY33652.js";import"./chunk-NRGMT74E.js";import"./chunk-TRSQVD6V.js";import"./chunk-7X72IACK.js";import"./chunk-2BMD37YV.js";import"./chunk-26UBFF6N.js";import"./chunk-PSCNHY7D.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-ELFCNCBY.js";import"./chunk-PBWQK23Z.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-X4Q5YSTE.js";import"./chunk-L6QV7NZI.js";import"./chunk-45SZOLCU.js";import"./chunk-WVGCQOLJ.js";import"./chunk-WL5EQYNL.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-DMI55M2N.js";import"./chunk-BQVVQ2LQ.js";import"./chunk-IKOFCODM.js";import{randomUUID}from"node:crypto";import{rm}from"node:fs/promises";var HOST_CLIENT_CAPABILITIES=[RENDERED_COMPONENTS_CAPABILITY,QUESTION_CAPABILITY],INTERACTIVE_HOST_FALLBACK_WARNING="Warning: shared interactive host unavailable; continuing locally",INTERACTIVE_HOST_RECONNECTING_WARNING="Warning: shared interactive host connection lost; reconnecting";async function createInteractiveHostRuntime(localRuntime,options){let sessionPath=localRuntime.session.sessionFile;if(!sessionPath)return localRuntime;let startHost=options.ensureHost??(hostOptions=>ensureHost(hostOptions)),remoteSession,remoteRuntime,reconnecting,disconnectQueued=!1,disposed=!1,fallbackWarned=!1,reconnectWarningShown=!1,warnReconnect=cause=>{reconnectWarningShown||(reconnectWarningShown=!0,options.onWarning?.({type:"interactive_host_action_failed",message:INTERACTIVE_HOST_RECONNECTING_WARNING,cause}))},warnFallback=cause=>{fallbackWarned||(fallbackWarned=!0,options.onWarning?.({type:"interactive_host_fallback",message:INTERACTIVE_HOST_FALLBACK_WARNING,cause}))},scheduleReconnect=()=>{},client=new RpcClient({socketPath:options.socket,onDisconnect:()=>{disconnectQueued=!0,scheduleReconnect()}});scheduleReconnect=()=>{!remoteSession||reconnecting||disposed||remoteRuntime?.isFallback||(remoteRuntime?.enterReconnecting(),reconnecting=(async()=>{let cause;for(let attempt=0;attempt<3;attempt++){if(disposed)return;disconnectQueued=!1;try{if(await startHost({socket:options.socket,agentDir:options.agentDir}),disposed||(await client.start(),disposed)||(await client.openSession({sessionPath,cwd:localRuntime.cwd}),disposed)||(remoteRuntime&&await remoteRuntime.reRegisterClientInfo(),disposed)||(await remoteSession.refresh(),disposed))return;fallbackWarned=!1,reconnectWarningShown=!1,remoteRuntime?.enterConnected();return}catch(error){if(cause=error,await client.stop().catch(()=>{}),disposed)return}}disposed||(await remoteRuntime?.enterFallback(),warnFallback(cause))})().finally(()=>{reconnecting=void 0,disconnectQueued&&!disposed&&!remoteRuntime?.isFallback&&scheduleReconnect()}))};try{await startHost({socket:options.socket,agentDir:options.agentDir}),await client.start(),await client.setClientInfo(80,[...HOST_CLIENT_CAPABILITIES]);let startupEvents=[],stopBuffering=client.onEvent(event=>startupEvents.push(event)),opened=await client.openSession({sessionPath,cwd:localRuntime.cwd,provider:localRuntime.session.model?.provider,modelId:localRuntime.session.model?.id,thinkingLevel:localRuntime.session.thinkingLevel});return remoteSession=createRemoteSessionProxy(localRuntime.session,localRuntime.services.agentDir,client,opened.state,options.onWarning,cause=>{remoteRuntime?.isReconnecting?warnReconnect(cause):warnFallback(cause)},startupEvents.filter(event=>!("sessionId"in event)||event.sessionId===opened.sessionId)),stopBuffering(),opened.state.isBashRunning&&!opened.attached&&await client.abortBash().catch(()=>{}),opened.attached&&await remoteSession.refresh(),remoteRuntime=new RemoteInteractiveRuntime(localRuntime,remoteSession,client,{onTransportGone:cause=>{remoteRuntime?.isReconnecting?warnReconnect(cause):warnFallback(cause)},get reconnecting(){return reconnecting},dispose:()=>{disposed=!0}}),remoteRuntime}catch(cause){return await client.stop().catch(()=>{}),warnFallback(cause),localRuntime}}var RemoteInteractiveRuntime=class{#local;#remoteSession;#client;#lifecycle;#onTransportGone;#rebindSession;#beforeSessionInvalidate;#state="connected";#fallbackHandoff;get isReconnecting(){return this.#state==="reconnecting"}get isFallback(){return this.#state==="fallback"}constructor(local,remoteSession,client,lifecycle){this.#local=local,this.#remoteSession=remoteSession,this.#client=client,this.#lifecycle=lifecycle,this.#onTransportGone=lifecycle?.onTransportGone??(()=>{})}async#call(call){try{return await call()}catch(error){if(isTransportGoneError(error))return this.#onTransportGone(error),{cancelled:!0};throw error}}enterConnected(){this.#state!=="disposed"&&this.#state!=="fallback"&&(this.#state="connected")}enterReconnecting(){this.#state!=="disposed"&&this.#state!=="fallback"&&(this.#state="reconnecting")}async enterFallback(){if(this.#state==="disposed"||this.#state==="fallback")return;this.#state="fallback",this.#beforeSessionInvalidate?.();let rebind=this.#rebindSession?.();rebind&&(this.#fallbackHandoff=rebind.catch(error=>{this.#onTransportGone(error)}),await this.#fallbackHandoff)}get session(){return this.#state==="fallback"||this.#state==="disposed"?this.#local.session:this.#remoteSession.session}get services(){return this.#local.services}get cwd(){return this.session.sessionManager.getCwd()}get diagnostics(){return this.#local.diagnostics}get modelFallbackMessage(){return this.#local.modelFallbackMessage}get launchProfile(){return this.#local.launchProfile}setBeforeSessionInvalidate(callback){this.#beforeSessionInvalidate=callback,this.#local.setBeforeSessionInvalidate(callback)}setRebindSession(callback){this.#rebindSession=callback,this.#local.setRebindSession(callback),callback&&this.#state==="fallback"&&!this.#fallbackHandoff&&(this.#fallbackHandoff=callback().catch(error=>{this.#onTransportGone(error)}))}setHostUiHandler(callback){this.#remoteSession.setHostUiHandler(callback)}sendHostUiProgress(record){this.#client.sendExtensionUIProgress(record).catch(()=>{})}#clientInfoSent=!1;#lastClientWidth=80;setClientInfo(width){this.#lastClientWidth=width;let capabilities=this.#clientInfoSent?void 0:[...HOST_CLIENT_CAPABILITIES];this.#clientInfoSent=!0,this.#client.setClientInfo(width,capabilities).catch(()=>{})}async reRegisterClientInfo(){await this.#client.setClientInfo(this.#lastClientWidth,[...HOST_CLIENT_CAPABILITIES])}async dispose(){if(this.#state==="disposed")return;this.#state="disposed",this.#lifecycle?.dispose(),await this.#lifecycle?.reconnecting?.catch(()=>{}),await this.#fallbackHandoff?.catch(()=>{});let errors=[];for(let cleanup of[()=>this.#remoteSession.abortLocalBash(),()=>this.#client.closeSession(),()=>this.#client.stop(),()=>this.#local.dispose()])try{await cleanup()}catch(error){errors.push(error)}if(errors.length>0)throw errors[0]}async newSession(options){return this.#state==="fallback"?this.#local.newSession(options):this.#remoteSession.aroundLocalReplacement(async()=>{let result=await this.#call(()=>this.#client.newSession(options?.parentSession));if(!result.cancelled){if(this.#beforeSessionInvalidate?.(),this.#remoteSession.abortLocalBash(),await this.#remoteSession.refresh(),options?.setup){let capture=SessionManager.inMemory(this.#remoteSession.session.sessionManager.getCwd());await options.setup(capture);for(let entry of capture.getEntries())await this.#client.appendSessionEntry(entry);await this.#remoteSession.refresh()}await this.#rebindSession?.(),options?.withSession&&await options.withSession(this.#remoteSession.createReplacedSessionContext())}return result}).catch(error=>{if(isTransportGoneError(error))return{cancelled:!0};throw error})}async switchSession(sessionPath,options){return this.#state==="fallback"?this.#local.switchSession(sessionPath,options):this.#remoteSession.aroundLocalReplacement(async()=>{let result=await this.#call(()=>this.#client.switchSession(sessionPath,options?.cwdOverride===void 0?void 0:{cwdOverride:options.cwdOverride}));return result.cancelled||(this.#beforeSessionInvalidate?.(),this.#remoteSession.abortLocalBash(),await this.#remoteSession.refresh(),await this.#rebindSession?.(),options?.projectTrustContextFactory?.(this.#remoteSession.session.sessionManager.getCwd()),options?.withSession&&await options.withSession(this.#remoteSession.createReplacedSessionContext())),result}).catch(error=>{if(isTransportGoneError(error))return{cancelled:!0};throw error})}async fork(entryId,options){return this.#state==="fallback"?this.#local.fork(entryId,options):this.#remoteSession.aroundLocalReplacement(async()=>{let result=await this.#call(()=>this.#client.fork(entryId,options));return result.cancelled||(this.#beforeSessionInvalidate?.(),this.#remoteSession.abortLocalBash(),await this.#refreshAndRebind(),options?.withSession&&await options.withSession(this.#remoteSession.createReplacedSessionContext())),{cancelled:result.cancelled,selectedText:result.text}}).catch(error=>{if(isTransportGoneError(error))return{cancelled:!0};throw error})}async importFromJsonl(inputPath,cwdOverride){return this.#state==="fallback"?this.#local.importFromJsonl(inputPath,cwdOverride):this.#remoteSession.aroundLocalReplacement(async()=>{let result=await this.#call(()=>this.#client.importJsonl(inputPath,cwdOverride));return result.cancelled||(this.#beforeSessionInvalidate?.(),this.#remoteSession.abortLocalBash(),await this.#refreshAndRebind()),result}).catch(error=>{if(isTransportGoneError(error))return{cancelled:!0};throw error})}async#refreshAndRebind(){await this.#remoteSession.refresh(),await this.#rebindSession?.()}};function createRemoteSessionProxy(local,agentDir,client,initialState,onWarning,onTransportGone,startupEvents=[]){let reportActionFailure=action=>error=>{isTransportGoneError(error)?onTransportGone?.(error):onWarning?.({type:"interactive_host_action_failed",message:`Warning: shared interactive host ${action} failed: ${error instanceof Error?error.message:String(error)}`,cause:error})},transportCall=async(action,call,cancelledValue)=>{try{return await call()}catch(error){if(!isTransportGoneError(error))throw error;return reportActionFailure(action)(error),cancelledValue}},state={...initialState},waitForBashCallbacks=async(promises,allowAbandonment)=>{if(promises.size===0)return!0;let settled=Promise.allSettled([...promises]).then(()=>!0),timeout,bounded=new Promise(resolve=>{timeout=setTimeout(resolve,allowAbandonment?100:5e3,!1),timeout.unref?.()});try{return await Promise.race([settled,bounded])}finally{timeout&&clearTimeout(timeout)}},executionNamespace=randomUUID(),cleanupRemoteBashOutput=async path=>{let cleanupTimeout;try{await Promise.race([client.cleanupBashOutput(path),new Promise((_,reject)=>{cleanupTimeout=setTimeout(()=>reject(new Error("RPC cleanup timed out")),1e3)})]);return}catch(transportError){try{await rm(path,{force:!0});return}catch(localError){onWarning?.({type:"interactive_host_action_failed",message:`Warning: failed to clean up shared bash output spill: ${localError instanceof Error?localError.message:String(localError)}`,cause:new AggregateError([transportError,localError])})}}finally{cleanupTimeout&&clearTimeout(cleanupTimeout)}},nextBashExecutionId=0,bashExecutions=new Map,hostUiHandler,pendingUiRequests=[],localBashAbortController,localBashRunning=!1,hostBashRunning=initialState.isBashRunning,nextQueuedInputOrder=Math.max(0,...initialState.ordered.map(item=>item.enqueueOrder)),sessionManager=local.sessionManager,settingsManager=SettingsManager.create(initialState.cwd,agentDir,{projectTrusted:initialState.projectTrusted}),updateBashState=()=>{state={...state,isBashRunning:localBashRunning||hostBashRunning}},remoteSessionManager=new Proxy({},{get(_target,property,_receiver){if(property==="appendLabelChange")return(entryId,label)=>{client.setLabel(entryId,label).catch(reportActionFailure("appendLabelChange"))};if(property==="getCwd")return()=>state.cwd;if(property==="getSessionName")return()=>state.sessionName;if(property==="getUsageTotals")return()=>state.usageTotals;let value=Reflect.get(sessionManager,property,sessionManager);return typeof value=="function"?value.bind(sessionManager):value}}),streamingAssistant,mirroredCurrentAssistantUsage=!1,localReplacementDepth=0,listeners=new Set,handleWireEvent=wireEvent=>{if(wireEvent.type==="extension_ui_request"){let request=wireEvent;hostUiHandler?Promise.resolve(hostUiHandler(request)).then(response=>response&&client.sendExtensionUIResponse(response)).catch(reportActionFailure("host UI response")):pendingUiRequests.push(request);return}if(wireEvent.type==="session_replaced"){localReplacementDepth===0&&refresh().catch(reportActionFailure("session refresh after replacement"));return}if(wireEvent.type==="agent_settled"&&(state={...state,isStreaming:!1,retryAttempt:0}),wireEvent.type==="bash_start"&&(hostBashRunning=!0,updateBashState()),wireEvent.type==="bash_end"&&(hostBashRunning=!1,updateBashState()),wireEvent.type==="bash_execution_update"&&wireEvent.id){let execution=bashExecutions.get(wireEvent.id);if(execution?.chunk&&!execution.hasError)try{let callbackPromise=Promise.resolve(execution.chunk(wireEvent.delta)).catch(error=>{throw execution.hasError||(execution.error=error,execution.hasError=!0,client.abortBash().catch(()=>{})),error});execution.promises.add(callbackPromise),callbackPromise.catch(()=>{}).finally(()=>execution.promises.delete(callbackPromise))}catch(error){execution.hasError||(execution.error=error,execution.hasError=!0,client.abortBash().catch(()=>{}))}}if(wireEvent.type==="agent_start"&&(state={...state,isStreaming:!0}),wireEvent.type==="compaction_start"&&(state={...state,isCompacting:!0}),wireEvent.type==="compaction_end"&&(state={...state,isCompacting:!1}),wireEvent.type==="auto_retry_start"&&(state={...state,retryAttempt:wireEvent.attempt}),wireEvent.type==="auto_retry_end"&&(state={...state,retryAttempt:0}),wireEvent.type==="queue_update"&&(nextQueuedInputOrder=Math.max(nextQueuedInputOrder,...wireEvent.ordered.map(item=>item.enqueueOrder)),state={...state,steering:[...wireEvent.steering],followUp:[...wireEvent.followUp],ordered:[...wireEvent.ordered],pendingMessageCount:wireEvent.steering.length+wireEvent.followUp.length}),wireEvent.type==="model_changed"&&(state={...state,model:wireEvent.model,thinkingLevel:wireEvent.thinkingLevel}),wireEvent.type==="thinking_level_changed"&&(state={...state,thinkingLevel:wireEvent.level}),wireEvent.type==="service_tier_changed"&&(state={...state,serviceTier:wireEvent.tier,fastMode:wireEvent.fastMode}),wireEvent.type==="session_settings_changed"&&(state={...state,steeringMode:wireEvent.steeringMode,followUpMode:wireEvent.followUpMode,autoCompactionEnabled:wireEvent.autoCompactionEnabled}),wireEvent.type==="entry_appended")try{sessionManager.appendEntry(wireEvent.entry),local.agent.state.messages=sessionManager.buildSessionContext().messages}catch{}if(wireEvent.type==="session_info_changed"&&(state={...state,sessionName:wireEvent.name}),wireEvent.type==="message_start"&&(wireEvent.message.role==="assistant"&&(streamingAssistant=structuredClone(wireEvent.message),mirroredCurrentAssistantUsage=!1),local.agent.state.messages.push(structuredClone(wireEvent.message))),wireEvent.type==="message_end"){if(wireEvent.message.role==="assistant"){streamingAssistant=structuredClone(wireEvent.message);let usage=wireEvent.message.usage;if(usage&&!mirroredCurrentAssistantUsage){mirroredCurrentAssistantUsage=!0;let latestPromptTokens=usage.input+usage.cacheRead+usage.cacheWrite,contextWindow=state.model?.contextWindow??0,contextTokens=usage.input+usage.cacheRead+usage.cacheWrite;state={...state,contextUsage:contextWindow>0?{tokens:contextTokens,contextWindow,percent:contextTokens/contextWindow*100}:void 0,usageTotals:{...state.usageTotals,input:state.usageTotals.input+usage.input,output:state.usageTotals.output+usage.output,cacheRead:state.usageTotals.cacheRead+usage.cacheRead,cacheWrite:state.usageTotals.cacheWrite+usage.cacheWrite,cost:state.usageTotals.cost+(usage.cost?.total??0),latestCacheHitRate:latestPromptTokens>0?usage.cacheRead/latestPromptTokens*100:void 0}}}}let messages=local.agent.state.messages;messages.at(-1)?.role===wireEvent.message.role&&(messages[messages.length-1]=structuredClone(wireEvent.message))}if(wireEvent.type==="compaction_end"&&wireEvent.accepted&&!wireEvent.aborted)try{local.sessionManager.reloadFromDisk?.(),sessionManager!==local.sessionManager&&sessionManager.reloadFromDisk?.(),local.agent.state.messages=sessionManager.buildSessionContext().messages}catch{}let event=hydrateMessageUpdate(wireEvent,streamingAssistant);for(let listener of listeners)listener(event)};client.onEvent(handleWireEvent);for(let event of startupEvents)handleWireEvent(event);let performRefresh=async()=>{let idsAtRefreshStart=new Set(sessionManager.getEntries().map(entry=>entry.id)),nextState=await transportCall("refresh",()=>client.getState());if(!nextState)return;state={...nextState},nextQueuedInputOrder=Math.max(0,...nextState.ordered.map(item=>item.enqueueOrder));let messages;if(settingsManager=SettingsManager.create(nextState.cwd,agentDir,{projectTrusted:nextState.projectTrusted}),nextState.sessionFile){sessionManager.getSessionFile()===nextState.sessionFile?sessionManager.reloadFromDisk?.():sessionManager=SessionManager.open(nextState.sessionFile,void 0,nextState.cwd);let authoritative=nextState.entries;if(authoritative?.length){let mirror=sessionManager.getEntries();if(!(mirror.length===authoritative.length&&mirror.every((entry,index)=>entry.id===authoritative[index]?.id))){let rebuilt=SessionManager.open(nextState.sessionFile,void 0,nextState.cwd);for(let entry of authoritative)rebuilt.appendEntry(entry);let authoritativeIds=new Set(authoritative.map(entry=>entry.id));for(let entry of mirror)!idsAtRefreshStart.has(entry.id)&&!authoritativeIds.has(entry.id)&&rebuilt.appendEntry(entry);sessionManager=rebuilt}}messages=sessionManager.buildSessionContext().messages}else messages=await transportCall("refresh",()=>client.getMessages(),[]);local.agent.state.messages.splice(0,local.agent.state.messages.length,...structuredClone(messages)),streamingAssistant=void 0},refreshChain=Promise.resolve(),refresh=()=>{let next=refreshChain.then(performRefresh,performRefresh);return refreshChain=next.then(()=>{},()=>{}),next};return{session:new Proxy(local,{get(target,property,receiver){if(property==="prompt")return async(message,options)=>{try{await client.prompt(message,{...options?.images?{images:options.images}:{},...options?.streamingBehavior?{streamingBehavior:options.streamingBehavior}:{},...options?.thinkingLevel?{thinkingLevel:options.thinkingLevel}:{},...options?.sessionTitlePrompt!==void 0?{sessionTitlePrompt:options.sessionTitlePrompt}:{},...options?.expandPromptTemplates!==void 0?{expandPromptTemplates:options.expandPromptTemplates}:{},...options?.promptDisposition?{promptDisposition:options.promptDisposition}:{},...options?.preflightResult?{preflightResult:options.preflightResult}:{}})}catch(error){if(!isTransportGoneError(error))throw error;reportActionFailure("prompt")(error)}};if(property==="abort")return()=>client.abort();if(property==="abortCompaction")return()=>{client.abortCompaction().catch(reportActionFailure("abortCompaction"))};if(property==="steer")return(message,images,recovery)=>{let enqueueOrder=recovery?.enqueueOrder??Math.max(0,...state.ordered.map(item=>item.enqueueOrder))+1;return state={...state,steering:[...state.steering,message],ordered:[...state.ordered,{text:message,mode:"steer",enqueueOrder}],pendingMessageCount:state.pendingMessageCount+1},transportCall("steer",()=>client.steer(message,images,{...recovery,enqueueOrder}))};if(property==="followUp")return(message,images,recovery)=>{let enqueueOrder=recovery?.enqueueOrder??Math.max(0,...state.ordered.map(item=>item.enqueueOrder))+1;return state={...state,followUp:[...state.followUp,message],ordered:[...state.ordered,{text:message,mode:"followUp",enqueueOrder}],pendingMessageCount:state.pendingMessageCount+1},transportCall("followUp",()=>client.followUp(message,images,{...recovery,enqueueOrder}))};if(property==="waitForIdle")return()=>client.waitForIdle();if(property==="getLastAssistantText")return()=>target.getLastAssistantText();if(property==="setModel"||property==="setSessionModel")return async model=>{let next=await transportCall("setModel",()=>client.setModel(model.provider,model.id),void 0);return next?{systemPromptName:next.systemPromptName,model:next}:void 0};if(property==="setSessionThinkingLevel")return level=>{client.setThinkingLevel(level,{scope:"turn"}).catch(reportActionFailure("setSessionThinkingLevel"))};if(property==="setSessionFastMode")return enabled=>{client.setFastMode(enabled).catch(reportActionFailure("setSessionFastMode"))};if(property==="abortRetry")return()=>{client.abortRetry().catch(reportActionFailure("abortRetry"))};if(property==="setAutoRetryEnabled")return enabled=>{client.setAutoRetry(enabled).catch(reportActionFailure("setAutoRetryEnabled"))};if(property==="reserveQueuedInputOrder")return()=>++nextQueuedInputOrder;if(property==="setFavoriteModels")return models=>{state={...state,favoriteModels:[...models]},client.setFavoriteModels(models).catch(reportActionFailure("setFavoriteModels"))};if(property==="setScopedModels")return models=>{state={...state,scopedModels:[...models]},client.setScopedModels(models).catch(reportActionFailure("setScopedModels"))};if(property==="cycleModel")return direction=>transportCall("cycleModel",()=>client.cycleModel(direction),void 0);if(property==="setThinkingLevel")return level=>{client.setThinkingLevel(level).catch(reportActionFailure("setThinkingLevel"))};if(property==="cycleThinkingLevel")return()=>transportCall("cycleThinkingLevel",()=>client.cycleThinkingLevel(),void 0).then(result=>result?.level);if(property==="getAvailableThinkingLevels")return()=>transportCall("getAvailableThinkingLevels",()=>client.getAvailableThinkingLevels(),[]);if(property==="setSteeringMode")return mode=>{client.setSteeringMode(mode).catch(reportActionFailure("setSteeringMode"))};if(property==="setFollowUpMode")return mode=>{client.setFollowUpMode(mode).catch(reportActionFailure("setFollowUpMode"))};if(property==="compact")return instructions=>transportCall("compact",()=>client.compact(instructions));if(property==="setAutoCompactionEnabled")return enabled=>{client.setAutoCompaction(enabled).catch(reportActionFailure("setAutoCompaction"))};if(property==="executeBash")return async(command,onChunk,options)=>{if(options?.operations&&typeof options.operations.exec=="function"){let abortController=new AbortController;localBashAbortController=abortController,localBashRunning=!0,updateBashState();let sessionAtStart=state.sessionId,prefix=settingsManager.getShellCommandPrefix(),resolvedCommand=prefix?`${prefix}
3
- ${command}`:command;try{let result=await executeBashWithOperations(resolvedCommand,state.cwd,options.operations,{onChunk,signal:abortController.signal});return state.sessionId===sessionAtStart&&await transportCall("recordBashResult",()=>client.recordBashResult(command,result,options.excludeFromContext)),result}finally{localBashAbortController=void 0,localBashRunning=!1,updateBashState()}}let executionId=`bash-${executionNamespace}-${++nextBashExecutionId}`,execution={chunk:onChunk,promises:new Set,error:void 0,hasError:!1};bashExecutions.set(executionId,execution);try{let result=await transportCall("bash",()=>client.bash(command,{excludeFromContext:options?.excludeFromContext,executionId,operations:options?.operations}),{output:"",exitCode:void 0,cancelled:!0,truncated:!1});if(!await waitForBashCallbacks(execution.promises,!1))throw result.fullOutputPath&&await cleanupRemoteBashOutput(result.fullOutputPath),new Error("Bash output callback did not settle within 5000ms");if(execution.hasError)throw result.fullOutputPath&&await cleanupRemoteBashOutput(result.fullOutputPath),execution.error;return result}finally{bashExecutions.delete(executionId)}};if(property==="abortBash")return()=>{localBashAbortController?localBashAbortController.abort():client.abortBash().catch(reportActionFailure("abortBash"))};if(property==="getContextUsage")return()=>state.contextUsage;if(property==="getSessionStats")return()=>transportCall("getSessionStats",()=>client.getSessionStats(),local.getSessionStats());if(property==="exportToHtml")return(outputPath,options)=>transportCall("exportToHtml",()=>client.exportHtml(outputPath,options?.themeName)).then(result=>result?.path);if(property==="setSessionName")return name=>client.setSessionName(name).catch(reportActionFailure("setSessionName"));if(property==="navigateTree")return async(targetId,options)=>{let result=await transportCall("navigateTree",()=>client.navigateTree(targetId,options),{cancelled:!0});return result.cancelled||await refresh(),result};if(property==="editAssistantMessage")return async(entryId,text,options)=>{let result=await client.editAssistantMessage(entryId,text,{expectedLeafId:options?.expectedLeafId,summarize:options?.summarize,customInstructions:options?.customInstructions});return result.outcome==="unchanged"?{cancelled:!1,unchanged:!0}:result.outcome==="cancelled"?{cancelled:!0,aborted:result.aborted}:(await refresh(),{cancelled:!1,entryId:result.entry.id})};if(property==="editUserMessage")return async(entryId,text,options)=>{let result;try{result=await client.editUserMessage(entryId,text,{expectedLeafId:options?.expectedLeafId,summarize:options?.summarize,customInstructions:options?.customInstructions})}catch(error){if(error instanceof RpcCommandError)switch(error.errorCode){case"streaming":throw new SessionStreamingError;case"not_found":throw new UserEditError("not-found",error.message);case"not_user":throw new UserEditError("not-user",error.message);case"empty":throw new UserEditError("empty",error.message);case"stale_leaf":throw new UserEditError("stale-leaf",error.message)}throw error}return result.outcome==="unchanged"?{cancelled:!1,unchanged:!0}:result.outcome==="cancelled"?{cancelled:!0,aborted:result.aborted}:(await refresh(),{cancelled:!1,entryId:result.entry.id})};if(property==="getUserMessagesForForking")return()=>transportCall("getUserMessagesForForking",()=>client.getForkMessages(),[]);if(property==="subscribe")return listener=>{listeners.add(listener);let localUnsubscribe=target.subscribe(listener);return()=>{listeners.delete(listener),localUnsubscribe()}};if(property==="isStreaming")return state.isStreaming;if(property==="isIdle")return!state.isStreaming;if(property==="isCompacting")return state.isCompacting;if(property==="pendingMessageCount")return state.pendingMessageCount;if(property==="getSteeringMessages")return()=>state.steering;if(property==="getFollowUpMessages")return()=>state.followUp;if(property==="clearQueue")return options=>{let result={steering:[...state.steering],followUp:[...state.followUp],ordered:[...state.ordered]};return Object.defineProperty(result,"ordered",{value:result.ordered,enumerable:!1}),client.clearQueue(options).catch(reportActionFailure("clearQueue")),result};if(property==="abortBranchSummary")return()=>{client.abortBranchSummary().catch(reportActionFailure("abortBranchSummary"))};if(property==="recordBashResult")return(command,result,options)=>{client.recordBashResult(command,result,options?.excludeFromContext).catch(reportActionFailure("recordBashResult"))};if(property!=="set_label"){if(property==="retryAttempt")return state.retryAttempt;if(property==="isBashRunning")return state.isBashRunning;if(property==="reload")return _options=>transportCall("reload",()=>client.reload(),{cancelled:!0});if(property==="checkReloadVeto")return()=>transportCall("checkReloadVeto",()=>client.checkReloadVeto(),{cancelled:!0});if(property==="exportToJsonl")return outputPath=>transportCall("exportToJsonl",()=>client.exportJsonl(outputPath)).then(result=>result?.path);if(property==="state"){let localState=target.state;return{...localState,model:state.model??localState.model,thinkingLevel:state.thinkingLevel,isStreaming:state.isStreaming,isCompacting:state.isCompacting}}return property==="sessionFile"?state.sessionFile:property==="sessionId"?state.sessionId:property==="sessionName"?state.sessionName:property==="serviceTier"?state.serviceTier:property==="steeringMode"?state.steeringMode:property==="followUpMode"?state.followUpMode:property==="autoCompactionEnabled"?state.autoCompactionEnabled:property==="isFastModeActive"?()=>state.fastMode:property==="sessionManager"?remoteSessionManager:property==="settingsManager"?settingsManager:property==="messages"?target.messages:property==="favoriteModels"?state.favoriteModels:property==="scopedModels"?state.scopedModels:property==="model"?state.model??target.model:property==="thinkingLevel"?state.thinkingLevel:Reflect.get(target,property,receiver)}}}),setHostUiHandler:callback=>{if(hostUiHandler=callback,callback)for(let request of pendingUiRequests.splice(0))Promise.resolve(callback(request)).then(response=>response&&client.sendExtensionUIResponse(response)).catch(reportActionFailure("host UI response"))},refresh,aroundLocalReplacement:async body=>{localReplacementDepth++;try{return await body()}finally{localReplacementDepth--}},abortLocalBash:()=>localBashAbortController?.abort(),createReplacedSessionContext:()=>{let context=local.createReplacedSessionContext();return Object.defineProperty(context,"cwd",{value:state.cwd}),Object.defineProperty(context,"sessionManager",{value:remoteSessionManager}),context.sendMessage=(message,options)=>transportCall("sendMessage",()=>client.sendCustomMessage(message,{triggerTurn:options?.triggerTurn,deliverAs:options?.deliverAs})),context.sendUserMessage=(content,options)=>{if(typeof content=="string")return transportCall("sendUserMessage",()=>client.prompt(content,{streamingBehavior:options?.deliverAs,expandPromptTemplates:options?.expandPromptTemplates}));let text=content.filter(part=>part.type==="text").map(part=>part.text).join(`
4
- `),images=content.filter(part=>part.type==="image");return transportCall("sendUserMessage",()=>client.prompt(text,{images,streamingBehavior:options?.deliverAs,expandPromptTemplates:options?.expandPromptTemplates}))},context}}}function hydrateMessageUpdate(event,streamingAssistant){if(event.type!=="message_update"||!streamingAssistant)return event;let update=event.assistantMessageEvent;if(update.type!=="text_delta"&&update.type!=="thinking_delta"&&update.type!=="toolcall_delta")return event;let content=streamingAssistant.content[update.contentIndex];if(update.type==="text_delta"&&content?.type==="text"&&(content.text+=update.delta),update.type==="thinking_delta"&&content?.type==="thinking"&&(content.thinking+=update.delta),update.type==="toolcall_delta"&&content?.type==="toolCall"){let raw=JSON.stringify(content.arguments)+update.delta;try{let parsed=JSON.parse(raw);typeof parsed=="object"&&parsed!==null&&!Array.isArray(parsed)&&(content.arguments=parsed)}catch{}}return streamingAssistant.usage=event.usage,{type:"message_update",message:structuredClone(streamingAssistant),assistantMessageEvent:{...update,partial:structuredClone(streamingAssistant)}}}function isInteractiveHostEvent(event){return typeof event=="object"&&event!==null&&"type"in event}export{INTERACTIVE_HOST_FALLBACK_WARNING,INTERACTIVE_HOST_RECONNECTING_WARNING,RemoteInteractiveRuntime,createInteractiveHostRuntime,createRemoteSessionProxy,isInteractiveHostEvent};
@@ -1,21 +0,0 @@
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{AgentSessionRuntime,EMPTY_SESSION_CONTEXT,HostMcpRegistry,ProviderScope,bindToProviderScope,createAgentSessionRuntime,isSessionBusySnapshot,runWithProviderScope}from"./chunk-VMKAYXHL.js";import"./chunk-IKXPBYSO.js";import"./chunk-FWBSGMAE.js";import"./chunk-MUTD2NOH.js";import{SessionManager,assertValidSessionId}from"./chunk-27IFXX3B.js";import"./chunk-YS5YEX4S.js";import{RPC_ERROR_INVALID_LAUNCH_PROFILE,RPC_ERROR_INVALID_SESSION_CONTEXT,RPC_ERROR_INVALID_SESSION_KIND,RPC_ERROR_MISSING_SESSION_ID,RPC_ERROR_OPEN_FAILED,RPC_ERROR_SESSION_CLOSING,RPC_ERROR_UNKNOWN_SESSION,SessionEventWriter,buildRpcSessionState,createRpcConnectionHandler,recordLoopBlockedMs,rpcCommandShapeError,sessionAutoTitleError,sessionContextError,sessionKindError}from"./chunk-PEHZYGYA.js";import{flushRawStdout,takeOverStdout,waitForRawStdoutBackpressure,writeRawStdout}from"./chunk-SLL375O7.js";import"./chunk-EJKCBRYK.js";import"./chunk-C2425O2Q.js";import"./chunk-3DEXCYNN.js";import"./chunk-YU2P3CAR.js";import"./chunk-BMX2U22F.js";import"./chunk-5X4KSPK5.js";import{GENERATION_HANDOFF_CAPABILITY,runAsHostGenerationProcess}from"./chunk-KMD5ZONU.js";import{AUTO_TITLE_PER_SESSION_CAPABILITY,AUTO_TITLE_SESSIONS_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,parseClientCapabilities}from"./chunk-HH3KJDWA.js";import{PUBLIC_SOCKET_IDENTITY_FILE,SESSION_PATH_RETRY_AFTER_MS,SOCKET_SECRET_FILE_ENV,armHostWatchdog,authenticateSocket,createEndpointReservations,ensureSocketSecret,parseIdleExitMs,readHostWatchdogConfigFromBrandEnv,readSocketIdentityFile,resolveSocketTransportAddress,shieldSocketDuringClose,socketEntryReplaced,socketSecretPath,statSocketIdentity,unlinkOwnedSocket,waitForSocketIdentityFile}from"./chunk-QKY33652.js";import{MAX_RPC_LINE_CHARACTERS,attachJsonlLineReader,hostGeneration,hostInstanceId,protocolIdentity}from"./chunk-NRGMT74E.js";import"./chunk-DA4W77J7.js";import"./chunk-H4QOEVS5.js";import"./chunk-HB35RBP4.js";import"./chunk-4T4GFAGK.js";import"./chunk-HBG6SQU5.js";import{killTrackedDetachedChildren}from"./chunk-TRSQVD6V.js";import"./chunk-36ACNYQR.js";import"./chunk-7X72IACK.js";import"./chunk-KUPQO7MC.js";import"./chunk-22MGY5JQ.js";import"./chunk-Y5A6TKBN.js";import"./chunk-2BMD37YV.js";import"./chunk-26UBFF6N.js";import"./chunk-PSCNHY7D.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-ELFCNCBY.js";import"./chunk-PRC5XIIH.js";import"./chunk-4LVZQRDG.js";import"./chunk-ZOFZRJSL.js";import"./chunk-2SOVDETB.js";import{VERSION,envValue,isBunBinary}from"./chunk-PBWQK23Z.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-WASCMT6Y.js";import"./chunk-X4Q5YSTE.js";import"./chunk-IXAUDPOK.js";import"./chunk-L6QV7NZI.js";import"./chunk-45SZOLCU.js";import"./chunk-WVGCQOLJ.js";import"./chunk-BPX6QWPD.js";import"./chunk-WL5EQYNL.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-DMI55M2N.js";import"./chunk-BQVVQ2LQ.js";import"./chunk-IKOFCODM.js";import{access,chmod,mkdir,unlink}from"node:fs/promises";import{createConnection,createServer}from"node:net";import{dirname as dirname2,join as join2}from"node:path";import{readdirSync,readFileSync}from"node:fs";var P_PID=1,WNOHANG=1,WEXITED=4,WNOWAIT={darwin:32,linux:16777216},SI_PID_OFFSET={darwin:12,linux:16},MAX_TRACKED_CHILDREN=4096;function supportedPlatform(platform){return platform==="darwin"||platform==="linux"?platform:void 0}async function loadChildReaperSyscalls(platform=process.platform){let supported=supportedPlatform(platform);if(supported===void 0||typeof globalThis.Bun>"u")return;let{dlopen,FFIType,ptr}=await import("bun:ffi"),wait=dlopen(supported==="darwin"?"libSystem.B.dylib":"libc.so.6",{waitid:{args:[FFIType.i32,FFIType.u32,FFIType.ptr,FFIType.i32],returns:FFIType.i32},waitpid:{args:[FFIType.i32,FFIType.ptr,FFIType.i32],returns:FFIType.i32}}),info=new Uint8Array(512),infoView=new DataView(info.buffer),status=new Int32Array(1),peekOptions=WEXITED|WNOHANG|WNOWAIT[supported],siPidOffset=SI_PID_OFFSET[supported];return{listDirectChildren:supported==="darwin"?darwinChildren(dlopen,FFIType,ptr):linuxChildren,isWaitable(pid){return info.fill(0),wait.symbols.waitid(P_PID,pid,ptr(info),peekOptions)===0&&infoView.getInt32(siPidOffset,!0)===pid},reapExited(pid){if(pid<=0)throw new Error(`child reaper refuses to wait on pid ${pid}`);return wait.symbols.waitpid(pid,ptr(status),WNOHANG)===pid},describe:supported==="darwin"?darwinName(dlopen,FFIType,ptr):linuxName}}function darwinChildren(dlopen,FFIType,ptr){let libproc=dlopen("libSystem.B.dylib",{proc_listchildpids:{args:[FFIType.i32,FFIType.ptr,FFIType.i32],returns:FFIType.i32}}),pids=new Int32Array(MAX_TRACKED_CHILDREN);return()=>{let found=libproc.symbols.proc_listchildpids(process.pid,ptr(pids),pids.byteLength);return found<=0?[]:Array.from(pids.subarray(0,Math.min(found,pids.length)))}}function darwinName(dlopen,FFIType,ptr){let libproc=dlopen("libSystem.B.dylib",{proc_name:{args:[FFIType.i32,FFIType.ptr,FFIType.u32],returns:FFIType.i32}}),name=new Uint8Array(256),decoder=new TextDecoder;return pid=>{name.fill(0);let written=libproc.symbols.proc_name(pid,ptr(name),name.length);return written<=0?"":decoder.decode(name.subarray(0,written))}}function linuxChildren(){let children=[];for(let entry of readdirSync("/proc")){let pid=Number(entry);if(!(!Number.isInteger(pid)||pid<=0)&&(parentOf(pid)===process.pid&&children.push(pid),children.length>=MAX_TRACKED_CHILDREN))break}return children}function linuxStat(pid){try{return readFileSync(`/proc/${pid}/stat`,"utf8")}catch{return}}function parentOf(pid){let stat=linuxStat(pid),tail=stat?.slice(stat.lastIndexOf(")")+2).split(" ");return tail===void 0?void 0:Number(tail[1])}function linuxName(pid){let stat=linuxStat(pid),open=stat?.indexOf("(")??-1,close=stat?.lastIndexOf(")")??-1;return stat===void 0||open===-1||close<=open?"":stat.slice(open+1,close)}var CHILD_REAPER_ENV="SENPI_RPC_HOST_REAPER",CHILD_REAPER_MIN_WAITABLE_MS_ENV="SENPI_RPC_HOST_REAPER_MIN_WAITABLE_MS",MIN_WAITABLE_FLOOR_MS=5e3,DEFAULT_MIN_WAITABLE_MS=3e4,TICK_MS=1e3,WARN_INTERVAL_MS=5*6e4,WARN_AT_WAITING=10,TOP_NAMES=3;function resolveChildReaperConfig(env){let override=Number(env[CHILD_REAPER_MIN_WAITABLE_MS_ENV]);return{enabled:env[CHILD_REAPER_ENV]!=="0",tickMs:TICK_MS,minWaitableMs:Number.isFinite(override)&&override>0?clampWindow(override):DEFAULT_MIN_WAITABLE_MS}}function clampWindow(milliseconds){return Math.max(MIN_WAITABLE_FLOOR_MS,milliseconds)}function createChildReaper(options){let now=options.now??Date.now,minWaitableMs=clampWindow(options.minWaitableMs??DEFAULT_MIN_WAITABLE_MS),tracked=new Map,lastWarnAt,report=(waiting,reaped)=>{options.log===void 0||reaped.length===0&&waiting.length<WARN_AT_WAITING||lastWarnAt!==void 0&&now()-lastWarnAt<WARN_INTERVAL_MS||(lastWarnAt=now(),options.log(`child reaper: reaped=${reaped.length} waiting=${waiting.length} top=${topNames(waiting,reaped)}`))};return{tick(){let children=options.syscalls.listDirectChildren(),present=new Set(children);for(let pid of[...tracked.keys()])present.has(pid)||tracked.delete(pid);let reaped=[];for(let pid of children){let child=tracked.get(pid)??{name:options.syscalls.describe(pid)||"unknown",waitableSince:void 0};if(tracked.set(pid,child),!options.syscalls.isWaitable(pid)){child.waitableSince=void 0;continue}if(child.waitableSince===void 0){child.waitableSince=now();continue}now()-child.waitableSince<minWaitableMs||options.syscalls.reapExited(pid)&&(tracked.delete(pid),reaped.push(child.name))}report(waitingNames(tracked),reaped)},get waitingPids(){return[...tracked].filter(([,child])=>child.waitableSince!==void 0).map(([pid])=>pid)}}}function waitingNames(tracked){return[...tracked.values()].filter(child=>child.waitableSince!==void 0).map(child=>child.name)}function topNames(waiting,reaped){let counts=new Map;for(let name of[...waiting,...reaped])counts.set(name,(counts.get(name)??0)+1);return[...counts].sort(([,left],[,right])=>right-left).slice(0,TOP_NAMES).map(([name,count])=>`${name} x${count}`).join(", ")}async function startHostChildReaper(log){let config=resolveChildReaperConfig(process.env);if(!config.enabled)return()=>{};let syscalls=await loadChildReaperSyscalls();if(syscalls===void 0)return log(`child reaper unavailable under ${runtimeName()}: children orphaned by a terminated worker thread stay as zombies until this host exits`),()=>{};let reaper=createChildReaper({syscalls,minWaitableMs:config.minWaitableMs,log}),timer=setInterval(()=>reaper.tick(),config.tickMs);return timer.unref(),()=>clearInterval(timer)}function runtimeName(){return typeof globalThis.Bun>"u"?"Node":`Bun on ${process.platform}`}var RPC_SESSION_IDLE_EVICTION_MS_ENV="SENPI_RPC_SESSION_IDLE_EVICTION_MS",RPC_HOST_EMPTY_EXIT_MS_ENV="SENPI_RPC_HOST_EMPTY_EXIT_MS",RPC_CLOSE_GRACE_MS_ENV="SENPI_RPC_CLOSE_GRACE_MS",DEFAULT_SESSION_IDLE_EVICTION_MS=30*6e4,DEFAULT_HOST_EMPTY_EXIT_MS=15*6e4;function resolveHostIdlePolicy(env,overrides={}){return{now:overrides.now??Date.now,idleEvictionMs:overrides.idleEvictionMs??parseIdleExitMs(env[RPC_SESSION_IDLE_EVICTION_MS_ENV])??DEFAULT_SESSION_IDLE_EVICTION_MS,emptyExitMs:overrides.emptyExitMs??parseIdleExitMs(env[RPC_HOST_EMPTY_EXIT_MS_ENV])??DEFAULT_HOST_EMPTY_EXIT_MS}}var HOST_RSS_WARN_MB_ENV="SENPI_RPC_HOST_RSS_WARN_MB";function parsePositiveInteger(value){if(value===void 0||!/^\d+$/.test(value.trim()))return;let parsed=Number(value.trim());return Number.isFinite(parsed)&&parsed>0?parsed:void 0}var HostMemorySampler=class{constructor(options){this.pressure=!1,this.idleReported=!1;let env=options.env??process.env;this.emit=options.emit,this.sessions=options.sessions,this.onPressure=options.onPressure,options.onIdlePressure&&(this.onIdlePressure=options.onIdlePressure),this.log=options.log??(message=>{process.stderr.write(message)}),this.now=options.now??Date.now,this.readRssBytes=options.readRssBytes??(()=>process.memoryUsage.rss()),this.warnMb=parsePositiveInteger(env[HOST_RSS_WARN_MB_ENV])??4096}start(){this.timer===void 0&&(this.timer=setInterval(()=>this.sample(),3e4),this.timer.unref?.())}stop(){this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0)}sample(){let rssMb=Math.round(this.readRssBytes()/1048576);if(rssMb<=this.warnMb){if(this.idleReported=!1,!this.pressure)return;this.pressure=!1,this.onPressure(!1);return}this.pressure||(this.pressure=!0,this.onPressure(!0));let sessions=this.sessions();sessions>0?this.idleReported=!1:this.idleReported||(this.idleReported=!0,this.onIdlePressure?.(rssMb)),this.emit({type:"host_memory_pressure",rssMb,sessions});let now=this.now();this.lastLoggedAt!==void 0&&now-this.lastLoggedAt<3e5||(this.lastLoggedAt=now,this.log(`senpi rpc host memory pressure: rssMb=${rssMb} sessions=${sessions} (idle parking halved)
3
- `))}};import{AsyncLocalStorage}from"node:async_hooks";var attributionStore=new AsyncLocalStorage,sequence=0,openActivities=new Map,lastFinished;function runWithSessionAttribution(attribution,task){let mark=++sequence;openActivities.set(mark,attribution);let finish=()=>{openActivities.delete(mark)&&(lastFinished={sequence:++sequence,attribution})},awaited=!1;try{let result=attributionStore.run(attribution,task);return isPromiseLike(result)&&(awaited=!0,Promise.resolve(result).then(finish,finish)),result}finally{awaited||finish()}}function isPromiseLike(value){return typeof value=="object"&&value!==null&&"then"in value&&typeof value.then=="function"}function openSessionAttributionSpan(attribution){let ambient=attributionStore.getStore(),merged={sessionId:attribution.sessionId??ambient?.sessionId,tool:attribution.tool},mark=++sequence;return openActivities.set(mark,merged),()=>{openActivities.delete(mark)&&(lastFinished={sequence:++sequence,attribution:merged})}}function sessionActivityMark(){return sequence}function sessionActivitySince(mark){if(lastFinished!==void 0&&lastFinished.sequence>mark)return lastFinished.attribution;let newest;for(let attribution of openActivities.values())newest=attribution;return newest}function toolRecord(record){if(!(!("type"in record)||typeof record.type!="string"))return{type:record.type,toolCallId:"toolCallId"in record&&typeof record.toolCallId=="string"?record.toolCallId:void 0,toolName:"toolName"in record&&typeof record.toolName=="string"?record.toolName:void 0}}function createToolAttributionSpans(sessionId){let spans=new Map,closeAll=()=>{for(let close of spans.values())close();spans.clear()};return{closeAll,observe:record=>{let parsed=toolRecord(record);if(parsed!==void 0){if(parsed.type==="tool_execution_start"&&parsed.toolCallId!==void 0){spans.get(parsed.toolCallId)?.(),spans.set(parsed.toolCallId,openSessionAttributionSpan({sessionId,tool:parsed.toolName}));return}if(parsed.type==="tool_execution_end"&&parsed.toolCallId!==void 0){spans.get(parsed.toolCallId)?.(),spans.delete(parsed.toolCallId);return}(parsed.type==="agent_settled"||parsed.type==="agent_idle")&&closeAll()}}}}var LOOP_LAG_WARN_MS_ENV="SENPI_RPC_LOOP_LAG_WARN_MS",LOOP_LAG_ERROR_MS_ENV="SENPI_RPC_LOOP_LAG_ERROR_MS",DEFAULT_LOOP_LAG_WARN_MS=500,DEFAULT_LOOP_LAG_ERROR_MS=5e3,LOOP_LAG_TICK_MS=200,LOOP_LAG_WARN_INTERVAL_MS=1e4;function describeAttribution(attribution){return attribution?.sessionId===void 0&&attribution?.tool===void 0?"no attributed session":`sessionId=${attribution.sessionId??"unknown"}${attribution.tool?` tool=${attribution.tool}`:""}`}var LoopLagWatchdog=class{constructor(options){this.activityMark=0;let env=options.env??process.env;this.emit=options.emit,this.log=options.log??(message=>{process.stderr.write(message)}),this.now=options.now??Date.now,this.warnMs=parseIdleExitMs(env[LOOP_LAG_WARN_MS_ENV])??DEFAULT_LOOP_LAG_WARN_MS,this.errorMs=parseIdleExitMs(env[LOOP_LAG_ERROR_MS_ENV])??DEFAULT_LOOP_LAG_ERROR_MS}start(){this.timer===void 0&&(this.expectedTickAt=this.now()+LOOP_LAG_TICK_MS,this.activityMark=sessionActivityMark(),this.timer=setInterval(()=>this.tick(),LOOP_LAG_TICK_MS),this.timer.unref?.())}stop(){this.timer!==void 0&&(clearInterval(this.timer),this.timer=void 0,this.expectedTickAt=void 0)}tick(){let now=this.now(),expectedAt=this.expectedTickAt??now,previousMark=this.activityMark;this.expectedTickAt=now+LOOP_LAG_TICK_MS,this.activityMark=sessionActivityMark();let driftMs=Math.round(now-expectedAt);if(recordLoopBlockedMs(driftMs),driftMs<=this.warnMs)return;let attribution=sessionActivitySince(previousMark);driftMs>this.errorMs&&this.emit({type:"host_stalled",driftMs,sessionId:attribution?.sessionId,tool:attribution?.tool}),!(this.lastWarnAt!==void 0&&now-this.lastWarnAt<LOOP_LAG_WARN_INTERVAL_MS)&&(this.lastWarnAt=now,this.log(`senpi rpc host stall: event loop blocked ${driftMs}ms (${describeAttribution(attribution)})
4
- `))}};function isHandoffBusy(snapshot){return isSessionBusySnapshot({...snapshot,hasActiveWakeSource:!1})}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(`
5
- `)){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}}),handler=await runWithProviderScope(entry.scope,async()=>{let taggedSink={writeRaw:bindToProviderScope(enqueueRecords),waitForBackpressure:bindToProviderScope(async()=>{})};return createRpcConnectionHandler(runtimeHost,taggedSink,{sessionId,shutdownHandler:bindToProviderScope(requestClose),disposeRuntime:!1,eventFlushScheduler:flush=>flush(),...options})});return await handler.ready,{handle:command=>runWithProviderScope(entry.scope,()=>handler.handleInputLine(JSON.stringify(command))),cancelPendingExtensionUiRequests:()=>runWithProviderScope(entry.scope,()=>handler.cancelPendingExtensionUiRequests()),rerenderComponents:()=>runWithProviderScope(entry.scope,()=>handler.rerenderComponents()),dispose:()=>(toolSpans.closeAll(),runWithProviderScope(entry.scope,()=>handler.dispose()))}}import{existsSync as existsSync2}from"node:fs";import{isAbsolute}from"node:path";import{existsSync,realpathSync}from"node:fs";import{basename,dirname,join,resolve}from"node:path";function canonicalSessionPath(path){let absolutePath=resolve(path),missing=[],existing=absolutePath;for(;!existsSync(existing);){let parent=dirname(existing);if(parent===existing)return absolutePath;missing.unshift(basename(existing)),existing=parent}try{return join(realpathSync(existing),...missing)}catch{return absolutePath}}function sessionDirectoryRemoved(sessionFile){return!existsSync(dirname(sessionFile))}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)}
6
- `)}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.reservationKey&&!sessionIsWriting(entry)&&host.markDetached(entry.reservationKey),entry):(entry.state="closing",onRole?.(!0),entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),entry)}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=()=>{released||(released=!0,releaseTimer&&clearTimeout(releaseTimer),entry.state="closed",host.delete(handle),entry.reservationKey&&host.releaseReservation(entry.reservationKey))},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=()=>{settled||(settled=!0,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 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.creationModel?{creationModel:Object.freeze({...profile.creationModel})}:{},...profile.sessionContext?{sessionContext:Object.freeze({...profile.sessionContext})}:{}})}function sessionIdentity(profile){return{kind:profile.sessionKind??"interactive",context:profile.sessionContext??EMPTY_SESSION_CONTEXT}}var RpcSessionRegistry=class{constructor(options){this.entries=new Map,this.reservations=new Set,this.nextHandle=0,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=>this.entries.delete(handle),releaseReservation:key=>{this.reservations.delete(key),this.options.pathReservations?.release(key)},markDetached:key=>this.options.pathReservations?.setAttached(key,!1),sync:()=>this.syncRuntimeMetadata()}}get size(){return this.entries.size}async openSession(profile,options){this.validateProfile(profile),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 this.settleClosingReservation(sessionPath),sessionPath&&this.reservations.has(sessionPath)){let existing=[...this.entries].find(([,entry3])=>entry3.reservationKey===sessionPath&&entry3.state==="open");if(!existing)throw new RpcSessionRegistryError("session_path_in_use");let[handle2,entry2]=existing,wasParked=entry2.retainOnDisconnect===!0&&entry2.attachments===0;if(entry2.attachments+=1,this.options.pathReservations?.setAttached(sessionPath,!0),options?.retainOnDisconnect&&(entry2.retainOnDisconnect=!0),!entry2.durableSessionId)throw new RpcSessionRegistryError("session_path_in_use");return entry2.lastCommandAt=this.now(),wasParked&&(entry2.lifecycleMutex=entry2.lifecycleMutex.then(()=>entry2.runtime?.emitAttachmentEvent("session_resumed")),await entry2.lifecycleMutex),{sessionId:handle2,durableSessionId:entry2.durableSessionId,sessionPath:entry2.sessionPath,attached:!0}}if(sessionPath){this.reservations.add(sessionPath);let holder=this.options.pathReservations?await this.options.pathReservations.claim(sessionPath):void 0;if(holder)throw this.reservations.delete(sessionPath),new RpcSessionRegistryError("session_path_in_use",void 0,{owner:holder,retry_after_ms:SESSION_PATH_RETRY_AFTER_MS})}let isResume=sessionPath!==void 0&&existsSync2(sessionPath),sessionStartEvent=isResume?{type:"session_start",reason:"resume"}:void 0,storedProfile=frozenProfile({...profile,...sessionPath?{sessionPath}:{}}),runtimeProfile=isResume?frozenProfile({...storedProfile,creationModel:void 0,initialThinkingLevel:void 0}):storedProfile,handle=`rpc-${++this.nextHandle}`,entry={state:"opening",scope:new ProviderScope,profile:storedProfile,...sessionIdentity(storedProfile),sessionPath,reservationKey:sessionPath,cwd:storedProfile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:this.now(),lifecycleMutex:Promise.resolve()};entry.switchSession=(sessionPath2,options2)=>{let operation=entry.lifecycleMutex.then(async()=>{if(entry.state!=="open"||!entry.runtime)throw new RpcSessionRegistryError("unknown_session");let runtime=entry.runtime,cwdOverride=options2?.cwdOverride,cwdChanged=cwdOverride!==void 0&&runtime.session.sessionManager.getCwd()!==cwdOverride,result=await runtime.switchSession(sessionPath2,options2);if(result.cancelled||!cwdChanged)return result;let replacement=new AgentSessionRuntime(runtime.session,runtime.services,this.options.createRuntime,[...runtime.diagnostics],runtime.modelFallbackMessage,runtime.launchProfile);return replacement.setRebindSession(entry.rebindSession),runtime.releaseSessionHold(),entry.runtime=replacement,this.syncRuntimeMetadata(),result});return entry.lifecycleMutex=operation.then(()=>{},()=>{}),operation},requestedDurableId!==void 0&&(entry.durableSessionId=requestedDurableId),this.entries.set(handle,entry);try{let newSessionOptions=requestedDurableId!==void 0?{id:requestedDurableId}:void 0,manager=sessionPath?SessionManager.open(sessionPath,void 0,storedProfile.cwd,newSessionOptions):SessionManager.create(storedProfile.cwd,void 0,newSessionOptions);return entry.runtime=await runWithProviderScope(entry.scope,()=>createAgentSessionRuntime(this.options.createRuntime,{cwd:manager.getCwd(),agentDir:this.options.agentDir,sessionManager:manager,sessionStartEvent,launchProfile:runtimeProfile})),entry.durableSessionId=manager.getSessionId(),entry.sessionPath??=manager.getSessionFile(),entry.state="open",{sessionId:handle,durableSessionId:entry.durableSessionId,sessionPath:entry.sessionPath}}catch(error2){try{await entry.runtime?.dispose()}catch{}finally{try{await entry.scope.close?.()}finally{this.entries.delete(handle),sessionPath&&(this.reservations.delete(sessionPath),this.options.pathReservations?.release(sessionPath))}}throw error2 instanceof RpcSessionRegistryError?error2:new RpcSessionRegistryError("open_failed",error2 instanceof Error?error2.message:void 0)}}async settleClosingReservation(sessionPath){let closing=[...this.entries.values()].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,this.closeGraceMs)})])}finally{deadline&&clearTimeout(deadline)}}peek(handle){return this.entries.get(handle)}getForCommand(handle,command){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return entry.lastCommandAt=this.now(),entry}beginClose(handle,onRole,options){return beginSessionClose(this.teardownHost,handle,onRole,options)}async close(handle){return closeSession(this.teardownHost,handle)}async closeMarked(handle){return closeMarkedSession(this.teardownHost,handle)}list(){return this.syncRuntimeMetadata(),[...this.entries].map(([sessionId,entry])=>({sessionId,durableSessionId:entry.durableSessionId,sessionPath:entry.sessionPath,cwd:entry.cwd,name:entry.runtime?.session.sessionManager.getSessionName(),kind:entry.kind,context:entry.context,attachments:Math.max(0,entry.attachments),status:entry.state==="quarantined"?"closing":entry.state}))}syncRuntimeMetadata(){for(let entry of this.entries.values()){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&&(this.reservations.delete(entry.reservationKey),this.options.pathReservations?.release(entry.reservationKey)),currentKey&&(this.reservations.add(currentKey),this.options.pathReservations?.claim(currentKey,entry.attachments>0)),entry.reservationKey=currentKey,entry.sessionPath=currentPath),entry.durableSessionId=manager.getSessionId(),entry.cwd=manager.getCwd()}}validateProfile(profile){if(!isAbsolute(profile.cwd)||profile.sessionPath!==void 0&&!isAbsolute(profile.sessionPath))throw new RpcSessionRegistryError("invalid_path");if(profile.durableSessionId!==void 0)try{assertValidSessionId(profile.durableSessionId)}catch(cause){throw new RpcSessionRegistryError("invalid_session_id",String(cause))}}};function selectSweepEvictions(registry,now,idleEvictionMs){let idle=[],orphaned=[];for(let{sessionId,status,sessionPath}of registry.list()){if(status!=="open")continue;let entry=registry.peek(sessionId);if(entry){if(entry.attachments===0&&sessionPath!==void 0&&sessionDirectoryRemoved(sessionPath)){orphaned.push(sessionId);continue}if(Number.isFinite(idleEvictionMs)){if(entry.worker?.busy||entry.runtime?.session.isSessionBusy){entry.lastCommandAt=now;continue}now-entry.lastCommandAt>=idleEvictionMs&&idle.push(sessionId)}}}return{idle,orphaned}}var DRAIN_SWEEP_MS=50;function error(id,command,code,data){return{id,type:"response",command,success:!1,error:code,...data&&{errorCode:code,errorData:data}}}var SessionCommandRouter=class{constructor(registry,writer,defaults,createBinding=createRpcSessionBinding,connectionOptions={},idle){if(this.bindings=new Map,this.sessionsByConnection=new Map,this.opensByConnection=new Map,this.releasedConnections=new Set,this.widths=new Map,this.pendingCapabilities=new Map,this.finalizations=new Map,this.draining=!1,this.handoffParks=0,this.drainExitRequested=!1,this.handoffClosed=new Set,this.activeRequests=new Map,this.memoryPressure=!1,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.canExitWhenEmpty=idle?.canExitWhenEmpty,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}beginDrain(){this.draining=!0,this.stopSweep(),this.sweepDrain(),!(this.drainTimer!==void 0||this.drainExitRequested)&&(this.drainTimer=setInterval(()=>this.sweepDrain(),DRAIN_SWEEP_MS),this.drainTimer.unref?.())}sweepDrain(){if(!this.activeRequests.has(void 0)){for(let{sessionId,status}of this.registry.list()){if(status!=="open")continue;let entry=this.registry.peek(sessionId);if(!entry||this.activeRequests.has(sessionId))continue;let snapshot=entry.runtime?.session.activitySnapshot;entry.worker?.handoffBusy===!0||snapshot!==void 0&&isHandoffBusy(snapshot)||(this.handoffClosed.add(sessionId),this.handoffParks++,this.evictIdleSession(sessionId,"handoff_parked").catch(cause=>{process.stderr.write(`senpi rpc handoff park ${sessionId} failed: ${String(cause)}
7
- `)}).finally(()=>{this.handoffParks--,this.sweepDrain()}))}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?.()))}}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")):(this.activeRequests.set(sessionId,(this.activeRequests.get(sessionId)??0)+1),runWithSessionAttribution({sessionId},()=>this.dispatch(command)).finally(()=>{let remaining=(this.activeRequests.get(sessionId)??1)-1;remaining>0?this.activeRequests.set(sessionId,remaining):this.activeRequests.delete(sessionId),this.draining&&this.sweepDrain()}))}async dispatch(command){if(command.type==="get_protocol_info"){let capabilities=new Set(["multi_session",AUTO_TITLE_SESSIONS_CAPABILITY,MEDIA_PLACEHOLDERS_CAPABILITY,RETAIN_ON_DISCONNECT_CAPABILITY,SESSION_CONTEXT_CAPABILITY,SESSION_KIND_CAPABILITY,AUTO_TITLE_PER_SESSION_CAPABILITY,DURABLE_SESSION_ID_CAPABILITY,...this.connectionOptions?.capabilities??[]]);return{id:command.id,type:"response",command:"get_protocol_info",success:!0,data:{protocolVersion:1,serverVersion:VERSION,capabilities:[...capabilities],mode:"multi",...protocolIdentity()}}}if(command.type==="list_sessions"){let rows=this.registry.list(),sessions=command.include_workers===!0?rows:rows.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==="open_session")return this.openWithBarrier(command);if(command.type==="close_session")return this.close(command);if(command.type==="set_client_info"&&!command.sessionId){let connection=this.writer.currentConnection();return 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.sessionId)return error(command.id,command.type,RPC_ERROR_MISSING_SESSION_ID);try{this.registry.getForCommand(command.sessionId,command.type);let binding=this.bindings.get(command.sessionId);if(!binding)return error(command.id,command.type,RPC_ERROR_UNKNOWN_SESSION);await binding.handle(command);return}catch(cause){return error(command.id,command.type,this.code(cause))}}async dispose(){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()}sweepIdleSessions(){let now=this.idleNow(),idleEvictionMs=this.memoryPressure?this.idleEvictionMs/2:this.idleEvictionMs,verdicts=selectSweepEvictions(this.registry,now,idleEvictionMs);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,owners=reason==="handoff_parked"?[...this.sessionsByConnection].filter(([,owned])=>owned.has(sessionId)).map(([connection])=>connection):[],claim=this.tryClaimClose(sessionId,{drainAttachments:!0});if(!claim)return;let binding=this.bindings.get(sessionId);binding?.cancelPendingExtensionUiRequests?.(),reason!=="handoff_parked"&&this.forgetSessionOwnership(sessionId),claim.finalizer?await this.finalizeClose(sessionId,binding,()=>parkedPath!==void 0&&reason===void 0?this.writer.parkSession(sessionId,parkedPath):this.writer.closeSession(sessionId,{type:"response",command:"close_session",success:!0,data:{}},reason??"idle_evicted",reason==="handoff_parked"?parkedPath:void 0)):await this.finalizations.get(sessionId)?.promise,reason==="handoff_parked"&&(this.forgetSessionOwnership(sessionId),await this.onHandoffParked?.(owners.filter(connection=>!this.sessionsByConnection.has(connection)))),this.writer.forgetSession(sessionId)}forgetSessionOwnership(sessionId){for(let[connection,owned]of this.sessionsByConnection)owned.delete(sessionId),owned.size===0&&this.sessionsByConnection.delete(connection);this.widths.delete(sessionId)}stopSweep(){this.sweepTimer!==void 0&&(clearInterval(this.sweepTimer),this.sweepTimer=void 0)}openWithBarrier(command){let owner=this.writer.currentConnection();if(owner===void 0)return this.open(command);let resolveBarrier,barrier=new Promise(resolve2=>{resolveBarrier=resolve2}),opens=this.opensByConnection.get(owner)??new Set,inFlight=0;for(let pending of this.opensByConnection.values())inFlight+=pending.size;return opens.add(barrier),this.opensByConnection.set(owner,opens),command.id!==void 0&&this.writer.sendOpenQueued(owner,{type:"queued",for_request:command.id,position:inFlight+1,in_flight:inFlight}),this.open(command,owner).finally(()=>{resolveBarrier(),opens.delete(barrier),opens.size===0&&this.opensByConnection.delete(owner)})}async open(command,owner){let kindError=sessionKindError(command.kind);if(kindError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_KIND}: ${kindError}`);let contextError=sessionContextError(command.context);if(contextError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_SESSION_CONTEXT}: ${contextError}`);let autoTitleError=sessionAutoTitleError(command.auto_title);if(autoTitleError)return error(command.id,"open_session",`${RPC_ERROR_INVALID_LAUNCH_PROFILE}: ${autoTitleError}`);let opened;try{opened=await this.registry.openSession({cwd:command.cwd??this.defaults.cwd,sessionPath:command.sessionPath,permissionPreset:command.permissionPreset??this.defaults.permissionPreset,creationModel:command.provider&&command.modelId?{provider:command.provider,modelId:command.modelId}:this.defaults.creationModel,initialThinkingLevel:command.thinkingLevel??this.defaults.initialThinkingLevel,sessionKind:command.kind,sessionContext:command.context,...command.durableSessionId!==void 0?{durableSessionId:command.durableSessionId}:{},...typeof command.auto_title=="boolean"?{autoTitle:command.auto_title}:{}},{retainOnDisconnect:command.retain_on_disconnect===!0});let openedSession=opened,entry=this.registry.getForCommand(openedSession.sessionId,"open_session");if(this.writer.setSessionKind(openedSession.sessionId,entry.kind),owner!==void 0&&(this.writer.hasRegisteredConnectionCapabilities(owner)||this.writer.setConnectionCapabilities(owner,this.pendingCapabilities.get(owner)??this.connectionOptions?.capabilities??[]),this.writer.attachConnectionToSession(owner,openedSession.sessionId)),owner!==void 0){let owned=this.sessionsByConnection.get(owner)??new Map;owned.set(openedSession.sessionId,(owned.get(openedSession.sessionId)??0)+1),this.sessionsByConnection.set(owner,owned)}if(!this.bindings.has(openedSession.sessionId)){this.bindings.set(openedSession.sessionId,await this.createBinding(openedSession.sessionId,entry,this.writer,()=>{this.close({type:"close_session",sessionId:openedSession.sessionId})},{...this.connectionOptions,capabilities:owner!==void 0?this.pendingCapabilities.get(owner)??this.connectionOptions?.capabilities??[]:this.connectionOptions?.capabilities,sharedWidth:{getWidth:()=>{let widths=this.widths.get(openedSession.sessionId);return widths?.size?Math.min(...widths.values()):80},setWidth:(connectionId,width)=>{if(connectionId!==void 0){let widths=this.widths.get(openedSession.sessionId)??new Map;widths.set(connectionId,width),this.widths.set(openedSession.sessionId,widths)}},clearWidth:connectionId=>{let widths=this.widths.get(openedSession.sessionId);connectionId!==void 0&&widths?.delete(connectionId)},setCapabilities:(connectionId,capabilities)=>{if(connectionId!==void 0){this.writer.setConnectionCapabilities(connectionId,capabilities),this.pendingCapabilities.set(connectionId,[...capabilities]);for(let binding of this.bindings.values())binding.rerenderComponents?.()}},hasRenderedComponents:sessionId=>this.writer.hasCapableConnection(sessionId),connectionId:()=>this.writer.currentConnection(),onChange:()=>{for(let binding of this.bindings.values())binding.rerenderComponents?.()}}})),entry.worker&&(entry.worker.bindingReady=!0);let settled=()=>{this.draining&&queueMicrotask(()=>this.sweepDrain())};typeof entry.worker?.subscribeSettled=="function"?entry.worker.subscribeSettled(settled):typeof entry.runtime?.session.subscribe=="function"&&entry.runtime.session.subscribe(event=>{(event.type==="agent_settled"||event.type==="agent_idle")&&settled()}),entry.worker&&entry.worker.exited.then(async()=>{await this.finalizations.get(openedSession.sessionId)?.promise,this.bindings.delete(openedSession.sessionId),this.forgetSessionOwnership(openedSession.sessionId),this.writer.forgetSession(openedSession.sessionId)})}!this.draining&&owner!==void 0&&this.releasedConnections.has(owner)&&(this.releaseOwnerAttachment(owner,openedSession.sessionId),await this.releaseOwnedSession(openedSession.sessionId));let state=entry.worker?.snapshot?.state??(entry.runtime?buildRpcSessionState(entry.runtime.session):void 0);if(!state)throw new Error("Session state was not created");this.writer.enqueue(opened.sessionId,{id:command.id,type:"response",command:"open_session",success:!0,data:{sessionId:opened.sessionId,state,...opened.attached?{attached:!0}:{}}});return}catch(cause){if(opened)try{await this.registry.close(opened.sessionId)}catch{}return error(command.id,"open_session",this.code(cause),this.detail(cause))}}async releaseConnection(connectionId){this.releasedConnections.add(connectionId),this.writer.clearConnectionCapabilities(connectionId);for(let sessionId of this.sessionsByConnection.get(connectionId)?.keys()??[])this.writer.detachConnectionFromSession(connectionId,sessionId);for(let widths of this.widths.values())widths.delete(connectionId);for(let binding of this.bindings.values())binding.rerenderComponents?.();let opens=this.opensByConnection.get(connectionId),owned=this.sessionsByConnection.get(connectionId);if(this.sessionsByConnection.delete(connectionId),this.draining){opens&&await Promise.all([...opens]),this.releasedConnections.delete(connectionId);return}if(owned===void 0){opens&&await Promise.all([...opens]),this.releasedConnections.delete(connectionId);return}await Promise.all([...owned].map(async([sessionId,count])=>{for(let attachment=0;attachment<count;attachment++){let live=this.registry.peek(sessionId),retained=live?.retainOnDisconnect===!0,session=live?.state==="open"?live.runtime?.session:void 0;if(!retained&&live?.state==="open"&&live.worker?.snapshot?.streaming){let unsubscribe=live.worker.subscribeSettled(()=>{unsubscribe(),this.releaseOwnedSession(sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred worker release ${sessionId} failed: ${String(cause)}
8
- `)})});continue}if(!retained&&session?.isStreaming){let released=!1,unsubscribe=session.subscribe(event=>{event.type!=="agent_settled"&&event.type!=="agent_idle"||released||(released=!0,unsubscribe(),this.releaseOwnedSession(sessionId).catch(cause=>{process.stderr.write(`senpi rpc deferred release for session ${sessionId} failed: ${String(cause)}
9
- `)}))});continue}await this.releaseOwnedSession(sessionId)}})),opens&&await Promise.all([...opens]),this.releasedConnections.delete(connectionId)}async releaseOwnedSession(sessionId){let live=this.registry.peek(sessionId),parks=live?.state==="open"&&live.retainOnDisconnect===!0&&live.attachments===1,claim=this.tryClaimClose(sessionId,{drainAttachments:!1,detach:!0});if(!claim)return;if(!claim.finalizer){parks&&live.runtime&&(live.lifecycleMutex=live.lifecycleMutex.then(()=>live.runtime?.emitAttachmentEvent("session_parked")),await live.lifecycleMutex),await this.finalizations.get(sessionId)?.promise;return}let binding=this.bindings.get(sessionId);binding?.cancelPendingExtensionUiRequests?.(),await this.finalizeClose(sessionId,binding)}claimClose(sessionId,options){let finalizer=!0,onRole=isFinalizer=>{finalizer=isFinalizer,isFinalizer&&!this.finalizations.has(sessionId)&&this.finalizations.set(sessionId,this.createFinalization())},entry=this.registry.beginClose(sessionId,onRole,{detach:options.detach});for(;options.drainAttachments&&entry.state==="open";)entry=this.registry.beginClose(sessionId,onRole);return{finalizer:finalizer&&entry.state==="closing"}}tryClaimClose(sessionId,options){try{return this.claimClose(sessionId,options)}catch{return}}async close(command){let response={id:command.id,type:"response",command:"close_session",success:!0,data:{}},owner=this.writer.currentConnection();if(owner!==void 0&&this.sessionsByConnection.get(owner)?.has(command.sessionId)!==!0)return error(command.id,"close_session",RPC_ERROR_UNKNOWN_SESSION);let reply=this.writer.reserveCloseResponse(command.sessionId,response);if(!reply)return;let claim;try{claim=this.claimClose(command.sessionId,{drainAttachments:!1})}catch(cause){return reply.release(),error(command.id,"close_session",this.code(cause))}try{owner!==void 0&&this.releaseOwnerAttachment(owner,command.sessionId),claim.finalizer?await this.finalizeClose(command.sessionId,this.bindings.get(command.sessionId),()=>reply.complete(!0,"client_close")):(await this.finalizations.get(command.sessionId)?.promise,reply.complete(!1));return}finally{reply.release()}}releaseOwnerAttachment(owner,sessionId){this.widths.get(sessionId)?.delete(owner),this.writer.detachConnectionFromSession(owner,sessionId);for(let binding of this.bindings.values())try{binding.rerenderComponents?.()}catch(cause){process.stderr.write(`senpi rpc rerender after close of session ${sessionId} failed: ${String(cause)}
10
- `)}let owned=this.sessionsByConnection.get(owner),count=owned?.get(sessionId);!owned||count===void 0||(count===1?owned.delete(sessionId):owned.set(sessionId,count-1),owned.size===0&&this.sessionsByConnection.delete(owner))}async finalizeClose(sessionId,binding,terminal){let finalization=this.finalizations.get(sessionId)??this.createFinalization();this.finalizations.set(sessionId,finalization);try{try{await binding?.dispose()}catch(cause){process.stderr.write(`senpi rpc binding dispose for session ${sessionId} failed: ${String(cause)}
11
- `)}this.bindings.delete(sessionId);try{await this.registry.closeMarked(sessionId)}catch(cause){process.stderr.write(`senpi rpc close for session ${sessionId} failed: ${String(cause)}
12
- `)}await this.registry.peek(sessionId)?.closeCompletion,terminal?.()}finally{finalization.resolve(),this.finalizations.delete(sessionId)}}createFinalization(){let resolveFinalization;return{promise:new Promise(resolve2=>{resolveFinalization=resolve2}),resolve:()=>resolveFinalization?.()}}detail(cause){return cause instanceof RpcSessionRegistryError?cause.detail:void 0}code(cause){return cause instanceof RpcSessionRegistryError?cause.code===RPC_ERROR_OPEN_FAILED?cause.message:cause.code:cause instanceof Error&&[RPC_ERROR_UNKNOWN_SESSION,RPC_ERROR_SESSION_CLOSING].includes(cause.message)?cause.message:cause instanceof Error&&cause.message?`${RPC_ERROR_OPEN_FAILED}: ${cause.message}`:RPC_ERROR_UNKNOWN_SESSION}};function socketSink(socket){let needsDrain=!1,cut=!1;return{writeRaw(chunk){!cut&&!socket.destroyed&&(needsDrain=!socket.write(chunk))},close(){if(cut||(cut=!0,socket.destroyed))return;socket.end();let grace=setTimeout(()=>socket.destroy(),5e3);grace.unref(),socket.once("close",()=>clearTimeout(grace))},waitForBackpressure(){return socket.destroyed||!needsDrain?Promise.resolve():(needsDrain=!1,new Promise(resolve2=>{let done=()=>{socket.off("drain",done),socket.off("close",done),resolve2()};socket.once("drain",done),socket.once("close",done)}))}}}import{isAbsolute as isAbsolute2}from"node:path";var SESSION_WORKER_LIMITS={workers:20,requests:64,controlRequests:4,controlBytes:1048576,requestBytes:16777216,outputBytes:16777216,reservations:64,openMs:3e4,controlMs:5e3},WORKER_CREDIT_CODES={granted:1,conflict:2,limit:3};var RESERVATION_DENIAL_CODES={conflict:"session_path_in_use",limit:"session_reservation_limit"},SessionPathReservations=class{constructor(){this.owners=new Map}owner(path){return this.owners.get(path)}count(handle){let count=0;for(let owner of this.owners.values())owner===handle&&count++;return count}reserve(handle,path,live){let owner=this.owners.get(path);return owner?owner===handle?"granted":"conflict":this.count(handle)>=SESSION_WORKER_LIMITS.reservations&&(!live||(this.reconcile(handle,live),this.count(handle)>=SESSION_WORKER_LIMITS.reservations))?"limit":(this.owners.set(path,handle),"granted")}reconcile(handle,live){for(let[path,owner]of this.owners)owner!==handle||path===live.sessionPath||live.livePaths.includes(path)||this.owners.delete(path)}releaseAll(handle){for(let[path,owner]of this.owners)owner===handle&&this.owners.delete(path)}};import{fileURLToPath}from"node:url";import{Worker}from"node:worker_threads";var SessionWorkerRequests=class{constructor(send,timeout){this.pending=new Map,this.serial=0,this.closed=!1,this.send=send,this.timeout=timeout}remainingOpenMs(){let now=Date.now();return this.openingDeadline===void 0&&(this.openingDeadline=now+SESSION_WORKER_LIMITS.openMs),Math.max(0,this.openingDeadline-now)}get activeCount(){return this.pending.size}request(message){if(this.closed)return Promise.reject(new Error("session_closing"));let control=message.type==="command"&&"type"in message.command&&typeof message.command.type=="string"&&["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(message.command.type),bytes=Buffer.byteLength(JSON.stringify(message)),count=0,pendingBytes=0;for(let pending of this.pending.values())pending.control===control&&(count++,pendingBytes+=pending.bytes);let maxCount=control?SESSION_WORKER_LIMITS.controlRequests:SESSION_WORKER_LIMITS.requests,maxBytes=control?SESSION_WORKER_LIMITS.controlBytes:SESSION_WORKER_LIMITS.requestBytes;if(count>=maxCount||pendingBytes+bytes>maxBytes)return Promise.reject(new Error("session_worker_request_limit"));let request=++this.serial;return new Promise((resolve2,reject)=>{let timer=message.type==="command"&&!control?void 0:setTimeout(this.timeout,control?SESSION_WORKER_LIMITS.controlMs:this.remainingOpenMs());this.pending.set(request,{resolve:resolve2,reject,bytes,control,timer});try{this.send({...message,request})}catch(cause){this.pending.delete(request),clearTimeout(timer),reject(cause instanceof Error?cause:new Error(String(cause)))}})}receive(message){let pending=this.pending.get(message.request);pending&&(clearTimeout(pending.timer),this.pending.delete(message.request),message.type==="result"&&message.error?pending.reject(new Error(message.error)):pending.resolve(message))}close(error2){this.closed=!0;for(let pending of this.pending.values())clearTimeout(pending.timer),pending.reject(error2);this.pending.clear()}};function acknowledgeGrant(signal,grant){let state=new Int32Array(signal);Atomics.store(state,0,WORKER_CREDIT_CODES[grant]),Atomics.notify(state,0)}function acknowledge(signal,granted){acknowledgeGrant(signal,granted?"granted":"conflict")}function respondDisplay(signal,display){let values=new Float64Array(signal);values[1]=display.width,values[2]=display.revision,Atomics.store(new Int32Array(signal),1,display.rendered?1:0),acknowledge(signal,!0)}var compiledWorkerEntry=typeof SENPI_RPC_SESSION_WORKER_ENTRY=="string"?SENPI_RPC_SESSION_WORKER_ENTRY:"./src/modes/rpc/session-worker.ts",SessionWorkerClient=class{constructor(callbacks){this.worker=new Worker(isBunBinary?fileURLToPath(new URL(compiledWorkerEntry,import.meta.url)).replaceAll("\\","/"):new URL(import.meta.url.endsWith(".ts")?"./session-worker.ts":"./session-worker.js",import.meta.url)),this.bindingReady=!1,this.requests=new SessionWorkerRequests(message=>this.worker.postMessage(message),()=>this.fail("session_worker_request_timeout")),this.stopped=!1,this.displayRevision=0,this.options={},this.listeners=new Set,this.controls=new Set,this.callbacks=callbacks,this.exited=new Promise(resolve2=>{this.worker.once("exit",()=>{!this.stopped&&!this.closeTimer&&this.fail("session_worker_exited"),this.stopped=!0,this.closeTimer&&clearTimeout(this.closeTimer),this.requests.close(new Error("session_worker_exited")),this.listeners.clear(),callbacks.exit(),this.publishTerminalFailure(),resolve2()})}),this.worker.on("message",message=>this.receive(message)),this.worker.on("error",error2=>this.fail(error2 instanceof Error?error2.message:String(error2)))}async prepare(configuration,profile){let result=await this.request({type:"prepare",configuration,profile});if(result.type!=="prepared")throw new Error("Invalid worker prepare response");return result.sessionPath}async commit(){let result=await this.request({type:"commit"});if(result.type!=="ready")throw new Error("Invalid worker commit response");return this.snapshot=result.snapshot,result.snapshot}async bind(sessionId,writer,requestClose,options){return this.sessionId=sessionId,this.writer=writer,this.requestClose=requestClose,this.options=options,await this.request({type:"bind",sessionId,display:this.display(),connection:writer.currentConnection()}),{handle:async command=>{await this.request({type:"command",command,connection:writer.currentConnection(),display:this.display()})},cancelPendingExtensionUiRequests:()=>this.post({type:"cancel_ui"}),rerenderComponents:()=>this.post({type:"display",display:this.display()}),dispose:async()=>{this.post({type:"cancel_ui"})}}}get busy(){return this.requests.activeCount>0||this.snapshot?.busy===!0}get handoffBusy(){return this.requests.activeCount>0||(this.snapshot?.handoffBusy??this.snapshot?.busy)===!0}subscribeSettled(listener){return this.listeners.add(listener),()=>this.listeners.delete(listener)}close(graceMs){return this.stopped||this.closeTimer?this.exited:(this.post({type:"close"}),this.closeTimer=setTimeout(()=>this.quarantine(),graceMs),this.exited)}quarantine(){this.stopped=!0,this.requests.close(new Error("session_closing")),this.worker.terminate()}display(){return{revision:++this.displayRevision,width:this.options.sharedWidth?.getWidth()??80,rendered:this.options.sharedWidth?.hasRenderedComponents?.(this.sessionId??"")??!1,capabilities:this.options.capabilities??[]}}request(message){return this.requests.request(message)}post(message){if(!this.stopped){if(message.type==="display"||message.type==="cancel_ui"){if(this.controls.has(message.type)){message.type==="display"&&(this.latestDisplay=message);return}this.controls.add(message.type)}this.worker.postMessage(message)}}receive(message){if(this.stopped){"signal"in message&&acknowledge(message.signal,!1);return}switch(message.type){case"prepared":case"ready":case"result":{this.requests.receive(message);return}case"reserve":acknowledgeGrant(message.signal,this.callbacks.reserve(message.path));return;case"snapshot":if(this.snapshot=message.snapshot,this.callbacks.reconcile(message.snapshot.liveSessionPaths),acknowledge(message.signal,!0),message.settled)for(let listener of[...this.listeners])listener();return;case"control_done":{if(this.controls.delete(message.control),message.control==="display"&&this.latestDisplay){let latest=this.latestDisplay;this.latestDisplay=void 0,this.post(latest)}return}case"output":{let writer=this.writer,sessionId=this.sessionId;if(!writer||!sessionId||this.stopped){acknowledge(message.signal,!1);return}message.snapshot?(this.snapshot=message.snapshot,this.callbacks.reconcile(message.snapshot.liveSessionPaths)):this.snapshot&&(this.snapshot={...this.snapshot,...message.activity,state:{...this.snapshot.state,isStreaming:message.activity.streaming}});let enqueue=()=>writer.enqueue(sessionId,message.record)?writer.waitForSessionBackpressure(sessionId):(acknowledge(message.signal,!1),this.fail("session_output_overflow_or_closed"),Promise.reject(new Error("session_output_overflow_or_closed")));(message.connection===void 0?enqueue():writer.withConnection(message.connection,enqueue)).then(()=>acknowledge(message.signal,!0),cause=>{acknowledge(message.signal,!1),this.fail(cause instanceof Error?cause.message:String(cause))});return}case"width":this.options.sharedWidth?.setWidth(message.connection,message.width),this.options.sharedWidth?.onChange?.(),respondDisplay(message.signal,this.display());return;case"capabilities":this.options.sharedWidth?.setCapabilities?.(message.connection,message.capabilities),respondDisplay(message.signal,this.display());return;case"request_close":this.requestClose?.();return;case"failure":this.fail(message.error);return}}fail(error2){this.stopped||(this.callbacks.failure(error2),this.terminalFailure=error2,this.writer&&this.sessionId&&this.writer.enqueue(this.sessionId,{type:"session_error",error:error2}),this.quarantine())}publishTerminalFailure(){let error2=this.terminalFailure,writer=this.writer,sessionId=this.sessionId;error2===void 0||!writer||!sessionId||(this.terminalFailure=void 0,writer.closeSession(sessionId,{type:"response",command:"close_session",success:!1,error:error2},"error"))}};var WorkerSessionRegistry=class{constructor(options){this.entries=new Map,this.reservations=new SessionPathReservations,this.serial=0,this.options=options,this.closeGraceMs=options.closeGraceMs,this.now=options.now,this.createWorker=options.createWorker??(callbacks=>new SessionWorkerClient(callbacks))}get size(){return this.entries.size}async openSession(profile,options){if(!isAbsolute2(profile.cwd)||profile.sessionPath!==void 0&&!isAbsolute2(profile.sessionPath))throw new RpcSessionRegistryError("invalid_path");let requestedDurableId=profile.durableSessionId;if(requestedDurableId!==void 0){try{assertValidSessionId(requestedDurableId)}catch(cause){throw new RpcSessionRegistryError("invalid_session_id",String(cause))}let requestedKey=profile.sessionPath?this.knownReservationKey(profile.sessionPath):void 0;for(let entry2 of this.entries.values())if(entry2.state!=="closed"&&entry2.durableSessionId===requestedDurableId&&!(requestedKey!==void 0&&entry2.reservationKey===requestedKey))throw new RpcSessionRegistryError("session_id_in_use")}if(profile.sessionPath){let key=this.knownReservationKey(profile.sessionPath),owner=key?this.reservations.owner(key):void 0;if(key&&owner)return this.attach(owner,key,options)}if(this.size>=SESSION_WORKER_LIMITS.workers)throw new Error("too_many_sessions");let handle=`rpc-${++this.serial}`,storedProfile=frozenProfile(profile),entry={state:"opening",scope:new ProviderScope,profile:storedProfile,...sessionIdentity(storedProfile),cwd:profile.cwd,attachments:1,retainOnDisconnect:options?.retainOnDisconnect===!0,lastCommandAt:this.now(),lifecycleMutex:Promise.resolve(),...requestedDurableId!==void 0?{durableSessionId:requestedDurableId}:{}},workerFailure,worker=this.createWorker({reserve:path=>this.reserve(handle,path),reconcile:livePaths=>this.reconcile(handle,livePaths),exit:()=>{this.entries.get(handle)===entry&&(entry.state="closed",this.entries.delete(handle),this.reservations.releaseAll(handle),entry.closeResolve?.())},failure:error2=>{workerFailure=error2,entry.state="quarantined",process.stderr.write(`senpi rpc session ${handle} quarantined: ${error2}
13
- `)}});entry.worker=worker,this.entries.set(handle,entry);try{let path=await worker.prepare(this.options.configuration,profile),owner=this.reservations.owner(path);if(owner){let attached=this.attach(owner,path,options);return entry.state="quarantined",worker.quarantine(),attached}let grant=this.reserve(handle,path);if(grant!=="granted")throw new RpcSessionRegistryError(RESERVATION_DENIAL_CODES[grant]);entry.reservationKey=path,entry.requestedPathKey=profile.sessionPath?path:void 0,entry.sessionPath=path;let snapshot=await worker.commit();if(entry.state!=="opening")throw workerFailure===void 0?new RpcSessionRegistryError("session_closing"):new RpcSessionRegistryError("open_failed",workerFailure);return entry.durableSessionId=snapshot.state.sessionId,entry.cwd=snapshot.state.cwd,entry.state="open",this.openResult(handle,entry)}catch(cause){throw entry.state="quarantined",worker.quarantine(),cause}}peek(handle){return this.entries.get(handle)}getForCommand(handle,command){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="quarantined"||entry.state==="closing"&&!["abort","abort_bash","extension_ui_response","extension_ui_progress"].includes(command))throw new RpcSessionRegistryError("session_closing");if(entry.state!=="open"&&entry.state!=="closing")throw new RpcSessionRegistryError("unknown_session");return entry.lastCommandAt=this.now(),entry}beginClose(handle,onRole,options){let entry=this.entries.get(handle);if(!entry)throw new RpcSessionRegistryError("unknown_session");if(entry.state==="closing"||entry.state==="quarantined")return onRole?.(!1),entry;if(entry.state!=="open"&&entry.state!=="opening")throw new RpcSessionRegistryError("unknown_session");return entry.attachments--,entry.attachments>0?entry:options?.detach&&entry.retainOnDisconnect?(entry.attachments=0,entry):(entry.state="closing",entry.closeCompletion=new Promise(resolve2=>{entry.closeResolve=resolve2}),onRole?.(!0),entry)}close(handle){return this.beginClose(handle).state==="closing"?this.closeMarked(handle):Promise.resolve()}async closeMarked(handle){let entry=this.entries.get(handle);if(entry?.state!=="closing"||!entry.worker)throw new RpcSessionRegistryError("unknown_session");if(entry.closeStarted)return entry.closeCompletion;entry.closeStarted=!0;let timer;await Promise.race([entry.worker.close(this.closeGraceMs),new Promise(resolve2=>{timer=setTimeout(()=>{entry.state!=="closed"&&(entry.state="quarantined"),resolve2()},this.closeGraceMs)})]),timer&&clearTimeout(timer)}list(){return[...this.entries].map(([sessionId,entry])=>{let state=entry.worker?.snapshot?.state;return{sessionId,durableSessionId:state?.sessionId??entry.durableSessionId,sessionPath:state?.sessionFile??entry.sessionPath,cwd:state?.cwd??entry.cwd,name:state?.sessionName,kind:entry.kind,context:entry.context,attachments:Math.max(0,entry.attachments),status:entry.state==="quarantined"?"closing":entry.state}})}knownReservationKey(path){if(this.reservations.owner(path))return path;for(let entry of this.entries.values()){if(entry.profile.sessionPath===path&&entry.requestedPathKey&&this.reservations.owner(entry.requestedPathKey))return entry.requestedPathKey;let snapshot=entry.worker?.snapshot;if(snapshot?.state.sessionFile===path)return snapshot.sessionPath}}attach(owner,path,options){let entry=this.entries.get(owner);if(entry?.state!=="open"||!entry.worker?.bindingReady||entry.worker.snapshot?.sessionPath!==path)throw new RpcSessionRegistryError("session_path_in_use");let result=this.openResult(owner,entry);return entry.attachments++,options?.retainOnDisconnect&&(entry.retainOnDisconnect=!0),entry.lastCommandAt=this.now(),{...result,attached:!0}}reservationCount(handle){return this.reservations.count(handle)}reserve(handle,path){let entry=this.entries.get(handle);return entry?this.reservations.owner(path)===handle?"granted":entry.state!=="opening"&&entry.state!=="open"?"conflict":this.reservations.reserve(handle,path,this.liveWorkerPaths(entry)):"conflict"}reconcile(handle,livePaths){let entry=this.entries.get(handle);if(entry?.state!=="open")return;let sessionPath=entry.worker?.snapshot?.sessionPath;this.reservations.reconcile(handle,{livePaths,sessionPath}),sessionPath&&(entry.reservationKey=sessionPath,entry.sessionPath=sessionPath)}liveWorkerPaths(entry){let snapshot=entry.state==="open"?entry.worker?.snapshot:void 0;if(snapshot)return{livePaths:snapshot.liveSessionPaths,sessionPath:snapshot.sessionPath}}openResult(handle,entry){let state=entry.worker?.snapshot?.state;if(!state)throw new RpcSessionRegistryError("open_failed");return{sessionId:handle,durableSessionId:state.sessionId,sessionPath:state.sessionFile}}};var WINDOWS_SHUTDOWN_HARD_EXIT_MS=2e3;function startHostObservers(router,writer,options={}){let loopLag=new LoopLagWatchdog({emit:record=>writer.broadcastHostRecord(record)}),memory=new HostMemorySampler({emit:record=>writer.broadcastHostRecord(record),sessions:()=>router.sessionCount,onPressure:pressure=>router.setMemoryPressure(pressure),...options.onIdlePressure?{onIdlePressure:options.onIdlePressure}:{}});return loopLag.start(),memory.start(),{stop:()=>{loopLag.stop(),memory.stop()}}}async function runMultiSessionHost(options){return runAsHostGenerationProcess(()=>options.listen===void 0||options.listen==="stdio://"?runStdioHost(options):runSocketHost(options,resolveSocketPath(options.listen,options.agentDir)))}function createHostCore(options,writer,capabilities=parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")),idle={}){let policy=resolveHostIdlePolicy(process.env,idle),router=new SessionCommandRouter(options.workerConfiguration?new WorkerSessionRegistry({configuration:options.workerConfiguration,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4}):new RpcSessionRegistry({agentDir:options.agentDir,createRuntime:options.createRuntime,mcpRegistry:new HostMcpRegistry,now:policy.now,closeGraceMs:idle.closeGraceMs??parseIdleExitMs(process.env[RPC_CLOSE_GRACE_MS_ENV])??1e4,pathReservations:createEndpointReservations({agentDir:options.agentDir,socket:listenSocketPath(options),instanceId:hostInstanceId(),onFailure:hostLog})}),writer,options,options.createBinding,{capabilities},{now:policy.now,idleEvictionMs:policy.idleEvictionMs,emptyExitMs:policy.emptyExitMs,onEmptyExit:idle.onEmptyExit,onHandoffParked:idle.onHandoffParked,canExitWhenEmpty:idle.canExitWhenEmpty});return{router,handle:async line=>{let parsed;try{parsed=JSON.parse(line)}catch(cause){await writer.enqueueControl(parseError(`Failed to parse command: ${errorMessage(cause)}`));return}let shapeError=rpcCommandShapeError(parsed);if(shapeError){await writer.enqueueControl(parseError(shapeError));return}let response=await router.handle(parsed);response&&await writer.enqueueControl(response)}}}async function runStdioHost(options){takeOverStdout();let sink={writeRaw:writeRawStdout,waitForBackpressure:waitForRawStdoutBackpressure},writer=new SessionEventWriter(sink.writeRaw,sink.waitForBackpressure),{router,handle}=createHostCore(options,writer,void 0,{onEmptyExit:()=>{shutdown(0)}}),observers=startHostObservers(router,writer),shuttingDown=!1,shutdown=async(exitCode=0)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0,observers.stop(),detach(),await router.dispose(),await writer.flush(),await flushRawStdout(),process.exit(exitCode)},onEnd=()=>{shutdown()};process.stdin.on("end",onEnd);let reportInputFailure=cause=>{process.stderr.write(`senpi rpc stdio request failed: ${errorMessage(cause)}
14
- `)},detachReader=attachJsonlLineReader(process.stdin,line=>{handle(line).catch(reportInputFailure)},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.enqueueControl(parseError(oversizedLineError())).catch(reportInputFailure)}}),detach=()=>{detachReader(),process.stdin.off("end",onEnd)};return registerShutdownSignals(shutdown),new Promise(()=>{})}async function runSocketHost(options,socketPath){await prepareSocketPath(socketPath);let writer=new SessionEventWriter(()=>{}),connections=new Map,draining=!1,handoffAnnounced=!1,{router,handle}=createHostCore(options,writer,[...parseClientCapabilities(envValue("RPC_CLIENT_CAPABILITIES")).filter(capability=>capability!=="rendered_components"),GENERATION_HANDOFF_CAPABILITY],{onEmptyExit:()=>{shutdown(0)},canExitWhenEmpty:()=>draining||connections.size===0,onHandoffParked:async ids=>{await Promise.all(ids.map(async id=>{await writer.flushConnection(id),connections.get(id)?.close()}))}}),observers=startHostObservers(router,writer,{onIdlePressure:rssMb=>{hostLog(`memory pressure with no sessions: rssMb=${rssMb}`),endpointSuperseded().then(superseded=>{superseded&&drainForHandoff()},noop)}}),nextConnection=0,shuttingDown=!1,secret=process.platform==="win32"?await ensureSocketSecret(process.env[SOCKET_SECRET_FILE_ENV]??socketSecretPath(socketPath)):void 0,watchdogConfig=readHostWatchdogConfigFromBrandEnv(),crashCleanupPaths=[...watchdogConfig?.cleanupPaths??[]],supervisorPublicSocketPath=process.platform==="win32"||socketPath.startsWith("\0")?void 0:watchdogConfig?.publicSocket,supervisorPublicOwnerFile=supervisorPublicSocketPath&&watchdogConfig?.scratchDir?join2(watchdogConfig.scratchDir,PUBLIC_SOCKET_IDENTITY_FILE):void 0,boundIdentity,supervisorPublicIdentity,server=createServer(socket=>{let accept=()=>{if(draining||shuttingDown){socket.destroy();return}let id=`socket-${++nextConnection}`,sink=socketSink(socket);writer.registerConnection(id,sink);let detachReader=attachJsonlLineReader(socket,line=>{writer.withConnection(id,()=>handle(line)).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
15
- `)})},{maxLineLength:MAX_RPC_LINE_CHARACTERS,onOversizedLine:()=>{writer.withConnection(id,()=>writer.enqueueControl(parseError(oversizedLineError()))).catch(cause=>process.stderr.write(`senpi rpc connection ${id} failed: ${errorMessage(cause)}
16
- `))}}),detached=!1,detach=()=>{detached||(detached=!0,detachReader(),writer.unregisterConnection(id),connections.delete(id),router.releaseConnection(id).catch(cause=>{process.stderr.write(`senpi rpc connection ${id} release failed: ${errorMessage(cause)}
17
- `)}))};connections.set(id,{id,sink,detach,close:()=>socket.destroy()}),socket.once("close",detach),socket.once("error",()=>detach())};secret?authenticateSocket(socket,secret,accept):accept()});server.on("error",cause=>{shuttingDown||process.stderr.write(`senpi rpc socket listener failed: ${errorMessage(cause)}
18
- `)});let stopChildReaper=await startHostChildReaper(hostLog),shutdown=async(exitCode=0,watchdogCleanup)=>{shuttingDown&&process.exit(exitCode),shuttingDown=!0,observers.stop(),stopChildReaper();try{await router.dispose(),await writer.flush();for(let connection of connections.values())connection.detach(),connection.close();await shieldSocketDuringClose(socketPath,()=>process.platform==="win32"?Promise.race([closeServer(server),delay(WINDOWS_SHUTDOWN_HARD_EXIT_MS)]):closeServer(server)),await unlinkOwnedSocket(socketPath,boundIdentity,hostLog),supervisorPublicSocketPath&&await unlinkOwnedSocket(supervisorPublicSocketPath,supervisorPublicIdentity,hostLog),watchdogCleanup&&await watchdogCleanup}finally{process.exit(exitCode)}},drainForHandoff=()=>{if(!shuttingDown){if(draining){handoffAnnounced&&router.beginDrain();return}draining=!0,crashCleanupPaths.length=0,hostLog("draining for a generation handoff"),endpointSuperseded().then(superseded=>{writer.broadcastHostRecord({type:"host_superseded",instanceId:hostInstanceId(),generation:hostGeneration(process.env),successor:superseded?{socket:supervisorPublicSocketPath??socketPath}:null}),handoffAnnounced=!0,router.beginDrain()}).catch(cause=>{hostLog(`handoff announcement failed: ${String(cause)}`)})}},endpointSuperseded=()=>supervisorPublicSocketPath===void 0?socketEntryReplaced(socketPath,boundIdentity):socketEntryReplaced(supervisorPublicSocketPath,supervisorPublicIdentity);registerShutdownSignals(shutdown),process.platform!=="win32"&&process.on("SIGUSR1",drainForHandoff);let watchdog=watchdogConfig&&supervisorPublicOwnerFile?{...watchdogConfig,cleanupPaths:crashCleanupPaths,beforeCleanup:async()=>{supervisorPublicIdentity??=await readSocketIdentityFile(supervisorPublicOwnerFile)}}:watchdogConfig&&{...watchdogConfig,cleanupPaths:crashCleanupPaths};return armHostWatchdog(watchdog,(reason,cleanup)=>{process.stderr.write(`senpi rpc host: ${reason}; shutting down
19
- `),shutdown(0,cleanup),setImmediate(killTrackedDetachedChildren)}),boundIdentity=await listen(server,socketPath,secret),supervisorPublicOwnerFile&&(supervisorPublicIdentity=await waitForSocketIdentityFile(supervisorPublicOwnerFile)),process.stderr.write(`senpi rpc listening on ${formatSocketAddress(socketPath)}
20
- `),new Promise(()=>{})}function delay(ms){return new Promise(resolve2=>setTimeout(resolve2,ms))}function noop(){}function parseError(error2){return{type:"response",command:"parse",success:!1,error:error2}}function oversizedLineError(){return`RPC input line exceeds ${MAX_RPC_LINE_CHARACTERS} characters.`}function errorMessage(cause){return cause instanceof Error?cause.message:String(cause)}function listenSocketPath(options){if(!(options.listen===void 0||options.listen==="stdio://"))return resolveSocketPath(options.listen,options.agentDir)}function resolveSocketPath(value,agentDir){if(value==="unix://")return join2(agentDir,"rpc","rpc.sock");if(value.startsWith("unix://")){let path=value.slice(7);return path.length===0?join2(agentDir,"rpc","rpc.sock"):path.startsWith("@")&&process.platform==="linux"?`\0${path.slice(1)}`:path}return value}function formatSocketAddress(socketPath){return socketPath.startsWith("\0")?`unix://@${socketPath.slice(1)}`:`unix://${socketPath}`}async function prepareSocketPath(socketPath){if(!(process.platform==="win32"||socketPath.startsWith("\0"))){await mkdir(dirname2(socketPath),{recursive:!0,mode:448});try{await access(socketPath)}catch(cause){if(isNodeErrorCode(cause,"ENOENT"))return;throw cause}if(await probeSocket(socketPath))throw new Error(`${socketPath}: address already in use by a live server.`);await unlink(socketPath)}}function probeSocket(socketPath){return new Promise(resolve2=>{let socket=createConnection(resolveSocketTransportAddress(socketPath,process.platform)),settle=live=>{socket.destroy(),resolve2(live)};socket.once("connect",()=>settle(!0)),socket.once("error",()=>settle(!1)),socket.setTimeout(1e3,()=>settle(!1))})}function listen(server,socketPath,secret){return new Promise((resolve2,reject)=>{server.once("error",reject),server.listen(resolveSocketTransportAddress(socketPath,process.platform,secret),async()=>{server.off("error",reject);try{if(process.platform!=="win32"&&!socketPath.startsWith("\0"))return await chmod(socketPath,384),resolve2(await statSocketIdentity(socketPath));resolve2(void 0)}catch(cause){reject(cause)}})})}function closeServer(server){return new Promise((resolve2,reject)=>{server.close(cause=>cause?reject(cause):resolve2())})}function hostLog(message){process.stderr.write(`senpi rpc host: ${message}
21
- `)}function isNodeErrorCode(cause,code){return cause instanceof Error&&"code"in cause&&cause.code===code}function registerShutdownSignals(shutdown){for(let signal of process.platform==="win32"?["SIGTERM"]:["SIGTERM","SIGHUP"])process.on(signal,()=>{killTrackedDetachedChildren(),shutdown(signal==="SIGHUP"?129:143)})}export{DEFAULT_HOST_EMPTY_EXIT_MS,DEFAULT_SESSION_IDLE_EVICTION_MS,RPC_HOST_EMPTY_EXIT_MS_ENV,RPC_SESSION_IDLE_EVICTION_MS_ENV,createHostCore,resolveHostIdlePolicy,runMultiSessionHost};
@@ -1,2 +0,0 @@
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-IKXPBYSO.js";import{KeybindingsManager}from"./chunk-MUTD2NOH.js";import"./chunk-SLL375O7.js";import{setKeybindings}from"./chunk-EJKCBRYK.js";import"./chunk-3DEXCYNN.js";import"./chunk-YU2P3CAR.js";import"./chunk-7X72IACK.js";import"./chunk-26UBFF6N.js";import"./chunk-PSCNHY7D.js";import"./chunk-GZVCRV7I.js";import"./chunk-U3VOXCGP.js";import"./chunk-RFB5CBW7.js";import"./chunk-2VZJTDUX.js";import"./chunk-ELFCNCBY.js";import"./chunk-ZOFZRJSL.js";import"./chunk-PBWQK23Z.js";import"./chunk-ATQFN5HI.js";import"./chunk-RBCQOIAD.js";import"./chunk-X4Q5YSTE.js";import"./chunk-L6QV7NZI.js";import"./chunk-45SZOLCU.js";import"./chunk-WVGCQOLJ.js";import"./chunk-WL5EQYNL.js";import"./chunk-WDTJ6JKE.js";import"./chunk-5ROMKDLK.js";import"./chunk-3W47LTXQ.js";import"./chunk-DMI55M2N.js";import"./chunk-BQVVQ2LQ.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};