@code-yeongyu/senpi 2026.9.21-2 → 2026.9.22-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/bundle/chunks/{anthropic-messages-C3ZY2ANT.js → anthropic-messages-2P7APOOQ.js} +1 -1
  3. package/dist/bundle/chunks/{app-server-command-HSX5RFAP.js → app-server-command-PRNA6QQU.js} +1 -1
  4. package/dist/bundle/chunks/{azure-openai-responses-7TAGS2VU.js → azure-openai-responses-3AH7MJWF.js} +1 -1
  5. package/dist/bundle/chunks/{bun-extension-importer-UO7V2MZ7.js → bun-extension-importer-H4IJCWWQ.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-OSDJ2SYO.js → chunk-5XC2FNJ5.js} +1 -1
  7. package/dist/bundle/chunks/{chunk-D5CL7PPD.js → chunk-64JQFFHH.js} +2 -2
  8. package/dist/bundle/chunks/{chunk-Z3KQB2R3.js → chunk-6OD4TT33.js} +95 -39
  9. package/dist/bundle/chunks/{chunk-NEEAKXDT.js → chunk-7EH64T6E.js} +2 -2
  10. package/dist/bundle/chunks/{chunk-MIVOQT3Q.js → chunk-ARJJU3MS.js} +1 -1
  11. package/dist/bundle/chunks/chunk-BOZ37BOT.js +14 -0
  12. package/dist/bundle/chunks/{chunk-POMPEGWQ.js → chunk-F3DXL5MX.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-GLKVDRNP.js → chunk-GXUYWMN2.js} +1 -1
  14. package/dist/bundle/chunks/chunk-HH3KJDWA.js +2 -0
  15. package/dist/bundle/chunks/{chunk-B7W62BM7.js → chunk-IPRJIKLL.js} +1 -1
  16. package/dist/bundle/chunks/chunk-JEFYJDHP.js +8 -0
  17. package/dist/bundle/chunks/{chunk-T6XA2IZR.js → chunk-JR4X6ECO.js} +1 -1
  18. package/dist/bundle/chunks/{chunk-I425CMTO.js → chunk-JZ6YQU3A.js} +4 -4
  19. package/dist/bundle/chunks/{chunk-KNM6SRPE.js → chunk-K3HEWWSS.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-M2XAY6I7.js → chunk-M2HSO7MH.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-UYVPLEOL.js → chunk-NK2RNX25.js} +1 -1
  22. package/dist/bundle/chunks/chunk-NMB4C6ZZ.js +2 -0
  23. package/dist/bundle/chunks/{chunk-VEO3ABZR.js → chunk-OLJ7LQJY.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-GVI2HP7N.js → chunk-OPNVT7BU.js} +1 -1
  25. package/dist/bundle/chunks/{chunk-XHMOFY4T.js → chunk-R6LVC7SP.js} +4 -4
  26. package/dist/bundle/chunks/{chunk-3SLCHXZO.js → chunk-UCPWK6TZ.js} +2 -2
  27. package/dist/bundle/chunks/{chunk-B2IM56LB.js → chunk-VYIJQQ5I.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-47GF6XYZ.js → chunk-YT2ZSZOY.js} +1 -1
  29. package/dist/bundle/chunks/{cli-main-GQTEEZ2V.js → cli-main-AFJNXUSL.js} +1 -1
  30. package/dist/bundle/chunks/github-copilot.js +1 -1
  31. package/dist/bundle/chunks/{google-generative-ai-JWIH75VF.js → google-generative-ai-Y2IYMUVC.js} +1 -1
  32. package/dist/bundle/chunks/{google-vertex-IRGAY5XR.js → google-vertex-TKBBMPHV.js} +1 -1
  33. package/dist/bundle/chunks/{host-command-KOEKIHIZ.js → host-command-OVA6GEWC.js} +1 -1
  34. package/dist/bundle/chunks/host-lifecycle-IDQPLYEA.js +3 -0
  35. package/dist/bundle/chunks/host-lifecycle.js +10 -6
  36. package/dist/bundle/chunks/{interactive-host-runtime-2KTFEW7O.js → interactive-host-runtime-F5L4USLR.js} +1 -1
  37. package/dist/bundle/chunks/{interactive-mode-I3ILWXQB.js → interactive-mode-UFBSCOP7.js} +1 -1
  38. package/dist/bundle/chunks/kimi-coding.js +2 -2
  39. package/dist/bundle/chunks/{list-tips-2KX65NWZ.js → list-tips-2QG7ASHS.js} +1 -1
  40. package/dist/bundle/chunks/{mistral-conversations-VOBYATVJ.js → mistral-conversations-ZYDVFRYF.js} +1 -1
  41. package/dist/bundle/chunks/multi-session-host-EUTEGVLS.js +21 -0
  42. package/dist/bundle/chunks/openai-codex-responses-MEIUNROM.js +10 -0
  43. package/dist/bundle/chunks/{openai-completions-YK6QTYOH.js → openai-completions-4V76L5ZJ.js} +1 -1
  44. package/dist/bundle/chunks/openai-responses-YR7WRBG3.js +2 -0
  45. package/dist/bundle/chunks/{package-manager-cli-HOL6CAI6.js → package-manager-cli-JPUWMUEJ.js} +1 -1
  46. package/dist/bundle/chunks/rotation-stream-S56Y7WMM.js +2 -0
  47. package/dist/bundle/chunks/{rpc-mode-L3DSGTVM.js → rpc-mode-JDVHUBZY.js} +1 -1
  48. package/dist/bundle/chunks/{session-picker-L3FYEQBL.js → session-picker-PFPJVVIC.js} +1 -1
  49. package/dist/bundle/chunks/session-worker.js +225 -164
  50. package/dist/bundle/cli.js +1 -1
  51. package/dist/bundle/index.js +1 -1
  52. package/dist/bundle/rpc-entry.js +1 -1
  53. package/dist/core/agent-session.d.ts +6 -4
  54. package/dist/core/agent-session.d.ts.map +1 -1
  55. package/dist/core/agent-session.js +9 -7
  56. package/dist/core/agent-session.js.map +1 -1
  57. package/dist/core/credential-pool/classify.d.ts.map +1 -1
  58. package/dist/core/credential-pool/classify.js +12 -0
  59. package/dist/core/credential-pool/classify.js.map +1 -1
  60. package/dist/core/credential-pool/failover.d.ts +37 -5
  61. package/dist/core/credential-pool/failover.d.ts.map +1 -1
  62. package/dist/core/credential-pool/failover.js +60 -24
  63. package/dist/core/credential-pool/failover.js.map +1 -1
  64. package/dist/core/credential-pool/rotation-events.d.ts +5 -0
  65. package/dist/core/credential-pool/rotation-events.d.ts.map +1 -0
  66. package/dist/core/credential-pool/rotation-events.js +25 -0
  67. package/dist/core/credential-pool/rotation-events.js.map +1 -0
  68. package/dist/core/credential-pool/rotation-stream.d.ts +4 -3
  69. package/dist/core/credential-pool/rotation-stream.d.ts.map +1 -1
  70. package/dist/core/credential-pool/rotation-stream.js +8 -11
  71. package/dist/core/credential-pool/rotation-stream.js.map +1 -1
  72. package/dist/core/extensions/builtin/ask-user/schema.d.ts +2 -25
  73. package/dist/core/extensions/builtin/ask-user/schema.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/ask-user/schema.js.map +1 -1
  75. package/dist/core/extensions/builtin/claude-sdk-oauth/api-id.d.ts +7 -0
  76. package/dist/core/extensions/builtin/claude-sdk-oauth/api-id.d.ts.map +1 -0
  77. package/dist/core/extensions/builtin/claude-sdk-oauth/api-id.js +7 -0
  78. package/dist/core/extensions/builtin/claude-sdk-oauth/api-id.js.map +1 -0
  79. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts.map +1 -1
  80. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js +3 -2
  81. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js.map +1 -1
  82. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +22 -1
  83. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  84. package/dist/core/extensions/builtin/claude-sdk-oauth/session-observability.d.ts +2 -0
  85. package/dist/core/extensions/builtin/claude-sdk-oauth/session-observability.d.ts.map +1 -1
  86. package/dist/core/extensions/builtin/claude-sdk-oauth/session-observability.js +4 -0
  87. package/dist/core/extensions/builtin/claude-sdk-oauth/session-observability.js.map +1 -1
  88. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  89. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +18 -1
  90. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  91. package/dist/core/extensions/builtin/claude-sdk-oauth/session-turn-attempt.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/claude-sdk-oauth/session-turn-attempt.js +18 -0
  93. package/dist/core/extensions/builtin/claude-sdk-oauth/session-turn-attempt.js.map +1 -1
  94. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +2 -7
  95. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
  96. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +2 -8
  97. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
  98. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js +1 -1
  99. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js.map +1 -1
  100. package/dist/core/extensions/builtin/mcp/expose/naming.d.ts +0 -1
  101. package/dist/core/extensions/builtin/mcp/expose/naming.d.ts.map +1 -1
  102. package/dist/core/extensions/builtin/mcp/expose/naming.js +0 -3
  103. package/dist/core/extensions/builtin/mcp/expose/naming.js.map +1 -1
  104. package/dist/core/extensions/builtin/mcp/expose/register.d.ts +1 -2
  105. package/dist/core/extensions/builtin/mcp/expose/register.d.ts.map +1 -1
  106. package/dist/core/extensions/builtin/mcp/expose/register.js +0 -21
  107. package/dist/core/extensions/builtin/mcp/expose/register.js.map +1 -1
  108. package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts +2 -2
  109. package/dist/core/extensions/builtin/mcp/expose/schema-compat.d.ts.map +1 -1
  110. package/dist/core/extensions/builtin/mcp/expose/schema-compat.js +2 -2
  111. package/dist/core/extensions/builtin/mcp/expose/schema-compat.js.map +1 -1
  112. package/dist/core/extensions/builtin/prompt-preset/file-operations.js +1 -1
  113. package/dist/core/extensions/builtin/prompt-preset/file-operations.js.map +1 -1
  114. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.d.ts +3 -0
  115. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.d.ts.map +1 -0
  116. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js +105 -0
  117. package/dist/core/extensions/builtin/prompt-preset/grok-4.7.js.map +1 -0
  118. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  119. package/dist/core/extensions/builtin/prompt-preset/presets.js +14 -0
  120. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  121. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  122. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  123. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  124. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  125. package/dist/core/extensions/bun-extension-importer.d.ts +1 -0
  126. package/dist/core/extensions/bun-extension-importer.d.ts.map +1 -1
  127. package/dist/core/extensions/bun-extension-importer.js +4 -0
  128. package/dist/core/extensions/bun-extension-importer.js.map +1 -1
  129. package/dist/core/extensions/extension-module-cache.d.ts +48 -0
  130. package/dist/core/extensions/extension-module-cache.d.ts.map +1 -0
  131. package/dist/core/extensions/extension-module-cache.js +111 -0
  132. package/dist/core/extensions/extension-module-cache.js.map +1 -0
  133. package/dist/core/extensions/loader.d.ts +1 -1
  134. package/dist/core/extensions/loader.d.ts.map +1 -1
  135. package/dist/core/extensions/loader.js +14 -56
  136. package/dist/core/extensions/loader.js.map +1 -1
  137. package/dist/core/http-dispatcher.d.ts +29 -0
  138. package/dist/core/http-dispatcher.d.ts.map +1 -1
  139. package/dist/core/http-dispatcher.js +30 -3
  140. package/dist/core/http-dispatcher.js.map +1 -1
  141. package/dist/core/model-resolver.js +1 -1
  142. package/dist/core/model-resolver.js.map +1 -1
  143. package/dist/core/retry-fallback/billing.d.ts.map +1 -1
  144. package/dist/core/retry-fallback/billing.js +20 -1
  145. package/dist/core/retry-fallback/billing.js.map +1 -1
  146. package/dist/core/session-manager.d.ts +3 -1
  147. package/dist/core/session-manager.d.ts.map +1 -1
  148. package/dist/core/session-manager.js +12 -6
  149. package/dist/core/session-manager.js.map +1 -1
  150. package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/assistant-render-descriptors.js +8 -7
  152. package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
  153. package/dist/modes/print-mode.d.ts.map +1 -1
  154. package/dist/modes/print-mode.js +7 -5
  155. package/dist/modes/print-mode.js.map +1 -1
  156. package/dist/modes/rpc/custom-capability.d.ts +7 -0
  157. package/dist/modes/rpc/custom-capability.d.ts.map +1 -1
  158. package/dist/modes/rpc/custom-capability.js +7 -0
  159. package/dist/modes/rpc/custom-capability.js.map +1 -1
  160. package/dist/modes/rpc/handoff-activity.d.ts +4 -0
  161. package/dist/modes/rpc/handoff-activity.d.ts.map +1 -0
  162. package/dist/modes/rpc/handoff-activity.js +6 -0
  163. package/dist/modes/rpc/handoff-activity.js.map +1 -0
  164. package/dist/modes/rpc/host-child-exit.d.ts +19 -0
  165. package/dist/modes/rpc/host-child-exit.d.ts.map +1 -0
  166. package/dist/modes/rpc/host-child-exit.js +35 -0
  167. package/dist/modes/rpc/host-child-exit.js.map +1 -0
  168. package/dist/modes/rpc/host-crash-record.d.ts +24 -0
  169. package/dist/modes/rpc/host-crash-record.d.ts.map +1 -0
  170. package/dist/modes/rpc/host-crash-record.js +75 -0
  171. package/dist/modes/rpc/host-crash-record.js.map +1 -0
  172. package/dist/modes/rpc/host-crash-record.test.d.ts +2 -0
  173. package/dist/modes/rpc/host-crash-record.test.d.ts.map +1 -0
  174. package/dist/modes/rpc/host-crash-record.test.js +91 -0
  175. package/dist/modes/rpc/host-crash-record.test.js.map +1 -0
  176. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  177. package/dist/modes/rpc/host-ensure.js +60 -17
  178. package/dist/modes/rpc/host-ensure.js.map +1 -1
  179. package/dist/modes/rpc/host-lifecycle.d.ts +4 -10
  180. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  181. package/dist/modes/rpc/host-lifecycle.js +83 -51
  182. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  183. package/dist/modes/rpc/host-supersession.d.ts +13 -2
  184. package/dist/modes/rpc/host-supersession.d.ts.map +1 -1
  185. package/dist/modes/rpc/host-supersession.js +40 -7
  186. package/dist/modes/rpc/host-supersession.js.map +1 -1
  187. package/dist/modes/rpc/multi-session-host.d.ts +1 -0
  188. package/dist/modes/rpc/multi-session-host.d.ts.map +1 -1
  189. package/dist/modes/rpc/multi-session-host.js +40 -7
  190. package/dist/modes/rpc/multi-session-host.js.map +1 -1
  191. package/dist/modes/rpc/observer-link.d.ts +48 -0
  192. package/dist/modes/rpc/observer-link.d.ts.map +1 -0
  193. package/dist/modes/rpc/observer-link.js +56 -0
  194. package/dist/modes/rpc/observer-link.js.map +1 -0
  195. package/dist/modes/rpc/rpc-mode.d.ts +12 -2
  196. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  197. package/dist/modes/rpc/rpc-mode.js +12 -2
  198. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  199. package/dist/modes/rpc/rpc-types.d.ts +36 -1
  200. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  201. package/dist/modes/rpc/rpc-types.js +8 -0
  202. package/dist/modes/rpc/rpc-types.js.map +1 -1
  203. package/dist/modes/rpc/session-command-router.d.ts +10 -4
  204. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  205. package/dist/modes/rpc/session-command-router.js +95 -19
  206. package/dist/modes/rpc/session-command-router.js.map +1 -1
  207. package/dist/modes/rpc/session-event-writer.d.ts +5 -3
  208. package/dist/modes/rpc/session-event-writer.d.ts.map +1 -1
  209. package/dist/modes/rpc/session-event-writer.js +21 -2
  210. package/dist/modes/rpc/session-event-writer.js.map +1 -1
  211. package/dist/modes/rpc/session-registry.d.ts +6 -1
  212. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  213. package/dist/modes/rpc/session-registry.js +34 -3
  214. package/dist/modes/rpc/session-registry.js.map +1 -1
  215. package/dist/modes/rpc/session-worker-client.d.ts +1 -0
  216. package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
  217. package/dist/modes/rpc/session-worker-client.js +3 -0
  218. package/dist/modes/rpc/session-worker-client.js.map +1 -1
  219. package/dist/modes/rpc/session-worker-protocol.d.ts +3 -1
  220. package/dist/modes/rpc/session-worker-protocol.d.ts.map +1 -1
  221. package/dist/modes/rpc/session-worker-protocol.js.map +1 -1
  222. package/dist/modes/rpc/session-worker.js +7 -1
  223. package/dist/modes/rpc/session-worker.js.map +1 -1
  224. package/dist/modes/rpc/socket-ownership.d.ts +16 -0
  225. package/dist/modes/rpc/socket-ownership.d.ts.map +1 -1
  226. package/dist/modes/rpc/socket-ownership.js +28 -4
  227. package/dist/modes/rpc/socket-ownership.js.map +1 -1
  228. package/dist/modes/rpc/worker-session-registry.d.ts +12 -5
  229. package/dist/modes/rpc/worker-session-registry.d.ts.map +1 -1
  230. package/dist/modes/rpc/worker-session-registry.js +10 -2
  231. package/dist/modes/rpc/worker-session-registry.js.map +1 -1
  232. package/docs/providers.md +9 -1
  233. package/docs/rpc.md +72 -10
  234. package/docs/settings.md +1 -1
  235. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +29 -0
  236. package/node_modules/@code-yeongyu/senpi-codemode/README.md +51 -13
  237. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  238. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +53 -9
  239. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/reserved-dispatch.ts +1 -0
  240. package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +18 -0
  241. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-status.ts +9 -4
  242. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +6 -0
  243. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/AGENTS.md +2 -2
  244. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +10 -0
  245. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +18 -6
  246. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +2 -6
  247. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +1 -1
  248. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/run-queue.ts +17 -7
  249. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +6 -1
  250. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel-contract.ts +2 -5
  251. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +37 -5
  252. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +11 -2
  253. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +6 -0
  254. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-contract.ts +2 -5
  255. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +14 -4
  256. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +18 -5
  257. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +3 -2
  258. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +4 -1
  259. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +9 -2
  260. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/AGENTS.md +2 -0
  261. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-execution.ts +19 -2
  262. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-runtime.ts +11 -3
  263. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-contract.ts +6 -1
  264. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +72 -20
  265. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-snapshot.ts +28 -4
  266. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-state.ts +5 -4
  267. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-status.ts +5 -2
  268. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-eval-result.ts +76 -25
  269. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-execution-event.ts +4 -0
  270. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-kernel-reset-refused-error.ts +12 -0
  271. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +2 -1
  272. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool-options.ts +3 -1
  273. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +58 -37
  274. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +15 -8
  275. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +32 -8
  276. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +89 -25
  277. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +4 -0
  278. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +51 -10
  279. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts +2 -1
  280. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  281. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +2 -13
  282. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  283. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +1 -0
  284. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
  285. package/node_modules/@earendil-works/pi-agent-core/dist/index.js +1 -0
  286. package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
  287. package/node_modules/@earendil-works/pi-agent-core/dist/tool-arguments.d.ts +5 -0
  288. package/node_modules/@earendil-works/pi-agent-core/dist/tool-arguments.d.ts.map +1 -0
  289. package/node_modules/@earendil-works/pi-agent-core/dist/tool-arguments.js +20 -0
  290. package/node_modules/@earendil-works/pi-agent-core/dist/tool-arguments.js.map +1 -0
  291. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  292. package/node_modules/@earendil-works/pi-ai/README.md +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +14 -56
  294. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +18 -27
  297. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts +40 -0
  299. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.d.ts.map +1 -0
  300. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js +102 -0
  301. package/node_modules/@earendil-works/pi-ai/dist/api/websocket-transport-failure.js.map +1 -0
  302. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts +4 -3
  303. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +28 -14
  305. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts +44 -0
  307. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.d.ts.map +1 -0
  308. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js +120 -0
  309. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-region.js.map +1 -0
  310. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts +2 -2
  311. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.d.ts.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js +2 -2
  313. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/failover.js.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +3 -0
  315. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
  316. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +21 -15
  317. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
  318. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +1 -0
  319. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
  320. package/node_modules/@earendil-works/pi-ai/dist/compat.js +1 -0
  321. package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
  322. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +2 -0
  323. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  324. package/node_modules/@earendil-works/pi-ai/dist/index.js +2 -0
  325. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-ai/dist/legacy-provider-ids.d.ts +8 -0
  327. package/node_modules/@earendil-works/pi-ai/dist/legacy-provider-ids.d.ts.map +1 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/legacy-provider-ids.js +26 -0
  329. package/node_modules/@earendil-works/pi-ai/dist/legacy-provider-ids.js.map +1 -0
  330. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  331. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  332. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-workers-ai.json +1 -1
  333. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  334. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  335. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  336. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  337. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  338. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  339. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  340. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json +1 -1
  341. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  342. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  343. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  344. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi.json +1 -1
  345. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts +9 -0
  346. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.d.ts.map +1 -0
  347. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js +43 -0
  348. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding-auth.js.map +1 -0
  349. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.d.ts.map +1 -1
  350. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js +3 -2
  351. package/node_modules/@earendil-works/pi-ai/dist/providers/kimi-coding.js.map +1 -1
  352. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts +19 -0
  353. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.d.ts.map +1 -0
  354. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js +63 -0
  355. package/node_modules/@earendil-works/pi-ai/dist/utils/provider-failure-description.js.map +1 -0
  356. package/node_modules/@earendil-works/pi-ai/dist/utils/retry-profile/classifiers.d.ts.map +1 -1
  357. package/node_modules/@earendil-works/pi-ai/dist/utils/retry-profile/classifiers.js +5 -1
  358. package/node_modules/@earendil-works/pi-ai/dist/utils/retry-profile/classifiers.js.map +1 -1
  359. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +17 -0
  360. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  361. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +22 -1
  362. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  363. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  364. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  365. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  366. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  367. package/node_modules/@earendil-works/pi-tui/dist/tui.js +12 -2
  368. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  369. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  370. package/package.json +7 -7
  371. package/dist/bundle/chunks/chunk-5J5R5AMP.js +0 -8
  372. package/dist/bundle/chunks/chunk-I3F6VZZF.js +0 -2
  373. package/dist/bundle/chunks/chunk-IDTLJYJ5.js +0 -10
  374. package/dist/bundle/chunks/chunk-U6Z6OBX4.js +0 -2
  375. package/dist/bundle/chunks/host-lifecycle-DGZJTBDJ.js +0 -3
  376. package/dist/bundle/chunks/multi-session-host-S5FWCIWE.js +0 -20
  377. package/dist/bundle/chunks/openai-codex-responses-L2PO2D6F.js +0 -10
  378. package/dist/bundle/chunks/openai-responses-YDUBVF4S.js +0 -2
  379. package/dist/bundle/chunks/rotation-stream-Y4YU6HV4.js +0 -2
@@ -56,11 +56,31 @@ export class PythonKernel {
56
56
  });
57
57
  }
58
58
 
59
- async interrupt(reason = "interrupted"): Promise<KernelInterruptHandle> {
59
+ cancelQueued(cellId: string, reason: string): boolean {
60
+ const pending = this.#queue.find((run) => run.input.cellId === cellId);
61
+ if (!pending) return false;
62
+ this.#settleRun(pending, failedPythonResult(cellId, reason));
63
+ return true;
64
+ }
65
+
66
+ queueSnapshot(): { activeCellId: string | null; queuedCellIds: readonly string[] } {
67
+ return {
68
+ activeCellId: this.#active?.input.cellId ?? null,
69
+ queuedCellIds: this.#queue.map((run) => run.input.cellId),
70
+ };
71
+ }
72
+
73
+ async interrupt(reason = "interrupted", cellId?: string): Promise<KernelInterruptHandle> {
60
74
  if (this.#failure) throw this.#failure;
61
- for (const pending of [...this.#queue]) {
62
- pending.interruptReason = reason;
63
- this.#settleRun(pending, failedPythonResult(pending.input.cellId, "Eval interrupted"));
75
+ if (cellId !== undefined && this.#active?.input.cellId !== cellId) {
76
+ const cancelled = this.cancelQueued(cellId, reason);
77
+ return { stateRetained: Promise.resolve(true), ...(cancelled ? {} : { note: "cell not found" }) };
78
+ }
79
+ if (cellId === undefined) {
80
+ for (const pending of [...this.#queue]) {
81
+ pending.interruptReason = reason;
82
+ this.#settleRun(pending, failedPythonResult(pending.input.cellId, "Eval interrupted"));
83
+ }
64
84
  }
65
85
  const active = this.#active;
66
86
  const transport = this.#transport;
@@ -155,6 +175,7 @@ export class PythonKernel {
155
175
  if (!pending || !this.#pending.has(pending.input.cellId)) return;
156
176
  this.#active = pending;
157
177
  pending.startedAt = performance.now();
178
+ pending.input.onStarted?.();
158
179
  const timeoutMs = pending.input.timeoutMs;
159
180
  if (timeoutMs !== undefined)
160
181
  pending.timeoutTimer = setTimeout(() => this.#timeoutRun(pending, timeoutMs), timeoutMs);
@@ -191,6 +212,14 @@ export class PythonKernel {
191
212
  if (this.#closed || generation !== this.#generation) throw new Error("Python kernel startup was superseded");
192
213
  this.#transport = await PythonKernelTransport.start({
193
214
  ...this.#options,
215
+ onMessage: (message) => {
216
+ if (message.type === "result") return;
217
+ const callback =
218
+ message.type === "ready" || message.type === "init-failed" || message.type === "closed"
219
+ ? this.#options.onMessage
220
+ : (this.#active?.input.onMessage ?? this.#options.onMessage);
221
+ callback?.(message);
222
+ },
194
223
  startupTimeoutMs: this.#options.startupTimeoutMs ?? startupTimeoutMs,
195
224
  isOwned: () => !this.#closed && generation === this.#generation,
196
225
  onRetirementFailure: (transport, error) => {
@@ -206,7 +235,10 @@ export class PythonKernel {
206
235
  #onResult(transport: PythonKernelTransport, result: ResultMessage): void {
207
236
  if (this.#transport !== transport) return;
208
237
  const pending = this.#pending.get(result.cellId);
209
- if (pending) this.#settleRun(pending, result);
238
+ if (pending) {
239
+ (pending.input.onMessage ?? this.#options.onMessage)?.(result);
240
+ this.#settleRun(pending, result);
241
+ }
210
242
  // A result frame from the live runner proves the process survived the interrupt.
211
243
  if (pending?.resolveStateRetained) pending.resolveStateRetained(true);
212
244
  }
@@ -529,9 +529,15 @@ def agent(
529
529
  schema: dict[str, Any] | None = None,
530
530
  isolated: bool | None = None,
531
531
  apply: bool | None = None,
532
- merge: bool | None = None,
532
+ merge: bool | str | None = None,
533
533
  handle: bool = False,
534
534
  ) -> Any:
535
+ """Delegate work; isolated/apply/merge need a host that supports isolation, otherwise a warning.
536
+
537
+ merge accepts "patch"/"branch" or False/True respectively. Unapplied foreground
538
+ changes raise an error with recovery instructions. A handle returns immediately;
539
+ await the completion notification or read task_output for the isolation result.
540
+ """
535
541
  args: dict[str, Any] = {"prompt": prompt}
536
542
  if agent is not None:
537
543
  args["agent"] = agent
@@ -546,7 +552,7 @@ def agent(
546
552
  if apply is not None:
547
553
  args["apply"] = bool(apply)
548
554
  if merge is not None:
549
- args["merge"] = bool(merge)
555
+ args["merge"] = merge
550
556
  if handle:
551
557
  args["handle"] = True
552
558
 
@@ -578,6 +584,9 @@ def agent(
578
584
  }
579
585
  if schema is not None:
580
586
  node["data"] = parsed
587
+ details = response_record.get("details")
588
+ if isinstance(details, dict) and "isolation" in details:
589
+ node["details"] = {"isolation": details["isolation"]}
581
590
  for key in (
582
591
  "isolated",
583
592
  "patch_path",
@@ -213,6 +213,10 @@ def output(*ids, format: "raw", offset: nil, limit: nil)
213
213
  __senpi_call_tool(SENPI_RESERVED_OUTPUT_TOOL, args)
214
214
  end
215
215
 
216
+ # isolated/apply/merge need a host that supports isolation; otherwise a warning.
217
+ # merge: "patch"/"branch" (false/true aliases). Unapplied foreground changes raise
218
+ # an error with recovery instructions. Handles return immediately: await completion
219
+ # notification or read task_output for the isolation result.
216
220
  def agent(prompt, agent: "task", model: nil, label: nil, schema: nil, isolated: nil, apply: nil, merge: nil, handle: false)
217
221
  args = { "prompt" => prompt.to_s, "agent" => agent }
218
222
  { "model" => model, "label" => label, "schema" => schema, "isolated" => isolated, "apply" => apply, "merge" => merge }.each do |key, value|
@@ -226,6 +230,8 @@ def agent(prompt, agent: "task", model: nil, label: nil, schema: nil, isolated:
226
230
  return result unless handle
227
231
  { "text" => text_value, "output" => text_value, "handle" => record["handle"] || (record["id"] && "agent://#{record["id"]}"), "id" => record["id"], "run_epoch" => record["run_epoch"], "agent" => record.fetch("agent", agent) }.tap do |node|
228
232
  node["data"] = result unless schema.nil?
233
+ details = record["details"]
234
+ node["details"] = { "isolation" => details["isolation"] } if details.is_a?(Hash) && details.key?("isolation")
229
235
  end
230
236
  end
231
237
 
@@ -1,12 +1,9 @@
1
1
  import type { BridgeConnectionConfig, KernelToHostMessage } from "../../bridge/protocol.ts";
2
+ import type { EvalKernelRunInput } from "../../tool/types.ts";
2
3
  import type { SessionEnvironment } from "../session-env.ts";
3
4
  import type { SubprocessSpawn } from "./subprocess-process.ts";
4
5
 
5
- export interface KernelRunInput {
6
- readonly cellId: string;
7
- readonly code: string;
8
- readonly timeoutMs?: number;
9
- }
6
+ export type KernelRunInput = EvalKernelRunInput;
10
7
 
11
8
  export type KernelResult = Extract<KernelToHostMessage, { type: "result" }>;
12
9
  export type ToolCallMessage = Extract<KernelToHostMessage, { type: "tool-call" }>;
@@ -49,12 +49,22 @@ export class SubprocessKernel {
49
49
  return run;
50
50
  }
51
51
 
52
- async interrupt(reason = "interrupted"): Promise<KernelInterruptHandle> {
52
+ cancelQueued(cellId: string, reason: string): boolean {
53
+ return this.runs.remove(cellId, reason);
54
+ }
55
+
56
+ queueSnapshot(): { activeCellId: string | null; queuedCellIds: readonly string[] } {
57
+ return this.runs.snapshot();
58
+ }
59
+
60
+ async interrupt(reason = "interrupted", cellId?: string): Promise<KernelInterruptHandle> {
61
+ if (cellId !== undefined && this.runs.active?.input.cellId !== cellId) {
62
+ const cancelled = this.cancelQueued(cellId, reason);
63
+ return { stateRetained: Promise.resolve(true), ...(cancelled ? {} : { note: "cell not found" }) };
64
+ }
53
65
  if (this.closed) return { stateRetained: Promise.resolve(true) };
54
66
  if (!this.runs.active) {
55
- if (!this.retirementPromise) return { stateRetained: Promise.resolve(true) };
56
- const queued = this.runs.takeWaiting();
57
- if (queued) this.runs.settle(queued, failureResult(queued, new CellInterruptedError(reason)));
67
+ this.runs.settleAll(new CellInterruptedError(reason));
58
68
  return { stateRetained: Promise.resolve(true) };
59
69
  }
60
70
  const process = this.process;
@@ -24,11 +24,24 @@ export class SubprocessRunQueue {
24
24
  const next = this.#queue.shift() ?? null;
25
25
  if (next) next.startedAt = startedAt;
26
26
  this.#active = next;
27
+ next?.input.onStarted?.();
27
28
  return next;
28
29
  }
29
30
 
30
- takeWaiting(): PendingRun | null {
31
- return this.#queue.shift() ?? null;
31
+ remove(cellId: string, reason = "interrupted"): boolean {
32
+ const index = this.#queue.findIndex((run) => run.input.cellId === cellId);
33
+ if (index < 0) return false;
34
+ const [run] = this.#queue.splice(index, 1);
35
+ if (!run) return false;
36
+ this.settle(run, failureResult(run, new Error(reason)));
37
+ return true;
38
+ }
39
+
40
+ snapshot(): { activeCellId: string | null; queuedCellIds: readonly string[] } {
41
+ return {
42
+ activeCellId: this.#active?.input.cellId ?? null,
43
+ queuedCellIds: this.#queue.map((run) => run.input.cellId),
44
+ };
32
45
  }
33
46
 
34
47
  releaseActive(run: PendingRun): boolean {
@@ -76,14 +89,14 @@ export class SubprocessRunQueue {
76
89
  case "result": {
77
90
  const run = this.#active;
78
91
  if (!run || run.input.cellId !== message.cellId) return false;
79
- onMessage?.(message);
92
+ (run.input.onMessage ?? onMessage)?.(message);
80
93
  this.releaseActive(run);
81
94
  this.settle(run, message);
82
95
  return true;
83
96
  }
84
97
  case "tool-call":
85
98
  if (!this.#active) return false;
86
- onMessage?.(message);
99
+ (this.#active.input.onMessage ?? onMessage)?.(message);
87
100
  this.pushToolCall(message);
88
101
  return false;
89
102
  case "text":
@@ -91,7 +104,7 @@ export class SubprocessRunQueue {
91
104
  case "log":
92
105
  case "phase":
93
106
  case "status":
94
- if (this.#active) onMessage?.(message);
107
+ if (this.#active) (this.#active.input.onMessage ?? onMessage)?.(message);
95
108
  return false;
96
109
  case "ready":
97
110
  case "init-failed":
@@ -26,7 +26,7 @@ Host: {{hostLine}} — cells execute here. Size \`parallel(thunks)\` pools to it
26
26
 
27
27
  \`language\`: {{#if py}}\`"py"\` IPython kernel{{/if}}{{#ifAll py js}}, {{/ifAll}}{{#if js}}\`"js"\` persistent JavaScript VM{{/if}}{{#if rb}}{{#ifAny py js}}, {{/ifAny}}\`"rb"\` persistent Ruby kernel{{/if}}{{#if jl}}{{#ifAny py js rb}}, {{/ifAny}}\`"jl"\` persistent Julia kernel{{/if}}.
28
28
 
29
- A cell that outlives the foreground window detaches: it keeps its language kernel busy (another language can continue) and completes as one notification with its value or error and buffered output. Its own execution time is capped at {{runBudgetSeconds}}s — time inside host tool calls is not charged; raise \`timeout\` only for a declared long run — and a killed js cell that cannot settle restarts its kernel with every global lost. Do not re-run a detached cell; read or cancel it with \`eval({ action: "peek", cell_id })\` / \`eval({ action: "stop", cell_id })\`.
29
+ A cell that outlives the foreground window detaches and keeps running; further cells on the same language queue behind it in submission order on the same kernel (state is shared, execution is serial) while other languages run at once, up to {{maxDetachedCells}} background cells per session; each detached cell completes as one notification. Do not re-run a detached or queued cell; read, cancel or enumerate them with \`eval({ action: "peek" | "stop", cell_id })\` / \`eval({ action: "list" })\`; list shows live and recently settled cells across languages without consuming notifications. Its own execution time is capped at {{runBudgetSeconds}}s — queue time and time inside host tool calls are not charged; the hard limit stays wall-clock from submission; raise \`timeout\` only for a declared long run — and a killed js cell that cannot settle restarts its kernel with every global lost.
30
30
 
31
31
  {{#if py}}Python runs on a live event loop: use top-level \`await\`; \`asyncio.run(…)\` raises.{{/if}}
32
32
  {{#if js}}{{#if jsBun}}JS runs in-process on Bun {{jsVersion}}: top-level \`await\`/\`return\` work; \`Bun.*\` builtins available, including \`new Bun.WebView()\` — a headless browser (navigate/click/evaluate/screenshot) to reach for before \`curl\` or a browser CLI when a page needs JS, a login, or a screenshot. Shell out through \`Bun.$\` or \`Bun.spawn\`, never \`Bun.spawnSync\`: a synchronous child blocks the worker and cannot be interrupted.{{#if bunSkillPath}} MUST READ the bun-1-4 skill at {{bunSkillPath}} before your first js cell — its builtins replace the npm packages you would otherwise install.{{/if}}{{else}}JS runs under Node.js worker: top-level \`await\`/\`return\` work; \`fetch\`/\`Buffer\` available.{{/if}}{{/if}}
@@ -56,7 +56,8 @@ tool_schema(name?) → dict
56
56
  Parameter schema of a tool (omit \`name\` to list tool names); a failed \`tool.<name>()\` call also returns the expected parameters.
57
57
  completion(prompt, model?="default", system?=None, schema?=None) → str | dict
58
58
  Oneshot, stateless. \`model\`: \`"smol"\` fast | \`"default"\` session | \`"slow"\` most capable. \`schema\` (JSON-Schema) → parsed structured output.
59
- {{#if spawns}}agent(prompt, agent?="{{spawnDefaultAgent}}", model?=None, label?=None, schema?=None, handle?=False) → str | dict
59
+ {{#if spawns}}agent(prompt, agent?="{{spawnDefaultAgent}}", model?=None, label?=None, schema?=None, isolated?=None, apply?=None, merge?=None, handle?=False) → str | dict
60
+ Isolation options need a host that supports isolation; otherwise a warning. \`merge\`: \`"patch"\`/\`"branch"\` (False/True aliases). Unapplied foreground changes throw with recovery instructions. Handles return immediately: await the completion notification or read \`task_output\` for the isolation result.
60
61
  Run a subagent → final output. \`agent\` picks a discovered agent. \`schema\` as in completion(). \`handle\` → workflow node { text, output, handle: \`agent://<id>\`, id, run_epoch, agent } (parsed under \`data\` with \`schema\`).
61
62
  {{/if}}workpool(agent, name, mode?) → { pool_id, push(items), close(), inspect(), cancel() }
62
63
  Thin host-tool adapter; agent is a plain-data spec. The host owns scheduling and keyed yields; explicitly close for automatic aggregate delivery. Requires the host workpool tool; omitted mode uses its default.
@@ -1,4 +1,4 @@
1
- import { DEFAULT_RUN_BUDGET_SECONDS } from "../config/settings.ts";
1
+ import { DEFAULT_MAX_DETACHED_CELLS, DEFAULT_RUN_BUDGET_SECONDS } from "../config/settings.ts";
2
2
  import type { EvalRuntimeInfo } from "../tool/types.ts";
3
3
  import { EVAL_PROMPT_TEMPLATE } from "./eval-prompt-template.ts";
4
4
 
@@ -30,6 +30,8 @@ export interface EvalPromptOptions {
30
30
  readonly bunSkillPath?: string;
31
31
  /** Kill deadline for a cell's own execution time, as configured; the description states it. */
32
32
  readonly runBudgetSeconds?: number;
33
+ /** Global background capacity advertised to the model. */
34
+ readonly maxDetachedCells?: number;
33
35
  }
34
36
 
35
37
  /** Prompt dialect for the eval-first batching emphasis. */
@@ -96,6 +98,7 @@ export function buildEvalPrompt(
96
98
  jsVersion: options.jsRuntime?.version ?? "",
97
99
  bunSkillPath: options.bunSkillPath ?? "",
98
100
  runBudgetSeconds: String(options.runBudgetSeconds ?? DEFAULT_RUN_BUDGET_SECONDS),
101
+ maxDetachedCells: String(options.maxDetachedCells ?? DEFAULT_MAX_DETACHED_CELLS),
99
102
  };
100
103
  const description = renderTemplate(EVAL_PROMPT_TEMPLATE, context)
101
104
  .replace(/\n{3,}/g, "\n\n")
@@ -15,6 +15,8 @@ export interface IdleTimeoutOptions {
15
15
  readonly timeoutMs: number;
16
16
  /** Defaults to {@link DEFAULT_MAX_PAUSE_GRACE_MS}; floored at `timeoutMs` so a pause never shortens the budget. */
17
17
  readonly maxPauseGraceMs?: number;
18
+ /** Optional absolute deadline that neither idle resets nor bridge pauses may extend. */
19
+ readonly deadlineMs?: number;
18
20
  readonly onTimeout: (event: IdleTimeoutEvent) => void;
19
21
  }
20
22
 
@@ -26,6 +28,7 @@ export interface TimeoutPauseHandle {
26
28
  export class IdleTimeout implements TimeoutPauseHandle {
27
29
  readonly #cellId: string;
28
30
  readonly #onTimeout: (event: IdleTimeoutEvent) => void;
31
+ readonly #absoluteDeadlineMs: number;
29
32
  readonly #controller = new AbortController();
30
33
  readonly signal = this.#controller.signal;
31
34
  readonly timeoutMs: number;
@@ -38,6 +41,7 @@ export class IdleTimeout implements TimeoutPauseHandle {
38
41
 
39
42
  constructor(options: IdleTimeoutOptions) {
40
43
  this.#cellId = options.cellId;
44
+ this.#absoluteDeadlineMs = options.deadlineMs ?? Number.POSITIVE_INFINITY;
41
45
  this.timeoutMs = Math.max(1, Math.floor(options.timeoutMs));
42
46
  this.maxPauseGraceMs = Math.max(
43
47
  this.timeoutMs,
@@ -78,7 +82,10 @@ export class IdleTimeout implements TimeoutPauseHandle {
78
82
 
79
83
  #arm(delayMs: number): void {
80
84
  this.#clearTimer();
81
- const timer = setTimeout(() => this.#expire(), Math.max(0, delayMs));
85
+ const timer = setTimeout(
86
+ () => this.#expire(),
87
+ Math.max(0, Math.min(delayMs, this.#absoluteDeadlineMs - Date.now())),
88
+ );
82
89
  timer.unref?.();
83
90
  this.#timer = timer;
84
91
  }
@@ -93,7 +100,7 @@ export class IdleTimeout implements TimeoutPauseHandle {
93
100
  if (this.#settled) return;
94
101
  const pausedDeadlineMs = this.#pausedDeadlineMs;
95
102
  if (this.#pauseDepth > 0 && pausedDeadlineMs === undefined) return;
96
- const deadlineMs = pausedDeadlineMs ?? this.#deadlineMs;
103
+ const deadlineMs = Math.min(pausedDeadlineMs ?? this.#deadlineMs, this.#absoluteDeadlineMs);
97
104
  const remainingMs = deadlineMs - Date.now();
98
105
  if (remainingMs > 0) {
99
106
  this.#arm(remainingMs);
@@ -26,6 +26,8 @@ anchor most suites).
26
26
  - Detached execution is a first-class state machine — snapshot, notification
27
27
  queue, spill-file notice, result conversion — never folded into ordinary
28
28
  cell execution.
29
+ - Cells enter `queued`, then `running`; detachment is orthogonal. Per-run kernel callbacks own output, never the latest language-level callback. Queued cells consume no run budget; the hard limit remains wall-clock from submission. Elapsed execution time starts at `runStartedAtMs`.
30
+ - `maxDetachedCells` (default 15, `SENPI_CODEMODE_MAX_DETACHED_CELLS` override) caps detached cells globally, including queued cells. Excess cells stay foreground until completion or the foreground deadline; queued stop preserves the active cell.
29
31
  - Unicode tree glyphs and status icons are intentional UI conventions.
30
32
 
31
33
  ## ANTI-PATTERNS
@@ -37,10 +37,12 @@ const NO_WATCHDOG: TimeoutPauseHandle & { dispose(): void } = {
37
37
 
38
38
  export class CellExecution {
39
39
  readonly #callerSignal: AbortSignal;
40
+ readonly #cellId: string;
40
41
  readonly #onAbort: (error: Error) => void;
41
42
  readonly #abortPromise: Promise<never>;
42
43
  readonly #detachedPromise: Promise<void>;
43
- readonly #watchdog: TimeoutPauseHandle & { dispose(): void };
44
+ readonly #timeoutFactory: EvalTimeoutFactory;
45
+ #watchdog: TimeoutPauseHandle & { dispose(): void };
44
46
  #rejectAbort: ((reason?: unknown) => void) | undefined;
45
47
  #resolveDetached: (() => void) | undefined;
46
48
  #kernel: EvalKernel | undefined;
@@ -48,7 +50,9 @@ export class CellExecution {
48
50
  #active = true;
49
51
 
50
52
  constructor(options: CellExecutionOptions) {
53
+ this.#timeoutFactory = options.timeoutFactory;
51
54
  this.#callerSignal = options.callerSignal;
55
+ this.#cellId = options.cellId;
52
56
  this.#onAbort = options.onAbort;
53
57
  this.#abortPromise = new Promise<never>((_resolve, reject) => {
54
58
  this.#rejectAbort = reject;
@@ -64,6 +68,7 @@ export class CellExecution {
64
68
  cellId: options.cellId,
65
69
  timeoutMs: idle.timeoutMs,
66
70
  maxPauseGraceMs: idle.maxPauseGraceMs,
71
+ deadlineMs: Date.now() + idle.maxPauseGraceMs,
67
72
  onTimeout: ({ error }) => idle.onTimeout(error),
68
73
  });
69
74
  this.#callerSignal.addEventListener("abort", this.#handleCallerAbort, {
@@ -83,6 +88,18 @@ export class CellExecution {
83
88
  this.#watchdog.resume();
84
89
  }
85
90
 
91
+ /** One final submission-window wait after background admission was refused; pauses cannot extend it. */
92
+ rearmIdle(timeoutMs: number, onTimeout: () => void): void {
93
+ this.#watchdog.dispose();
94
+ this.#watchdog = this.#timeoutFactory.create({
95
+ cellId: this.#cellId,
96
+ timeoutMs,
97
+ maxPauseGraceMs: timeoutMs,
98
+ deadlineMs: Date.now() + timeoutMs,
99
+ onTimeout,
100
+ });
101
+ }
102
+
86
103
  setKernel(kernel: EvalKernel): void {
87
104
  this.#kernel = kernel;
88
105
  }
@@ -130,7 +147,7 @@ export class CellExecution {
130
147
  return;
131
148
  }
132
149
  this.#interruptDeadline = setTimeout(() => this.#settleAbort(error), INTERRUPT_DELIVERY_GRACE_MS);
133
- const handle = Promise.resolve().then(async () => await kernel.interrupt(error.message));
150
+ const handle = Promise.resolve().then(async () => await kernel.interrupt(error.message, this.#cellId));
134
151
  this.interruptHandle = handle;
135
152
  void handle.then(
136
153
  () => this.#settleAbort(error),
@@ -12,6 +12,8 @@ export interface CellState {
12
12
  readonly input: EvalToolInput;
13
13
  readonly runtime?: EvalRuntimeInfo;
14
14
  readonly startedAt: number;
15
+ runStartedAt?: number | undefined;
16
+ queuedBehind?: readonly string[] | undefined;
15
17
  readonly signal: AbortSignal;
16
18
  readonly onUpdate: AgentToolUpdateCallback<EvalToolDetails> | undefined;
17
19
  readonly toolCalls: ToolCall[];
@@ -23,7 +25,7 @@ export interface CellState {
23
25
  phase: string | undefined;
24
26
  error: string | undefined;
25
27
  durationMs: number;
26
- status: "pending" | "running" | "complete" | "error";
28
+ status: "pending" | "queued" | "running" | "complete" | "error";
27
29
  }
28
30
 
29
31
  export interface CellResultBuilderOptions {
@@ -52,7 +54,7 @@ export class CellResultBuilder {
52
54
  this.emitUpdate(false);
53
55
  },
54
56
  });
55
- options.state.status = "running";
57
+ if (options.state.status !== "queued") options.state.status = "running";
56
58
  this.emitUpdate(false);
57
59
  }
58
60
 
@@ -145,7 +147,10 @@ export class CellResultBuilder {
145
147
  output: this.#state.output,
146
148
  status: this.#state.status,
147
149
  durationMs: this.#state.durationMs,
148
- startedAt: this.#state.startedAt,
150
+ ...(this.#state.status === "queued"
151
+ ? {}
152
+ : { startedAt: this.#state.runStartedAt ?? this.#state.startedAt }),
153
+ ...(this.#state.queuedBehind === undefined ? {} : { queuedBehind: this.#state.queuedBehind }),
149
154
  ...(statusEvents === undefined ? {} : { statusEvents }),
150
155
  ...(output?.hasMarkdown ? { hasMarkdown: true } : {}),
151
156
  },
@@ -158,6 +163,9 @@ export class CellResultBuilder {
158
163
  }
159
164
 
160
165
  #liveUpdateText(): string {
166
+ if (this.#state.status === "queued" && this.#state.queuedBehind?.length) {
167
+ return `queued behind ${this.#state.queuedBehind.join(", ")} in the ${this.#state.input.language} kernel`;
168
+ }
161
169
  const summary = this.#state.input.summary === undefined ? "" : ` ${this.#state.input.summary}`;
162
170
  const aggregateOutput = this.#output.aggregateText();
163
171
  const outputLines = aggregateOutput.split("\n");
@@ -2,12 +2,14 @@ import type { AgentToolResult } from "@code-yeongyu/senpi";
2
2
  import type { WakeSourceState } from "../extension/wake-source-state.ts";
3
3
  import type { EvalLanguage, EvalToolDetails } from "./types.ts";
4
4
 
5
- export type EvalDetachedCellState = "running" | "detached" | "completed" | "failed" | "cancelled";
5
+ export type EvalDetachedCellState = "queued" | "running" | "detached" | "completed" | "failed" | "cancelled";
6
6
 
7
7
  export interface EvalDetachedCellSnapshot {
8
8
  readonly cellId: string;
9
9
  readonly language: EvalLanguage;
10
+ readonly startedAtMs: number;
10
11
  readonly state: EvalDetachedCellState;
12
+ readonly queuedBehind?: readonly string[];
11
13
  readonly outputTail: string;
12
14
  readonly result: AgentToolResult<EvalToolDetails>;
13
15
  readonly stateRetained: boolean | undefined;
@@ -33,6 +35,7 @@ export interface EvalDetachedCellStatusEntry {
33
35
  readonly language: EvalLanguage;
34
36
  readonly summary?: string;
35
37
  readonly startedAtMs: number;
38
+ readonly queuedBehind?: readonly string[];
36
39
  }
37
40
 
38
41
  export interface EvalDetachedCellManagerOptions {
@@ -42,6 +45,8 @@ export interface EvalDetachedCellManagerOptions {
42
45
  readonly hardLimitSeconds?: number;
43
46
  /** Kill deadline for a cell's own execution time in seconds; a per-call `timeout` replaces it. Defaults to 300s. */
44
47
  readonly runBudgetSeconds?: number;
48
+ /** Global detached-cell capacity; defaults to 15. Full capacity keeps new cells foreground. */
49
+ readonly maxDetachedCells?: number;
45
50
  readonly onStatusChange?: (entries: readonly EvalDetachedCellStatusEntry[]) => void;
46
51
  /** Receives a full per-source liveness snapshot on every detached-cell transition; used by the goal builtin. */
47
52
  readonly onWakeSourceState?: (state: WakeSourceState) => void;