@code-yeongyu/senpi 2026.9.27-2 → 2026.9.27-3

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 (293) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/bundle/chunks/anthropic-messages-3FGAXYJS.js +8 -0
  3. package/dist/bundle/chunks/{app-server-command-ATWHNOOO.js → app-server-command-ZVB35UIJ.js} +1 -1
  4. package/dist/bundle/chunks/azure-openai-responses-4SUOOZZ4.js +2 -0
  5. package/dist/bundle/chunks/{chunk-KMJXSXRX.js → chunk-357I4IUU.js} +2 -2
  6. package/dist/bundle/chunks/chunk-3SIQIY57.js +8 -0
  7. package/dist/bundle/chunks/chunk-45SZOLCU.js +2 -0
  8. package/dist/bundle/chunks/{chunk-77ACEMYL.js → chunk-6J6RDMBY.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-FD34HSJJ.js → chunk-C6LQNMRB.js} +1 -1
  10. package/dist/bundle/chunks/chunk-ELM77A26.js +2 -0
  11. package/dist/bundle/chunks/chunk-GZVCRV7I.js +3 -0
  12. package/dist/bundle/chunks/{chunk-TTY5BHCG.js → chunk-H2SGCPMD.js} +1 -1
  13. package/dist/bundle/chunks/chunk-KLBKUBDV.js +2 -0
  14. package/dist/bundle/chunks/chunk-L6QV7NZI.js +2 -0
  15. package/dist/bundle/chunks/{chunk-ZKZAATFM.js → chunk-LDB5UMH2.js} +2 -2
  16. package/dist/bundle/chunks/{chunk-HZAKOVHN.js → chunk-LGKKU4VM.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-6Q6DGME2.js → chunk-NMDALHXH.js} +1 -1
  18. package/dist/bundle/chunks/chunk-NNILBBOH.js +18 -0
  19. package/dist/bundle/chunks/{chunk-SUQDU5KM.js → chunk-OQRUK2DK.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-67BC7VZV.js → chunk-OZN2KUPR.js} +6 -6
  21. package/dist/bundle/chunks/{chunk-X3T45623.js → chunk-QK4QKRTF.js} +1 -1
  22. package/dist/bundle/chunks/{chunk-WM5FVFAP.js → chunk-QPZVJQC5.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-HPY47AVX.js → chunk-QYAO24GB.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-6W2DB2GC.js → chunk-RULGEHQM.js} +1 -1
  25. package/dist/bundle/chunks/{chunk-6SLQ5HFO.js → chunk-RYI6XR6Z.js} +55 -53
  26. package/dist/bundle/chunks/chunk-U3VOXCGP.js +2 -0
  27. package/dist/bundle/chunks/{chunk-LPFZGWG2.js → chunk-Y7EIVDHZ.js} +1 -1
  28. package/dist/bundle/chunks/chunk-ZIVYE5YK.js +2 -0
  29. package/dist/bundle/chunks/cli-main-RONHLFWZ.js +3 -0
  30. package/dist/bundle/chunks/google-generative-ai-ZTGKZTGU.js +2 -0
  31. package/dist/bundle/chunks/google-vertex-CCZ376YK.js +2 -0
  32. package/dist/bundle/chunks/help-fast-path-5LRG6FCG.js +2 -0
  33. package/dist/bundle/chunks/host-command-JVPGQR74.js +2 -0
  34. package/dist/bundle/chunks/host-lifecycle-R4HLXLBM.js +3 -0
  35. package/dist/bundle/chunks/host-lifecycle.js +4 -4
  36. package/dist/bundle/chunks/interactive-host-runtime-FES2G62G.js +4 -0
  37. package/dist/bundle/chunks/interactive-mode-45EP2FVL.js +2 -0
  38. package/dist/bundle/chunks/{list-tips-EBRNBPBM.js → list-tips-XXMRDHN6.js} +1 -1
  39. package/dist/bundle/chunks/{multi-session-host-CE3W6COI.js → multi-session-host-EFCMD5OT.js} +6 -6
  40. package/dist/bundle/chunks/{openai-completions-4CLXDDHJ.js → openai-completions-OP6VFNUR.js} +1 -1
  41. package/dist/bundle/chunks/openai-images-6U5FCN5S.js +2 -0
  42. package/dist/bundle/chunks/openai-responses-7PWMBGYX.js +2 -0
  43. package/dist/bundle/chunks/openrouter-images-QIKWQZUD.js +2 -0
  44. package/dist/bundle/chunks/{package-manager-cli-2PHRL2SX.js → package-manager-cli-5XJS3TYM.js} +1 -1
  45. package/dist/bundle/chunks/rotation-stream-KW7PTEC4.js +2 -0
  46. package/dist/bundle/chunks/rpc-mode-ZHYECU24.js +2 -0
  47. package/dist/bundle/chunks/session-picker-QHIYVQP4.js +2 -0
  48. package/dist/bundle/chunks/session-worker.js +245 -238
  49. package/dist/bundle/chunks/{state-store-Q5EWEAFG.js → state-store-D4GGGT3J.js} +1 -1
  50. package/dist/bundle/cli.js +1 -1
  51. package/dist/bundle/index.js +1 -1
  52. package/dist/bundle/rpc-entry.js +1 -1
  53. package/dist/cli/continue-moved.d.ts +15 -0
  54. package/dist/cli/continue-moved.d.ts.map +1 -0
  55. package/dist/cli/continue-moved.js +26 -0
  56. package/dist/cli/continue-moved.js.map +1 -0
  57. package/dist/core/agent-session-runtime.d.ts +3 -0
  58. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  59. package/dist/core/agent-session-runtime.js +43 -10
  60. package/dist/core/agent-session-runtime.js.map +1 -1
  61. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts.map +1 -1
  62. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +5 -1
  63. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js.map +1 -1
  64. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-claim.d.ts +13 -1
  65. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-claim.d.ts.map +1 -1
  66. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-claim.js +25 -2
  67. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-claim.js.map +1 -1
  68. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +1 -0
  69. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts.map +1 -1
  70. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.js.map +1 -1
  71. package/dist/core/extensions/builtin/mcp/catalog.d.ts +3 -0
  72. package/dist/core/extensions/builtin/mcp/catalog.d.ts.map +1 -1
  73. package/dist/core/extensions/builtin/mcp/catalog.js +9 -0
  74. package/dist/core/extensions/builtin/mcp/catalog.js.map +1 -1
  75. package/dist/core/extensions/builtin/mcp/connection-types.d.ts +2 -0
  76. package/dist/core/extensions/builtin/mcp/connection-types.d.ts.map +1 -1
  77. package/dist/core/extensions/builtin/mcp/connection-types.js.map +1 -1
  78. package/dist/core/extensions/builtin/mcp/connection.d.ts +1 -1
  79. package/dist/core/extensions/builtin/mcp/connection.d.ts.map +1 -1
  80. package/dist/core/extensions/builtin/mcp/connection.js +3 -2
  81. package/dist/core/extensions/builtin/mcp/connection.js.map +1 -1
  82. package/dist/core/extensions/builtin/mcp/expose/session.d.ts +3 -0
  83. package/dist/core/extensions/builtin/mcp/expose/session.d.ts.map +1 -1
  84. package/dist/core/extensions/builtin/mcp/expose/session.js +9 -2
  85. package/dist/core/extensions/builtin/mcp/expose/session.js.map +1 -1
  86. package/dist/core/extensions/builtin/mcp/service-register.d.ts.map +1 -1
  87. package/dist/core/extensions/builtin/mcp/service-register.js +7 -1
  88. package/dist/core/extensions/builtin/mcp/service-register.js.map +1 -1
  89. package/dist/core/extensions/builtin/mcp/service-tools-changed.d.ts +18 -0
  90. package/dist/core/extensions/builtin/mcp/service-tools-changed.d.ts.map +1 -0
  91. package/dist/core/extensions/builtin/mcp/service-tools-changed.js +61 -0
  92. package/dist/core/extensions/builtin/mcp/service-tools-changed.js.map +1 -0
  93. package/dist/core/extensions/builtin/mcp/service-types.d.ts +13 -0
  94. package/dist/core/extensions/builtin/mcp/service-types.d.ts.map +1 -1
  95. package/dist/core/extensions/builtin/mcp/service-types.js.map +1 -1
  96. package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
  97. package/dist/core/extensions/builtin/mcp/service.js +4 -37
  98. package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
  99. package/dist/core/extensions/builtin/mcp/shared-lease.js +1 -1
  100. package/dist/core/extensions/builtin/mcp/shared-lease.js.map +1 -1
  101. package/dist/core/extensions/builtin/mcp/startup-race.d.ts.map +1 -1
  102. package/dist/core/extensions/builtin/mcp/startup-race.js +11 -1
  103. package/dist/core/extensions/builtin/mcp/startup-race.js.map +1 -1
  104. package/dist/core/moved-sessions.d.ts +10 -0
  105. package/dist/core/moved-sessions.d.ts.map +1 -0
  106. package/dist/core/moved-sessions.js +84 -0
  107. package/dist/core/moved-sessions.js.map +1 -0
  108. package/dist/core/process-crash-record.d.ts +62 -0
  109. package/dist/core/process-crash-record.d.ts.map +1 -0
  110. package/dist/core/process-crash-record.js +216 -0
  111. package/dist/core/process-crash-record.js.map +1 -0
  112. package/dist/core/resume-target.d.ts +20 -0
  113. package/dist/core/resume-target.d.ts.map +1 -0
  114. package/dist/core/resume-target.js +30 -0
  115. package/dist/core/resume-target.js.map +1 -0
  116. package/dist/core/session-discovery.d.ts.map +1 -1
  117. package/dist/core/session-discovery.js +1 -0
  118. package/dist/core/session-discovery.js.map +1 -1
  119. package/dist/core/session-hold-errors.d.ts +20 -0
  120. package/dist/core/session-hold-errors.d.ts.map +1 -0
  121. package/dist/core/session-hold-errors.js +28 -0
  122. package/dist/core/session-hold-errors.js.map +1 -0
  123. package/dist/core/session-holders.d.ts +22 -0
  124. package/dist/core/session-holders.d.ts.map +1 -0
  125. package/dist/core/session-holders.js +234 -0
  126. package/dist/core/session-holders.js.map +1 -0
  127. package/dist/core/session-manager.d.ts +5 -0
  128. package/dist/core/session-manager.d.ts.map +1 -1
  129. package/dist/core/session-manager.js.map +1 -1
  130. package/dist/core/session-rebind.d.ts +7 -1
  131. package/dist/core/session-rebind.d.ts.map +1 -1
  132. package/dist/core/session-rebind.js +21 -5
  133. package/dist/core/session-rebind.js.map +1 -1
  134. package/dist/core/session-summary-index-file.d.ts.map +1 -1
  135. package/dist/core/session-summary-index-file.js +5 -2
  136. package/dist/core/session-summary-index-file.js.map +1 -1
  137. package/dist/core/session-summary.d.ts +3 -0
  138. package/dist/core/session-summary.d.ts.map +1 -1
  139. package/dist/core/session-summary.js +7 -0
  140. package/dist/core/session-summary.js.map +1 -1
  141. package/dist/legacy-dir-copy.d.ts +9 -0
  142. package/dist/legacy-dir-copy.d.ts.map +1 -0
  143. package/dist/legacy-dir-copy.js +69 -0
  144. package/dist/legacy-dir-copy.js.map +1 -0
  145. package/dist/legacy-senpi-dir-migration.d.ts.map +1 -1
  146. package/dist/legacy-senpi-dir-migration.js +64 -48
  147. package/dist/legacy-senpi-dir-migration.js.map +1 -1
  148. package/dist/main.d.ts.map +1 -1
  149. package/dist/main.js +45 -19
  150. package/dist/main.js.map +1 -1
  151. package/dist/migrations-state.d.ts +1 -1
  152. package/dist/migrations-state.d.ts.map +1 -1
  153. package/dist/migrations-state.js +5 -1
  154. package/dist/migrations-state.js.map +1 -1
  155. package/dist/migrations.d.ts.map +1 -1
  156. package/dist/migrations.js +4 -0
  157. package/dist/migrations.js.map +1 -1
  158. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/session-selector.js +5 -3
  160. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  161. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  162. package/dist/modes/interactive/interactive-mode.js +8 -4
  163. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  164. package/dist/modes/interactive/resume-rebind.d.ts +12 -0
  165. package/dist/modes/interactive/resume-rebind.d.ts.map +1 -0
  166. package/dist/modes/interactive/resume-rebind.js +37 -0
  167. package/dist/modes/interactive/resume-rebind.js.map +1 -0
  168. package/dist/modes/interactive/tips/catalog/computer-tips.d.ts +7 -0
  169. package/dist/modes/interactive/tips/catalog/computer-tips.d.ts.map +1 -0
  170. package/dist/modes/interactive/tips/catalog/computer-tips.js +36 -0
  171. package/dist/modes/interactive/tips/catalog/computer-tips.js.map +1 -0
  172. package/dist/modes/interactive/tips/registry.d.ts.map +1 -1
  173. package/dist/modes/interactive/tips/registry.js +2 -0
  174. package/dist/modes/interactive/tips/registry.js.map +1 -1
  175. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  176. package/dist/modes/rpc/connection-handler.js +3 -0
  177. package/dist/modes/rpc/connection-handler.js.map +1 -1
  178. package/dist/modes/rpc/host-child-exit.d.ts.map +1 -1
  179. package/dist/modes/rpc/host-child-exit.js +4 -0
  180. package/dist/modes/rpc/host-child-exit.js.map +1 -1
  181. package/dist/modes/rpc/host-crash-record.d.ts +8 -0
  182. package/dist/modes/rpc/host-crash-record.d.ts.map +1 -1
  183. package/dist/modes/rpc/host-crash-record.js.map +1 -1
  184. package/dist/modes/rpc/host-crash-record.test.js +11 -0
  185. package/dist/modes/rpc/host-crash-record.test.js.map +1 -1
  186. package/dist/modes/rpc/rpc-client.d.ts +2 -2
  187. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  188. package/dist/modes/rpc/rpc-client.js +14 -6
  189. package/dist/modes/rpc/rpc-client.js.map +1 -1
  190. package/dist/modes/rpc/rpc-request-deadline.d.ts +17 -0
  191. package/dist/modes/rpc/rpc-request-deadline.d.ts.map +1 -0
  192. package/dist/modes/rpc/rpc-request-deadline.js +27 -0
  193. package/dist/modes/rpc/rpc-request-deadline.js.map +1 -0
  194. package/dist/modes/rpc/rpc-types.d.ts +9 -2
  195. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  196. package/dist/modes/rpc/rpc-types.js.map +1 -1
  197. package/dist/modes/rpc/session-command-router.d.ts +3 -6
  198. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  199. package/dist/modes/rpc/session-command-router.js +9 -22
  200. package/dist/modes/rpc/session-command-router.js.map +1 -1
  201. package/dist/modes/rpc/session-path-key.d.ts +10 -0
  202. package/dist/modes/rpc/session-path-key.d.ts.map +1 -0
  203. package/dist/modes/rpc/session-path-key.js +33 -0
  204. package/dist/modes/rpc/session-path-key.js.map +1 -0
  205. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  206. package/dist/modes/rpc/session-registry.js +6 -10
  207. package/dist/modes/rpc/session-registry.js.map +1 -1
  208. package/dist/modes/rpc/session-sweep.d.ts +18 -0
  209. package/dist/modes/rpc/session-sweep.d.ts.map +1 -0
  210. package/dist/modes/rpc/session-sweep.js +32 -0
  211. package/dist/modes/rpc/session-sweep.js.map +1 -0
  212. package/dist/pi-dir-restore.d.ts +4 -0
  213. package/dist/pi-dir-restore.d.ts.map +1 -0
  214. package/dist/pi-dir-restore.js +92 -0
  215. package/dist/pi-dir-restore.js.map +1 -0
  216. package/docs/rpc.md +8 -3
  217. package/docs/sdk.md +29 -0
  218. package/docs/sessions.md +4 -0
  219. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  220. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  221. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +2 -2
  222. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  223. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +7 -0
  224. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  225. package/node_modules/@earendil-works/pi-agent-core/dist/assistant-terminal-state.d.ts.map +1 -1
  226. package/node_modules/@earendil-works/pi-agent-core/dist/assistant-terminal-state.js +3 -1
  227. package/node_modules/@earendil-works/pi-agent-core/dist/assistant-terminal-state.js.map +1 -1
  228. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +3 -1
  229. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  231. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  232. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +10 -7
  234. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +9 -1
  237. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  241. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/provider-diagnostic.d.ts +33 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/provider-diagnostic.d.ts.map +1 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/provider-diagnostic.js +56 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/provider-diagnostic.js.map +1 -0
  246. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  247. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +3 -0
  249. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  251. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-carrier.d.ts +5 -0
  252. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-carrier.d.ts.map +1 -0
  253. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-carrier.js +18 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-carrier.js.map +1 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-sources.d.ts +26 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-sources.d.ts.map +1 -0
  257. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-sources.js +103 -0
  258. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-sources.js.map +1 -0
  259. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-vocabulary.d.ts +36 -0
  260. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-vocabulary.d.ts.map +1 -0
  261. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-vocabulary.js +129 -0
  262. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-diagnostic-vocabulary.js.map +1 -0
  263. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.js +5 -4
  265. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-retry.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  267. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  268. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  269. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  270. package/package.json +7 -7
  271. package/dist/bundle/chunks/anthropic-messages-UYDVRFAS.js +0 -8
  272. package/dist/bundle/chunks/azure-openai-responses-DODWR4W6.js +0 -2
  273. package/dist/bundle/chunks/chunk-2L26KPZ6.js +0 -8
  274. package/dist/bundle/chunks/chunk-3CC5ZOBV.js +0 -13
  275. package/dist/bundle/chunks/chunk-L6JO4M6J.js +0 -3
  276. package/dist/bundle/chunks/chunk-SFYHCFRO.js +0 -2
  277. package/dist/bundle/chunks/chunk-TTHMOL5G.js +0 -2
  278. package/dist/bundle/chunks/chunk-UYCGOK6M.js +0 -2
  279. package/dist/bundle/chunks/chunk-ZTVQY5V6.js +0 -2
  280. package/dist/bundle/chunks/cli-main-HOM6UH3H.js +0 -3
  281. package/dist/bundle/chunks/google-generative-ai-VIEFECKJ.js +0 -2
  282. package/dist/bundle/chunks/google-vertex-Q64CKFID.js +0 -2
  283. package/dist/bundle/chunks/help-fast-path-YGYHMV2W.js +0 -2
  284. package/dist/bundle/chunks/host-command-XXSAFWBW.js +0 -2
  285. package/dist/bundle/chunks/host-lifecycle-GOMGJ25O.js +0 -3
  286. package/dist/bundle/chunks/interactive-host-runtime-IYCZWJGX.js +0 -4
  287. package/dist/bundle/chunks/interactive-mode-ZMO7YVYU.js +0 -2
  288. package/dist/bundle/chunks/openai-images-JA5N5DUU.js +0 -2
  289. package/dist/bundle/chunks/openai-responses-IBFGBAJP.js +0 -2
  290. package/dist/bundle/chunks/openrouter-images-MW5TXV7L.js +0 -2
  291. package/dist/bundle/chunks/rotation-stream-NATO6IMN.js +0 -2
  292. package/dist/bundle/chunks/rpc-mode-WCETTMFV.js +0 -2
  293. package/dist/bundle/chunks/session-picker-BP7THCWF.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, realpathSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, resolve } from \"node:path\";\nimport { ProviderScope, runWithProviderScope } from \"@earendil-works/pi-ai/node/provider-scope\";\nimport {\n\ttype AgentSessionLaunchProfile,\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"../../core/agent-session-runtime.ts\";\nimport type { HostMcpRegistry } from \"../../core/extensions/builtin/mcp/host-registry.ts\";\nimport type { SessionContext, SessionKind, SessionStartEvent } from \"../../core/extensions/types.ts\";\nimport { EMPTY_SESSION_CONTEXT } from \"../../core/extensions/types.ts\";\nimport { assertValidSessionId, SessionManager } from \"../../core/session-manager.ts\";\nimport { SESSION_PATH_RETRY_AFTER_MS, type SessionPathReservations } from \"./host-reservations.ts\";\nimport { beginSessionClose, closeMarkedSession, closeSession, type SessionTeardownHost } from \"./session-teardown.ts\";\nimport type { SessionWorkerClient } from \"./session-worker-client.ts\";\n\n/** The immutable flags selected when a routing session is opened. */\nexport interface RpcSessionLaunchProfile extends AgentSessionLaunchProfile {\n\tsessionPath?: string;\n\t/**\n\t * Durable session id chosen by the caller, applied ONLY when this open creates the session.\n\t * An existing session file keeps the id in its header, so a resume never rewrites identity.\n\t */\n\tdurableSessionId?: string;\n}\n\nexport type SessionRuntime = AgentSessionRuntime;\nexport type RpcSessionState = \"opening\" | \"open\" | \"closing\" | \"quarantined\" | \"closed\";\n\nexport interface RpcSessionEntry {\n\tstate: RpcSessionState;\n\truntime?: SessionRuntime;\n\tworker?: SessionWorkerClient;\n\t/** Visibility class chosen by the open, frozen for the entry's life. */\n\treadonly kind: SessionKind;\n\t/** Frozen opaque labels the open attached; `{}` when it attached none. */\n\treadonly context: SessionContext;\n\t/** Resolves replacement against the runtime currently owned by this entry. */\n\tswitchSession?: SessionRuntime[\"switchSession\"];\n\t/** Rebind callback installed by the shared RPC connection handler. */\n\trebindSession?: Parameters<SessionRuntime[\"setRebindSession\"]>[0];\n\tscope: ProviderScope;\n\tprofile: Readonly<RpcSessionLaunchProfile>;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\t/** Canonical reservation key for path-opened sessions; matches the reservations set. */\n\treservationKey?: string;\n\t/** Key granted for the spelling this session was opened with; cleared once superseded. */\n\trequestedPathKey?: string;\n\t/** Current runtime cwd, which can change when a session is replaced. */\n\tcwd: string;\n\t/** Live attachments (open + later attaches). The runtime is disposed only when the last one closes. */\n\tattachments: number;\n\t/**\n\t * Opt-in retention: a dropped connection only DETACHES from this session. The\n\t * entry stays open at zero attachments (still listed, still running its turn,\n\t * still holding its path) until an explicit close_session or idle eviction.\n\t * Requested per `open_session`; an attach may turn it on, never off.\n\t */\n\tretainOnDisconnect?: boolean;\n\t/** Timestamp of the last routed command / observed activity; drives idle eviction. */\n\tlastCommandAt: number;\n\tlifecycleMutex: Promise<void>;\n\tcloseCompletion?: Promise<void>;\n\tcloseResolve?: () => void;\n\tcloseStarted?: boolean;\n}\n\nexport class RpcSessionRegistryError extends Error {\n\treadonly code:\n\t\t| \"unknown_session\"\n\t\t| \"session_closing\"\n\t\t| \"session_path_in_use\"\n\t\t| \"session_id_in_use\"\n\t\t| \"session_reservation_limit\"\n\t\t| \"invalid_path\"\n\t\t| \"invalid_session_id\"\n\t\t| \"host_memory_pressure\"\n\t\t| \"open_failed\";\n\t/** Machine-readable context for the wire (`errorData`): who holds a path, when to retry. */\n\treadonly detail?: Readonly<Record<string, unknown>>;\n\n\tconstructor(code: RpcSessionRegistryError[\"code\"], reason?: string, detail?: Readonly<Record<string, unknown>>) {\n\t\tsuper(code === \"open_failed\" && reason ? `${code}: ${reason}` : code);\n\t\tthis.code = code;\n\t\tthis.name = \"RpcSessionRegistryError\";\n\t\tif (detail) this.detail = detail;\n\t}\n}\n\nexport interface RpcSessionRegistryOptions {\n\tagentDir: string;\n\tcreateRuntime: CreateAgentSessionRuntimeFactory;\n\tmcpRegistry?: HostMcpRegistry;\n\t/** Injectable clock (defaults to Date.now) so idle bookkeeping is testable. */\n\tnow?: () => number;\n\t/** Maximum time to wait for graceful runtime teardown before forced release. */\n\tcloseGraceMs?: number;\n\t/**\n\t * Cross-GENERATION path claims. During a handoff two hosts are alive at once, and only a\n\t * claim outside either process can keep them off one JSONL. Absent for an embedded registry\n\t * that is the only host of its agent directory.\n\t */\n\tpathReservations?: SessionPathReservations;\n}\n\n/**\n * Why the host currently declines to CREATE a worker session: it is above its RSS refuse\n * watermark. Carried verbatim to the client as `errorData` so it knows when to retry.\n */\nexport interface WorkerAdmissionRefusal {\n\treadonly rssMb: number;\n\treadonly retry_after_ms: number;\n}\n\n/** Host-side lifecycle policy for one `open_session`, distinct from the session's launch profile. */\nexport interface RpcSessionOpenOptions {\n\t/** Keep the session alive when its last client disconnects (`open_session.retain_on_disconnect`). */\n\tretainOnDisconnect?: boolean;\n}\n\n/** One `list_sessions` row. `context` is published only to a listing that asked for workers. */\nexport interface RpcSessionRow {\n\tsessionId: string;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\tcwd: string;\n\tname?: string;\n\tstatus: Exclude<RpcSessionState, \"quarantined\">;\n\tattachments: number;\n\tkind: SessionKind;\n\tcontext: SessionContext;\n}\n\nexport interface OpenRpcSession {\n\tsessionId: string;\n\tdurableSessionId: string;\n\tsessionPath?: string;\n\t/** True when this open attached to an already-open session instead of creating one. */\n\tattached?: boolean;\n}\n\nfunction canonicalPath(path: string): string {\n\tconst absolutePath = resolve(path);\n\tif (existsSync(absolutePath)) return realpathSync(absolutePath);\n\treturn `${realpathSync(dirname(absolutePath))}/${basename(absolutePath)}`;\n}\n\n/** Freezes an open's launch inputs, including the nested objects a client supplied. */\nexport function frozenProfile(profile: RpcSessionLaunchProfile): Readonly<RpcSessionLaunchProfile> {\n\treturn Object.freeze({\n\t\t...profile,\n\t\t...(profile.creationModel ? { creationModel: Object.freeze({ ...profile.creationModel }) } : {}),\n\t\t...(profile.sessionContext ? { sessionContext: Object.freeze({ ...profile.sessionContext }) } : {}),\n\t});\n}\n\n/**\n * The visibility class and labels an entry keeps for its life, normalized once here so no\n * lifecycle, listing or delivery decision has to re-apply the defaults. Reads the already\n * frozen profile, so the entry and the runtime share one frozen context object.\n */\nexport function sessionIdentity(profile: Readonly<RpcSessionLaunchProfile>): {\n\treadonly kind: SessionKind;\n\treadonly context: SessionContext;\n} {\n\treturn { kind: profile.sessionKind ?? \"interactive\", context: profile.sessionContext ?? EMPTY_SESSION_CONTEXT };\n}\n\n/** Process-local lifecycle owner for multi-session RPC runtimes. */\nexport class RpcSessionRegistry {\n\tprivate readonly entries = new Map<string, RpcSessionEntry>();\n\tprivate readonly reservations = new Set<string>();\n\tprivate readonly teardownHost: SessionTeardownHost;\n\tprivate nextHandle = 0;\n\tprivate readonly options: RpcSessionRegistryOptions;\n\tprivate readonly now: () => number;\n\treadonly closeGraceMs: number;\n\tprivate workerRefusal: WorkerAdmissionRefusal | undefined;\n\n\tconstructor(options: RpcSessionRegistryOptions) {\n\t\tthis.options =\n\t\t\toptions.mcpRegistry === undefined\n\t\t\t\t? options\n\t\t\t\t: {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcreateRuntime: (runtimeOptions) =>\n\t\t\t\t\t\t\toptions.createRuntime({ ...runtimeOptions, mcpRegistry: options.mcpRegistry }),\n\t\t\t\t\t};\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.closeGraceMs = options.closeGraceMs ?? 10_000;\n\t\tthis.teardownHost = {\n\t\t\tcloseGraceMs: this.closeGraceMs,\n\t\t\tget: (handle) => this.entries.get(handle),\n\t\t\tdelete: (handle) => this.entries.delete(handle),\n\t\t\treleaseReservation: (key) => {\n\t\t\t\tthis.reservations.delete(key);\n\t\t\t\tthis.options.pathReservations?.release(key);\n\t\t\t},\n\t\t\tmarkDetached: (key) => this.options.pathReservations?.setAttached(key, false),\n\t\t\tsync: () => this.syncRuntimeMetadata(),\n\t\t};\n\t}\n\n\t/** Number of live entries, including ones still opening or closing. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/**\n\t * While set, an open that would CREATE a worker session is refused with\n\t * `host_memory_pressure`; attaches to a live path and interactive opens are unaffected.\n\t * The only memory-driven refusal on the in-process path - never an occupancy count.\n\t */\n\tsetWorkerAdmission(refusal: WorkerAdmissionRefusal | undefined): void {\n\t\tthis.workerRefusal = refusal;\n\t}\n\n\tasync openSession(profile: RpcSessionLaunchProfile, options?: RpcSessionOpenOptions): Promise<OpenRpcSession> {\n\t\tthis.validateProfile(profile);\n\t\tthis.syncRuntimeMetadata();\n\t\tconst sessionPath = profile.sessionPath ? canonicalPath(profile.sessionPath) : undefined;\n\t\t// Taken SYNCHRONOUSLY, before any await, exactly like the path reservation below: a\n\t\t// concurrent open naming the same durable id must find this one already recorded rather\n\t\t// than a window between the decision and the record of it. Two LIVE sessions may never\n\t\t// share a durable id - every per-session artifact a client keys by it would collide.\n\t\t// Re-opening the SAME file is an attach/resume, not a collision: the id is the file's own.\n\t\tconst requestedDurableId = profile.durableSessionId;\n\t\tif (requestedDurableId !== undefined) {\n\t\t\tfor (const entry of this.entries.values()) {\n\t\t\t\tif (entry.state === \"closed\") continue;\n\t\t\t\tif (entry.durableSessionId !== requestedDurableId) continue;\n\t\t\t\tif (sessionPath !== undefined && entry.reservationKey === sessionPath) continue;\n\t\t\t\tthrow new RpcSessionRegistryError(\"session_id_in_use\");\n\t\t\t}\n\t\t}\n\t\tif (sessionPath) await this.settleClosingReservation(sessionPath);\n\t\tif (sessionPath && this.reservations.has(sessionPath)) {\n\t\t\t// Attach-on-open: a live session outlives individual client attachments, so a\n\t\t\t// resume (or a second surface) for an already-hosted path joins the existing\n\t\t\t// runtime instead of failing. An entry still opening keeps the exclusive\n\t\t\t// reservation and rejects as before.\n\t\t\tconst existing = [...this.entries].find(\n\t\t\t\t([, entry]) => entry.reservationKey === sessionPath && entry.state === \"open\",\n\t\t\t);\n\t\t\tif (!existing) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tconst [handle, entry] = existing;\n\t\t\tconst wasParked = entry.retainOnDisconnect === true && entry.attachments === 0;\n\t\t\tentry.attachments += 1;\n\t\t\t// The claim carries the attachment state another generation decides on: a path this host is\n\t\t\t// actively serving a client on is never reclaimable from it.\n\t\t\tthis.options.pathReservations?.setAttached(sessionPath, true);\n\t\t\t// Retention is a property of the live session: any attach may ask for it, and\n\t\t\t// no attach may revoke it for the clients that already rely on it.\n\t\t\tif (options?.retainOnDisconnect) entry.retainOnDisconnect = true;\n\t\t\tif (!entry.durableSessionId) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tentry.lastCommandAt = this.now();\n\t\t\tif (wasParked) {\n\t\t\t\tentry.lifecycleMutex = entry.lifecycleMutex.then(() =>\n\t\t\t\t\tentry.runtime?.emitAttachmentEvent(\"session_resumed\"),\n\t\t\t\t);\n\t\t\t\tawait entry.lifecycleMutex;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsessionId: handle,\n\t\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\t\tsessionPath: entry.sessionPath,\n\t\t\t\tattached: true,\n\t\t\t};\n\t\t}\n\t\tif (this.workerRefusal && profile.sessionKind === \"worker\")\n\t\t\tthrow new RpcSessionRegistryError(\"host_memory_pressure\", undefined, { ...this.workerRefusal });\n\t\tif (sessionPath) {\n\t\t\t// Taken SYNCHRONOUSLY, before any await: a concurrent open for the same path must find the\n\t\t\t// reservation already held, not a window between the decision and the record of it.\n\t\t\tthis.reservations.add(sessionPath);\n\t\t\t// Another generation of this daemon may still be writing this file. Its claim is the only\n\t\t\t// thing this process can see across a handoff, and a live one means \"retry\", not \"gone\".\n\t\t\t// Only AWAIT when there is a cross-generation claim to take: `await undefined` still costs a\n\t\t\t// microtask, and an embedded registry (no second generation) must reach the \"opening\" entry\n\t\t\t// in the same tick a caller that raced it would look, exactly as it did before generations.\n\t\t\tconst holder = this.options.pathReservations\n\t\t\t\t? await this.options.pathReservations.claim(sessionPath)\n\t\t\t\t: undefined;\n\t\t\tif (holder) {\n\t\t\t\tthis.reservations.delete(sessionPath);\n\t\t\t\tthrow new RpcSessionRegistryError(\"session_path_in_use\", undefined, {\n\t\t\t\t\towner: holder,\n\t\t\t\t\tretry_after_ms: SESSION_PATH_RETRY_AFTER_MS,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Resume vs create parity (D1 + omo SenpiSessionRuntime.ts:198-200):\n\t\t// Create-only launch semantics mirror classic startup flags. A resumed\n\t\t// session restores its persisted model and thinking level instead of being\n\t\t// overridden by the new open_session request.\n\t\tconst isResume = sessionPath !== undefined && existsSync(sessionPath);\n\t\t// Re-opening an existing session file is a resume, exactly like interactive\n\t\t// /resume (AgentSessionRuntime.switchSession). Without the event the session\n\t\t// starts with reason \"startup\" and every extension that only rebuilds state\n\t\t// on a resume - the ask-user dangling-question hook - stays unreachable from\n\t\t// the RPC restart path. A session created by this open stays \"startup\".\n\t\tconst sessionStartEvent: SessionStartEvent | undefined = isResume\n\t\t\t? { type: \"session_start\", reason: \"resume\" }\n\t\t\t: undefined;\n\t\tconst storedProfile = frozenProfile({ ...profile, ...(sessionPath ? { sessionPath } : {}) });\n\t\tconst runtimeProfile = isResume\n\t\t\t? frozenProfile({ ...storedProfile, creationModel: undefined, initialThinkingLevel: undefined })\n\t\t\t: storedProfile;\n\n\t\tconst handle = `rpc-${++this.nextHandle}`;\n\t\tconst entry: RpcSessionEntry = {\n\t\t\tstate: \"opening\",\n\t\t\tscope: new ProviderScope(),\n\t\t\tprofile: storedProfile,\n\t\t\t...sessionIdentity(storedProfile),\n\t\t\tsessionPath,\n\t\t\treservationKey: sessionPath,\n\t\t\tcwd: storedProfile.cwd,\n\t\t\tattachments: 1,\n\t\t\tretainOnDisconnect: options?.retainOnDisconnect === true,\n\t\t\tlastCommandAt: this.now(),\n\t\t\tlifecycleMutex: Promise.resolve(),\n\t\t};\n\t\tentry.switchSession = (sessionPath, options) => {\n\t\t\tconst operation = entry.lifecycleMutex.then(async () => {\n\t\t\t\tif (entry.state !== \"open\" || !entry.runtime) {\n\t\t\t\t\tthrow new RpcSessionRegistryError(\"unknown_session\");\n\t\t\t\t}\n\t\t\t\tconst runtime = entry.runtime;\n\t\t\t\tconst cwdOverride = options?.cwdOverride;\n\t\t\t\tconst cwdChanged = cwdOverride !== undefined && runtime.session.sessionManager.getCwd() !== cwdOverride;\n\t\t\t\tconst result = await runtime.switchSession(sessionPath, options);\n\t\t\t\tif (result.cancelled || !cwdChanged) return result;\n\n\t\t\t\t// A multi-session binding outlives an individual replacement. Keep the\n\t\t\t\t// entry's runtime object aligned with the replacement so every attached\n\t\t\t\t// client resolves getters and future commands against the new cwd-bound\n\t\t\t\t// runtime, not the object created during open_session.\n\t\t\t\tconst replacement = new AgentSessionRuntime(\n\t\t\t\t\truntime.session,\n\t\t\t\t\truntime.services,\n\t\t\t\t\tthis.options.createRuntime,\n\t\t\t\t\t[...runtime.diagnostics],\n\t\t\t\t\truntime.modelFallbackMessage,\n\t\t\t\t\truntime.launchProfile,\n\t\t\t\t);\n\t\t\t\treplacement.setRebindSession(entry.rebindSession);\n\t\t\t\tentry.runtime = replacement;\n\t\t\t\tthis.syncRuntimeMetadata();\n\t\t\t\treturn result;\n\t\t\t});\n\t\t\tentry.lifecycleMutex = operation.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t\treturn operation;\n\t\t};\n\t\t// Recorded before the first await so the synchronous collision guard above sees an open\n\t\t// that is still being built. `manager.getSessionId()` overwrites it below with the\n\t\t// authoritative value, which on a resume is the header's id, not the requested one.\n\t\tif (requestedDurableId !== undefined) entry.durableSessionId = requestedDurableId;\n\t\tthis.entries.set(handle, entry);\n\t\ttry {\n\t\t\tconst newSessionOptions = requestedDurableId !== undefined ? { id: requestedDurableId } : undefined;\n\t\t\tconst manager = sessionPath\n\t\t\t\t? SessionManager.open(sessionPath, undefined, storedProfile.cwd, newSessionOptions)\n\t\t\t\t: SessionManager.create(storedProfile.cwd, undefined, newSessionOptions);\n\t\t\tentry.runtime = await runWithProviderScope(entry.scope, () =>\n\t\t\t\tcreateAgentSessionRuntime(this.options.createRuntime, {\n\t\t\t\t\tcwd: manager.getCwd(),\n\t\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\t\tsessionManager: manager,\n\t\t\t\t\tsessionStartEvent,\n\t\t\t\t\tlaunchProfile: runtimeProfile,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.sessionPath ??= manager.getSessionFile();\n\t\t\tentry.state = \"open\";\n\t\t\treturn { sessionId: handle, durableSessionId: entry.durableSessionId, sessionPath: entry.sessionPath };\n\t\t} catch (error) {\n\t\t\t// Runtime construction may have started extensions, watchers, and provider\n\t\t\t// registrations before it rejects. Keep the reservation and entry private\n\t\t\t// until all of those resources have been torn down, then release them as\n\t\t\t// one rollback so the path can immediately be opened again.\n\t\t\ttry {\n\t\t\t\tawait entry.runtime?.dispose();\n\t\t\t} catch {\n\t\t\t\t// The original construction error remains the externally visible cause.\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait entry.scope.close?.();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.entries.delete(handle);\n\t\t\t\t\tif (sessionPath) {\n\t\t\t\t\t\tthis.reservations.delete(sessionPath);\n\t\t\t\t\t\tthis.options.pathReservations?.release(sessionPath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (error instanceof RpcSessionRegistryError) throw error;\n\t\t\tthrow new RpcSessionRegistryError(\"open_failed\", error instanceof Error ? error.message : undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Waits out a teardown already in flight for this path before the open decides.\n\t *\n\t * A close FREES the path, but the entry keeps its reservation until its runtime is\n\t * disposed, so an open landing inside that window used to be refused with\n\t * `session_path_in_use` for a session that no longer exists - making \"reopen the\n\t * path I just closed\" a race against disposal latency, which no client can time.\n\t * The open now waits for the teardown it would have been refused by and then opens\n\t * the file fresh. Bounded by the same grace window that bounds the teardown itself\n\t * (`closeMarkedSession` force-releases at that deadline), so a wedged disposal\n\t * still ends in the ordinary refusal instead of an open that never answers.\n\t */\n\tprivate async settleClosingReservation(sessionPath: string): Promise<void> {\n\t\tconst closing = [...this.entries.values()].find(\n\t\t\t(entry) => entry.reservationKey === sessionPath && entry.state === \"closing\",\n\t\t);\n\t\tif (!closing?.closeCompletion) return;\n\t\tlet deadline: ReturnType<typeof setTimeout> | undefined;\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\tclosing.closeCompletion,\n\t\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\t\tdeadline = setTimeout(resolve, this.closeGraceMs);\n\t\t\t\t}),\n\t\t\t]);\n\t\t} finally {\n\t\t\tif (deadline) clearTimeout(deadline);\n\t\t}\n\t}\n\n\t/**\n\t * Read-only lookup with no state transitions or attachment accounting.\n\t * Exists so lifecycle decisions (e.g. deferring a dropped connection's\n\t * release while a turn is still streaming) can inspect the live entry\n\t * without claiming it.\n\t */\n\tpeek(handle: string): RpcSessionEntry | undefined {\n\t\treturn this.entries.get(handle);\n\t}\n\n\tgetForCommand(handle: string, command: string): RpcSessionEntry {\n\t\tconst entry = this.entries.get(handle);\n\t\tif (!entry) throw new RpcSessionRegistryError(\"unknown_session\");\n\t\tif (\n\t\t\tentry.state === \"closing\" &&\n\t\t\t![\"abort\", \"abort_bash\", \"extension_ui_response\", \"extension_ui_progress\"].includes(command)\n\t\t) {\n\t\t\tthrow new RpcSessionRegistryError(\"session_closing\");\n\t\t}\n\t\tif (entry.state !== \"open\" && entry.state !== \"closing\") throw new RpcSessionRegistryError(\"unknown_session\");\n\t\t// Every routed command counts as activity for idle eviction. Lookups that\n\t\t// must not refresh idleness (sweeps, listing) use peek()/list() instead.\n\t\tentry.lastCommandAt = this.now();\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Starts a close synchronously and returns the live entry for routing decisions.\n\t * `detach` marks a client going away rather than the session ending, which a\n\t * retained entry answers by staying open at zero attachments.\n\t */\n\tbeginClose(handle: string, onRole?: (finalizer: boolean) => void, options?: { detach?: boolean }): RpcSessionEntry {\n\t\treturn beginSessionClose(this.teardownHost, handle, onRole, options);\n\t}\n\n\tasync close(handle: string): Promise<void> {\n\t\treturn closeSession(this.teardownHost, handle);\n\t}\n\n\t/** Completes a close previously made visible by beginClose(). */\n\tasync closeMarked(handle: string): Promise<void> {\n\t\treturn closeMarkedSession(this.teardownHost, handle);\n\t}\n\n\tlist(): RpcSessionRow[] {\n\t\tthis.syncRuntimeMetadata();\n\t\treturn [...this.entries].map(([sessionId, entry]) => ({\n\t\t\tsessionId,\n\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\tsessionPath: entry.sessionPath,\n\t\t\tcwd: entry.cwd,\n\t\t\tname: entry.runtime?.session.sessionManager.getSessionName(),\n\t\t\tkind: entry.kind,\n\t\t\tcontext: entry.context,\n\t\t\t// A closing entry has already released its last attachment; never publish that as negative.\n\t\t\tattachments: Math.max(0, entry.attachments),\n\t\t\tstatus: entry.state === \"quarantined\" ? \"closing\" : entry.state,\n\t\t}));\n\t}\n\n\t/** Reconcile path and durable identity after runtime replacement. */\n\tprivate syncRuntimeMetadata(): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\tconst manager = entry.runtime?.session.sessionManager;\n\t\t\tif (!manager) continue;\n\t\t\tconst currentPath = manager.getSessionFile();\n\t\t\tconst currentKey = currentPath ? canonicalPath(currentPath) : undefined;\n\t\t\t// Preserve the originally canonicalized key while the runtime still points at\n\t\t\t// the same path. SessionManager may expose a symlink-resolved spelling after\n\t\t\t// opening a file that did not exist yet; treating that as replacement would\n\t\t\t// break ordinary attach-on-open aliases.\n\t\t\t//\n\t\t\t// A moved path is not the only reason to reconcile: a session opened WITHOUT\n\t\t\t// `sessionPath` lands its created file straight into `sessionPath` and never\n\t\t\t// takes a reservation, so comparing paths alone leaves that file unclaimed\n\t\t\t// forever and a later open of it builds a SECOND runtime over the same\n\t\t\t// transcript. Reconcile whenever the canonical key we hold is not the key the\n\t\t\t// runtime is actually writing.\n\t\t\tif (currentPath !== entry.sessionPath || currentKey !== entry.reservationKey) {\n\t\t\t\tif (entry.reservationKey) {\n\t\t\t\t\tthis.reservations.delete(entry.reservationKey);\n\t\t\t\t\tthis.options.pathReservations?.release(entry.reservationKey);\n\t\t\t\t}\n\t\t\t\tif (currentKey) {\n\t\t\t\t\tthis.reservations.add(currentKey);\n\t\t\t\t\t// A replacement moved this session to another file; the claim follows it, carrying the\n\t\t\t\t\t// attachment state it is now held at. A file a live foreign generation holds is left\n\t\t\t\t\t// alone by claim() itself.\n\t\t\t\t\tvoid this.options.pathReservations?.claim(currentKey, entry.attachments > 0);\n\t\t\t\t}\n\t\t\t\tentry.reservationKey = currentKey;\n\t\t\t\tentry.sessionPath = currentPath;\n\t\t\t}\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.cwd = manager.getCwd();\n\t\t}\n\t}\n\n\tprivate validateProfile(profile: RpcSessionLaunchProfile): void {\n\t\tif (!isAbsolute(profile.cwd) || (profile.sessionPath !== undefined && !isAbsolute(profile.sessionPath))) {\n\t\t\tthrow new RpcSessionRegistryError(\"invalid_path\");\n\t\t}\n\t\tif (profile.durableSessionId !== undefined) {\n\t\t\ttry {\n\t\t\t\tassertValidSessionId(profile.durableSessionId);\n\t\t\t} catch (cause) {\n\t\t\t\tthrow new RpcSessionRegistryError(\"invalid_session_id\", String(cause));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { isAbsolute } from \"node:path\";\nimport { ProviderScope, runWithProviderScope } from \"@earendil-works/pi-ai/node/provider-scope\";\nimport {\n\ttype AgentSessionLaunchProfile,\n\tAgentSessionRuntime,\n\ttype CreateAgentSessionRuntimeFactory,\n\tcreateAgentSessionRuntime,\n} from \"../../core/agent-session-runtime.ts\";\nimport type { HostMcpRegistry } from \"../../core/extensions/builtin/mcp/host-registry.ts\";\nimport type { SessionContext, SessionKind, SessionStartEvent } from \"../../core/extensions/types.ts\";\nimport { EMPTY_SESSION_CONTEXT } from \"../../core/extensions/types.ts\";\nimport { assertValidSessionId, SessionManager } from \"../../core/session-manager.ts\";\nimport { SESSION_PATH_RETRY_AFTER_MS, type SessionPathReservations } from \"./host-reservations.ts\";\nimport { canonicalSessionPath } from \"./session-path-key.ts\";\nimport { beginSessionClose, closeMarkedSession, closeSession, type SessionTeardownHost } from \"./session-teardown.ts\";\nimport type { SessionWorkerClient } from \"./session-worker-client.ts\";\n\n/** The immutable flags selected when a routing session is opened. */\nexport interface RpcSessionLaunchProfile extends AgentSessionLaunchProfile {\n\tsessionPath?: string;\n\t/**\n\t * Durable session id chosen by the caller, applied ONLY when this open creates the session.\n\t * An existing session file keeps the id in its header, so a resume never rewrites identity.\n\t */\n\tdurableSessionId?: string;\n}\n\nexport type SessionRuntime = AgentSessionRuntime;\nexport type RpcSessionState = \"opening\" | \"open\" | \"closing\" | \"quarantined\" | \"closed\";\n\nexport interface RpcSessionEntry {\n\tstate: RpcSessionState;\n\truntime?: SessionRuntime;\n\tworker?: SessionWorkerClient;\n\t/** Visibility class chosen by the open, frozen for the entry's life. */\n\treadonly kind: SessionKind;\n\t/** Frozen opaque labels the open attached; `{}` when it attached none. */\n\treadonly context: SessionContext;\n\t/** Resolves replacement against the runtime currently owned by this entry. */\n\tswitchSession?: SessionRuntime[\"switchSession\"];\n\t/** Rebind callback installed by the shared RPC connection handler. */\n\trebindSession?: Parameters<SessionRuntime[\"setRebindSession\"]>[0];\n\tscope: ProviderScope;\n\tprofile: Readonly<RpcSessionLaunchProfile>;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\t/** Canonical reservation key for path-opened sessions; matches the reservations set. */\n\treservationKey?: string;\n\t/** Key granted for the spelling this session was opened with; cleared once superseded. */\n\trequestedPathKey?: string;\n\t/** Current runtime cwd, which can change when a session is replaced. */\n\tcwd: string;\n\t/** Live attachments (open + later attaches). The runtime is disposed only when the last one closes. */\n\tattachments: number;\n\t/**\n\t * Opt-in retention: a dropped connection only DETACHES from this session. The\n\t * entry stays open at zero attachments (still listed, still running its turn,\n\t * still holding its path) until an explicit close_session or idle eviction.\n\t * Requested per `open_session`; an attach may turn it on, never off.\n\t */\n\tretainOnDisconnect?: boolean;\n\t/** Timestamp of the last routed command / observed activity; drives idle eviction. */\n\tlastCommandAt: number;\n\tlifecycleMutex: Promise<void>;\n\tcloseCompletion?: Promise<void>;\n\tcloseResolve?: () => void;\n\tcloseStarted?: boolean;\n}\n\nexport class RpcSessionRegistryError extends Error {\n\treadonly code:\n\t\t| \"unknown_session\"\n\t\t| \"session_closing\"\n\t\t| \"session_path_in_use\"\n\t\t| \"session_id_in_use\"\n\t\t| \"session_reservation_limit\"\n\t\t| \"invalid_path\"\n\t\t| \"invalid_session_id\"\n\t\t| \"host_memory_pressure\"\n\t\t| \"open_failed\";\n\t/** Machine-readable context for the wire (`errorData`): who holds a path, when to retry. */\n\treadonly detail?: Readonly<Record<string, unknown>>;\n\n\tconstructor(code: RpcSessionRegistryError[\"code\"], reason?: string, detail?: Readonly<Record<string, unknown>>) {\n\t\tsuper(code === \"open_failed\" && reason ? `${code}: ${reason}` : code);\n\t\tthis.code = code;\n\t\tthis.name = \"RpcSessionRegistryError\";\n\t\tif (detail) this.detail = detail;\n\t}\n}\n\nexport interface RpcSessionRegistryOptions {\n\tagentDir: string;\n\tcreateRuntime: CreateAgentSessionRuntimeFactory;\n\tmcpRegistry?: HostMcpRegistry;\n\t/** Injectable clock (defaults to Date.now) so idle bookkeeping is testable. */\n\tnow?: () => number;\n\t/** Maximum time to wait for graceful runtime teardown before forced release. */\n\tcloseGraceMs?: number;\n\t/**\n\t * Cross-GENERATION path claims. During a handoff two hosts are alive at once, and only a\n\t * claim outside either process can keep them off one JSONL. Absent for an embedded registry\n\t * that is the only host of its agent directory.\n\t */\n\tpathReservations?: SessionPathReservations;\n}\n\n/**\n * Why the host currently declines to CREATE a worker session: it is above its RSS refuse\n * watermark. Carried verbatim to the client as `errorData` so it knows when to retry.\n */\nexport interface WorkerAdmissionRefusal {\n\treadonly rssMb: number;\n\treadonly retry_after_ms: number;\n}\n\n/** Host-side lifecycle policy for one `open_session`, distinct from the session's launch profile. */\nexport interface RpcSessionOpenOptions {\n\t/** Keep the session alive when its last client disconnects (`open_session.retain_on_disconnect`). */\n\tretainOnDisconnect?: boolean;\n}\n\n/** One `list_sessions` row. `context` is published only to a listing that asked for workers. */\nexport interface RpcSessionRow {\n\tsessionId: string;\n\tdurableSessionId?: string;\n\tsessionPath?: string;\n\tcwd: string;\n\tname?: string;\n\tstatus: Exclude<RpcSessionState, \"quarantined\">;\n\tattachments: number;\n\tkind: SessionKind;\n\tcontext: SessionContext;\n}\n\nexport interface OpenRpcSession {\n\tsessionId: string;\n\tdurableSessionId: string;\n\tsessionPath?: string;\n\t/** True when this open attached to an already-open session instead of creating one. */\n\tattached?: boolean;\n}\n\n/** Freezes an open's launch inputs, including the nested objects a client supplied. */\nexport function frozenProfile(profile: RpcSessionLaunchProfile): Readonly<RpcSessionLaunchProfile> {\n\treturn Object.freeze({\n\t\t...profile,\n\t\t...(profile.creationModel ? { creationModel: Object.freeze({ ...profile.creationModel }) } : {}),\n\t\t...(profile.sessionContext ? { sessionContext: Object.freeze({ ...profile.sessionContext }) } : {}),\n\t});\n}\n\n/**\n * The visibility class and labels an entry keeps for its life, normalized once here so no\n * lifecycle, listing or delivery decision has to re-apply the defaults. Reads the already\n * frozen profile, so the entry and the runtime share one frozen context object.\n */\nexport function sessionIdentity(profile: Readonly<RpcSessionLaunchProfile>): {\n\treadonly kind: SessionKind;\n\treadonly context: SessionContext;\n} {\n\treturn { kind: profile.sessionKind ?? \"interactive\", context: profile.sessionContext ?? EMPTY_SESSION_CONTEXT };\n}\n\n/** Process-local lifecycle owner for multi-session RPC runtimes. */\nexport class RpcSessionRegistry {\n\tprivate readonly entries = new Map<string, RpcSessionEntry>();\n\tprivate readonly reservations = new Set<string>();\n\tprivate readonly teardownHost: SessionTeardownHost;\n\tprivate nextHandle = 0;\n\tprivate readonly options: RpcSessionRegistryOptions;\n\tprivate readonly now: () => number;\n\treadonly closeGraceMs: number;\n\tprivate workerRefusal: WorkerAdmissionRefusal | undefined;\n\n\tconstructor(options: RpcSessionRegistryOptions) {\n\t\tthis.options =\n\t\t\toptions.mcpRegistry === undefined\n\t\t\t\t? options\n\t\t\t\t: {\n\t\t\t\t\t\t...options,\n\t\t\t\t\t\tcreateRuntime: (runtimeOptions) =>\n\t\t\t\t\t\t\toptions.createRuntime({ ...runtimeOptions, mcpRegistry: options.mcpRegistry }),\n\t\t\t\t\t};\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.closeGraceMs = options.closeGraceMs ?? 10_000;\n\t\tthis.teardownHost = {\n\t\t\tcloseGraceMs: this.closeGraceMs,\n\t\t\tget: (handle) => this.entries.get(handle),\n\t\t\tdelete: (handle) => this.entries.delete(handle),\n\t\t\treleaseReservation: (key) => {\n\t\t\t\tthis.reservations.delete(key);\n\t\t\t\tthis.options.pathReservations?.release(key);\n\t\t\t},\n\t\t\tmarkDetached: (key) => this.options.pathReservations?.setAttached(key, false),\n\t\t\tsync: () => this.syncRuntimeMetadata(),\n\t\t};\n\t}\n\n\t/** Number of live entries, including ones still opening or closing. */\n\tget size(): number {\n\t\treturn this.entries.size;\n\t}\n\n\t/**\n\t * While set, an open that would CREATE a worker session is refused with\n\t * `host_memory_pressure`; attaches to a live path and interactive opens are unaffected.\n\t * The only memory-driven refusal on the in-process path - never an occupancy count.\n\t */\n\tsetWorkerAdmission(refusal: WorkerAdmissionRefusal | undefined): void {\n\t\tthis.workerRefusal = refusal;\n\t}\n\n\tasync openSession(profile: RpcSessionLaunchProfile, options?: RpcSessionOpenOptions): Promise<OpenRpcSession> {\n\t\tthis.validateProfile(profile);\n\t\tthis.syncRuntimeMetadata();\n\t\tconst sessionPath = profile.sessionPath ? canonicalSessionPath(profile.sessionPath) : undefined;\n\t\t// Taken SYNCHRONOUSLY, before any await, exactly like the path reservation below: a\n\t\t// concurrent open naming the same durable id must find this one already recorded rather\n\t\t// than a window between the decision and the record of it. Two LIVE sessions may never\n\t\t// share a durable id - every per-session artifact a client keys by it would collide.\n\t\t// Re-opening the SAME file is an attach/resume, not a collision: the id is the file's own.\n\t\tconst requestedDurableId = profile.durableSessionId;\n\t\tif (requestedDurableId !== undefined) {\n\t\t\tfor (const entry of this.entries.values()) {\n\t\t\t\tif (entry.state === \"closed\") continue;\n\t\t\t\tif (entry.durableSessionId !== requestedDurableId) continue;\n\t\t\t\tif (sessionPath !== undefined && entry.reservationKey === sessionPath) continue;\n\t\t\t\tthrow new RpcSessionRegistryError(\"session_id_in_use\");\n\t\t\t}\n\t\t}\n\t\tif (sessionPath) await this.settleClosingReservation(sessionPath);\n\t\tif (sessionPath && this.reservations.has(sessionPath)) {\n\t\t\t// Attach-on-open: a live session outlives individual client attachments, so a\n\t\t\t// resume (or a second surface) for an already-hosted path joins the existing\n\t\t\t// runtime instead of failing. An entry still opening keeps the exclusive\n\t\t\t// reservation and rejects as before.\n\t\t\tconst existing = [...this.entries].find(\n\t\t\t\t([, entry]) => entry.reservationKey === sessionPath && entry.state === \"open\",\n\t\t\t);\n\t\t\tif (!existing) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tconst [handle, entry] = existing;\n\t\t\tconst wasParked = entry.retainOnDisconnect === true && entry.attachments === 0;\n\t\t\tentry.attachments += 1;\n\t\t\t// The claim carries the attachment state another generation decides on: a path this host is\n\t\t\t// actively serving a client on is never reclaimable from it.\n\t\t\tthis.options.pathReservations?.setAttached(sessionPath, true);\n\t\t\t// Retention is a property of the live session: any attach may ask for it, and\n\t\t\t// no attach may revoke it for the clients that already rely on it.\n\t\t\tif (options?.retainOnDisconnect) entry.retainOnDisconnect = true;\n\t\t\tif (!entry.durableSessionId) throw new RpcSessionRegistryError(\"session_path_in_use\");\n\t\t\tentry.lastCommandAt = this.now();\n\t\t\tif (wasParked) {\n\t\t\t\tentry.lifecycleMutex = entry.lifecycleMutex.then(() =>\n\t\t\t\t\tentry.runtime?.emitAttachmentEvent(\"session_resumed\"),\n\t\t\t\t);\n\t\t\t\tawait entry.lifecycleMutex;\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsessionId: handle,\n\t\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\t\tsessionPath: entry.sessionPath,\n\t\t\t\tattached: true,\n\t\t\t};\n\t\t}\n\t\tif (this.workerRefusal && profile.sessionKind === \"worker\")\n\t\t\tthrow new RpcSessionRegistryError(\"host_memory_pressure\", undefined, { ...this.workerRefusal });\n\t\tif (sessionPath) {\n\t\t\t// Taken SYNCHRONOUSLY, before any await: a concurrent open for the same path must find the\n\t\t\t// reservation already held, not a window between the decision and the record of it.\n\t\t\tthis.reservations.add(sessionPath);\n\t\t\t// Another generation of this daemon may still be writing this file. Its claim is the only\n\t\t\t// thing this process can see across a handoff, and a live one means \"retry\", not \"gone\".\n\t\t\t// Only AWAIT when there is a cross-generation claim to take: `await undefined` still costs a\n\t\t\t// microtask, and an embedded registry (no second generation) must reach the \"opening\" entry\n\t\t\t// in the same tick a caller that raced it would look, exactly as it did before generations.\n\t\t\tconst holder = this.options.pathReservations\n\t\t\t\t? await this.options.pathReservations.claim(sessionPath)\n\t\t\t\t: undefined;\n\t\t\tif (holder) {\n\t\t\t\tthis.reservations.delete(sessionPath);\n\t\t\t\tthrow new RpcSessionRegistryError(\"session_path_in_use\", undefined, {\n\t\t\t\t\towner: holder,\n\t\t\t\t\tretry_after_ms: SESSION_PATH_RETRY_AFTER_MS,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// Resume vs create parity (D1 + omo SenpiSessionRuntime.ts:198-200):\n\t\t// Create-only launch semantics mirror classic startup flags. A resumed\n\t\t// session restores its persisted model and thinking level instead of being\n\t\t// overridden by the new open_session request.\n\t\tconst isResume = sessionPath !== undefined && existsSync(sessionPath);\n\t\t// Re-opening an existing session file is a resume, exactly like interactive\n\t\t// /resume (AgentSessionRuntime.switchSession). Without the event the session\n\t\t// starts with reason \"startup\" and every extension that only rebuilds state\n\t\t// on a resume - the ask-user dangling-question hook - stays unreachable from\n\t\t// the RPC restart path. A session created by this open stays \"startup\".\n\t\tconst sessionStartEvent: SessionStartEvent | undefined = isResume\n\t\t\t? { type: \"session_start\", reason: \"resume\" }\n\t\t\t: undefined;\n\t\tconst storedProfile = frozenProfile({ ...profile, ...(sessionPath ? { sessionPath } : {}) });\n\t\tconst runtimeProfile = isResume\n\t\t\t? frozenProfile({ ...storedProfile, creationModel: undefined, initialThinkingLevel: undefined })\n\t\t\t: storedProfile;\n\n\t\tconst handle = `rpc-${++this.nextHandle}`;\n\t\tconst entry: RpcSessionEntry = {\n\t\t\tstate: \"opening\",\n\t\t\tscope: new ProviderScope(),\n\t\t\tprofile: storedProfile,\n\t\t\t...sessionIdentity(storedProfile),\n\t\t\tsessionPath,\n\t\t\treservationKey: sessionPath,\n\t\t\tcwd: storedProfile.cwd,\n\t\t\tattachments: 1,\n\t\t\tretainOnDisconnect: options?.retainOnDisconnect === true,\n\t\t\tlastCommandAt: this.now(),\n\t\t\tlifecycleMutex: Promise.resolve(),\n\t\t};\n\t\tentry.switchSession = (sessionPath, options) => {\n\t\t\tconst operation = entry.lifecycleMutex.then(async () => {\n\t\t\t\tif (entry.state !== \"open\" || !entry.runtime) {\n\t\t\t\t\tthrow new RpcSessionRegistryError(\"unknown_session\");\n\t\t\t\t}\n\t\t\t\tconst runtime = entry.runtime;\n\t\t\t\tconst cwdOverride = options?.cwdOverride;\n\t\t\t\tconst cwdChanged = cwdOverride !== undefined && runtime.session.sessionManager.getCwd() !== cwdOverride;\n\t\t\t\tconst result = await runtime.switchSession(sessionPath, options);\n\t\t\t\tif (result.cancelled || !cwdChanged) return result;\n\n\t\t\t\t// A multi-session binding outlives an individual replacement. Keep the\n\t\t\t\t// entry's runtime object aligned with the replacement so every attached\n\t\t\t\t// client resolves getters and future commands against the new cwd-bound\n\t\t\t\t// runtime, not the object created during open_session.\n\t\t\t\tconst replacement = new AgentSessionRuntime(\n\t\t\t\t\truntime.session,\n\t\t\t\t\truntime.services,\n\t\t\t\t\tthis.options.createRuntime,\n\t\t\t\t\t[...runtime.diagnostics],\n\t\t\t\t\truntime.modelFallbackMessage,\n\t\t\t\t\truntime.launchProfile,\n\t\t\t\t);\n\t\t\t\treplacement.setRebindSession(entry.rebindSession);\n\t\t\t\truntime.releaseSessionHold();\n\t\t\t\tentry.runtime = replacement;\n\t\t\t\tthis.syncRuntimeMetadata();\n\t\t\t\treturn result;\n\t\t\t});\n\t\t\tentry.lifecycleMutex = operation.then(\n\t\t\t\t() => undefined,\n\t\t\t\t() => undefined,\n\t\t\t);\n\t\t\treturn operation;\n\t\t};\n\t\t// Recorded before the first await so the synchronous collision guard above sees an open\n\t\t// that is still being built. `manager.getSessionId()` overwrites it below with the\n\t\t// authoritative value, which on a resume is the header's id, not the requested one.\n\t\tif (requestedDurableId !== undefined) entry.durableSessionId = requestedDurableId;\n\t\tthis.entries.set(handle, entry);\n\t\ttry {\n\t\t\tconst newSessionOptions = requestedDurableId !== undefined ? { id: requestedDurableId } : undefined;\n\t\t\tconst manager = sessionPath\n\t\t\t\t? SessionManager.open(sessionPath, undefined, storedProfile.cwd, newSessionOptions)\n\t\t\t\t: SessionManager.create(storedProfile.cwd, undefined, newSessionOptions);\n\t\t\tentry.runtime = await runWithProviderScope(entry.scope, () =>\n\t\t\t\tcreateAgentSessionRuntime(this.options.createRuntime, {\n\t\t\t\t\tcwd: manager.getCwd(),\n\t\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\t\tsessionManager: manager,\n\t\t\t\t\tsessionStartEvent,\n\t\t\t\t\tlaunchProfile: runtimeProfile,\n\t\t\t\t}),\n\t\t\t);\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.sessionPath ??= manager.getSessionFile();\n\t\t\tentry.state = \"open\";\n\t\t\treturn { sessionId: handle, durableSessionId: entry.durableSessionId, sessionPath: entry.sessionPath };\n\t\t} catch (error) {\n\t\t\t// Runtime construction may have started extensions, watchers, and provider\n\t\t\t// registrations before it rejects. Keep the reservation and entry private\n\t\t\t// until all of those resources have been torn down, then release them as\n\t\t\t// one rollback so the path can immediately be opened again.\n\t\t\ttry {\n\t\t\t\tawait entry.runtime?.dispose();\n\t\t\t} catch {\n\t\t\t\t// The original construction error remains the externally visible cause.\n\t\t\t} finally {\n\t\t\t\ttry {\n\t\t\t\t\tawait entry.scope.close?.();\n\t\t\t\t} finally {\n\t\t\t\t\tthis.entries.delete(handle);\n\t\t\t\t\tif (sessionPath) {\n\t\t\t\t\t\tthis.reservations.delete(sessionPath);\n\t\t\t\t\t\tthis.options.pathReservations?.release(sessionPath);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (error instanceof RpcSessionRegistryError) throw error;\n\t\t\tthrow new RpcSessionRegistryError(\"open_failed\", error instanceof Error ? error.message : undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Waits out a teardown already in flight for this path before the open decides.\n\t *\n\t * A close FREES the path, but the entry keeps its reservation until its runtime is\n\t * disposed, so an open landing inside that window used to be refused with\n\t * `session_path_in_use` for a session that no longer exists - making \"reopen the\n\t * path I just closed\" a race against disposal latency, which no client can time.\n\t * The open now waits for the teardown it would have been refused by and then opens\n\t * the file fresh. Bounded by the same grace window that bounds the teardown itself\n\t * (`closeMarkedSession` force-releases at that deadline), so a wedged disposal\n\t * still ends in the ordinary refusal instead of an open that never answers.\n\t */\n\tprivate async settleClosingReservation(sessionPath: string): Promise<void> {\n\t\tconst closing = [...this.entries.values()].find(\n\t\t\t(entry) => entry.reservationKey === sessionPath && entry.state === \"closing\",\n\t\t);\n\t\tif (!closing?.closeCompletion) return;\n\t\tlet deadline: ReturnType<typeof setTimeout> | undefined;\n\t\ttry {\n\t\t\tawait Promise.race([\n\t\t\t\tclosing.closeCompletion,\n\t\t\t\tnew Promise<void>((resolve) => {\n\t\t\t\t\tdeadline = setTimeout(resolve, this.closeGraceMs);\n\t\t\t\t}),\n\t\t\t]);\n\t\t} finally {\n\t\t\tif (deadline) clearTimeout(deadline);\n\t\t}\n\t}\n\n\t/**\n\t * Read-only lookup with no state transitions or attachment accounting.\n\t * Exists so lifecycle decisions (e.g. deferring a dropped connection's\n\t * release while a turn is still streaming) can inspect the live entry\n\t * without claiming it.\n\t */\n\tpeek(handle: string): RpcSessionEntry | undefined {\n\t\treturn this.entries.get(handle);\n\t}\n\n\tgetForCommand(handle: string, command: string): RpcSessionEntry {\n\t\tconst entry = this.entries.get(handle);\n\t\tif (!entry) throw new RpcSessionRegistryError(\"unknown_session\");\n\t\tif (\n\t\t\tentry.state === \"closing\" &&\n\t\t\t![\"abort\", \"abort_bash\", \"extension_ui_response\", \"extension_ui_progress\"].includes(command)\n\t\t) {\n\t\t\tthrow new RpcSessionRegistryError(\"session_closing\");\n\t\t}\n\t\tif (entry.state !== \"open\" && entry.state !== \"closing\") throw new RpcSessionRegistryError(\"unknown_session\");\n\t\t// Every routed command counts as activity for idle eviction. Lookups that\n\t\t// must not refresh idleness (sweeps, listing) use peek()/list() instead.\n\t\tentry.lastCommandAt = this.now();\n\t\treturn entry;\n\t}\n\n\t/**\n\t * Starts a close synchronously and returns the live entry for routing decisions.\n\t * `detach` marks a client going away rather than the session ending, which a\n\t * retained entry answers by staying open at zero attachments.\n\t */\n\tbeginClose(handle: string, onRole?: (finalizer: boolean) => void, options?: { detach?: boolean }): RpcSessionEntry {\n\t\treturn beginSessionClose(this.teardownHost, handle, onRole, options);\n\t}\n\n\tasync close(handle: string): Promise<void> {\n\t\treturn closeSession(this.teardownHost, handle);\n\t}\n\n\t/** Completes a close previously made visible by beginClose(). */\n\tasync closeMarked(handle: string): Promise<void> {\n\t\treturn closeMarkedSession(this.teardownHost, handle);\n\t}\n\n\tlist(): RpcSessionRow[] {\n\t\tthis.syncRuntimeMetadata();\n\t\treturn [...this.entries].map(([sessionId, entry]) => ({\n\t\t\tsessionId,\n\t\t\tdurableSessionId: entry.durableSessionId,\n\t\t\tsessionPath: entry.sessionPath,\n\t\t\tcwd: entry.cwd,\n\t\t\tname: entry.runtime?.session.sessionManager.getSessionName(),\n\t\t\tkind: entry.kind,\n\t\t\tcontext: entry.context,\n\t\t\t// A closing entry has already released its last attachment; never publish that as negative.\n\t\t\tattachments: Math.max(0, entry.attachments),\n\t\t\tstatus: entry.state === \"quarantined\" ? \"closing\" : entry.state,\n\t\t}));\n\t}\n\n\t/** Reconcile path and durable identity after runtime replacement. */\n\tprivate syncRuntimeMetadata(): void {\n\t\tfor (const entry of this.entries.values()) {\n\t\t\tconst manager = entry.runtime?.session.sessionManager;\n\t\t\tif (!manager) continue;\n\t\t\tconst currentPath = manager.getSessionFile();\n\t\t\tconst currentKey = currentPath ? canonicalSessionPath(currentPath) : undefined;\n\t\t\t// Preserve the originally canonicalized key while the runtime still points at\n\t\t\t// the same path. SessionManager may expose a symlink-resolved spelling after\n\t\t\t// opening a file that did not exist yet; treating that as replacement would\n\t\t\t// break ordinary attach-on-open aliases.\n\t\t\t//\n\t\t\t// A moved path is not the only reason to reconcile: a session opened WITHOUT\n\t\t\t// `sessionPath` lands its created file straight into `sessionPath` and never\n\t\t\t// takes a reservation, so comparing paths alone leaves that file unclaimed\n\t\t\t// forever and a later open of it builds a SECOND runtime over the same\n\t\t\t// transcript. Reconcile whenever the canonical key we hold is not the key the\n\t\t\t// runtime is actually writing.\n\t\t\tif (currentPath !== entry.sessionPath || currentKey !== entry.reservationKey) {\n\t\t\t\tif (entry.reservationKey) {\n\t\t\t\t\tthis.reservations.delete(entry.reservationKey);\n\t\t\t\t\tthis.options.pathReservations?.release(entry.reservationKey);\n\t\t\t\t}\n\t\t\t\tif (currentKey) {\n\t\t\t\t\tthis.reservations.add(currentKey);\n\t\t\t\t\t// A replacement moved this session to another file; the claim follows it, carrying the\n\t\t\t\t\t// attachment state it is now held at. A file a live foreign generation holds is left\n\t\t\t\t\t// alone by claim() itself.\n\t\t\t\t\tvoid this.options.pathReservations?.claim(currentKey, entry.attachments > 0);\n\t\t\t\t}\n\t\t\t\tentry.reservationKey = currentKey;\n\t\t\t\tentry.sessionPath = currentPath;\n\t\t\t}\n\t\t\tentry.durableSessionId = manager.getSessionId();\n\t\t\tentry.cwd = manager.getCwd();\n\t\t}\n\t}\n\n\tprivate validateProfile(profile: RpcSessionLaunchProfile): void {\n\t\tif (!isAbsolute(profile.cwd) || (profile.sessionPath !== undefined && !isAbsolute(profile.sessionPath))) {\n\t\t\tthrow new RpcSessionRegistryError(\"invalid_path\");\n\t\t}\n\t\tif (profile.durableSessionId !== undefined) {\n\t\t\ttry {\n\t\t\t\tassertValidSessionId(profile.durableSessionId);\n\t\t\t} catch (cause) {\n\t\t\t\tthrow new RpcSessionRegistryError(\"invalid_session_id\", String(cause));\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { RpcSessionRegistry } from "./session-registry.ts";
2
+ export interface SweepVerdicts {
3
+ /** Open sessions idle past the window: a retained one parks, any other closes as `idle_evicted`. */
4
+ readonly idle: readonly string[];
5
+ /**
6
+ * Sessions no client holds whose transcript directory is gone. Nothing can reopen them by path
7
+ * and they can never persist again, so they close as `session_dir_removed` (senpi#2206).
8
+ */
9
+ readonly orphaned: readonly string[];
10
+ }
11
+ /**
12
+ * One occupancy sweep's decisions. "Idle" is the COMPLETE session-owned activity contract
13
+ * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and other published
14
+ * wake sources, compaction, barrier-held session work): a busy session restarts its idle clock
15
+ * instead, so work that outlives a turn is never killed. A non-finite window evicts nothing idle.
16
+ */
17
+ export declare function selectSweepEvictions(registry: Pick<RpcSessionRegistry, "list" | "peek">, now: number, idleEvictionMs: number): SweepVerdicts;
18
+ //# sourceMappingURL=session-sweep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-sweep.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/session-sweep.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,MAAM,WAAW,aAAa;IAC7B,oGAAoG;IACpG,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAAC,EACnD,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,MAAM,GACpB,aAAa,CAmBf"}
@@ -0,0 +1,32 @@
1
+ import { sessionDirectoryRemoved } from "./session-path-key.js";
2
+ /**
3
+ * One occupancy sweep's decisions. "Idle" is the COMPLETE session-owned activity contract
4
+ * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and other published
5
+ * wake sources, compaction, barrier-held session work): a busy session restarts its idle clock
6
+ * instead, so work that outlives a turn is never killed. A non-finite window evicts nothing idle.
7
+ */
8
+ export function selectSweepEvictions(registry, now, idleEvictionMs) {
9
+ const idle = [];
10
+ const orphaned = [];
11
+ for (const { sessionId, status, sessionPath } of registry.list()) {
12
+ if (status !== "open")
13
+ continue;
14
+ const entry = registry.peek(sessionId);
15
+ if (!entry)
16
+ continue;
17
+ if (entry.attachments === 0 && sessionPath !== undefined && sessionDirectoryRemoved(sessionPath)) {
18
+ orphaned.push(sessionId);
19
+ continue;
20
+ }
21
+ if (!Number.isFinite(idleEvictionMs))
22
+ continue;
23
+ if (entry.worker?.busy || entry.runtime?.session.isSessionBusy) {
24
+ entry.lastCommandAt = now;
25
+ continue;
26
+ }
27
+ if (now - entry.lastCommandAt >= idleEvictionMs)
28
+ idle.push(sessionId);
29
+ }
30
+ return { idle, orphaned };
31
+ }
32
+ //# sourceMappingURL=session-sweep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-sweep.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-sweep.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAahE;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CACnC,QAAmD,EACnD,GAAW,EACX,cAAsB;IAEtB,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAClE,IAAI,MAAM,KAAK,MAAM;YAAE,SAAS;QAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,SAAS;QACrB,IAAI,KAAK,CAAC,WAAW,KAAK,CAAC,IAAI,WAAW,KAAK,SAAS,IAAI,uBAAuB,CAAC,WAAW,CAAC,EAAE,CAAC;YAClG,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzB,SAAS;QACV,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,SAAS;QAC/C,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,IAAI,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC;YAChE,KAAK,CAAC,aAAa,GAAG,GAAG,CAAC;YAC1B,SAAS;QACV,CAAC;QACD,IAAI,GAAG,GAAG,KAAK,CAAC,aAAa,IAAI,cAAc;YAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC3B,CAAC","sourcesContent":["import { sessionDirectoryRemoved } from \"./session-path-key.ts\";\nimport type { RpcSessionRegistry } from \"./session-registry.ts\";\n\nexport interface SweepVerdicts {\n\t/** Open sessions idle past the window: a retained one parks, any other closes as `idle_evicted`. */\n\treadonly idle: readonly string[];\n\t/**\n\t * Sessions no client holds whose transcript directory is gone. Nothing can reopen them by path\n\t * and they can never persist again, so they close as `session_dir_removed` (senpi#2206).\n\t */\n\treadonly orphaned: readonly string[];\n}\n\n/**\n * One occupancy sweep's decisions. \"Idle\" is the COMPLETE session-owned activity contract\n * (`AgentSession.isSessionBusy`: agent run, bash, background terminal jobs and other published\n * wake sources, compaction, barrier-held session work): a busy session restarts its idle clock\n * instead, so work that outlives a turn is never killed. A non-finite window evicts nothing idle.\n */\nexport function selectSweepEvictions(\n\tregistry: Pick<RpcSessionRegistry, \"list\" | \"peek\">,\n\tnow: number,\n\tidleEvictionMs: number,\n): SweepVerdicts {\n\tconst idle: string[] = [];\n\tconst orphaned: string[] = [];\n\tfor (const { sessionId, status, sessionPath } of registry.list()) {\n\t\tif (status !== \"open\") continue;\n\t\tconst entry = registry.peek(sessionId);\n\t\tif (!entry) continue;\n\t\tif (entry.attachments === 0 && sessionPath !== undefined && sessionDirectoryRemoved(sessionPath)) {\n\t\t\torphaned.push(sessionId);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!Number.isFinite(idleEvictionMs)) continue;\n\t\tif (entry.worker?.busy || entry.runtime?.session.isSessionBusy) {\n\t\t\tentry.lastCommandAt = now;\n\t\t\tcontinue;\n\t\t}\n\t\tif (now - entry.lastCommandAt >= idleEvictionMs) idle.push(sessionId);\n\t}\n\treturn { idle, orphaned };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import { type ScanMigrationName } from "./migrations-state.ts";
2
+ /** Copies back what an earlier start moved out of `~/.pi`, only into an agent/mom dir holding no user state. */
3
+ export declare function restoreDrainedPiDirs(completed: ReadonlySet<ScanMigrationName>, homeDir?: string): void;
4
+ //# sourceMappingURL=pi-dir-restore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-dir-restore.d.ts","sourceRoot":"","sources":["../src/pi-dir-restore.ts"],"names":[],"mappings":"AAWA,OAAO,EAA6B,KAAK,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAkE1F,gHAAgH;AAChH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,WAAW,CAAC,iBAAiB,CAAC,EAAE,OAAO,GAAE,MAAkB,GAAG,IAAI,CAejH"}
@@ -0,0 +1,92 @@
1
+ import { existsSync, lstatSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ import chalk from "chalk";
5
+ import { CONFIG_DIR_NAME, getAgentDir } from "./config.js";
6
+ import { copyMissingEntries, isRegenerableEntry, isWithinOrSamePath, pathsPointToSameLocation, } from "./legacy-dir-copy.js";
7
+ import { MIGRATIONS_STATE_FILENAME } from "./migrations-state.js";
8
+ /** Upstream pi's agent-dir entries; anything else in our agent dir is our own state and never goes to pi. */
9
+ const UPSTREAM_PI_AGENT_ENTRIES = new Set([
10
+ "auth.json",
11
+ "settings.json",
12
+ "models.json",
13
+ "models-store.json",
14
+ "keybindings.json",
15
+ "sessions",
16
+ "extensions",
17
+ "skills",
18
+ "prompts",
19
+ "themes",
20
+ "npm",
21
+ "git",
22
+ "experimental",
23
+ "AGENTS.md",
24
+ "CLAUDE.md",
25
+ "SYSTEM.md",
26
+ "APPEND_SYSTEM.md",
27
+ ]);
28
+ function isDirectory(path) {
29
+ return existsSync(path) && statSync(path).isDirectory();
30
+ }
31
+ /**
32
+ * Before this release, the first start moved `~/.pi/agent` and `~/.pi/mom` into this product's
33
+ * directories. A recorded run of that migration, or engine state written by a build older than the
34
+ * migrations state file, is the evidence that it may have happened on this agent dir.
35
+ */
36
+ function movingMigrationMayHaveRun(agentDir, completed) {
37
+ if (completed.has("migrateLegacySenpiDirs"))
38
+ return true;
39
+ if (existsSync(join(agentDir, MIGRATIONS_STATE_FILENAME)))
40
+ return false;
41
+ return isDirectory(agentDir) && readdirSync(agentDir).some((entry) => UPSTREAM_PI_AGENT_ENTRIES.has(entry));
42
+ }
43
+ /** pi writes `{}` into `auth.json` and `models-store.json` when it starts with an empty directory. */
44
+ function isEmptyJsonStub(path) {
45
+ const stat = lstatSync(path);
46
+ if (!stat.isFile() || stat.size > 16)
47
+ return false;
48
+ const text = readFileSync(path, "utf-8").trim();
49
+ return text === "{}" || text === "[]";
50
+ }
51
+ function holdsNoUserState(dir) {
52
+ if (!existsSync(dir))
53
+ return true;
54
+ return readdirSync(dir).every((entry) => isRegenerableEntry(entry) || isEmptyJsonStub(join(dir, entry)));
55
+ }
56
+ function restoreDir(from, to, include) {
57
+ if (!isDirectory(from) || !holdsNoUserState(to))
58
+ return;
59
+ if (existsSync(to) && pathsPointToSameLocation(from, to))
60
+ return;
61
+ for (const entry of existsSync(to) ? readdirSync(to) : []) {
62
+ if (include(entry) && existsSync(join(from, entry)) && isEmptyJsonStub(join(to, entry))) {
63
+ rmSync(join(to, entry));
64
+ }
65
+ }
66
+ const restored = copyMissingEntries(from, to, include);
67
+ if (restored.length > 0) {
68
+ console.log(chalk.green(`Restored ${to} from ${from}: an earlier start had moved it there.`));
69
+ console.log(chalk.dim("Both directories now hold independent copies."));
70
+ }
71
+ }
72
+ /** Copies back what an earlier start moved out of `~/.pi`, only into an agent/mom dir holding no user state. */
73
+ export function restoreDrainedPiDirs(completed, homeDir = homedir()) {
74
+ if (CONFIG_DIR_NAME === ".pi")
75
+ return;
76
+ const agentDir = getAgentDir();
77
+ const brandDir = join(homeDir, CONFIG_DIR_NAME);
78
+ const piDir = join(homeDir, ".pi");
79
+ if (!isWithinOrSamePath(agentDir, brandDir) || !isDirectory(piDir))
80
+ return;
81
+ if (!movingMigrationMayHaveRun(agentDir, completed))
82
+ return;
83
+ try {
84
+ restoreDir(agentDir, join(piDir, "agent"), (entry) => UPSTREAM_PI_AGENT_ENTRIES.has(entry));
85
+ restoreDir(join(brandDir, "mom"), join(piDir, "mom"), (entry) => !isRegenerableEntry(entry));
86
+ }
87
+ catch (error) {
88
+ const reason = error instanceof Error ? error.message : String(error);
89
+ console.warn(chalk.yellow(`Could not restore ${piDir}: ${reason}`));
90
+ }
91
+ }
92
+ //# sourceMappingURL=pi-dir-restore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi-dir-restore.js","sourceRoot":"","sources":["../src/pi-dir-restore.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, lstatSync, readdirSync, readFileSync, rmSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport chalk from \"chalk\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"./config.ts\";\nimport {\n\tcopyMissingEntries,\n\tisRegenerableEntry,\n\tisWithinOrSamePath,\n\tpathsPointToSameLocation,\n} from \"./legacy-dir-copy.ts\";\nimport { MIGRATIONS_STATE_FILENAME, type ScanMigrationName } from \"./migrations-state.ts\";\n\n/** Upstream pi's agent-dir entries; anything else in our agent dir is our own state and never goes to pi. */\nconst UPSTREAM_PI_AGENT_ENTRIES: ReadonlySet<string> = new Set([\n\t\"auth.json\",\n\t\"settings.json\",\n\t\"models.json\",\n\t\"models-store.json\",\n\t\"keybindings.json\",\n\t\"sessions\",\n\t\"extensions\",\n\t\"skills\",\n\t\"prompts\",\n\t\"themes\",\n\t\"npm\",\n\t\"git\",\n\t\"experimental\",\n\t\"AGENTS.md\",\n\t\"CLAUDE.md\",\n\t\"SYSTEM.md\",\n\t\"APPEND_SYSTEM.md\",\n]);\n\nfunction isDirectory(path: string): boolean {\n\treturn existsSync(path) && statSync(path).isDirectory();\n}\n\n/**\n * Before this release, the first start moved `~/.pi/agent` and `~/.pi/mom` into this product's\n * directories. A recorded run of that migration, or engine state written by a build older than the\n * migrations state file, is the evidence that it may have happened on this agent dir.\n */\nfunction movingMigrationMayHaveRun(agentDir: string, completed: ReadonlySet<ScanMigrationName>): boolean {\n\tif (completed.has(\"migrateLegacySenpiDirs\")) return true;\n\tif (existsSync(join(agentDir, MIGRATIONS_STATE_FILENAME))) return false;\n\treturn isDirectory(agentDir) && readdirSync(agentDir).some((entry) => UPSTREAM_PI_AGENT_ENTRIES.has(entry));\n}\n\n/** pi writes `{}` into `auth.json` and `models-store.json` when it starts with an empty directory. */\nfunction isEmptyJsonStub(path: string): boolean {\n\tconst stat = lstatSync(path);\n\tif (!stat.isFile() || stat.size > 16) return false;\n\tconst text = readFileSync(path, \"utf-8\").trim();\n\treturn text === \"{}\" || text === \"[]\";\n}\n\nfunction holdsNoUserState(dir: string): boolean {\n\tif (!existsSync(dir)) return true;\n\treturn readdirSync(dir).every((entry) => isRegenerableEntry(entry) || isEmptyJsonStub(join(dir, entry)));\n}\n\nfunction restoreDir(from: string, to: string, include: (entry: string) => boolean): void {\n\tif (!isDirectory(from) || !holdsNoUserState(to)) return;\n\tif (existsSync(to) && pathsPointToSameLocation(from, to)) return;\n\tfor (const entry of existsSync(to) ? readdirSync(to) : []) {\n\t\tif (include(entry) && existsSync(join(from, entry)) && isEmptyJsonStub(join(to, entry))) {\n\t\t\trmSync(join(to, entry));\n\t\t}\n\t}\n\tconst restored = copyMissingEntries(from, to, include);\n\tif (restored.length > 0) {\n\t\tconsole.log(chalk.green(`Restored ${to} from ${from}: an earlier start had moved it there.`));\n\t\tconsole.log(chalk.dim(\"Both directories now hold independent copies.\"));\n\t}\n}\n\n/** Copies back what an earlier start moved out of `~/.pi`, only into an agent/mom dir holding no user state. */\nexport function restoreDrainedPiDirs(completed: ReadonlySet<ScanMigrationName>, homeDir: string = homedir()): void {\n\tif (CONFIG_DIR_NAME === \".pi\") return;\n\tconst agentDir = getAgentDir();\n\tconst brandDir = join(homeDir, CONFIG_DIR_NAME);\n\tconst piDir = join(homeDir, \".pi\");\n\tif (!isWithinOrSamePath(agentDir, brandDir) || !isDirectory(piDir)) return;\n\tif (!movingMigrationMayHaveRun(agentDir, completed)) return;\n\n\ttry {\n\t\trestoreDir(agentDir, join(piDir, \"agent\"), (entry) => UPSTREAM_PI_AGENT_ENTRIES.has(entry));\n\t\trestoreDir(join(brandDir, \"mom\"), join(piDir, \"mom\"), (entry) => !isRegenerableEntry(entry));\n\t} catch (error) {\n\t\tconst reason = error instanceof Error ? error.message : String(error);\n\t\tconsole.warn(chalk.yellow(`Could not restore ${piDir}: ${reason}`));\n\t}\n}\n"]}
package/docs/rpc.md CHANGED
@@ -735,8 +735,10 @@ REPORT: nothing here aborts a turn, kills a session, or refuses an `open_session
735
735
  `position` is 1-based and `in_flight` counts opens already accepted across the whole host,
736
736
  since every session shares one loop. It is addressed to the opener only, carries the request
737
737
  id under `for_request` rather than the response-id field, and is dropped if that connection
738
- has disconnected. A client that later times out can report where it was queued instead of a
739
- bare deadline.
738
+ has disconnected. The bundled `RpcClient` treats it as the host's acknowledgement: an
739
+ acknowledged open waits up to 10 minutes for its response instead of the 30 s request
740
+ deadline (a busy host was measured answering after 57 s), and a timeout after it names the
741
+ queue position instead of a bare deadline. A lost transport still rejects at once.
740
742
  `SENPI_RPC_LOOP_LAG_ERROR_MS` (default 5000) additionally broadcasts a `host_stalled` record
741
743
  (`{ type, driftMs, sessionId?, tool? }`) to every connection, like the other content-free lifecycle records.
742
744
  - **Stall attribution**: each routed command is dispatched inside an `AsyncLocalStorage` scope carrying its routing
@@ -1135,6 +1137,8 @@ The `model` field is a full [Model](#model) object or `null`. The `sessionName`
1135
1137
 
1136
1138
  `serviceTier` is the tier a request would carry right now (`"auto"`, `"flex"`, or `"priority"`), omitted when no tier applies. `fastMode` is `true` when the active model is served at the priority ("fast") tier — either because fast mode is on for this session or because the model selection itself pins `priority`. The two never disagree: whenever `fastMode` is `true`, `serviceTier` is `"priority"`.
1137
1139
 
1140
+ `lastProviderDiagnostic` is present after a failed turn whose provider supplied structured evidence: `{"category": "rate_limit", "httpStatus": 429, "code": "rate_limit_error", "evidence": "structured_code"}`. `category` is one of `auth`, `rate_limit`, `quota`, `context_limit`, `invalid_request`, `provider_unavailable`, `unknown`; `httpStatus` is absent for errors delivered inside a streamed response. It describes the same failure as the latest assistant `errorMessage` and is replaced or cleared with it. The failed assistant message in `message_end`, `agent_end`, `get_messages` and the session file carries the same object as `providerDiagnostic`. See [Provider failure diagnostics](sdk.md#provider-failure-diagnostics) for how it is derived.
1141
+
1138
1142
  #### get_messages
1139
1143
 
1140
1144
  Get all messages in the conversation.
@@ -2154,7 +2158,7 @@ Events are streamed to stdout as JSON lines during agent operation. Events do no
2154
2158
  | `loaded_surfaces_changed` | Loaded skills, extensions, or MCP inventory changed; re-read `get_commands` and `get_loaded_surfaces` |
2155
2159
  | `model_changed` | Active model changed (any source), with the thinking level in force afterwards |
2156
2160
  | `service_tier_changed` | Effective service tier or fast-mode state changed |
2157
- | `session_closed` | Multi-session host: a routing handle ended. Optional `reason`: `client_close`, `idle_evicted`, `host_shutdown`, `replaced`, `handoff_parked`, `error` |
2161
+ | `session_closed` | Multi-session host: a routing handle ended. Optional `reason`: `client_close`, `idle_evicted`, `host_shutdown`, `replaced`, `handoff_parked`, `session_dir_removed`, `error` |
2158
2162
  | `session_parked` | Multi-session host: a retained session was released to disk at the idle window (`sessionId`, `sessionPath`). Replaces `session_closed` for that handle |
2159
2163
  | `host_stalled` | Multi-session host: the event loop was blocked past `SENPI_RPC_LOOP_LAG_ERROR_MS`, with the drift and the session/tool blamed for it |
2160
2164
  | `host_memory_pressure` | Multi-session host: RSS is above `SENPI_RPC_HOST_RSS_WARN_MB`, with the live session count |
@@ -2180,6 +2184,7 @@ When a multi-session host ends a routing handle it may name why:
2180
2184
  | --- | --- |
2181
2185
  | `client_close` | An attached client sent `close_session` |
2182
2186
  | `idle_evicted` | The idle sweep ended a session that was not retained |
2187
+ | `session_dir_removed` | No client held the session and its transcript directory was deleted; the sweep ended it, whatever the idle window |
2183
2188
  | `host_shutdown` | The host process is exiting (SIGTERM, idle-exit, empty-host). A retained session is closed, not parked |
2184
2189
  | `replaced` | The routing handle ended because the live session behind it was replaced |
2185
2190
  | `handoff_parked` | A generation handoff drained this host; reopen with `open_session { sessionPath }` |
package/docs/sdk.md CHANGED
@@ -252,6 +252,7 @@ const state = session.agent.state;
252
252
  // state.tools: AgentTool[] - available tools
253
253
  // state.streamingMessage?: AgentMessage - current partial assistant message
254
254
  // state.errorMessage?: string - latest assistant error
255
+ // state.providerDiagnostic?: ProviderDiagnostic - structured family of that error, when known
255
256
 
256
257
  // Replace messages (useful for branching or restoration)
257
258
  session.agent.state.messages = messages; // copies the top-level array
@@ -263,6 +264,34 @@ session.agent.state.tools = tools; // copies the top-level array
263
264
  await session.agent.waitForIdle();
264
265
  ```
265
266
 
267
+ #### Provider failure diagnostics
268
+
269
+ A failed turn is an assistant message with `stopReason: "error"` and a human-readable `errorMessage`. When the provider rejected the request with structured evidence, the same message also carries an optional `providerDiagnostic`, so callers can branch on the failure family without parsing `errorMessage`:
270
+
271
+ ```typescript
272
+ // Shape of ProviderDiagnostic, exported from "@earendil-works/pi-ai":
273
+ // {
274
+ // category: "auth" | "rate_limit" | "quota" | "context_limit" | "invalid_request" | "provider_unavailable" | "unknown";
275
+ // httpStatus?: number; // 400..599; absent for an error delivered inside an HTTP 200 stream
276
+ // code?: string; // provider token from a closed allowlist, e.g. "rate_limit_error", "insufficient_quota"
277
+ // evidence: "structured_status" | "structured_code";
278
+ // }
279
+ import type { ProviderDiagnostic } from "@earendil-works/pi-ai";
280
+
281
+ session.subscribe((event) => {
282
+ if (event.type !== "message_end" || event.message.role !== "assistant") return;
283
+ if (event.message.providerDiagnostic?.category === "auth") promptForLogin();
284
+ });
285
+
286
+ // After the run settles, the latest failure is also on the agent state
287
+ const diagnostic: ProviderDiagnostic | undefined = session.agent.state.providerDiagnostic;
288
+ ```
289
+
290
+ - Only the Anthropic Messages and OpenAI-compatible Chat Completions adapters mint it today, from the HTTP status and error code of the SDK error their own transport call raised, an Anthropic `event: error` SSE envelope, or an OpenAI-compatible in-stream `error` chunk. Message text, response headers, request ids, and errors thrown by caller callbacks such as `onPayload` never produce one.
291
+ - A recognized `code` decides the category (`evidence: "structured_code"`); without one, the status alone decides it (`evidence: "structured_status"`: 401 is `auth`, 400 `invalid_request`, 5xx `provider_unavailable`, and any other 4xx such as a bare 402/403/429 is `unknown`). A code that contradicts the status, or a status outside 400..599, yields no diagnostic. `billing_error` maps to `unknown`, not `quota`.
292
+ - The field is at most 512 bytes. It is additive: `errorMessage`, retries, model fallback and CLI exit codes are identical with or without it. It is absent on aborted turns and on failures without structured provider evidence.
293
+ - Values that crossed a boundary (a persisted session, a wire message) can be revalidated with `sanitizeProviderDiagnostic(value)` from `@earendil-works/pi-ai`, which returns a fresh canonical copy or `undefined`.
294
+
266
295
  ### Events
267
296
 
268
297
  Subscribe to events to receive streaming output and lifecycle notifications.
package/docs/sessions.md CHANGED
@@ -24,6 +24,10 @@ Sessions are filed by the directory they started in. Each session also records w
24
24
 
25
25
  When `--session <id>` (or a pick in `--resume`) finds a session filed under another path and the current directory is the same git repository, senpi shows both paths and offers to move the session here. Answering `y` rebinds it: the session file moves to the current project, its recorded working directory is updated, and it keeps its id, history, goal, loops, and monitors. The old path no longer lists it. Use `--fork <id>` to copy it into a new session instead. A session from a different repository gets the fork prompt as before.
26
26
 
27
+ The in-session `/resume` selector asks the same question when you pick such a session; answering No opens it where it is. The current-folder view of `/resume` and `--resume` also lists this repository's sessions whose old path no longer exists, marked "moved from <old path>", and `--continue` in a project with no session of its own offers the newest of them.
28
+
29
+ A session that another senpi process still has open is never moved: the move stops and names that process (pid and directory) so you can quit it first. Each open session is advertised under `session-holders/` next to the session file; a record left by a process that has exited is ignored.
30
+
27
31
  `--rebind <path|id>` does the same without asking, for scripts. It refuses when the two directories are provably different repositories. Without an interactive terminal, `--session` never prompts: it prints the exact `--rebind` and `--fork` commands and exits with a non-zero status.
28
32
 
29
33
  For the JSONL file format and SessionManager API, see [Session Format](session-format.md).
@@ -12,6 +12,18 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.9.27-3] - 2026-09-27
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ ### Removed
26
+
15
27
  ## [2026.9.27-2] - 2026-09-27
16
28
 
17
29
  ### Breaking Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.9.27-2",
3
+ "version": "2026.9.27-3",
4
4
  "private": true,
5
5
  "description": "Source-only senpi extension package for codemode evaluation tools",
6
6
  "type": "module",
@@ -31,14 +31,14 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@babel/parser": "8.0.4",
34
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.27-2",
34
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.27-3",
35
35
  "typebox": "1.3.34"
36
36
  },
37
37
  "peerDependencies": {
38
- "@code-yeongyu/senpi": "2026.9.27-2"
38
+ "@code-yeongyu/senpi": "2026.9.27-3"
39
39
  },
40
40
  "devDependencies": {
41
- "@code-yeongyu/senpi": "2026.9.27-2"
41
+ "@code-yeongyu/senpi": "2026.9.27-3"
42
42
  },
43
43
  "keywords": [
44
44
  "senpi",
@@ -1,9 +1,9 @@
1
- import type { Context, ImageContent, Message, SimpleStreamOptions, ThinkingBudgets, Transport } from "@earendil-works/pi-ai";
1
+ import { type Context, type ImageContent, type Message, type SimpleStreamOptions, type ThinkingBudgets, type Transport } from "@earendil-works/pi-ai";
2
2
  import type { AfterToolCallContext, AfterToolCallResult, AgentContext, AgentEvent, AgentLoopConfig, AgentLoopTurnUpdate, AgentMessage, AgentState, BeforeToolCallContext, BeforeToolCallResult, PrepareNextTurnContext, QueueMode, ShouldStopAfterTurnContext, StreamFn, ToolExecutionMode } from "./types.ts";
3
3
  export type { QueueMode } from "./types.ts";
4
4
  /** Options for constructing an {@link Agent}. */
5
5
  export interface AgentOptions {
6
- initialState?: Partial<Omit<AgentState, "pendingToolCalls" | "isStreaming" | "streamingMessage" | "errorMessage">>;
6
+ initialState?: Partial<Omit<AgentState, "pendingToolCalls" | "isStreaming" | "streamingMessage" | "errorMessage" | "providerDiagnostic">>;
7
7
  convertToLlm?: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
8
8
  transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
9
9
  streamFn: StreamFn;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}