@code-yeongyu/senpi 2026.9.10 → 2026.9.11

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 (337) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/core/agent-session.d.ts +57 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +130 -20
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/auth-storage.d.ts +2 -0
  7. package/dist/core/auth-storage.d.ts.map +1 -1
  8. package/dist/core/auth-storage.js +49 -17
  9. package/dist/core/auth-storage.js.map +1 -1
  10. package/dist/core/brand.d.ts +5 -0
  11. package/dist/core/brand.d.ts.map +1 -1
  12. package/dist/core/brand.js +13 -0
  13. package/dist/core/brand.js.map +1 -1
  14. package/dist/core/changelog-source.d.ts +8 -0
  15. package/dist/core/changelog-source.d.ts.map +1 -0
  16. package/dist/core/changelog-source.js +19 -0
  17. package/dist/core/changelog-source.js.map +1 -0
  18. package/dist/core/credential-accounts.d.ts +3 -0
  19. package/dist/core/credential-accounts.d.ts.map +1 -1
  20. package/dist/core/credential-accounts.js +20 -1
  21. package/dist/core/credential-accounts.js.map +1 -1
  22. package/dist/core/credential-pool/classify.d.ts.map +1 -1
  23. package/dist/core/credential-pool/classify.js +8 -0
  24. package/dist/core/credential-pool/classify.js.map +1 -1
  25. package/dist/core/extensions/builtin/account/index.d.ts.map +1 -1
  26. package/dist/core/extensions/builtin/account/index.js +7 -3
  27. package/dist/core/extensions/builtin/account/index.js.map +1 -1
  28. package/dist/core/extensions/builtin/account-display-name.d.ts +7 -0
  29. package/dist/core/extensions/builtin/account-display-name.d.ts.map +1 -0
  30. package/dist/core/extensions/builtin/account-display-name.js +40 -0
  31. package/dist/core/extensions/builtin/account-display-name.js.map +1 -0
  32. package/dist/core/extensions/builtin/ask-user/format.d.ts.map +1 -1
  33. package/dist/core/extensions/builtin/ask-user/format.js +7 -2
  34. package/dist/core/extensions/builtin/ask-user/format.js.map +1 -1
  35. package/dist/core/extensions/builtin/ask-user/pending.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/ask-user/pending.js +3 -0
  37. package/dist/core/extensions/builtin/ask-user/pending.js.map +1 -1
  38. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js +21 -9
  40. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js.map +1 -1
  41. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts +1 -0
  42. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts.map +1 -1
  43. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js +11 -6
  44. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js.map +1 -1
  45. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts +9 -0
  46. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js +10 -1
  48. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js.map +1 -1
  49. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +3 -0
  50. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  51. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +19 -10
  53. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  54. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +3 -9
  56. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -1
  57. package/dist/core/extensions/builtin/config-reload/routine-settings.d.ts.map +1 -1
  58. package/dist/core/extensions/builtin/config-reload/routine-settings.js +1 -0
  59. package/dist/core/extensions/builtin/config-reload/routine-settings.js.map +1 -1
  60. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.d.ts.map +1 -1
  61. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js +5 -3
  62. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js.map +1 -1
  63. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts +1 -0
  64. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts.map +1 -1
  65. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.js.map +1 -1
  66. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts.map +1 -1
  67. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js +3 -9
  68. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js.map +1 -1
  69. package/dist/core/extensions/builtin/goal/agent-end-continuation.d.ts.map +1 -1
  70. package/dist/core/extensions/builtin/goal/agent-end-continuation.js +13 -1
  71. package/dist/core/extensions/builtin/goal/agent-end-continuation.js.map +1 -1
  72. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  73. package/dist/core/extensions/builtin/goal/prompt.js +11 -8
  74. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  75. package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts +1 -0
  76. package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts.map +1 -1
  77. package/dist/core/extensions/builtin/goal/terminal-provider-error.js +28 -0
  78. package/dist/core/extensions/builtin/goal/terminal-provider-error.js.map +1 -1
  79. package/dist/core/extensions/builtin/goal/todo-gate.js +2 -2
  80. package/dist/core/extensions/builtin/goal/todo-gate.js.map +1 -1
  81. package/dist/core/extensions/builtin/goal/tool-registration.js +2 -2
  82. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  83. package/dist/core/extensions/builtin/gpt-account.d.ts.map +1 -1
  84. package/dist/core/extensions/builtin/gpt-account.js +19 -8
  85. package/dist/core/extensions/builtin/gpt-account.js.map +1 -1
  86. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts +3 -0
  87. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts.map +1 -0
  88. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js +19 -0
  89. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js.map +1 -0
  90. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +6 -6
  91. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +26 -7
  93. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  95. package/dist/core/extensions/builtin/prompt-preset/presets.js +29 -0
  96. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  97. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  98. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  99. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  100. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  101. package/dist/core/high-reasoning-warning.d.ts.map +1 -1
  102. package/dist/core/high-reasoning-warning.js +5 -1
  103. package/dist/core/high-reasoning-warning.js.map +1 -1
  104. package/dist/core/manual-continue.d.ts +14 -0
  105. package/dist/core/manual-continue.d.ts.map +1 -1
  106. package/dist/core/manual-continue.js +13 -0
  107. package/dist/core/manual-continue.js.map +1 -1
  108. package/dist/core/model-runtime.d.ts.map +1 -1
  109. package/dist/core/model-runtime.js +2 -2
  110. package/dist/core/model-runtime.js.map +1 -1
  111. package/dist/core/remote-catalog-merge.d.ts +16 -0
  112. package/dist/core/remote-catalog-merge.d.ts.map +1 -0
  113. package/dist/core/remote-catalog-merge.js +75 -0
  114. package/dist/core/remote-catalog-merge.js.map +1 -0
  115. package/dist/core/remote-catalog-provider.d.ts +3 -0
  116. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  117. package/dist/core/remote-catalog-provider.js +12 -40
  118. package/dist/core/remote-catalog-provider.js.map +1 -1
  119. package/dist/core/session-entry-materializer.d.ts +12 -0
  120. package/dist/core/session-entry-materializer.d.ts.map +1 -0
  121. package/dist/core/session-entry-materializer.js +26 -0
  122. package/dist/core/session-entry-materializer.js.map +1 -0
  123. package/dist/core/session-manager.d.ts +36 -1
  124. package/dist/core/session-manager.d.ts.map +1 -1
  125. package/dist/core/session-manager.js +38 -8
  126. package/dist/core/session-manager.js.map +1 -1
  127. package/dist/core/settings-manager.d.ts +3 -0
  128. package/dist/core/settings-manager.d.ts.map +1 -1
  129. package/dist/core/settings-manager.js +10 -0
  130. package/dist/core/settings-manager.js.map +1 -1
  131. package/dist/modes/app-server/daemon/process.d.ts +6 -1
  132. package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
  133. package/dist/modes/app-server/daemon/process.js +23 -4
  134. package/dist/modes/app-server/daemon/process.js.map +1 -1
  135. package/dist/modes/app-server/protocol/account.d.ts +2 -0
  136. package/dist/modes/app-server/protocol/account.d.ts.map +1 -1
  137. package/dist/modes/app-server/protocol/account.js.map +1 -1
  138. package/dist/modes/interactive/components/ask-user-question-keys.d.ts +1 -1
  139. package/dist/modes/interactive/components/ask-user-question-keys.d.ts.map +1 -1
  140. package/dist/modes/interactive/components/ask-user-question-keys.js +65 -17
  141. package/dist/modes/interactive/components/ask-user-question-keys.js.map +1 -1
  142. package/dist/modes/interactive/components/ask-user-question-render.d.ts +2 -1
  143. package/dist/modes/interactive/components/ask-user-question-render.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/ask-user-question-render.js +39 -9
  145. package/dist/modes/interactive/components/ask-user-question-render.js.map +1 -1
  146. package/dist/modes/interactive/components/ask-user-question-state.d.ts +14 -4
  147. package/dist/modes/interactive/components/ask-user-question-state.d.ts.map +1 -1
  148. package/dist/modes/interactive/components/ask-user-question-state.js +63 -6
  149. package/dist/modes/interactive/components/ask-user-question-state.js.map +1 -1
  150. package/dist/modes/interactive/components/ask-user-question.d.ts +2 -0
  151. package/dist/modes/interactive/components/ask-user-question.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/ask-user-question.js +27 -14
  153. package/dist/modes/interactive/components/ask-user-question.js.map +1 -1
  154. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/footer.js +51 -19
  156. package/dist/modes/interactive/components/footer.js.map +1 -1
  157. package/dist/modes/interactive/components/login-dialog.d.ts +11 -0
  158. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/login-dialog.js +29 -9
  160. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  161. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  162. package/dist/modes/interactive/components/tree-selector.js +7 -0
  163. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  164. package/dist/modes/interactive/help-content.d.ts.map +1 -1
  165. package/dist/modes/interactive/help-content.js +4 -0
  166. package/dist/modes/interactive/help-content.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +13 -4
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +44 -15
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/tips/catalog/input-tips.js +1 -1
  172. package/dist/modes/interactive/tips/catalog/input-tips.js.map +1 -1
  173. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  174. package/dist/modes/rpc/connection-handler.js +3 -1
  175. package/dist/modes/rpc/connection-handler.js.map +1 -1
  176. package/dist/modes/rpc/connection-question-bridge.js +1 -1
  177. package/dist/modes/rpc/connection-question-bridge.js.map +1 -1
  178. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  179. package/dist/modes/rpc/host-ensure.js +33 -11
  180. package/dist/modes/rpc/host-ensure.js.map +1 -1
  181. package/dist/modes/rpc/host-lifecycle.d.ts +14 -0
  182. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  183. package/dist/modes/rpc/host-lifecycle.js +31 -5
  184. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  185. package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
  186. package/dist/modes/rpc/rpc-input-validation.js +2 -0
  187. package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
  188. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  189. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  190. package/dist/modes/rpc/rpc-types.js.map +1 -1
  191. package/dist/utils/changelog.d.ts +3 -1
  192. package/dist/utils/changelog.d.ts.map +1 -1
  193. package/dist/utils/changelog.js +89 -23
  194. package/dist/utils/changelog.js.map +1 -1
  195. package/dist/utils/paths.d.ts +5 -0
  196. package/dist/utils/paths.d.ts.map +1 -1
  197. package/dist/utils/paths.js +14 -1
  198. package/dist/utils/paths.js.map +1 -1
  199. package/docs/app-server.md +6 -0
  200. package/docs/extensions.md +19 -3
  201. package/docs/rpc.md +10 -0
  202. package/docs/settings.md +2 -1
  203. package/docs/tui.md +1 -1
  204. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +28 -0
  205. package/node_modules/@code-yeongyu/senpi-codemode/README.md +5 -4
  206. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  207. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output-buffer.ts +58 -0
  208. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +9 -64
  209. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +1 -1
  210. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  211. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts +17 -0
  212. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts.map +1 -0
  213. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js +90 -0
  214. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js.map +1 -0
  215. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts +23 -0
  216. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts.map +1 -0
  217. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js +71 -0
  218. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js.map +1 -0
  219. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts +873 -0
  220. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts.map +1 -0
  221. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js +303 -0
  222. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js.map +1 -0
  223. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts +12 -0
  224. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts.map +1 -0
  225. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js +35 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js.map +1 -0
  227. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts +23 -0
  228. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts.map +1 -0
  229. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js +23 -0
  230. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js.map +1 -0
  231. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts +24 -0
  232. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts.map +1 -0
  233. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js +116 -0
  234. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js.map +1 -0
  235. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts +20 -0
  236. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts.map +1 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js +153 -0
  238. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js.map +1 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts +12 -0
  240. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts.map +1 -0
  241. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js +3 -0
  242. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js.map +1 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts +6 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts.map +1 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js +6 -0
  246. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js.map +1 -0
  247. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts +14 -0
  248. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts.map +1 -0
  249. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js +162 -0
  250. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js.map +1 -0
  251. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts +5 -0
  252. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts.map +1 -0
  253. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js +23 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js.map +1 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts +25 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts.map +1 -0
  257. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js +124 -0
  258. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js.map +1 -0
  259. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts +18 -0
  260. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts.map +1 -0
  261. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js +101 -0
  262. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js.map +1 -0
  263. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts +14 -0
  264. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts.map +1 -0
  265. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js +111 -0
  266. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js.map +1 -0
  267. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +5 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts +24 -0
  271. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts.map +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js +86 -0
  273. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js.map +1 -0
  274. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts +2 -0
  275. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js +5 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +51 -4
  279. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +196 -7
  281. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts +8 -0
  283. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +10 -0
  285. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +9 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.d.ts.map +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js +2 -0
  291. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js.map +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +1 -0
  293. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/compat.js +3 -0
  295. package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +4 -4
  297. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/models.js +14 -5
  301. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
  303. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +2 -0
  304. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  309. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  311. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  313. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  315. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts +12 -0
  316. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts.map +1 -0
  317. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js +62 -0
  318. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js.map +1 -0
  319. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +10 -0
  320. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -0
  321. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +28 -0
  322. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -0
  323. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +3 -1
  324. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  325. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  327. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +4 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  329. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  330. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  331. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  332. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts +1 -1
  333. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts.map +1 -1
  334. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js +55 -16
  335. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js.map +1 -1
  336. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  337. package/package.json +7 -7
@@ -104,7 +104,7 @@ export class ConnectionQuestionBridge {
104
104
  return false;
105
105
  answers = response.answers;
106
106
  comment = response.comment;
107
- if (!comment?.trim() && unanswered().length)
107
+ if (!comment?.trim() && Object.keys(answers).length === 0)
108
108
  return false;
109
109
  finish(comment?.trim() ? "comment-submitted" : "answered");
110
110
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"connection-question-bridge.js","sourceRoot":"","sources":["../../../src/modes/rpc/connection-question-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext, QuestionRequest, QuestionResponse } from \"../../core/extensions/types.ts\";\nimport type { RpcExtensionUIProgress, RpcExtensionUIResponse, RpcQuestionUiRequest } from \"./rpc-types.ts\";\n\ntype Options = Parameters<NonNullable<ExtensionUIContext[\"question\"]>>[1];\ntype Pending = {\n\tframe: RpcQuestionUiRequest;\n\tprogress: (draft: RpcExtensionUIProgress) => void;\n\trespond: (response: RpcExtensionUIResponse) => boolean;\n\tcancel: () => void;\n};\nexport const sessionQuestionBridges = new WeakMap<object, ConnectionQuestionBridge>();\n\nexport class ConnectionQuestionBridge {\n\tprivate readonly pending = new Map<string, Pending>();\n\tprivate readonly resolved = new Set<string>();\n\tprivate readonly output: (record: object) => void;\n\tconstructor(output: (record: object) => void) {\n\t\tthis.output = output;\n\t}\n\tpendingQuestions(): RpcQuestionUiRequest[] {\n\t\treturn [...this.pending.values()].map(({ frame }) => ({\n\t\t\t...frame,\n\t\t\tremainingMs: Math.max(0, frame.deadlineAtMs - Date.now()),\n\t\t}));\n\t}\n\task(request: QuestionRequest, opts?: Options): Promise<QuestionResponse> {\n\t\tconst id = crypto.randomUUID();\n\t\tconst askedAtMs = Date.now();\n\t\tconst timeout = opts?.timeout ?? request.timeoutMs;\n\t\tconst frame: RpcQuestionUiRequest = {\n\t\t\ttype: \"extension_ui_request\",\n\t\t\tmethod: \"question\",\n\t\t\tid,\n\t\t\trequestId: request.requestId,\n\t\t\ttoolCallId: request.requestId,\n\t\t\twaitForAnswer: request.waitForAnswer,\n\t\t\tquestions: request.questions,\n\t\t\ttimeout,\n\t\t\taskedAtMs,\n\t\t\tdeadlineAtMs: askedAtMs + timeout,\n\t\t\tremainingMs: timeout,\n\t\t};\n\t\treturn new Promise((resolve) => {\n\t\t\tlet answers: QuestionResponse[\"answers\"] = {};\n\t\t\tlet comment: string | undefined;\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet finished = false;\n\t\t\tconst unanswered = () =>\n\t\t\t\trequest.questions\n\t\t\t\t\t.filter((q) => !answers[q.id]?.selected.length && !answers[q.id]?.text?.trim())\n\t\t\t\t\t.map((q) => q.id);\n\t\t\tconst finish = (status: QuestionResponse[\"status\"]) => {\n\t\t\t\tif (finished) return;\n\t\t\t\tfinished = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\topts?.signal?.removeEventListener(\"abort\", cancel);\n\t\t\t\tthis.pending.delete(id);\n\t\t\t\tthis.resolved.add(id);\n\t\t\t\tconst result: QuestionResponse = {\n\t\t\t\t\tstatus,\n\t\t\t\t\tanswers,\n\t\t\t\t\tcomment,\n\t\t\t\t\tunanswered: unanswered(),\n\t\t\t\t\t...(status === \"timed_out\" ? { autoResolvedAfterMs: Date.now() - askedAtMs } : {}),\n\t\t\t\t};\n\t\t\t\tthis.output({\n\t\t\t\t\ttype: \"question_resolved\",\n\t\t\t\t\tid,\n\t\t\t\t\trequestId: frame.requestId,\n\t\t\t\t\ttoolCallId: frame.toolCallId,\n\t\t\t\t\toutcome: status,\n\t\t\t\t\tanswers,\n\t\t\t\t\tcomment,\n\t\t\t\t\tunanswered: result.unanswered,\n\t\t\t\t\tdeadlineAtMs: frame.deadlineAtMs,\n\t\t\t\t});\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\t// An aborted dialog is a cancellation unless the aborting side resolved a\n\t\t\t// terminal status of its own: the ask-user extension's idle timer settles\n\t\t\t// the question `timed_out` and aborts with that status, and connections\n\t\t\t// must see the outcome the extension resolved (docs/rpc.md question).\n\t\t\tconst cancel = () => {\n\t\t\t\tconst reason: unknown = opts?.signal?.reason;\n\t\t\t\tfinish(reason === \"timed_out\" ? \"timed_out\" : \"cancelled\");\n\t\t\t};\n\t\t\tconst arm = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tframe.deadlineAtMs = Date.now() + timeout;\n\t\t\t\ttimer = setTimeout(() => finish(\"timed_out\"), timeout);\n\t\t\t};\n\t\t\tthis.pending.set(id, {\n\t\t\t\tframe,\n\t\t\t\tcancel,\n\t\t\t\tprogress: (draft) => {\n\t\t\t\t\tif (draft.answers !== undefined) answers = draft.answers;\n\t\t\t\t\tif (draft.comment !== undefined) comment = draft.comment;\n\t\t\t\t\tarm();\n\t\t\t\t\topts?.onProgress?.({ answers, comment });\n\t\t\t\t\tif (!finished)\n\t\t\t\t\t\tthis.output({\n\t\t\t\t\t\t\ttype: \"question_updated\",\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\tdeadlineAtMs: frame.deadlineAtMs,\n\t\t\t\t\t\t\tremainingMs: Math.max(0, frame.deadlineAtMs - Date.now()),\n\t\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\trespond: (response) => {\n\t\t\t\t\tif (\"cancelled\" in response) {\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tif (!(\"answers\" in response)) return false;\n\t\t\t\t\tanswers = response.answers;\n\t\t\t\t\tcomment = response.comment;\n\t\t\t\t\tif (!comment?.trim() && unanswered().length) return false;\n\t\t\t\t\tfinish(comment?.trim() ? \"comment-submitted\" : \"answered\");\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t});\n\t\t\tarm();\n\t\t\tthis.output(frame);\n\t\t\topts?.signal?.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tif (opts?.signal?.aborted) cancel();\n\t\t});\n\t}\n\trespond(response: RpcExtensionUIResponse): boolean | \"question_incomplete\" | \"question_already_resolved\" {\n\t\tconst pending = this.pending.get(response.id);\n\t\tif (pending) return pending.respond(response) || \"question_incomplete\";\n\t\treturn this.resolved.has(response.id) ? \"question_already_resolved\" : false;\n\t}\n\tprogress(draft: RpcExtensionUIProgress): void {\n\t\tthis.pending.get(draft.id)?.progress(draft);\n\t}\n\tcancelAll(): void {\n\t\tfor (const pending of this.pending.values()) pending.cancel();\n\t}\n}\n\nexport async function degradeQuestion(\n\tui: Pick<ExtensionUIContext, \"select\" | \"input\">,\n\trequest: QuestionRequest,\n\topts?: Options,\n): Promise<QuestionResponse> {\n\tconst answers: QuestionResponse[\"answers\"] = {};\n\tconst other = \"Other (type an answer)\";\n\tfor (const question of request.questions) {\n\t\tconst selected = await ui.select(\n\t\t\tquestion.question,\n\t\t\t[...question.options.map((option) => option.label), other],\n\t\t\topts,\n\t\t);\n\t\tif (selected === other) {\n\t\t\tconst text = await ui.input(question.question, undefined, opts);\n\t\t\tif (text?.trim()) answers[question.id] = { selected: [], text };\n\t\t} else if (selected !== undefined) answers[question.id] = { selected: [selected] };\n\t}\n\tconst comment = await ui.input(\"Anything else? (optional)\", undefined, opts);\n\tconst unanswered = request.questions.filter((q) => !answers[q.id]).map((q) => q.id);\n\treturn {\n\t\tstatus: comment?.trim() ? \"comment-submitted\" : unanswered.length ? \"cancelled\" : \"answered\",\n\t\tanswers,\n\t\tcomment,\n\t\tunanswered,\n\t};\n}\n"]}
1
+ {"version":3,"file":"connection-question-bridge.js","sourceRoot":"","sources":["../../../src/modes/rpc/connection-question-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ExtensionUIContext, QuestionRequest, QuestionResponse } from \"../../core/extensions/types.ts\";\nimport type { RpcExtensionUIProgress, RpcExtensionUIResponse, RpcQuestionUiRequest } from \"./rpc-types.ts\";\n\ntype Options = Parameters<NonNullable<ExtensionUIContext[\"question\"]>>[1];\ntype Pending = {\n\tframe: RpcQuestionUiRequest;\n\tprogress: (draft: RpcExtensionUIProgress) => void;\n\trespond: (response: RpcExtensionUIResponse) => boolean;\n\tcancel: () => void;\n};\nexport const sessionQuestionBridges = new WeakMap<object, ConnectionQuestionBridge>();\n\nexport class ConnectionQuestionBridge {\n\tprivate readonly pending = new Map<string, Pending>();\n\tprivate readonly resolved = new Set<string>();\n\tprivate readonly output: (record: object) => void;\n\tconstructor(output: (record: object) => void) {\n\t\tthis.output = output;\n\t}\n\tpendingQuestions(): RpcQuestionUiRequest[] {\n\t\treturn [...this.pending.values()].map(({ frame }) => ({\n\t\t\t...frame,\n\t\t\tremainingMs: Math.max(0, frame.deadlineAtMs - Date.now()),\n\t\t}));\n\t}\n\task(request: QuestionRequest, opts?: Options): Promise<QuestionResponse> {\n\t\tconst id = crypto.randomUUID();\n\t\tconst askedAtMs = Date.now();\n\t\tconst timeout = opts?.timeout ?? request.timeoutMs;\n\t\tconst frame: RpcQuestionUiRequest = {\n\t\t\ttype: \"extension_ui_request\",\n\t\t\tmethod: \"question\",\n\t\t\tid,\n\t\t\trequestId: request.requestId,\n\t\t\ttoolCallId: request.requestId,\n\t\t\twaitForAnswer: request.waitForAnswer,\n\t\t\tquestions: request.questions,\n\t\t\ttimeout,\n\t\t\taskedAtMs,\n\t\t\tdeadlineAtMs: askedAtMs + timeout,\n\t\t\tremainingMs: timeout,\n\t\t};\n\t\treturn new Promise((resolve) => {\n\t\t\tlet answers: QuestionResponse[\"answers\"] = {};\n\t\t\tlet comment: string | undefined;\n\t\t\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\t\t\tlet finished = false;\n\t\t\tconst unanswered = () =>\n\t\t\t\trequest.questions\n\t\t\t\t\t.filter((q) => !answers[q.id]?.selected.length && !answers[q.id]?.text?.trim())\n\t\t\t\t\t.map((q) => q.id);\n\t\t\tconst finish = (status: QuestionResponse[\"status\"]) => {\n\t\t\t\tif (finished) return;\n\t\t\t\tfinished = true;\n\t\t\t\tclearTimeout(timer);\n\t\t\t\topts?.signal?.removeEventListener(\"abort\", cancel);\n\t\t\t\tthis.pending.delete(id);\n\t\t\t\tthis.resolved.add(id);\n\t\t\t\tconst result: QuestionResponse = {\n\t\t\t\t\tstatus,\n\t\t\t\t\tanswers,\n\t\t\t\t\tcomment,\n\t\t\t\t\tunanswered: unanswered(),\n\t\t\t\t\t...(status === \"timed_out\" ? { autoResolvedAfterMs: Date.now() - askedAtMs } : {}),\n\t\t\t\t};\n\t\t\t\tthis.output({\n\t\t\t\t\ttype: \"question_resolved\",\n\t\t\t\t\tid,\n\t\t\t\t\trequestId: frame.requestId,\n\t\t\t\t\ttoolCallId: frame.toolCallId,\n\t\t\t\t\toutcome: status,\n\t\t\t\t\tanswers,\n\t\t\t\t\tcomment,\n\t\t\t\t\tunanswered: result.unanswered,\n\t\t\t\t\tdeadlineAtMs: frame.deadlineAtMs,\n\t\t\t\t});\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\t// An aborted dialog is a cancellation unless the aborting side resolved a\n\t\t\t// terminal status of its own: the ask-user extension's idle timer settles\n\t\t\t// the question `timed_out` and aborts with that status, and connections\n\t\t\t// must see the outcome the extension resolved (docs/rpc.md question).\n\t\t\tconst cancel = () => {\n\t\t\t\tconst reason: unknown = opts?.signal?.reason;\n\t\t\t\tfinish(reason === \"timed_out\" ? \"timed_out\" : \"cancelled\");\n\t\t\t};\n\t\t\tconst arm = () => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tframe.deadlineAtMs = Date.now() + timeout;\n\t\t\t\ttimer = setTimeout(() => finish(\"timed_out\"), timeout);\n\t\t\t};\n\t\t\tthis.pending.set(id, {\n\t\t\t\tframe,\n\t\t\t\tcancel,\n\t\t\t\tprogress: (draft) => {\n\t\t\t\t\tif (draft.answers !== undefined) answers = draft.answers;\n\t\t\t\t\tif (draft.comment !== undefined) comment = draft.comment;\n\t\t\t\t\tarm();\n\t\t\t\t\topts?.onProgress?.({ answers, comment });\n\t\t\t\t\tif (!finished)\n\t\t\t\t\t\tthis.output({\n\t\t\t\t\t\t\ttype: \"question_updated\",\n\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\tdeadlineAtMs: frame.deadlineAtMs,\n\t\t\t\t\t\t\tremainingMs: Math.max(0, frame.deadlineAtMs - Date.now()),\n\t\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\trespond: (response) => {\n\t\t\t\t\tif (\"cancelled\" in response) {\n\t\t\t\t\t\tcancel();\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tif (!(\"answers\" in response)) return false;\n\t\t\t\t\tanswers = response.answers;\n\t\t\t\t\tcomment = response.comment;\n\t\t\t\t\tif (!comment?.trim() && Object.keys(answers).length === 0) return false;\n\t\t\t\t\tfinish(comment?.trim() ? \"comment-submitted\" : \"answered\");\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t});\n\t\t\tarm();\n\t\t\tthis.output(frame);\n\t\t\topts?.signal?.addEventListener(\"abort\", cancel, { once: true });\n\t\t\tif (opts?.signal?.aborted) cancel();\n\t\t});\n\t}\n\trespond(response: RpcExtensionUIResponse): boolean | \"question_incomplete\" | \"question_already_resolved\" {\n\t\tconst pending = this.pending.get(response.id);\n\t\tif (pending) return pending.respond(response) || \"question_incomplete\";\n\t\treturn this.resolved.has(response.id) ? \"question_already_resolved\" : false;\n\t}\n\tprogress(draft: RpcExtensionUIProgress): void {\n\t\tthis.pending.get(draft.id)?.progress(draft);\n\t}\n\tcancelAll(): void {\n\t\tfor (const pending of this.pending.values()) pending.cancel();\n\t}\n}\n\nexport async function degradeQuestion(\n\tui: Pick<ExtensionUIContext, \"select\" | \"input\">,\n\trequest: QuestionRequest,\n\topts?: Options,\n): Promise<QuestionResponse> {\n\tconst answers: QuestionResponse[\"answers\"] = {};\n\tconst other = \"Other (type an answer)\";\n\tfor (const question of request.questions) {\n\t\tconst selected = await ui.select(\n\t\t\tquestion.question,\n\t\t\t[...question.options.map((option) => option.label), other],\n\t\t\topts,\n\t\t);\n\t\tif (selected === other) {\n\t\t\tconst text = await ui.input(question.question, undefined, opts);\n\t\t\tif (text?.trim()) answers[question.id] = { selected: [], text };\n\t\t} else if (selected !== undefined) answers[question.id] = { selected: [selected] };\n\t}\n\tconst comment = await ui.input(\"Anything else? (optional)\", undefined, opts);\n\tconst unanswered = request.questions.filter((q) => !answers[q.id]).map((q) => q.id);\n\treturn {\n\t\tstatus: comment?.trim() ? \"comment-submitted\" : unanswered.length ? \"cancelled\" : \"answered\",\n\t\tanswers,\n\t\tcomment,\n\t\tunanswered,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"AAsBA,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAE7B,MAAM,qBAAqB,CAAC;AAU7B,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;AAExD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAChF,wFAAwF;QACxF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,2EAA2E;QAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACtC,oFAAoF;QACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD;;;;WAIG;QACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,4EAA4E;QAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;KAC7E,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AA4BD;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,qDAAwE,CAAC;AAErH,wBAAgB,qBAAqB,CAAC,QAAQ,SAAgB,GAAG,eAAe,CAS/E;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBjF;AAgaD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,GAAE,OAAqB,GAC7B;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf,CAWA"}
1
+ {"version":3,"file":"host-ensure.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"AAsBA,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,wBAAwB,EAE7B,MAAM,qBAAqB,CAAC;AAU7B,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,CAAC;AAExD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE;QAChB,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;QAChC,QAAQ,CAAC,KAAK,CAAC,EAAE;YAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAC;QAChF,wFAAwF;QACxF,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,2EAA2E;QAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACtC,oFAAoF;QACpF,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QACjD;;;;WAIG;QACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAClD,4EAA4E;QAC5E,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;KAC7E,CAAC;CACF;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AA4BD;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,qDAAwE,CAAC;AAErH,wBAAgB,qBAAqB,CAAC,QAAQ,SAAgB,GAAG,eAAe,CAS/E;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBjF;AAqbD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,QAAQ,GAAE,OAAqB,GAC7B;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CACf,CAWA"}
@@ -74,13 +74,13 @@ export async function ensureHost(options) {
74
74
  async function ensureHostLocked(paths, socket, agentDir, policy, testOptions) {
75
75
  const pidFile = await readPidFile(paths);
76
76
  const protocol = await probeProtocolInfo(socket, EXISTING_HOST_PROBE_TIMEOUT_MS);
77
- const probe = testOptions?.readProcessStartTime ?? readProcessStartTime;
78
- const pidMatches = pidFile ? await processMatchesPidFile(pidFile, probe) : false;
79
77
  if (isCompatible(protocol)) {
80
78
  // A compatible socket is attachable even when another client surface
81
79
  // started it. Only hosts we spawned are eligible for lifecycle management.
82
80
  return { pid: pidFile?.pid ?? 0, socket, reused: true };
83
81
  }
82
+ const probe = testOptions?.readProcessStartTime ?? readProcessStartTime;
83
+ const pidMatches = pidFile ? await matchesPidFileOrUnknown(pidFile, probe) : false;
84
84
  if (protocol && !pidMatches) {
85
85
  throw new Error(`RPC socket ${socket} is owned by an unmanaged host`);
86
86
  }
@@ -136,13 +136,16 @@ async function startHost(paths, socket, agentDir, policy, testOptions) {
136
136
  ]);
137
137
  // UNKNOWN identity on a live child: the probe was starved, not the host. Give the CIM table
138
138
  // one unhurried read (the per-attempt win32 default is 1s, which a loaded runner exceeds on
139
- // every attempt) before deciding. Without an identity the pidfile cannot carry an ownership
140
- // guard, so a healthy host must still be kept rather than torn down for an unreadable probe.
141
- const processStartTime = observedStartTime ?? (await readProcessStartTime(child.pid, process.platform, 15_000).catch(() => undefined));
142
- if (processStartTime === undefined) {
143
- throw new Error(`RPC socket host pid ${child.pid} started but its process identity stayed unreadable; refusing to register an unguarded pidfile`);
144
- }
145
- pidFile = { pid: child.pid, processStartTime };
139
+ // every attempt) before deciding.
140
+ const unhurriedProbe = testOptions?.readProcessStartTime
141
+ ? testOptions.readProcessStartTime
142
+ : (pid) => readProcessStartTime(pid, process.platform, 15_000);
143
+ const processStartTime = observedStartTime ?? (await unhurriedProbe(child.pid).catch(() => undefined));
144
+ // Still unreadable: the host is ours, alive, and about to prove itself on the socket, so it is
145
+ // registered WITHOUT an ownership guard instead of being torn down for a starved probe. A
146
+ // guard-less record never claims ownership and never authorizes a signal - every later caller
147
+ // reads it as unknown - so the worst case is a fresh host next time, not a killed healthy one.
148
+ pidFile = { pid: child.pid, processStartTime: processStartTime ?? null };
146
149
  await testOptions?.beforePidFileWrite?.();
147
150
  await writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\n`, { mode: 0o600 });
148
151
  child.unref();
@@ -205,6 +208,21 @@ async function startHost(paths, socket, agentDir, policy, testOptions) {
205
208
  // cannot prove this start owned.
206
209
  throw new Error(diagnostic);
207
210
  }
211
+ /**
212
+ * Ownership for the reuse decision. An identity we cannot read proves nothing: it can neither
213
+ * claim the host nor authorize a kill, so it reads as "not ours" and the caller starts fresh
214
+ * rather than failing the whole ensure on an observation gap.
215
+ */
216
+ async function matchesPidFileOrUnknown(pidFile, probe) {
217
+ try {
218
+ return await processMatchesPidFile(pidFile, probe);
219
+ }
220
+ catch (error) {
221
+ if (error instanceof ProcessIdentityUnreadableError)
222
+ return false;
223
+ throw error;
224
+ }
225
+ }
208
226
  async function stopSpawnedChild(child, childExit, termTimeoutMs) {
209
227
  const exited = () => child.exitCode !== null || child.signalCode !== null;
210
228
  if (exited())
@@ -317,8 +335,6 @@ async function probeProtocolInfo(socketPath, timeoutMs) {
317
335
  }
318
336
  return new Promise((resolveProbe) => {
319
337
  const socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));
320
- if (secret)
321
- sendSocketHandshake(socket, secret);
322
338
  let buffer = "";
323
339
  let settled = false;
324
340
  const finish = (value) => {
@@ -342,6 +358,12 @@ async function probeProtocolInfo(socketPath, timeoutMs) {
342
358
  });
343
359
  socket.once("error", () => finish());
344
360
  socket.once("close", () => finish());
361
+ // Register the error listener before sending the Windows named-pipe handshake.
362
+ // When an idle host has already removed its pipe, the handshake write can
363
+ // surface ENOENT immediately; without the listener this probe escapes instead
364
+ // of becoming the expected "no existing host" result for the next ensure.
365
+ if (secret)
366
+ sendSocketHandshake(socket, secret);
345
367
  });
346
368
  }
347
369
  function readProtocolInfo(text) {
@@ -1 +1 @@
1
- {"version":3,"file":"host-ensure.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, open, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { createConnection } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ENV_AGENT_DIR, getAgentDir, isBunBinary, VERSION } from \"../../config.ts\";\nimport {\n\ttype DaemonPidFile,\n\tProcessIdentityUnreadableError,\n\tparseDaemonPidFile,\n\tprocessIsLive,\n\tprocessMatchesPidFile,\n\treadProcessStartTime,\n\twaitForStartTime,\n} from \"../app-server/daemon/process.ts\";\nimport {\n\tCUSTOM_UNSUPPORTED_CAPABILITY,\n\tEXTENSION_EVENTS_CAPABILITY,\n\tRPC_CLIENT_CAPABILITIES_ENV,\n} from \"./custom-capability.ts\";\nimport {\n\tDEFAULT_HOST_IDLE_EXIT_MS,\n\ttype HostColdStart,\n\ttype HostLifecyclePolicyInput,\n\tINTERNAL_SUPERVISOR_FLAG,\n} from \"./host-lifecycle.ts\";\nimport { acquireOwnershipSafeLock } from \"./ownership-safe-lock.ts\";\nimport {\n\tcreateSocketSecret,\n\treadSocketSecret,\n\tresolveSocketTransportAddress,\n\tsendSocketHandshake,\n\tsocketSecretPath,\n} from \"./socket-transport.ts\";\n\nexport type { HostColdStart, HostLifecyclePolicyInput };\n\nexport interface HostDaemonPaths {\n\treadonly dir: string;\n\treadonly pidFile: string;\n\treadonly lockFile: string;\n\treadonly settingsFile: string;\n\treadonly stderrLog: string;\n}\n\nexport interface EnsureHostOptions {\n\treadonly socket: string;\n\treadonly agentDir?: string;\n\t/** Host lifecycle policy recorded in settings.json (env overrides win at runtime). */\n\treadonly policy?: HostLifecyclePolicyInput;\n\treadonly _test?: {\n\t\treadonly readinessTimeoutMs?: number;\n\t\treadonly stopTimeoutMs?: number;\n\t\treadonly spawn?: { readonly command: string; readonly args: readonly string[] };\n\t\t/** Extra env merged over process.env for the spawned host (hermetic test/QA wiring). */\n\t\treadonly env?: Readonly<Record<string, string>>;\n\t\t/** Extra CLI args forwarded through the supervisor to the host process. */\n\t\treadonly hostArgs?: readonly string[];\n\t\t/** Runs after endpoint ownership is locked; deterministic concurrency-test gate. */\n\t\treadonly afterLockAcquired?: () => Promise<void>;\n\t\t/**\n\t\t * Runs after the child is spawned but before its pidfile is registered, so a\n\t\t * test can force the startup failure a loaded runner produces without having\n\t\t * to stall the real process-identity probe.\n\t\t */\n\t\treadonly beforePidFileWrite?: () => Promise<void>;\n\t\t/** Overrides the process-identity probe so a test can force its failure. */\n\t\treadonly readProcessStartTime?: (pid: number) => Promise<string | undefined>;\n\t};\n}\n\nexport interface EnsuredHost {\n\treadonly pid: number;\n\treadonly socket: string;\n\treadonly reused: boolean;\n}\n\ntype ProtocolInfo = {\n\treadonly serverVersion: string;\n\treadonly capabilities: readonly string[];\n};\n\nconst REQUIRED_CAPABILITIES = [\"multi_session\", EXTENSION_EVENTS_CAPABILITY] as const;\nconst SPAWNED_HOST_PROBE_TIMEOUT_MS = 10_000;\nconst EXISTING_HOST_PROBE_TIMEOUT_MS = 10_000;\nconst DEFAULT_READINESS_TIMEOUT_MS = 10_000;\nconst DEFAULT_STOP_TIMEOUT_MS = 10_000;\nconst SIGKILL_GRACE_MS = 2_000;\n/**\n * A lock waiter must outlast the longest critical section a holder can run:\n * probing an existing host, stopping an incompatible one (SIGTERM wait plus the\n * SIGKILL grace), then spawning the replacement and waiting for it to answer.\n * Each SQLite busy wait stays short because it blocks the event loop; this\n * cumulative budget is what covers the whole section, with headroom for a slow\n * runner. A waiter that gives up early surfaces as a raw \"database is locked\"\n * failure on the second of two concurrent starts.\n */\nconst ENSURE_LOCK_WAIT_MS =\n\tEXISTING_HOST_PROBE_TIMEOUT_MS + DEFAULT_STOP_TIMEOUT_MS + SIGKILL_GRACE_MS + DEFAULT_READINESS_TIMEOUT_MS + 10_000;\nconst LOCK_BUSY_WAIT_MS = 100;\nconst lockOptions = {\n\tretries: { retries: ENSURE_LOCK_WAIT_MS / LOCK_BUSY_WAIT_MS, minTimeout: 20, maxTimeout: LOCK_BUSY_WAIT_MS },\n} as const;\n/**\n * Every ensured host starts with this installation-wide profile, independent of\n * the first caller. In particular, extension_events must remain available when\n * a terminal client starts the shared host before the desktop connects.\n */\nexport const PINNED_HOST_CLIENT_CAPABILITIES = [EXTENSION_EVENTS_CAPABILITY, CUSTOM_UNSUPPORTED_CAPABILITY] as const;\n\nexport function createHostDaemonPaths(agentDir = getAgentDir()): HostDaemonPaths {\n\tconst dir = join(agentDir, \"rpc-host-daemon\");\n\treturn {\n\t\tdir,\n\t\tpidFile: join(dir, \"host.pid\"),\n\t\tlockFile: join(dir, \"daemon.lock\"),\n\t\tsettingsFile: join(dir, \"settings.json\"),\n\t\tstderrLog: join(dir, \"stderr.log\"),\n\t};\n}\n\nexport async function ensureHost(options: EnsureHostOptions): Promise<EnsuredHost> {\n\tconst socket = normalizeSocketPath(options.socket);\n\tconst paths = createHostDaemonPaths(options.agentDir);\n\tawait mkdir(paths.dir, { recursive: true });\n\t// The public socket is the shared resource; agent directories are not a\n\t// sufficient lock scope when two installations target the same endpoint.\n\tconst lockTarget = join(tmpdir(), \"senpi-rpc-host-locks\", createSocketLockName(socket));\n\tawait mkdir(dirname(lockTarget), { recursive: true });\n\tawait writeFile(lockTarget, \"\", { flag: \"a\", mode: 0o600 });\n\t// Opportunistic GC of other installs' leftovers stays OUTSIDE the endpoint lock.\n\t// Its cost scales with the whole tmpdir and, on win32, adds a ~1s process probe per\n\t// candidate; inside the critical section that inflated the hold for every concurrent\n\t// ensureHost until a waiter exhausted its budget and surfaced a raw \"database is\n\t// locked\". Its own guards (60s age, dead owner pid) already make it safe unlocked.\n\tawait reapOrphanedInternalHostDirs();\n\tconst release = await acquireOwnershipSafeLock(`${lockTarget}.lock`, lockOptions);\n\ttry {\n\t\tawait options._test?.afterLockAcquired?.();\n\t\treturn await ensureHostLocked(paths, socket, options.agentDir ?? getAgentDir(), options.policy, options._test);\n\t} finally {\n\t\tawait release();\n\t}\n}\n\nasync function ensureHostLocked(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\tconst pidFile = await readPidFile(paths);\n\tconst protocol = await probeProtocolInfo(socket, EXISTING_HOST_PROBE_TIMEOUT_MS);\n\tconst probe = testOptions?.readProcessStartTime ?? readProcessStartTime;\n\tconst pidMatches = pidFile ? await processMatchesPidFile(pidFile, probe) : false;\n\tif (isCompatible(protocol)) {\n\t\t// A compatible socket is attachable even when another client surface\n\t\t// started it. Only hosts we spawned are eligible for lifecycle management.\n\t\treturn { pid: pidFile?.pid ?? 0, socket, reused: true };\n\t}\n\tif (protocol && !pidMatches) {\n\t\tthrow new Error(`RPC socket ${socket} is owned by an unmanaged host`);\n\t}\n\tif (pidFile && pidMatches) {\n\t\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, probe);\n\t}\n\tawait cleanupState(paths);\n\treturn startHost(paths, socket, agentDir, policy, testOptions);\n}\n\nasync function startHost(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\t// The settings file must exist before the supervisor reads it at boot, so it\n\t// records the policy before the spawn instead of beside the pidfile.\n\tif (process.platform === \"win32\") await createSocketSecret(socketSecretPath(socket));\n\tawait writeFile(\n\t\tpaths.settingsFile,\n\t\t`${JSON.stringify({\n\t\t\tsocket,\n\t\t\tcapabilities: PINNED_HOST_CLIENT_CAPABILITIES,\n\t\t\tcoldStart: policy?.coldStart ?? \"transient\",\n\t\t\tidleExitMs: policy?.idleExitMs ?? DEFAULT_HOST_IDLE_EXIT_MS,\n\t\t})}\\n`,\n\t\t{ mode: 0o600 },\n\t);\n\tconst stderr = await open(paths.stderrLog, \"w\", 0o600);\n\tlet pidFile: DaemonPidFile | undefined;\n\tlet child: ReturnType<typeof spawn> | undefined;\n\tlet exitedEarly: ChildExit | undefined;\n\tlet childExit: Promise<ChildExit> | undefined;\n\ttry {\n\t\tconst launch = testOptions?.spawn ?? defaultHostLaunch(socket, testOptions?.hostArgs ?? []);\n\t\tchild = spawn(launch.command, [...launch.args], {\n\t\t\tdetached: true,\n\t\t\twindowsHide: true,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...(testOptions?.env ?? {}),\n\t\t\t\t[ENV_AGENT_DIR]: agentDir,\n\t\t\t\t[RPC_CLIENT_CAPABILITIES_ENV]: PINNED_HOST_CLIENT_CAPABILITIES.join(\",\"),\n\t\t\t},\n\t\t\tstdio: [\"ignore\", \"ignore\", stderr.fd],\n\t\t});\n\t\tchildExit = new Promise((resolveExit) => {\n\t\t\tchild!.once(\"exit\", (code, signal) => {\n\t\t\t\texitedEarly = { code, signal };\n\t\t\t\tresolveExit(exitedEarly);\n\t\t\t});\n\t\t});\n\t\tif (child.pid === undefined) throw new Error(\"failed to spawn RPC socket host\");\n\t\tconst probe = testOptions?.readProcessStartTime ?? readProcessStartTime;\n\t\tconst observedStartTime = await Promise.race([\n\t\t\twaitForStartTime(child.pid, 10_000, probe),\n\t\t\tchildExit.then(() => {\n\t\t\t\tthrow new Error(\"RPC socket host exited before its start time could be read\");\n\t\t\t}),\n\t\t]);\n\t\t// UNKNOWN identity on a live child: the probe was starved, not the host. Give the CIM table\n\t\t// one unhurried read (the per-attempt win32 default is 1s, which a loaded runner exceeds on\n\t\t// every attempt) before deciding. Without an identity the pidfile cannot carry an ownership\n\t\t// guard, so a healthy host must still be kept rather than torn down for an unreadable probe.\n\t\tconst processStartTime =\n\t\t\tobservedStartTime ?? (await readProcessStartTime(child.pid, process.platform, 15_000).catch(() => undefined));\n\t\tif (processStartTime === undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`RPC socket host pid ${child.pid} started but its process identity stayed unreadable; refusing to register an unguarded pidfile`,\n\t\t\t);\n\t\t}\n\t\tpidFile = { pid: child.pid, processStartTime };\n\t\tawait testOptions?.beforePidFileWrite?.();\n\t\tawait writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\\n`, { mode: 0o600 });\n\t\tchild.unref();\n\t} catch (error: unknown) {\n\t\t// Whether the child died on its own decides which diagnostic is true, and the\n\t\t// cleanup kill below records an `exitedEarly` indistinguishable from a real\n\t\t// self-exit. Latch it before killing, or the catch reports the SIGTERM it is\n\t\t// about to send and discards the actual startup failure.\n\t\tconst exitedBeforeCleanup = exitedEarly;\n\t\t// Keep the ChildProcess handle owned until registration succeeds. If startup\n\t\t// fails before the pidfile is written, terminate this exact child through\n\t\t// its still-attached handle rather than leaving an unmanaged daemon behind.\n\t\tif (!exitedBeforeCleanup && child && child.exitCode === null && child.signalCode === null) {\n\t\t\ttry {\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t} catch {}\n\t\t\tif (childExit) await Promise.race([childExit, delay(2_000)]);\n\t\t\tif (child.exitCode === null && child.signalCode === null) {\n\t\t\t\ttry {\n\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\t\tif (!exitedBeforeCleanup) {\n\t\t\tawait cleanupState(paths);\n\t\t\tthrow error;\n\t\t}\n\t\tconst diagnostic = await appendStderr(\n\t\t\tpaths,\n\t\t\t`RPC socket host exited with code ${exitedBeforeCleanup.code ?? \"null\"}${exitedBeforeCleanup.signal ? ` (${exitedBeforeCleanup.signal})` : \"\"} before answering get_protocol_info`,\n\t\t);\n\t\tawait cleanupState(paths);\n\t\tthrow new Error(diagnostic);\n\t} finally {\n\t\tawait stderr.close();\n\t}\n\tconst readinessTimeoutMs = testOptions?.readinessTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS;\n\tconst result = await pollProtocolInfo(socket, readinessTimeoutMs, childExit);\n\tif (isCompatible(result.protocol)) return { pid: pidFile.pid, socket, reused: false };\n\t// Teardown runs for the diagnostic's sake, so it must never replace it: a stop\n\t// failure here (unreadable identity, a host that outlives SIGKILL) would other-\n\t// wise propagate instead of the readiness message and skip cleanupState below,\n\t// leaving the pidfile and socket behind. Record it and keep going.\n\t// This child is ours and its handle is still attached: stop it through the handle.\n\t// Validating ownership through the pidfile would re-run the identity probe whose\n\t// failure is the very thing a loaded runner produces here.\n\tconst stopFailure = await stopSpawnedChild(\n\t\tchild,\n\t\tchildExit,\n\t\ttestOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS,\n\t).then(\n\t\t() => undefined,\n\t\t(error: unknown) => (error instanceof Error ? error.message : String(error)),\n\t);\n\tconst message = result.protocol\n\t\t? `RPC socket host answered get_protocol_info with serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with serverVersion ${VERSION} and required capabilities ${JSON.stringify(REQUIRED_CAPABILITIES)}`\n\t\t: result.exited\n\t\t\t? `RPC socket host exited with code ${result.exited.code ?? \"null\"}${result.exited.signal ? ` (${result.exited.signal})` : \"\"} before answering get_protocol_info`\n\t\t\t: `spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`;\n\tconst diagnostic = await appendStderr(\n\t\tpaths,\n\t\tstopFailure === undefined ? message : `${message} (teardown also reported: ${stopFailure})`,\n\t);\n\tawait cleanupState(paths);\n\t// The supervisor may have failed before binding, or another owner may have\n\t// appeared while readiness was being checked. Never unlink an endpoint we\n\t// cannot prove this start owned.\n\tthrow new Error(diagnostic);\n}\n\nasync function stopSpawnedChild(\n\tchild: ChildProcess,\n\tchildExit: Promise<ChildExit>,\n\ttermTimeoutMs: number,\n): Promise<void> {\n\tconst exited = () => child.exitCode !== null || child.signalCode !== null;\n\tif (exited()) return;\n\tconst signal = (name: NodeJS.Signals) => {\n\t\ttry {\n\t\t\tchild.kill(name);\n\t\t} catch (error: unknown) {\n\t\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t\t}\n\t};\n\tconst waitFor = (ms: number) => Promise.race([childExit.then(() => true), delay(ms).then(() => exited())]);\n\tsignal(\"SIGTERM\");\n\tif (await waitFor(termTimeoutMs)) return;\n\tsignal(\"SIGKILL\");\n\tif (!(await waitFor(SIGKILL_GRACE_MS))) {\n\t\tthrow new Error(`RPC socket host pid ${child.pid ?? \"?\"} remained alive after SIGKILL`);\n\t}\n}\n\nasync function stopManagedHost(\n\tpidFile: DaemonPidFile,\n\ttermTimeoutMs: number,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<void> {\n\tawait signalValidated(pidFile, \"SIGTERM\", readStartTime);\n\tif (await waitForGone(pidFile, termTimeoutMs, readStartTime)) return;\n\tawait signalValidated(pidFile, \"SIGKILL\", readStartTime);\n\tif (!(await waitForGone(pidFile, SIGKILL_GRACE_MS, readStartTime))) {\n\t\tthrow new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);\n\t}\n}\n\ntype PidFileOwnership = \"owns\" | \"gone\" | \"unknown\";\n\n// One probe per call: the teardown loops below are themselves the retry, so the\n// budget inside processMatchesPidFile would only multiply their wall time. A probe\n// that fails against a LIVE pid is \"unknown\" — it proves nothing about ownership, so\n// signalling on it would be unsafe and treating it as \"gone\" would abandon a host that\n// may still be running. A failed probe against a dead pid is \"gone\".\nasync function resolvePidFileOwnership(\n\tpidFile: DaemonPidFile,\n\treadStartTime: (pid: number) => Promise<string | undefined>,\n): Promise<PidFileOwnership> {\n\ttry {\n\t\treturn (await processMatchesPidFile(pidFile, readStartTime, processIsLive, { attempts: 1 })) ? \"owns\" : \"gone\";\n\t} catch (error: unknown) {\n\t\tif (error instanceof ProcessIdentityUnreadableError) return \"unknown\";\n\t\tthrow error;\n\t}\n}\n\nasync function signalValidated(\n\tpidFile: DaemonPidFile,\n\tsignal: NodeJS.Signals,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<void> {\n\tif ((await resolvePidFileOwnership(pidFile, readStartTime)) !== \"owns\") return;\n\ttry {\n\t\tprocess.kill(pidFile.pid, signal);\n\t} catch (error: unknown) {\n\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t}\n}\n\nasync function waitForGone(\n\tpidFile: DaemonPidFile,\n\ttimeoutMs: number,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<boolean> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif ((await resolvePidFileOwnership(pidFile, readStartTime)) === \"gone\") return true;\n\t\tawait delay(50);\n\t}\n\treturn (await resolvePidFileOwnership(pidFile, readStartTime)) === \"gone\";\n}\n\ntype ChildExit = { readonly code: number | null; readonly signal: NodeJS.Signals | null };\n\ntype ProtocolPollResult = { readonly protocol?: ProtocolInfo; readonly exited?: ChildExit };\n\nasync function pollProtocolInfo(\n\tsocket: string,\n\ttimeoutMs: number,\n\tchildExit?: Promise<ChildExit>,\n): Promise<ProtocolPollResult> {\n\tconst deadline = Date.now() + timeoutMs;\n\tlet lastProtocol: ProtocolInfo | undefined;\n\twhile (Date.now() <= deadline) {\n\t\tconst probe = probeProtocolInfo(\n\t\t\tsocket,\n\t\t\tMath.min(SPAWNED_HOST_PROBE_TIMEOUT_MS, Math.max(1, deadline - Date.now())),\n\t\t);\n\t\tconst raced = childExit ? await Promise.race([probe, childExit]) : await probe;\n\t\tif (isChildExit(raced)) {\n\t\t\t// A supervisor exit can be triggered by the Windows identity watchdog\n\t\t\t// while a named-pipe client is still composing its protocol reply. Do\n\t\t\t// not terminate the host based solely on that exit until this probe has\n\t\t\t// had a chance to deliver an answer. A host that never answers still\n\t\t\t// resolves through probeProtocolInfo's bounded timeout/close handling.\n\t\t\tconst info = await probe;\n\t\t\tif (info) {\n\t\t\t\tlastProtocol = info;\n\t\t\t\tif (isCompatible(info)) return { protocol: info };\n\t\t\t} else {\n\t\t\t\treturn { protocol: lastProtocol, exited: raced };\n\t\t\t}\n\t\t} else if (raced) {\n\t\t\tlastProtocol = raced;\n\t\t\tif (isCompatible(raced)) return { protocol: raced };\n\t\t}\n\t\tawait delay(50);\n\t}\n\treturn { protocol: lastProtocol };\n}\n\nfunction isChildExit(value: ProtocolInfo | ChildExit | undefined): value is ChildExit {\n\treturn !!value && \"code\" in value && \"signal\" in value;\n}\n\nasync function probeProtocolInfo(socketPath: string, timeoutMs: number): Promise<ProtocolInfo | undefined> {\n\tlet secret: Buffer | undefined;\n\tif (process.platform === \"win32\") {\n\t\ttry {\n\t\t\tsecret = await readSocketSecret(socketSecretPath(socketPath));\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn new Promise((resolveProbe) => {\n\t\tconst socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));\n\t\tif (secret) sendSocketHandshake(socket, secret);\n\t\tlet buffer = \"\";\n\t\tlet settled = false;\n\t\tconst finish = (value?: ProtocolInfo): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tsocket.destroy();\n\t\t\tresolveProbe(value);\n\t\t};\n\t\tconst timeout = setTimeout(() => finish(), timeoutMs);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.write('{\"id\":\"ensure-host-probe\",\"type\":\"get_protocol_info\"}\\n');\n\t\t});\n\t\tsocket.on(\"data\", (chunk) => {\n\t\t\tbuffer += chunk.toString(\"utf8\");\n\t\t\tconst newline = buffer.indexOf(\"\\n\");\n\t\t\tif (newline === -1) return;\n\t\t\tfinish(readProtocolInfo(buffer.slice(0, newline)));\n\t\t});\n\t\tsocket.once(\"error\", () => finish());\n\t\tsocket.once(\"close\", () => finish());\n\t});\n}\n\nfunction readProtocolInfo(text: string): ProtocolInfo | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || parsed.id !== \"ensure-host-probe\" || parsed.success !== true || !isRecord(parsed.data)) {\n\t\treturn undefined;\n\t}\n\tconst { serverVersion, capabilities } = parsed.data;\n\tif (typeof serverVersion !== \"string\" || !Array.isArray(capabilities)) return undefined;\n\tif (!capabilities.every((capability) => typeof capability === \"string\")) return undefined;\n\treturn { serverVersion, capabilities };\n}\n\nfunction isCompatible(protocol: ProtocolInfo | undefined): boolean {\n\treturn (\n\t\tprotocol?.serverVersion === VERSION &&\n\t\tREQUIRED_CAPABILITIES.every((capability) => protocol.capabilities.includes(capability))\n\t);\n}\n\nasync function readPidFile(paths: HostDaemonPaths): Promise<DaemonPidFile | undefined> {\n\ttry {\n\t\treturn parseDaemonPidFile(await readFile(paths.pidFile, \"utf8\"));\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function reapOrphanedInternalHostDirs(): Promise<void> {\n\ttry {\n\t\tconst entries = await readdir(tmpdir(), { withFileTypes: true });\n\t\tawait Promise.all(\n\t\t\tentries\n\t\t\t\t.filter((entry) => entry.isDirectory() && entry.name.startsWith(\"senpi-rpc-host-internal-\"))\n\t\t\t\t.map(async (entry) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst owner = JSON.parse(await readFile(join(tmpdir(), entry.name, \".owner\"), \"utf8\")) as {\n\t\t\t\t\t\t\tpid?: unknown;\n\t\t\t\t\t\t\tprocessStartTime?: unknown;\n\t\t\t\t\t\t\tcreatedAt?: unknown;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof owner.pid === \"number\" &&\n\t\t\t\t\t\t\ttypeof owner.processStartTime === \"string\" &&\n\t\t\t\t\t\t\ttypeof owner.createdAt === \"number\" &&\n\t\t\t\t\t\t\towner.processStartTime.length > 0 &&\n\t\t\t\t\t\t\towner.createdAt < Date.now() - 60_000 &&\n\t\t\t\t\t\t\t(await readdir(join(tmpdir(), entry.name))).length === 1 &&\n\t\t\t\t\t\t\t!(await processMatchesPidFile({ pid: owner.pid, processStartTime: owner.processStartTime }).catch(\n\t\t\t\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\t\t\t\t// Unreadable but live: assume the owner is alive rather than steal its lock.\n\t\t\t\t\t\t\t\t\tif (error instanceof ProcessIdentityUnreadableError) return true;\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tawait rm(join(tmpdir(), entry.name), { recursive: true, force: true });\n\t\t\t\t\t} catch {}\n\t\t\t\t}),\n\t\t);\n\t} catch {}\n}\n\nasync function cleanupState(paths: HostDaemonPaths): Promise<void> {\n\tawait rm(paths.pidFile, { force: true });\n\tawait rm(paths.settingsFile, { force: true });\n}\n\nasync function appendStderr(paths: HostDaemonPaths, message: string): Promise<string> {\n\ttry {\n\t\tconst stderr = (await readFile(paths.stderrLog, \"utf8\")).trim();\n\t\treturn stderr ? `${message}\\n${stderr}` : message;\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return message;\n\t\tthrow error;\n\t}\n}\n\nfunction createSocketLockName(socket: string): string {\n\treturn createHash(\"sha256\")\n\t\t.update(resolveSocketTransportAddress(socket, process.platform), \"utf8\")\n\t\t.digest(\"hex\")\n\t\t.slice(0, 32);\n}\n\nfunction normalizeSocketPath(value: string): string {\n\tif (value.startsWith(\"unix://\")) return value.slice(\"unix://\".length);\n\treturn value;\n}\n\n/**\n * Default launch: the host-lifecycle supervisor owns the public socket and the\n * idle-exit policy; it spawns the committed RPC socket host itself. Any extra\n * hostArgs are forwarded verbatim to the host CLI (e.g. provider pinning).\n *\n * A compiled standalone binary cannot re-enter itself through a script path:\n * bun executables always boot their embedded entrypoint and parse the whole\n * argv as CLI arguments, so `host-lifecycle.ts --socket <path>` dies with\n * \"Unknown option: --socket\" before the host ever answers get_protocol_info.\n * Compiled binaries therefore re-enter through the hidden\n * `--internal-rpc-host-supervisor` route that main() dispatches before\n * argument parsing. Exported for tests.\n */\nexport function defaultHostLaunch(\n\tsocket: string,\n\thostArgs: readonly string[],\n\tcompiled: boolean = isBunBinary,\n): {\n\tcommand: string;\n\targs: string[];\n} {\n\tif (compiled) {\n\t\treturn {\n\t\t\tcommand: process.execPath,\n\t\t\targs: [INTERNAL_SUPERVISOR_FLAG, \"--socket\", socket, ...hostArgs],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [...process.execArgv, resolveHostLifecycleEntryPath(), \"--socket\", socket, ...hostArgs],\n\t};\n}\n\nfunction resolveHostLifecycleEntryPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), `host-lifecycle${extension}`);\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNodeErrorCode(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
1
+ {"version":3,"file":"host-ensure.js","sourceRoot":"","sources":["../../../src/modes/rpc/host-ensure.ts"],"names":[],"mappings":"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","sourcesContent":["import { type ChildProcess, spawn } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, open, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\nimport { createConnection } from \"node:net\";\nimport { tmpdir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { ENV_AGENT_DIR, getAgentDir, isBunBinary, VERSION } from \"../../config.ts\";\nimport {\n\ttype DaemonPidFile,\n\tProcessIdentityUnreadableError,\n\tparseDaemonPidFile,\n\tprocessIsLive,\n\tprocessMatchesPidFile,\n\treadProcessStartTime,\n\twaitForStartTime,\n} from \"../app-server/daemon/process.ts\";\nimport {\n\tCUSTOM_UNSUPPORTED_CAPABILITY,\n\tEXTENSION_EVENTS_CAPABILITY,\n\tRPC_CLIENT_CAPABILITIES_ENV,\n} from \"./custom-capability.ts\";\nimport {\n\tDEFAULT_HOST_IDLE_EXIT_MS,\n\ttype HostColdStart,\n\ttype HostLifecyclePolicyInput,\n\tINTERNAL_SUPERVISOR_FLAG,\n} from \"./host-lifecycle.ts\";\nimport { acquireOwnershipSafeLock } from \"./ownership-safe-lock.ts\";\nimport {\n\tcreateSocketSecret,\n\treadSocketSecret,\n\tresolveSocketTransportAddress,\n\tsendSocketHandshake,\n\tsocketSecretPath,\n} from \"./socket-transport.ts\";\n\nexport type { HostColdStart, HostLifecyclePolicyInput };\n\nexport interface HostDaemonPaths {\n\treadonly dir: string;\n\treadonly pidFile: string;\n\treadonly lockFile: string;\n\treadonly settingsFile: string;\n\treadonly stderrLog: string;\n}\n\nexport interface EnsureHostOptions {\n\treadonly socket: string;\n\treadonly agentDir?: string;\n\t/** Host lifecycle policy recorded in settings.json (env overrides win at runtime). */\n\treadonly policy?: HostLifecyclePolicyInput;\n\treadonly _test?: {\n\t\treadonly readinessTimeoutMs?: number;\n\t\treadonly stopTimeoutMs?: number;\n\t\treadonly spawn?: { readonly command: string; readonly args: readonly string[] };\n\t\t/** Extra env merged over process.env for the spawned host (hermetic test/QA wiring). */\n\t\treadonly env?: Readonly<Record<string, string>>;\n\t\t/** Extra CLI args forwarded through the supervisor to the host process. */\n\t\treadonly hostArgs?: readonly string[];\n\t\t/** Runs after endpoint ownership is locked; deterministic concurrency-test gate. */\n\t\treadonly afterLockAcquired?: () => Promise<void>;\n\t\t/**\n\t\t * Runs after the child is spawned but before its pidfile is registered, so a\n\t\t * test can force the startup failure a loaded runner produces without having\n\t\t * to stall the real process-identity probe.\n\t\t */\n\t\treadonly beforePidFileWrite?: () => Promise<void>;\n\t\t/** Overrides the process-identity probe so a test can force its failure. */\n\t\treadonly readProcessStartTime?: (pid: number) => Promise<string | undefined>;\n\t};\n}\n\nexport interface EnsuredHost {\n\treadonly pid: number;\n\treadonly socket: string;\n\treadonly reused: boolean;\n}\n\ntype ProtocolInfo = {\n\treadonly serverVersion: string;\n\treadonly capabilities: readonly string[];\n};\n\nconst REQUIRED_CAPABILITIES = [\"multi_session\", EXTENSION_EVENTS_CAPABILITY] as const;\nconst SPAWNED_HOST_PROBE_TIMEOUT_MS = 10_000;\nconst EXISTING_HOST_PROBE_TIMEOUT_MS = 10_000;\nconst DEFAULT_READINESS_TIMEOUT_MS = 10_000;\nconst DEFAULT_STOP_TIMEOUT_MS = 10_000;\nconst SIGKILL_GRACE_MS = 2_000;\n/**\n * A lock waiter must outlast the longest critical section a holder can run:\n * probing an existing host, stopping an incompatible one (SIGTERM wait plus the\n * SIGKILL grace), then spawning the replacement and waiting for it to answer.\n * Each SQLite busy wait stays short because it blocks the event loop; this\n * cumulative budget is what covers the whole section, with headroom for a slow\n * runner. A waiter that gives up early surfaces as a raw \"database is locked\"\n * failure on the second of two concurrent starts.\n */\nconst ENSURE_LOCK_WAIT_MS =\n\tEXISTING_HOST_PROBE_TIMEOUT_MS + DEFAULT_STOP_TIMEOUT_MS + SIGKILL_GRACE_MS + DEFAULT_READINESS_TIMEOUT_MS + 10_000;\nconst LOCK_BUSY_WAIT_MS = 100;\nconst lockOptions = {\n\tretries: { retries: ENSURE_LOCK_WAIT_MS / LOCK_BUSY_WAIT_MS, minTimeout: 20, maxTimeout: LOCK_BUSY_WAIT_MS },\n} as const;\n/**\n * Every ensured host starts with this installation-wide profile, independent of\n * the first caller. In particular, extension_events must remain available when\n * a terminal client starts the shared host before the desktop connects.\n */\nexport const PINNED_HOST_CLIENT_CAPABILITIES = [EXTENSION_EVENTS_CAPABILITY, CUSTOM_UNSUPPORTED_CAPABILITY] as const;\n\nexport function createHostDaemonPaths(agentDir = getAgentDir()): HostDaemonPaths {\n\tconst dir = join(agentDir, \"rpc-host-daemon\");\n\treturn {\n\t\tdir,\n\t\tpidFile: join(dir, \"host.pid\"),\n\t\tlockFile: join(dir, \"daemon.lock\"),\n\t\tsettingsFile: join(dir, \"settings.json\"),\n\t\tstderrLog: join(dir, \"stderr.log\"),\n\t};\n}\n\nexport async function ensureHost(options: EnsureHostOptions): Promise<EnsuredHost> {\n\tconst socket = normalizeSocketPath(options.socket);\n\tconst paths = createHostDaemonPaths(options.agentDir);\n\tawait mkdir(paths.dir, { recursive: true });\n\t// The public socket is the shared resource; agent directories are not a\n\t// sufficient lock scope when two installations target the same endpoint.\n\tconst lockTarget = join(tmpdir(), \"senpi-rpc-host-locks\", createSocketLockName(socket));\n\tawait mkdir(dirname(lockTarget), { recursive: true });\n\tawait writeFile(lockTarget, \"\", { flag: \"a\", mode: 0o600 });\n\t// Opportunistic GC of other installs' leftovers stays OUTSIDE the endpoint lock.\n\t// Its cost scales with the whole tmpdir and, on win32, adds a ~1s process probe per\n\t// candidate; inside the critical section that inflated the hold for every concurrent\n\t// ensureHost until a waiter exhausted its budget and surfaced a raw \"database is\n\t// locked\". Its own guards (60s age, dead owner pid) already make it safe unlocked.\n\tawait reapOrphanedInternalHostDirs();\n\tconst release = await acquireOwnershipSafeLock(`${lockTarget}.lock`, lockOptions);\n\ttry {\n\t\tawait options._test?.afterLockAcquired?.();\n\t\treturn await ensureHostLocked(paths, socket, options.agentDir ?? getAgentDir(), options.policy, options._test);\n\t} finally {\n\t\tawait release();\n\t}\n}\n\nasync function ensureHostLocked(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\tconst pidFile = await readPidFile(paths);\n\tconst protocol = await probeProtocolInfo(socket, EXISTING_HOST_PROBE_TIMEOUT_MS);\n\tif (isCompatible(protocol)) {\n\t\t// A compatible socket is attachable even when another client surface\n\t\t// started it. Only hosts we spawned are eligible for lifecycle management.\n\t\treturn { pid: pidFile?.pid ?? 0, socket, reused: true };\n\t}\n\tconst probe = testOptions?.readProcessStartTime ?? readProcessStartTime;\n\tconst pidMatches = pidFile ? await matchesPidFileOrUnknown(pidFile, probe) : false;\n\tif (protocol && !pidMatches) {\n\t\tthrow new Error(`RPC socket ${socket} is owned by an unmanaged host`);\n\t}\n\tif (pidFile && pidMatches) {\n\t\tawait stopManagedHost(pidFile, testOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS, probe);\n\t}\n\tawait cleanupState(paths);\n\treturn startHost(paths, socket, agentDir, policy, testOptions);\n}\n\nasync function startHost(\n\tpaths: HostDaemonPaths,\n\tsocket: string,\n\tagentDir: string,\n\tpolicy: HostLifecyclePolicyInput | undefined,\n\ttestOptions: EnsureHostOptions[\"_test\"],\n): Promise<EnsuredHost> {\n\t// The settings file must exist before the supervisor reads it at boot, so it\n\t// records the policy before the spawn instead of beside the pidfile.\n\tif (process.platform === \"win32\") await createSocketSecret(socketSecretPath(socket));\n\tawait writeFile(\n\t\tpaths.settingsFile,\n\t\t`${JSON.stringify({\n\t\t\tsocket,\n\t\t\tcapabilities: PINNED_HOST_CLIENT_CAPABILITIES,\n\t\t\tcoldStart: policy?.coldStart ?? \"transient\",\n\t\t\tidleExitMs: policy?.idleExitMs ?? DEFAULT_HOST_IDLE_EXIT_MS,\n\t\t})}\\n`,\n\t\t{ mode: 0o600 },\n\t);\n\tconst stderr = await open(paths.stderrLog, \"w\", 0o600);\n\tlet pidFile: DaemonPidFile | undefined;\n\tlet child: ReturnType<typeof spawn> | undefined;\n\tlet exitedEarly: ChildExit | undefined;\n\tlet childExit: Promise<ChildExit> | undefined;\n\ttry {\n\t\tconst launch = testOptions?.spawn ?? defaultHostLaunch(socket, testOptions?.hostArgs ?? []);\n\t\tchild = spawn(launch.command, [...launch.args], {\n\t\t\tdetached: true,\n\t\t\twindowsHide: true,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\t...(testOptions?.env ?? {}),\n\t\t\t\t[ENV_AGENT_DIR]: agentDir,\n\t\t\t\t[RPC_CLIENT_CAPABILITIES_ENV]: PINNED_HOST_CLIENT_CAPABILITIES.join(\",\"),\n\t\t\t},\n\t\t\tstdio: [\"ignore\", \"ignore\", stderr.fd],\n\t\t});\n\t\tchildExit = new Promise((resolveExit) => {\n\t\t\tchild!.once(\"exit\", (code, signal) => {\n\t\t\t\texitedEarly = { code, signal };\n\t\t\t\tresolveExit(exitedEarly);\n\t\t\t});\n\t\t});\n\t\tif (child.pid === undefined) throw new Error(\"failed to spawn RPC socket host\");\n\t\tconst probe = testOptions?.readProcessStartTime ?? readProcessStartTime;\n\t\tconst observedStartTime = await Promise.race([\n\t\t\twaitForStartTime(child.pid, 10_000, probe),\n\t\t\tchildExit.then(() => {\n\t\t\t\tthrow new Error(\"RPC socket host exited before its start time could be read\");\n\t\t\t}),\n\t\t]);\n\t\t// UNKNOWN identity on a live child: the probe was starved, not the host. Give the CIM table\n\t\t// one unhurried read (the per-attempt win32 default is 1s, which a loaded runner exceeds on\n\t\t// every attempt) before deciding.\n\t\tconst unhurriedProbe = testOptions?.readProcessStartTime\n\t\t\t? testOptions.readProcessStartTime\n\t\t\t: (pid: number) => readProcessStartTime(pid, process.platform, 15_000);\n\t\tconst processStartTime = observedStartTime ?? (await unhurriedProbe(child.pid).catch(() => undefined));\n\t\t// Still unreadable: the host is ours, alive, and about to prove itself on the socket, so it is\n\t\t// registered WITHOUT an ownership guard instead of being torn down for a starved probe. A\n\t\t// guard-less record never claims ownership and never authorizes a signal - every later caller\n\t\t// reads it as unknown - so the worst case is a fresh host next time, not a killed healthy one.\n\t\tpidFile = { pid: child.pid, processStartTime: processStartTime ?? null };\n\t\tawait testOptions?.beforePidFileWrite?.();\n\t\tawait writeFile(paths.pidFile, `${JSON.stringify(pidFile)}\\n`, { mode: 0o600 });\n\t\tchild.unref();\n\t} catch (error: unknown) {\n\t\t// Whether the child died on its own decides which diagnostic is true, and the\n\t\t// cleanup kill below records an `exitedEarly` indistinguishable from a real\n\t\t// self-exit. Latch it before killing, or the catch reports the SIGTERM it is\n\t\t// about to send and discards the actual startup failure.\n\t\tconst exitedBeforeCleanup = exitedEarly;\n\t\t// Keep the ChildProcess handle owned until registration succeeds. If startup\n\t\t// fails before the pidfile is written, terminate this exact child through\n\t\t// its still-attached handle rather than leaving an unmanaged daemon behind.\n\t\tif (!exitedBeforeCleanup && child && child.exitCode === null && child.signalCode === null) {\n\t\t\ttry {\n\t\t\t\tchild.kill(\"SIGTERM\");\n\t\t\t} catch {}\n\t\t\tif (childExit) await Promise.race([childExit, delay(2_000)]);\n\t\t\tif (child.exitCode === null && child.signalCode === null) {\n\t\t\t\ttry {\n\t\t\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\t\tif (!exitedBeforeCleanup) {\n\t\t\tawait cleanupState(paths);\n\t\t\tthrow error;\n\t\t}\n\t\tconst diagnostic = await appendStderr(\n\t\t\tpaths,\n\t\t\t`RPC socket host exited with code ${exitedBeforeCleanup.code ?? \"null\"}${exitedBeforeCleanup.signal ? ` (${exitedBeforeCleanup.signal})` : \"\"} before answering get_protocol_info`,\n\t\t);\n\t\tawait cleanupState(paths);\n\t\tthrow new Error(diagnostic);\n\t} finally {\n\t\tawait stderr.close();\n\t}\n\tconst readinessTimeoutMs = testOptions?.readinessTimeoutMs ?? DEFAULT_READINESS_TIMEOUT_MS;\n\tconst result = await pollProtocolInfo(socket, readinessTimeoutMs, childExit);\n\tif (isCompatible(result.protocol)) return { pid: pidFile.pid, socket, reused: false };\n\t// Teardown runs for the diagnostic's sake, so it must never replace it: a stop\n\t// failure here (unreadable identity, a host that outlives SIGKILL) would other-\n\t// wise propagate instead of the readiness message and skip cleanupState below,\n\t// leaving the pidfile and socket behind. Record it and keep going.\n\t// This child is ours and its handle is still attached: stop it through the handle.\n\t// Validating ownership through the pidfile would re-run the identity probe whose\n\t// failure is the very thing a loaded runner produces here.\n\tconst stopFailure = await stopSpawnedChild(\n\t\tchild,\n\t\tchildExit,\n\t\ttestOptions?.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS,\n\t).then(\n\t\t() => undefined,\n\t\t(error: unknown) => (error instanceof Error ? error.message : String(error)),\n\t);\n\tconst message = result.protocol\n\t\t? `RPC socket host answered get_protocol_info with serverVersion ${result.protocol.serverVersion} and capabilities ${JSON.stringify(result.protocol.capabilities)}, but is incompatible with serverVersion ${VERSION} and required capabilities ${JSON.stringify(REQUIRED_CAPABILITIES)}`\n\t\t: result.exited\n\t\t\t? `RPC socket host exited with code ${result.exited.code ?? \"null\"}${result.exited.signal ? ` (${result.exited.signal})` : \"\"} before answering get_protocol_info`\n\t\t\t: `spawned RPC socket host did not answer get_protocol_info within ${readinessTimeoutMs}ms`;\n\tconst diagnostic = await appendStderr(\n\t\tpaths,\n\t\tstopFailure === undefined ? message : `${message} (teardown also reported: ${stopFailure})`,\n\t);\n\tawait cleanupState(paths);\n\t// The supervisor may have failed before binding, or another owner may have\n\t// appeared while readiness was being checked. Never unlink an endpoint we\n\t// cannot prove this start owned.\n\tthrow new Error(diagnostic);\n}\n\n/**\n * Ownership for the reuse decision. An identity we cannot read proves nothing: it can neither\n * claim the host nor authorize a kill, so it reads as \"not ours\" and the caller starts fresh\n * rather than failing the whole ensure on an observation gap.\n */\nasync function matchesPidFileOrUnknown(\n\tpidFile: DaemonPidFile,\n\tprobe: (pid: number) => Promise<string | undefined>,\n): Promise<boolean> {\n\ttry {\n\t\treturn await processMatchesPidFile(pidFile, probe);\n\t} catch (error: unknown) {\n\t\tif (error instanceof ProcessIdentityUnreadableError) return false;\n\t\tthrow error;\n\t}\n}\n\nasync function stopSpawnedChild(\n\tchild: ChildProcess,\n\tchildExit: Promise<ChildExit>,\n\ttermTimeoutMs: number,\n): Promise<void> {\n\tconst exited = () => child.exitCode !== null || child.signalCode !== null;\n\tif (exited()) return;\n\tconst signal = (name: NodeJS.Signals) => {\n\t\ttry {\n\t\t\tchild.kill(name);\n\t\t} catch (error: unknown) {\n\t\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t\t}\n\t};\n\tconst waitFor = (ms: number) => Promise.race([childExit.then(() => true), delay(ms).then(() => exited())]);\n\tsignal(\"SIGTERM\");\n\tif (await waitFor(termTimeoutMs)) return;\n\tsignal(\"SIGKILL\");\n\tif (!(await waitFor(SIGKILL_GRACE_MS))) {\n\t\tthrow new Error(`RPC socket host pid ${child.pid ?? \"?\"} remained alive after SIGKILL`);\n\t}\n}\n\nasync function stopManagedHost(\n\tpidFile: DaemonPidFile,\n\ttermTimeoutMs: number,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<void> {\n\tawait signalValidated(pidFile, \"SIGTERM\", readStartTime);\n\tif (await waitForGone(pidFile, termTimeoutMs, readStartTime)) return;\n\tawait signalValidated(pidFile, \"SIGKILL\", readStartTime);\n\tif (!(await waitForGone(pidFile, SIGKILL_GRACE_MS, readStartTime))) {\n\t\tthrow new Error(`RPC socket host pid ${pidFile.pid} remained alive after SIGKILL`);\n\t}\n}\n\ntype PidFileOwnership = \"owns\" | \"gone\" | \"unknown\";\n\n// One probe per call: the teardown loops below are themselves the retry, so the\n// budget inside processMatchesPidFile would only multiply their wall time. A probe\n// that fails against a LIVE pid is \"unknown\" — it proves nothing about ownership, so\n// signalling on it would be unsafe and treating it as \"gone\" would abandon a host that\n// may still be running. A failed probe against a dead pid is \"gone\".\nasync function resolvePidFileOwnership(\n\tpidFile: DaemonPidFile,\n\treadStartTime: (pid: number) => Promise<string | undefined>,\n): Promise<PidFileOwnership> {\n\ttry {\n\t\treturn (await processMatchesPidFile(pidFile, readStartTime, processIsLive, { attempts: 1 })) ? \"owns\" : \"gone\";\n\t} catch (error: unknown) {\n\t\tif (error instanceof ProcessIdentityUnreadableError) return \"unknown\";\n\t\tthrow error;\n\t}\n}\n\nasync function signalValidated(\n\tpidFile: DaemonPidFile,\n\tsignal: NodeJS.Signals,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<void> {\n\tif ((await resolvePidFileOwnership(pidFile, readStartTime)) !== \"owns\") return;\n\ttry {\n\t\tprocess.kill(pidFile.pid, signal);\n\t} catch (error: unknown) {\n\t\tif (!isNodeErrorCode(error, \"ESRCH\")) throw error;\n\t}\n}\n\nasync function waitForGone(\n\tpidFile: DaemonPidFile,\n\ttimeoutMs: number,\n\treadStartTime: (pid: number) => Promise<string | undefined> = readProcessStartTime,\n): Promise<boolean> {\n\tconst deadline = Date.now() + timeoutMs;\n\twhile (Date.now() <= deadline) {\n\t\tif ((await resolvePidFileOwnership(pidFile, readStartTime)) === \"gone\") return true;\n\t\tawait delay(50);\n\t}\n\treturn (await resolvePidFileOwnership(pidFile, readStartTime)) === \"gone\";\n}\n\ntype ChildExit = { readonly code: number | null; readonly signal: NodeJS.Signals | null };\n\ntype ProtocolPollResult = { readonly protocol?: ProtocolInfo; readonly exited?: ChildExit };\n\nasync function pollProtocolInfo(\n\tsocket: string,\n\ttimeoutMs: number,\n\tchildExit?: Promise<ChildExit>,\n): Promise<ProtocolPollResult> {\n\tconst deadline = Date.now() + timeoutMs;\n\tlet lastProtocol: ProtocolInfo | undefined;\n\twhile (Date.now() <= deadline) {\n\t\tconst probe = probeProtocolInfo(\n\t\t\tsocket,\n\t\t\tMath.min(SPAWNED_HOST_PROBE_TIMEOUT_MS, Math.max(1, deadline - Date.now())),\n\t\t);\n\t\tconst raced = childExit ? await Promise.race([probe, childExit]) : await probe;\n\t\tif (isChildExit(raced)) {\n\t\t\t// A supervisor exit can be triggered by the Windows identity watchdog\n\t\t\t// while a named-pipe client is still composing its protocol reply. Do\n\t\t\t// not terminate the host based solely on that exit until this probe has\n\t\t\t// had a chance to deliver an answer. A host that never answers still\n\t\t\t// resolves through probeProtocolInfo's bounded timeout/close handling.\n\t\t\tconst info = await probe;\n\t\t\tif (info) {\n\t\t\t\tlastProtocol = info;\n\t\t\t\tif (isCompatible(info)) return { protocol: info };\n\t\t\t} else {\n\t\t\t\treturn { protocol: lastProtocol, exited: raced };\n\t\t\t}\n\t\t} else if (raced) {\n\t\t\tlastProtocol = raced;\n\t\t\tif (isCompatible(raced)) return { protocol: raced };\n\t\t}\n\t\tawait delay(50);\n\t}\n\treturn { protocol: lastProtocol };\n}\n\nfunction isChildExit(value: ProtocolInfo | ChildExit | undefined): value is ChildExit {\n\treturn !!value && \"code\" in value && \"signal\" in value;\n}\n\nasync function probeProtocolInfo(socketPath: string, timeoutMs: number): Promise<ProtocolInfo | undefined> {\n\tlet secret: Buffer | undefined;\n\tif (process.platform === \"win32\") {\n\t\ttry {\n\t\t\tsecret = await readSocketSecret(socketSecretPath(socketPath));\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn new Promise((resolveProbe) => {\n\t\tconst socket = createConnection(resolveSocketTransportAddress(socketPath, process.platform, secret));\n\t\tlet buffer = \"\";\n\t\tlet settled = false;\n\t\tconst finish = (value?: ProtocolInfo): void => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timeout);\n\t\t\tsocket.destroy();\n\t\t\tresolveProbe(value);\n\t\t};\n\t\tconst timeout = setTimeout(() => finish(), timeoutMs);\n\t\tsocket.once(\"connect\", () => {\n\t\t\tsocket.write('{\"id\":\"ensure-host-probe\",\"type\":\"get_protocol_info\"}\\n');\n\t\t});\n\t\tsocket.on(\"data\", (chunk) => {\n\t\t\tbuffer += chunk.toString(\"utf8\");\n\t\t\tconst newline = buffer.indexOf(\"\\n\");\n\t\t\tif (newline === -1) return;\n\t\t\tfinish(readProtocolInfo(buffer.slice(0, newline)));\n\t\t});\n\t\tsocket.once(\"error\", () => finish());\n\t\tsocket.once(\"close\", () => finish());\n\t\t// Register the error listener before sending the Windows named-pipe handshake.\n\t\t// When an idle host has already removed its pipe, the handshake write can\n\t\t// surface ENOENT immediately; without the listener this probe escapes instead\n\t\t// of becoming the expected \"no existing host\" result for the next ensure.\n\t\tif (secret) sendSocketHandshake(socket, secret);\n\t});\n}\n\nfunction readProtocolInfo(text: string): ProtocolInfo | undefined {\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(text);\n\t} catch {\n\t\treturn undefined;\n\t}\n\tif (!isRecord(parsed) || parsed.id !== \"ensure-host-probe\" || parsed.success !== true || !isRecord(parsed.data)) {\n\t\treturn undefined;\n\t}\n\tconst { serverVersion, capabilities } = parsed.data;\n\tif (typeof serverVersion !== \"string\" || !Array.isArray(capabilities)) return undefined;\n\tif (!capabilities.every((capability) => typeof capability === \"string\")) return undefined;\n\treturn { serverVersion, capabilities };\n}\n\nfunction isCompatible(protocol: ProtocolInfo | undefined): boolean {\n\treturn (\n\t\tprotocol?.serverVersion === VERSION &&\n\t\tREQUIRED_CAPABILITIES.every((capability) => protocol.capabilities.includes(capability))\n\t);\n}\n\nasync function readPidFile(paths: HostDaemonPaths): Promise<DaemonPidFile | undefined> {\n\ttry {\n\t\treturn parseDaemonPidFile(await readFile(paths.pidFile, \"utf8\"));\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return undefined;\n\t\tthrow error;\n\t}\n}\n\nasync function reapOrphanedInternalHostDirs(): Promise<void> {\n\ttry {\n\t\tconst entries = await readdir(tmpdir(), { withFileTypes: true });\n\t\tawait Promise.all(\n\t\t\tentries\n\t\t\t\t.filter((entry) => entry.isDirectory() && entry.name.startsWith(\"senpi-rpc-host-internal-\"))\n\t\t\t\t.map(async (entry) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst owner = JSON.parse(await readFile(join(tmpdir(), entry.name, \".owner\"), \"utf8\")) as {\n\t\t\t\t\t\t\tpid?: unknown;\n\t\t\t\t\t\t\tprocessStartTime?: unknown;\n\t\t\t\t\t\t\tcreatedAt?: unknown;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof owner.pid === \"number\" &&\n\t\t\t\t\t\t\ttypeof owner.processStartTime === \"string\" &&\n\t\t\t\t\t\t\ttypeof owner.createdAt === \"number\" &&\n\t\t\t\t\t\t\towner.processStartTime.length > 0 &&\n\t\t\t\t\t\t\towner.createdAt < Date.now() - 60_000 &&\n\t\t\t\t\t\t\t(await readdir(join(tmpdir(), entry.name))).length === 1 &&\n\t\t\t\t\t\t\t!(await processMatchesPidFile({ pid: owner.pid, processStartTime: owner.processStartTime }).catch(\n\t\t\t\t\t\t\t\t(error: unknown) => {\n\t\t\t\t\t\t\t\t\t// Unreadable but live: assume the owner is alive rather than steal its lock.\n\t\t\t\t\t\t\t\t\tif (error instanceof ProcessIdentityUnreadableError) return true;\n\t\t\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t))\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\tawait rm(join(tmpdir(), entry.name), { recursive: true, force: true });\n\t\t\t\t\t} catch {}\n\t\t\t\t}),\n\t\t);\n\t} catch {}\n}\n\nasync function cleanupState(paths: HostDaemonPaths): Promise<void> {\n\tawait rm(paths.pidFile, { force: true });\n\tawait rm(paths.settingsFile, { force: true });\n}\n\nasync function appendStderr(paths: HostDaemonPaths, message: string): Promise<string> {\n\ttry {\n\t\tconst stderr = (await readFile(paths.stderrLog, \"utf8\")).trim();\n\t\treturn stderr ? `${message}\\n${stderr}` : message;\n\t} catch (error: unknown) {\n\t\tif (isNodeErrorCode(error, \"ENOENT\")) return message;\n\t\tthrow error;\n\t}\n}\n\nfunction createSocketLockName(socket: string): string {\n\treturn createHash(\"sha256\")\n\t\t.update(resolveSocketTransportAddress(socket, process.platform), \"utf8\")\n\t\t.digest(\"hex\")\n\t\t.slice(0, 32);\n}\n\nfunction normalizeSocketPath(value: string): string {\n\tif (value.startsWith(\"unix://\")) return value.slice(\"unix://\".length);\n\treturn value;\n}\n\n/**\n * Default launch: the host-lifecycle supervisor owns the public socket and the\n * idle-exit policy; it spawns the committed RPC socket host itself. Any extra\n * hostArgs are forwarded verbatim to the host CLI (e.g. provider pinning).\n *\n * A compiled standalone binary cannot re-enter itself through a script path:\n * bun executables always boot their embedded entrypoint and parse the whole\n * argv as CLI arguments, so `host-lifecycle.ts --socket <path>` dies with\n * \"Unknown option: --socket\" before the host ever answers get_protocol_info.\n * Compiled binaries therefore re-enter through the hidden\n * `--internal-rpc-host-supervisor` route that main() dispatches before\n * argument parsing. Exported for tests.\n */\nexport function defaultHostLaunch(\n\tsocket: string,\n\thostArgs: readonly string[],\n\tcompiled: boolean = isBunBinary,\n): {\n\tcommand: string;\n\targs: string[];\n} {\n\tif (compiled) {\n\t\treturn {\n\t\t\tcommand: process.execPath,\n\t\t\targs: [INTERNAL_SUPERVISOR_FLAG, \"--socket\", socket, ...hostArgs],\n\t\t};\n\t}\n\treturn {\n\t\tcommand: process.execPath,\n\t\targs: [...process.execArgv, resolveHostLifecycleEntryPath(), \"--socket\", socket, ...hostArgs],\n\t};\n}\n\nfunction resolveHostLifecycleEntryPath(): string {\n\tconst modulePath = fileURLToPath(import.meta.url);\n\tconst extension = modulePath.endsWith(\".ts\") ? \".ts\" : \".js\";\n\treturn resolve(dirname(modulePath), `host-lifecycle${extension}`);\n}\n\nfunction delay(ms: number): Promise<void> {\n\treturn new Promise((resolveDelay) => setTimeout(resolveDelay, ms));\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNodeErrorCode(error: unknown, code: string): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === code;\n}\n"]}
@@ -15,6 +15,20 @@ export interface HostLifecyclePolicy {
15
15
  readonly coldStart: HostColdStart;
16
16
  readonly idleExitMs: number;
17
17
  }
18
+ /**
19
+ * The internal hop must stay short enough for sun_path (104 bytes on macOS)
20
+ * regardless of where the public socket lives, and private against other local
21
+ * users, so it gets its own 0700 directory under the OS temp directory.
22
+ *
23
+ * On win32 the directory lives under the caller-supplied rpc-host-daemon
24
+ * directory, which ensureHost() creates but a direct --internal-rpc-host-supervisor
25
+ * launch does not, so the parent is created recursively.
26
+ */
27
+ export declare function createInternalSocketPath(baseDir?: string, platform?: NodeJS.Platform): Promise<{
28
+ socket: string;
29
+ dir?: string;
30
+ secretPath?: string;
31
+ }>;
18
32
  export declare function parseColdStart(value: string | undefined): HostColdStart | undefined;
19
33
  export declare function parseIdleExitMs(value: string | undefined): number | undefined;
20
34
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/host-lifecycle.ts"],"names":[],"mappings":";AA4EA,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY,CAAC;AAEvD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,8BAA8B,CAAC;AAC/D,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,gCAAgC,CAAC;AACnE,sFAAsF;AACtF,eAAO,MAAM,yBAAyB,QAAc,CAAC;AAErD,+EAA+E;AAC/E,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAcD;;;;;;;;GAQG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,SAAW,EAClB,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAsBhE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAEnF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI7E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,OAAO,EACjB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAC/C,mBAAmB,CASrB;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,GAC3B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAGtC;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAE1D;;;;GAIG;AACH,qBAAa,eAAe;IAC3B,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAE5B,YAAY,UAAU,EAAE,MAAM,EAAE,GAAG,GAAE,MAAM,MAAiB,EAG3D;IAED,MAAM,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAa/C;CACD;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,gGAAgG;AAChG,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AASzE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CASjG;AAED,sGAAsG;AACtG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,gBAAgB,GAAG,SAAS,CAgCzF;AAED,0FAA0F;AAC1F,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,gBAAgB,EACxB,cAAc,EAAE,MAAM,EACtB,QAAQ,GAAE,OAAqB,GAC7B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAmBrC;AAWD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CACnC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,EAC3C,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAC1C;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAUrD;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkR/E"}
@@ -51,7 +51,7 @@ import { createHostDaemonPaths } from "./host-ensure.js";
51
51
  import { HOST_CLEANUP_PATHS_ENV, HOST_PUBLIC_SOCKET_ENV, HOST_SCRATCH_DIR_ENV, HOST_WATCH_FD_ENV, HOST_WATCH_PPID_ENV, } from "./host-watchdog.js";
52
52
  import { attachJsonlLineReader, MAX_RPC_LINE_CHARACTERS } from "./jsonl.js";
53
53
  import { PUBLIC_SOCKET_IDENTITY_FILE, shieldSocketDuringClose, statSocketIdentity, unlinkOwnedSocket, writeSocketIdentityFile, } from "./socket-ownership.js";
54
- import { authenticateSocket, createSocketSecret, readSocketSecret, resolveSocketTransportAddress, SOCKET_SECRET_FILE_ENV, sendSocketHandshake, socketSecretPath, } from "./socket-transport.js";
54
+ import { authenticateSocket, createSocketSecret, ensureSocketSecret, resolveSocketTransportAddress, SOCKET_SECRET_FILE_ENV, sendSocketHandshake, socketSecretPath, } from "./socket-transport.js";
55
55
  /** Environment override for the cold-start policy: `transient` or `persistent`. */
56
56
  export const HOST_COLD_START_ENV = "SENPI_RPC_HOST_COLD_START";
57
57
  /** Environment override for the idle-exit window in milliseconds. */
@@ -72,11 +72,15 @@ const CHILD_WATCH_FD = 3;
72
72
  * The internal hop must stay short enough for sun_path (104 bytes on macOS)
73
73
  * regardless of where the public socket lives, and private against other local
74
74
  * users, so it gets its own 0700 directory under the OS temp directory.
75
+ *
76
+ * On win32 the directory lives under the caller-supplied rpc-host-daemon
77
+ * directory, which ensureHost() creates but a direct --internal-rpc-host-supervisor
78
+ * launch does not, so the parent is created recursively.
75
79
  */
76
- async function createInternalSocketPath(baseDir = tmpdir()) {
77
- if (process.platform === "win32") {
80
+ export async function createInternalSocketPath(baseDir = tmpdir(), platform = process.platform) {
81
+ if (platform === "win32") {
78
82
  const dir = join(baseDir, `internal-${randomUUID()}`);
79
- await mkdir(dir, { recursive: false, mode: 0o700 });
83
+ await mkdir(dir, { recursive: true, mode: 0o700 });
80
84
  return {
81
85
  socket: `\\\\.\\pipe\\senpi-rpc-internal-${randomUUID()}`,
82
86
  dir,
@@ -285,11 +289,16 @@ export async function runHostSupervisor(launch) {
285
289
  const paths = createHostDaemonPaths(launch.agentDir ?? getAgentDir());
286
290
  const policy = resolveHostPolicy(await readSettingsFile(paths.settingsFile), process.env);
287
291
  const publicSocket = launch.socket;
292
+ // Direct-launch contract: the supervisor owns the public secret. ensureHost()
293
+ // writes it before spawning, but the hidden --internal-rpc-host-supervisor route
294
+ // has no such caller, so a fresh profile would otherwise die reading it (#1370).
295
+ // It is provisioned BEFORE the internal hop and the child so a provisioning
296
+ // failure leaves no scratch directory and no host process behind.
297
+ const publicSecret = process.platform === "win32" ? await ensurePublicSocketSecret(publicSocket) : undefined;
288
298
  const internal = await createInternalSocketPath(paths.dir);
289
299
  const internalSocket = internal.socket;
290
300
  const internalSecretPath = internal.secretPath ?? socketSecretPath(internalSocket);
291
301
  const internalSecret = process.platform === "win32" ? await createSocketSecret(internalSecretPath) : undefined;
292
- const publicSecret = process.platform === "win32" ? await readSocketSecret(socketSecretPath(publicSocket)) : undefined;
293
302
  const clientSockets = new Set();
294
303
  const busySessions = new Map();
295
304
  let observerHealthy = false;
@@ -563,6 +572,23 @@ function registerSupervisorSignals(shutdown) {
563
572
  });
564
573
  }
565
574
  }
575
+ /**
576
+ * Reuses an existing valid secret - including one ensureHost() just wrote - and
577
+ * creates one (with its parent directories, mode 0600) when it is missing or
578
+ * unusable. Reuse is required, not just an optimization: on win32 the pipe name
579
+ * is derived from the socket path AND the secret, so rotating it here would
580
+ * point this supervisor at a different endpoint than its caller published.
581
+ * A failure names the bootstrap step and the path it could not provision.
582
+ */
583
+ async function ensurePublicSocketSecret(publicSocket) {
584
+ const secretPath = socketSecretPath(publicSocket);
585
+ try {
586
+ return await ensureSocketSecret(secretPath);
587
+ }
588
+ catch (cause) {
589
+ throw new Error(`senpi rpc host supervisor: cannot provision public socket secret ${secretPath}`, { cause });
590
+ }
591
+ }
566
592
  async function readSettingsFile(settingsFile) {
567
593
  try {
568
594
  return JSON.parse(await readFile(settingsFile, "utf8"));