@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
@@ -93,6 +93,7 @@ Configuration is loaded in this order:
93
93
  "foregroundWindowSeconds": 60,
94
94
  "runBudgetSeconds": 300,
95
95
  "hardLimitSeconds": 1800,
96
+ "maxDetachedCells": 15,
96
97
  "parallelPoolWidth": 4,
97
98
  "taskTools": {
98
99
  "task": "task",
@@ -110,9 +111,10 @@ Configuration is loaded in this order:
110
111
  | --- | --- | --- |
111
112
  | `languages` | `py`/`js` enabled; `rb`/`jl` disabled | Selects desired languages before interpreter detection. |
112
113
  | `cellTimeoutSeconds` | `30` | Idle time an interactive call blocks the turn before the cell detaches. Print/json calls never detach. |
113
- | `foregroundWindowSeconds` | `60` | Caps `cellTimeoutSeconds` and the grace a bridge-parked cell gets before it detaches, so an interactive call never blocks the turn longer than this. Env override: `SENPI_CODEMODE_FOREGROUND_SECONDS`. |
114
- | `runBudgetSeconds` | `300` | Kill deadline for a cell's own execution time - child processes, network, timers, CPU. Time parked in host tool calls (`agent()`, `tool.*`) is not charged, and the budget keeps counting after the cell detaches. A per-call `timeout` replaces it for that cell. Env override: `SENPI_CODEMODE_RUN_BUDGET_SECONDS`. |
115
- | `hardLimitSeconds` | `1800` | Wall-clock kill deadline for a cell, parked or not; a per-call `timeout` above it raises it. Env override: `SENPI_CODEMODE_HARD_LIMIT_SECONDS`. |
114
+ | `foregroundWindowSeconds` | `60` | Submission-based foreground limit, including queue and bridge pauses. The cell detaches if capacity is available; otherwise it is cancelled with `eval_background_capacity_reached`. Env override: `SENPI_CODEMODE_FOREGROUND_SECONDS`. |
115
+ | `runBudgetSeconds` | `300` | Kill deadline for a cell's own execution time - child processes, network, timers, CPU. Time queued or parked in host tool calls (`agent()`, `tool.*`) is not charged, and the budget keeps counting after the cell detaches. A per-call `timeout` replaces it for that cell. Env override: `SENPI_CODEMODE_RUN_BUDGET_SECONDS`. |
116
+ | `hardLimitSeconds` | `1800` | Wall-clock kill deadline from submission, including queue and parked time; a per-call `timeout` above it raises it. Env override: `SENPI_CODEMODE_HARD_LIMIT_SECONDS`. |
117
+ | `maxDetachedCells` | `15` | Global detached-cell capacity across all kernels, including queued cells. At capacity, interactive cells stay foreground until completion or the foreground window elapses. Env override: `SENPI_CODEMODE_MAX_DETACHED_CELLS`. |
116
118
  | `parallelPoolWidth` | `4` | Maximum concurrent `parallel()` thunks. |
117
119
  | `taskTools.task` | `"task"` | Registered tool name used by `agent()`. |
118
120
  | `taskTools.output` | `"task_output"` | Registered tool name used by `output()`. |
@@ -126,6 +128,9 @@ enables; `0` or `false` disables. Any other value leaves the file setting in
126
128
  effect.
127
129
 
128
130
  Malformed JSON or invalid settings fall back to defaults with a warning.
131
+ The detached-cell environment override uses the run-budget parser: a positive
132
+ base-10 integer wins over the file value; zero, negative, and malformed values
133
+ leave the file value in effect.
129
134
 
130
135
  ## Cell helpers
131
136
 
@@ -162,13 +167,25 @@ tasks return the requested transcript. Missing tools produce a clear
162
167
  availability error instead of importing an orchestration package. `agent()`
163
168
  delegates through the tool contract, so task-engine permissions, progress
164
169
  updates, and transcripts remain owned by that engine.
165
- `isolated`, `apply`, and `merge` are accepted for compatibility but emit a
166
- warning because this task-engine integration has no isolation model.
170
+ `isolated` and `apply` accept booleans; `merge` accepts `"patch"` or `"branch"`
171
+ (and `false`/`true` aliases respectively). The bridge checks the configured task
172
+ parameter schema once per bridge, using the same host catalog as `tool_schema()`.
173
+ If it advertises `isolated`, these options are forwarded; otherwise they are
174
+ omitted with the existing warning. Senpi does not implement isolation itself.
175
+ A foreground host result with `details.isolation.changes_applied === false`
176
+ raises `AgentIsolationNotAppliedError` (`isolation_not_applied`), including any
177
+ `patch_path`, `branch_name`, and `manual_command` recovery fields in its message.
178
+ The bridge retains host `details.isolation`; successful foreground helpers still
179
+ return text or parsed JSON.
167
180
 
168
181
  Background `agent()` handles retain `id` and `agent://<id>` and include `run_epoch`.
169
182
  The host must return structured `details.task_id` (`st_` plus lowercase hex) and
170
183
  an integer `details.run_epoch >= 0`. Missing or malformed details raise
171
- `invalid_task_handle`; prose IDs are never used. Foreground text/JSON is unchanged.
184
+ `invalid_task_handle`; prose IDs are never used. Handles return immediately,
185
+ so final isolation results are not available on the initial handle: await the
186
+ completion notification or read `task_output` (via `output()`) after completion.
187
+ Any isolation metadata supplied by the host on a handle is preserved as
188
+ `details.isolation`, not interpreted as a foreground apply failure.
172
189
 
173
190
  `workpool` takes exactly one of `{category, prompt, model?}` or
174
191
  `{subagent_type, prompt, model?}` as its plain-data agent spec. Mode is `fresh`
@@ -203,22 +220,28 @@ without a `summary` fails with a teaching error.
203
220
  `eval` accepts `on_timeout: "detach"|"error"`. The default is `"detach"` in
204
221
  interactive TUI, RPC, and app-server sessions; print and JSON one-shot runs
205
222
  default to `"error"` so their result is never silently detached. A detached
206
- cell keeps only its own language kernel busy. A new same-language call returns
207
- a busy error with its cell id and output tail; calls in other languages continue
208
- normally. Do not re-run the cell.
223
+ cell keeps only its own language kernel busy. New same-language cells are admitted
224
+ into its FIFO queue; calls in other languages continue normally. Queued cells may
225
+ also detach, within the global `maxDetachedCells` cap. At capacity, the first idle
226
+ detach attempt leaves the cell foreground and re-arms one wait for the remaining
227
+ submission-based foreground window. At the window, it detaches if a slot is now
228
+ free; otherwise it settles `cancelled` with `eval_background_capacity_reached`,
229
+ listing the live cells and a stop-or-wait remedy. Cells that complete inside the
230
+ window return normally. Cancelling a queued cell never interrupts its predecessor.
231
+ Do not re-run a detached or queued cell; each detached cell completes as one notification.
209
232
 
210
233
  Queued steering also detaches an eligible interactive foreground call, including
211
234
  one paused in a host tool bridge, without cancelling its computation. If the
212
- language's detached slot is occupied, steering leaves the call waiting. Follow-up
235
+ global detached cap is reached, steering leaves the call waiting. Follow-up
213
236
  messages, explicit `on_timeout: "error"`, and print/JSON calls do not trigger this
214
237
  transition; caller abort and existing deadlines retain their cancellation behavior.
215
238
 
216
239
  Every cell, detached or not, is bounded by two kill deadlines. The run budget
217
240
  (`runBudgetSeconds`, or the call's `timeout`) charges only the cell's own
218
- execution time and is paused while a host tool call is in flight, so a cell
241
+ execution time and is paused while queued or while a host tool call is in flight, so a cell
219
242
  waiting on `agent()` survives while a runaway child process or loop does not.
220
243
  The hard limit (`hardLimitSeconds`, raised by a larger `timeout`) is wall-clock
221
- and bounds parked cells too. A cell killed by either deadline reports which one
244
+ from submission and bounds queued and parked cells too. A cell killed by either deadline reports which one
222
245
  in its result or completion notification, together with whether kernel state
223
246
  survived; the tool schema states the configured numbers. The `timeout` value
224
247
  never changes the idle detach deadline: that is `cellTimeoutSeconds` capped by
@@ -227,9 +250,24 @@ never changes the idle detach deadline: that is `cellTimeoutSeconds` capped by
227
250
  While any cell is detached, the interactive footer shows a highlighted
228
251
  `↗ <language> · <summary>` status on the extension status line (the cell id
229
252
  when the call had no summary), clearing as soon as the last detached cell settles.
253
+ Queued entries are labelled `queued`; an all-queued footer shows `(queued)` instead
254
+ of an elapsed duration. Elapsed time counts only from execution start.
255
+
256
+ Use `eval({ action: "list" })` without a language or cell id to see live and
257
+ recently settled cells across languages. Each line includes the id, language,
258
+ state, elapsed execution seconds, queue predecessors, and summary (or a short code
259
+ preview); `details.cells` carries the typed cell metadata. Listing never consumes
260
+ completion notifications.
261
+
262
+ A run with `reset: true` resets only its selected language and is refused with
263
+ `eval_kernel_busy_reset_refused` while any other cell in that language is live,
264
+ including queued cells. The requesting cell fails without changing the kernel or
265
+ cancelling existing work. Stop those cells explicitly or wait for their completion
266
+ notifications before resetting; live cells in other languages do not block reset.
230
267
 
231
268
  Use `eval({ action: "peek", cell_id })` for its state and buffered output, or
232
- `eval({ action: "stop", cell_id })` to cancel it. Python stop interrupts the
269
+ `eval({ action: "stop", cell_id })` to cancel it. Stopping a queued cell removes it
270
+ without interrupting the active cell; kernel state is retained. Python running-cell stop interrupts the
233
271
  existing kernel and preserves variables. JavaScript stop is cooperative first:
234
272
  the worker rejects the cell's pending bridge `tool.*` calls and kills the
235
273
  `Bun.spawn` children it started, and a cell that settles within the 2 s grace
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.9.21-2",
3
+ "version": "2026.9.22-2",
4
4
  "private": true,
5
5
  "description": "Source-only senpi extension package for codemode evaluation tools",
6
6
  "type": "module",
@@ -31,14 +31,14 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@babel/parser": "8.0.4",
34
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.21-2",
34
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.22-2",
35
35
  "typebox": "1.3.34"
36
36
  },
37
37
  "peerDependencies": {
38
- "@code-yeongyu/senpi": "2026.9.21-2"
38
+ "@code-yeongyu/senpi": "2026.9.22-2"
39
39
  },
40
40
  "devDependencies": {
41
- "@code-yeongyu/senpi": "2026.9.21-2"
41
+ "@code-yeongyu/senpi": "2026.9.22-2"
42
42
  },
43
43
  "keywords": [
44
44
  "senpi",
@@ -2,6 +2,7 @@ import type { AgentToolResult } from "@code-yeongyu/senpi";
2
2
  import { type Static, Type } from "typebox";
3
3
  import { Check, Errors } from "typebox/value";
4
4
  import type { EvalStatusEvent, ExecuteTool } from "../tool/types.ts";
5
+ import type { EvalSchemaToolInfo } from "./schema-bridge.ts";
5
6
 
6
7
  const agentArgsSchema = Type.Object(
7
8
  {
@@ -14,7 +15,7 @@ const agentArgsSchema = Type.Object(
14
15
  tools: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
15
16
  isolated: Type.Optional(Type.Boolean()),
16
17
  apply: Type.Optional(Type.Boolean()),
17
- merge: Type.Optional(Type.Boolean()),
18
+ merge: Type.Optional(Type.Union([Type.Boolean(), Type.Literal("patch"), Type.Literal("branch")])),
18
19
  },
19
20
  { additionalProperties: false },
20
21
  );
@@ -43,6 +44,9 @@ type TaskParams = {
43
44
  readonly name?: string;
44
45
  readonly run_in_background: boolean;
45
46
  readonly tools?: readonly string[];
47
+ readonly isolated?: boolean;
48
+ readonly apply?: boolean;
49
+ readonly merge?: "patch" | "branch";
46
50
  };
47
51
  type ProgressContext = { readonly fallbackId: string; readonly warning?: string };
48
52
 
@@ -54,15 +58,32 @@ export interface RunEvalAgentOptions {
54
58
  readonly callId: string;
55
59
  readonly taskToolName: string;
56
60
  readonly executeTool: AgentExecuteTool;
61
+ readonly listTools?: () => readonly EvalSchemaToolInfo[];
57
62
  readonly signal?: AbortSignal;
58
63
  readonly emitStatus?: (event: EvalStatusEvent) => void;
59
64
  }
60
65
 
61
- export type EvalAgentResult =
66
+ export type EvalAgentResult = (
62
67
  | { readonly text: string }
63
68
  | { readonly text: string; readonly data: unknown }
64
69
  | { readonly text: string; readonly parseError: string }
65
- | { readonly text: string; readonly id: string; readonly handle: string; readonly run_epoch: number };
70
+ | { readonly text: string; readonly id: string; readonly handle: string; readonly run_epoch: number }
71
+ ) & { readonly details?: { readonly isolation: Readonly<Record<string, unknown>> } };
72
+
73
+ // The session-owned executor identifies a bridge across JS and HTTP calls; do not retain retired sessions.
74
+ const isolationCapabilities = new WeakMap<AgentExecuteTool, Map<string, boolean>>();
75
+
76
+ export class AgentIsolationNotAppliedError extends Error {
77
+ readonly name = "AgentIsolationNotAppliedError";
78
+ readonly code = "isolation_not_applied";
79
+
80
+ constructor(isolation: Readonly<Record<string, unknown>>) {
81
+ const recovery = ["patch_path", "branch_name", "manual_command"]
82
+ .flatMap((key) => (typeof isolation[key] === "string" ? [`${key}: ${isolation[key]}`] : []))
83
+ .join("; ");
84
+ super(`agent() isolated changes were not applied${recovery ? `; ${recovery}` : ""}`);
85
+ }
86
+ }
66
87
 
67
88
  class AgentArgumentsError extends Error {
68
89
  readonly name = "AgentArgumentsError";
@@ -92,7 +113,8 @@ class AgentHandleError extends Error {
92
113
  export async function runEvalAgent(args: unknown, options: RunEvalAgentOptions): Promise<EvalAgentResult> {
93
114
  const parsed = parseAgentArgs(args);
94
115
  const structured = Object.hasOwn(parsed, "schema");
95
- const warning = droppedOptionsWarning(parsed);
116
+ const supportsIsolation = taskSupportsIsolation(options);
117
+ const warning = supportsIsolation ? undefined : droppedOptionsWarning(parsed);
96
118
  const fallbackId = parsed.label ?? options.callId;
97
119
  if (warning) options.emitStatus?.({ op: "agent", id: fallbackId, status: "running", warning });
98
120
 
@@ -104,7 +126,7 @@ export async function runEvalAgent(args: unknown, options: RunEvalAgentOptions):
104
126
 
105
127
  let result: AgentToolResult<unknown>;
106
128
  try {
107
- result = await options.executeTool(options.taskToolName, toTaskParams(parsed, structured), {
129
+ result = await options.executeTool(options.taskToolName, toTaskParams(parsed, structured, supportsIsolation), {
108
130
  ...(options.signal ? { signal: options.signal } : {}),
109
131
  ...(options.emitStatus
110
132
  ? {
@@ -119,12 +141,15 @@ export async function runEvalAgent(args: unknown, options: RunEvalAgentOptions):
119
141
  }
120
142
 
121
143
  const text = resultText(result);
144
+ const isolation =
145
+ isRecord(result.details) && isRecord(result.details.isolation) ? result.details.isolation : undefined;
146
+ const metadata = isolation === undefined ? {} : { details: { isolation } };
122
147
  if (parsed.handle === true) {
123
148
  const { task_id: id, run_epoch } = resultTaskHandle(result);
124
- return { text, id, handle: `agent://${id}`, run_epoch };
149
+ return { text, id, handle: `agent://${id}`, run_epoch, ...metadata };
125
150
  }
126
- if (!structured) return { text };
127
- return parseStructuredText(text);
151
+ if (isolation?.changes_applied === false) throw new AgentIsolationNotAppliedError(isolation);
152
+ return { ...(structured ? parseStructuredText(text) : { text }), ...metadata };
128
153
  }
129
154
 
130
155
  function parseAgentArgs(value: unknown): AgentArgs {
@@ -135,7 +160,21 @@ function parseAgentArgs(value: unknown): AgentArgs {
135
160
  throw new AgentArgumentsError(summary || "invalid value");
136
161
  }
137
162
 
138
- function toTaskParams(args: AgentArgs, structured: boolean): TaskParams {
163
+ function taskSupportsIsolation(options: RunEvalAgentOptions): boolean {
164
+ let capabilities = isolationCapabilities.get(options.executeTool);
165
+ if (!capabilities) {
166
+ capabilities = new Map();
167
+ isolationCapabilities.set(options.executeTool, capabilities);
168
+ }
169
+ const cached = capabilities.get(options.taskToolName);
170
+ if (cached !== undefined) return cached;
171
+ const schema = options.listTools?.().find((tool) => tool.name === options.taskToolName)?.parameters;
172
+ const supported = isRecord(schema) && isRecord(schema.properties) && schema.properties.isolated !== undefined;
173
+ capabilities.set(options.taskToolName, supported);
174
+ return supported;
175
+ }
176
+
177
+ function toTaskParams(args: AgentArgs, structured: boolean, supportsIsolation: boolean): TaskParams {
139
178
  return {
140
179
  prompt: structured
141
180
  ? `${args.prompt}\n\nRespond ONLY with JSON matching this JSON-Schema:\n${JSON.stringify(args.schema)}`
@@ -145,6 +184,11 @@ function toTaskParams(args: AgentArgs, structured: boolean): TaskParams {
145
184
  ...(args.label === undefined ? {} : { name: args.label }),
146
185
  run_in_background: args.handle === true,
147
186
  ...(args.tools === undefined ? {} : { tools: args.tools }),
187
+ ...(supportsIsolation && args.isolated !== undefined ? { isolated: args.isolated } : {}),
188
+ ...(supportsIsolation && args.apply !== undefined ? { apply: args.apply } : {}),
189
+ ...(supportsIsolation && args.merge !== undefined
190
+ ? { merge: args.merge === true ? "branch" : args.merge === false ? "patch" : args.merge }
191
+ : {}),
148
192
  };
149
193
  }
150
194
 
@@ -35,6 +35,7 @@ export async function runReservedTool(toolName: string, context: ReservedDispatc
35
35
  callId: context.callId,
36
36
  taskToolName: context.taskToolName,
37
37
  executeTool: context.executeTool,
38
+ ...(context.listTools === undefined ? {} : { listTools: context.listTools }),
38
39
  ...(context.signal === undefined ? {} : { signal: context.signal }),
39
40
  emitStatus: context.emitStatus,
40
41
  });
@@ -22,6 +22,7 @@ export const codemodeSettingsSchema = Type.Object(
22
22
  foregroundWindowSeconds: Type.Optional(Type.Number({ minimum: 1 })),
23
23
  runBudgetSeconds: Type.Optional(Type.Number({ minimum: 1 })),
24
24
  hardLimitSeconds: Type.Optional(Type.Number({ minimum: 1 })),
25
+ maxDetachedCells: Type.Optional(Type.Number({ minimum: 1 })),
25
26
  parallelPoolWidth: Type.Optional(Type.Number({ minimum: 1 })),
26
27
  taskTools: Type.Optional(
27
28
  Type.Object(
@@ -80,6 +81,8 @@ export interface CodemodeSettings {
80
81
  readonly runBudgetSeconds: number;
81
82
  /** Wall-clock kill deadline for a single cell; bounds detached and bridge-parked cells too. */
82
83
  readonly hardLimitSeconds: number;
84
+ /** Maximum detached cells across all language kernels. */
85
+ readonly maxDetachedCells?: number;
83
86
  readonly parallelPoolWidth: number;
84
87
  readonly taskTools?: CodemodeTaskTools;
85
88
  readonly outputSink?: CodemodeOutputSink;
@@ -87,6 +90,7 @@ export interface CodemodeSettings {
87
90
  }
88
91
 
89
92
  export type ResolvedCodemodeSettings = CodemodeSettings & {
93
+ readonly maxDetachedCells: number;
90
94
  readonly taskTools: CodemodeTaskTools;
91
95
  readonly outputSink: CodemodeOutputSink;
92
96
  readonly statusEvents: boolean;
@@ -129,7 +133,10 @@ export const FOREGROUND_WINDOW_ENVIRONMENT_FLAG = "SENPI_CODEMODE_FOREGROUND_SEC
129
133
  */
130
134
  export const DEFAULT_RUN_BUDGET_SECONDS = 300;
131
135
 
136
+ export const DEFAULT_MAX_DETACHED_CELLS = 15;
137
+
132
138
  export const RUN_BUDGET_ENVIRONMENT_FLAG = "SENPI_CODEMODE_RUN_BUDGET_SECONDS";
139
+ export const MAX_DETACHED_CELLS_ENVIRONMENT_FLAG = "SENPI_CODEMODE_MAX_DETACHED_CELLS";
133
140
 
134
141
  // OMP settings-schema.ts:3211-3299 has language/path settings only; eval.ts:427
135
142
  // defaults timeout to 30s, and codemode pins concurrency-bridge.ts:30 width to 4.
@@ -144,6 +151,7 @@ export const defaultCodemodeSettings: ResolvedCodemodeSettings = {
144
151
  foregroundWindowSeconds: DEFAULT_FOREGROUND_WINDOW_SECONDS,
145
152
  runBudgetSeconds: DEFAULT_RUN_BUDGET_SECONDS,
146
153
  hardLimitSeconds: DEFAULT_HARD_LIMIT_SECONDS,
154
+ maxDetachedCells: DEFAULT_MAX_DETACHED_CELLS,
147
155
  parallelPoolWidth: 4,
148
156
  taskTools: {
149
157
  task: "task",
@@ -207,6 +215,15 @@ export function resolveRunBudgetSeconds(settings: CodemodeSettings, env: Environ
207
215
  return positiveSecondsOverride(env[RUN_BUDGET_ENVIRONMENT_FLAG]) ?? settings.runBudgetSeconds;
208
216
  }
209
217
 
218
+ /** Uses the same positive-integer environment parsing as the run budget. */
219
+ export function resolveMaxDetachedCells(settings: CodemodeSettings, env: Environment = process.env): number {
220
+ return (
221
+ positiveSecondsOverride(env[MAX_DETACHED_CELLS_ENVIRONMENT_FLAG]) ??
222
+ settings.maxDetachedCells ??
223
+ DEFAULT_MAX_DETACHED_CELLS
224
+ );
225
+ }
226
+
210
227
  function positiveSecondsOverride(value: string | undefined): number | undefined {
211
228
  if (value === undefined) return undefined;
212
229
  const parsed = Number.parseInt(value, 10);
@@ -250,6 +267,7 @@ function mergeSettings(input: CodemodeSettingsInput): ResolvedCodemodeSettings {
250
267
  foregroundWindowSeconds: input.foregroundWindowSeconds ?? defaultCodemodeSettings.foregroundWindowSeconds,
251
268
  runBudgetSeconds: input.runBudgetSeconds ?? defaultCodemodeSettings.runBudgetSeconds,
252
269
  hardLimitSeconds: input.hardLimitSeconds ?? defaultCodemodeSettings.hardLimitSeconds,
270
+ maxDetachedCells: input.maxDetachedCells ?? DEFAULT_MAX_DETACHED_CELLS,
253
271
  parallelPoolWidth: input.parallelPoolWidth ?? defaultCodemodeSettings.parallelPoolWidth,
254
272
  taskTools: {
255
273
  task: input.taskTools?.task ?? defaultCodemodeSettings.taskTools.task,
@@ -28,7 +28,8 @@ function packLabels(labels: readonly string[], budget: number): string {
28
28
  }
29
29
 
30
30
  function labelOf(entry: EvalDetachedCellStatusEntry): string {
31
- return entry.summary === undefined || entry.summary.length === 0 ? entry.cellId : entry.summary;
31
+ const label = entry.summary === undefined || entry.summary.length === 0 ? entry.cellId : entry.summary;
32
+ return entry.queuedBehind === undefined ? label : `queued ${label}`;
32
33
  }
33
34
 
34
35
  /**
@@ -52,10 +53,12 @@ export function formatElapsedSeconds(value: number): string {
52
53
  return `${hours}h ${remainingMinutes}m`;
53
54
  }
54
55
 
55
- /** Whole seconds since the oldest detached cell was created; never negative on clock skew. */
56
+ /** Whole seconds since the oldest executing detached cell started; queued cells do not tick. */
56
57
  export function evalCellElapsedSeconds(entries: readonly EvalDetachedCellStatusEntry[], nowMs: number): number {
57
58
  let oldest = Number.POSITIVE_INFINITY;
58
- for (const entry of entries) oldest = Math.min(oldest, entry.startedAtMs);
59
+ for (const entry of entries) {
60
+ if (entry.queuedBehind === undefined) oldest = Math.min(oldest, entry.startedAtMs);
61
+ }
59
62
  if (!Number.isFinite(oldest)) return 0;
60
63
  return Math.max(0, Math.round((nowMs - oldest) / 1000));
61
64
  }
@@ -67,7 +70,9 @@ export function formatEvalCellStatus(
67
70
  ): string | undefined {
68
71
  const first = entries[0];
69
72
  if (first === undefined) return undefined;
70
- const suffix = ` (${formatElapsedSeconds(evalCellElapsedSeconds(entries, nowMs))})`;
73
+ const suffix = entries.every((entry) => entry.queuedBehind !== undefined)
74
+ ? " (queued)"
75
+ : ` (${formatElapsedSeconds(evalCellElapsedSeconds(entries, nowMs))})`;
71
76
  if (entries.length === 1) {
72
77
  const head = `${DETACHED_GLYPH} ${first.language} · `;
73
78
  return head + truncateEnd(labelOf(first), MAX_STATUS_LENGTH - head.length - suffix.length) + suffix;
@@ -7,6 +7,7 @@ import {
7
7
  defaultCodemodeSettings,
8
8
  resolveForegroundWindowSeconds,
9
9
  resolveHardLimitSeconds,
10
+ resolveMaxDetachedCells,
10
11
  resolveRunBudgetSeconds,
11
12
  } from "./config/settings.ts";
12
13
  import { EvalNotifier } from "./extension/eval-notifier.ts";
@@ -113,6 +114,9 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
113
114
  statusTicker.sync(entries);
114
115
  };
115
116
  const emitWakeSourceState = (state: WakeSourceState): void => {
117
+ // Same dual publication as the settle payload below: the in-process bus
118
+ // feeds the TUI footer, the rpc channel feeds out-of-process consumers.
119
+ pi.rpc?.emit(WAKE_SOURCE_STATE_EVENT, state);
116
120
  pi.events?.emit(WAKE_SOURCE_STATE_EVENT, state);
117
121
  };
118
122
  const registerEvalForRuntime = (
@@ -181,6 +185,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
181
185
  settings: defaultCodemodeSettings,
182
186
  cellManager: new EvalDetachedCellManager({
183
187
  notifier,
188
+ maxDetachedCells: resolveMaxDetachedCells(defaultCodemodeSettings),
184
189
  hardLimitSeconds: resolveHardLimitSeconds(defaultCodemodeSettings),
185
190
  runBudgetSeconds: resolveRunBudgetSeconds(defaultCodemodeSettings),
186
191
  onStatusChange: showDetachedCells,
@@ -219,6 +224,7 @@ export default function senpiCodemode(pi: CodemodeExtensionAPI, options: SenpiCo
219
224
  const cellManager = new EvalDetachedCellManager({
220
225
  artifactsDir: runtime.artifactsDir,
221
226
  notifier,
227
+ maxDetachedCells: resolveMaxDetachedCells(runtime.settings),
222
228
  hardLimitSeconds: resolveHardLimitSeconds(runtime.settings),
223
229
  runBudgetSeconds: resolveRunBudgetSeconds(runtime.settings),
224
230
  onStatusChange: showDetachedCells,
@@ -28,8 +28,8 @@ runner/prelude assets).
28
28
  AST-parsed (Babel) and rewritten to bridge-compatible dynamic imports.
29
29
  - JS runs on worker threads with an inline-worker fallback; py/rb/jl run as
30
30
  framed subprocesses through `shared/`.
31
- - Subprocess retirement/restart, worker recovery, timeout, and interrupt
32
- semantics live here, never in the tool layer.
31
+ - Each language keeps one serial FIFO kernel. Queued cancellation removes only
32
+ that cell; active interruption and runtime recovery stay in the kernel layer.
33
33
  - Every kernel exposes the active session's `PI_*` environment (`session-env.ts`):
34
34
  inherited values are deleted before the session's values are applied, so any
35
35
  child spawned from a cell sees the same session environment a bash-tool child
@@ -254,6 +254,12 @@ function output(ids...; format="raw", offset=nothing, limit=nothing)
254
254
  senpi_with_bridge_timeout_pause(() -> senpi_call_tool("__output__", arguments))
255
255
  end
256
256
 
257
+ """
258
+ Delegate work with isolated/apply/merge; needs a host that supports isolation, otherwise a warning.
259
+ merge accepts "patch"/"branch" (false/true aliases). Unapplied foreground changes raise
260
+ an error with recovery instructions. Handles return immediately: await the completion
261
+ notification or read task_output for the isolation result.
262
+ """
257
263
  function agent(prompt::AbstractString; agent="task", model=nothing, label=nothing, schema=nothing, isolated=nothing, apply=nothing, merge=nothing, handle=false, kwargs...)
258
264
  arguments = Dict{String, Any}("prompt" => string(prompt), "agent" => agent)
259
265
  for (key, value) in (("model", model), ("label", label), ("schema", schema), ("isolated", isolated), ("apply", apply), ("merge", merge))
@@ -272,6 +278,10 @@ function agent(prompt::AbstractString; agent="task", model=nothing, label=nothin
272
278
  result["handle"] = get(record, "handle", result["id"] === nothing ? nothing : "agent://" * string(result["id"]))
273
279
  result["run_epoch"] = get(record, "run_epoch", nothing)
274
280
  schema !== nothing && (result["data"] = parsed)
281
+ details = get(record, "details", nothing)
282
+ if details isa AbstractDict && haskey(details, "isolation")
283
+ result["details"] = Dict("isolation" => details["isolation"])
284
+ end
275
285
  result
276
286
  end
277
287
 
@@ -90,13 +90,26 @@ export class JavaScriptKernel {
90
90
  return await promise;
91
91
  }
92
92
 
93
- async interrupt(reason = "interrupted"): Promise<KernelInterruptHandle> {
93
+ cancelQueued(cellId: string, reason: string): boolean {
94
+ return this.#runs.remove(cellId, reason);
95
+ }
96
+
97
+ queueSnapshot(): { activeCellId: string | null; queuedCellIds: readonly string[] } {
98
+ return this.#runs.snapshot();
99
+ }
100
+
101
+ async interrupt(reason = "interrupted", cellId?: string): Promise<KernelInterruptHandle> {
94
102
  assertJavaScriptKernelOpen(this.#lifecycle, "interrupt");
95
103
  const active = this.#runs.active;
104
+ if (cellId !== undefined && active?.input.cellId !== cellId) {
105
+ const cancelled = this.cancelQueued(cellId, reason);
106
+ return { stateRetained: Promise.resolve(true), ...(cancelled ? {} : { note: "cell not found" }) };
107
+ }
96
108
  if (!active) {
97
- const queued = this.#runs.takeInterruptTarget();
98
- if (!queued) return { stateRetained: Promise.resolve(true) };
99
- this.#runs.settle(queued, stoppedResult(queued.input.cellId, `JS cell interrupted: ${reason}`));
109
+ // A worker still stuck in startup is not a healthy idle worker: retiring it is the only recovery.
110
+ const wedgedInStartup = this.#slot.startingUp;
111
+ this.#runs.settleAll(`JS cell interrupted: ${reason}`);
112
+ if (!wedgedInStartup) return { stateRetained: Promise.resolve(true) };
100
113
  await this.#restartAfterStop();
101
114
  return { stateRetained: Promise.resolve(false) };
102
115
  }
@@ -262,8 +275,7 @@ export class JavaScriptKernel {
262
275
  this.#trackChildEvent(message.event);
263
276
  return;
264
277
  }
265
- this.#options.onMessage?.(message);
266
- this.#runs.active?.input.onMessage?.(message);
278
+ (this.#runs.active?.input.onMessage ?? this.#options.onMessage)?.(message);
267
279
  if (message.type === "tool-call") {
268
280
  const waiter = this.#toolWaiters.shift();
269
281
  if (waiter) waiter(message);
@@ -1,4 +1,5 @@
1
1
  import type { KernelToHostMessage } from "../../bridge/protocol.ts";
2
+ import type { EvalKernelRunInput } from "../../tool/types.ts";
2
3
  import type { SessionEnvironment } from "../session-env.ts";
3
4
 
4
5
  export type ResultMessage = Extract<KernelToHostMessage, { type: "result" }>;
@@ -28,12 +29,7 @@ export interface JavaScriptKernelOptions {
28
29
  readonly foreignLanguageNames?: KernelToolNameSource;
29
30
  }
30
31
 
31
- export interface JavaScriptRunInput {
32
- readonly cellId: string;
33
- readonly code: string;
34
- readonly timeoutMs?: number;
35
- readonly onMessage?: (message: KernelToHostMessage) => void;
36
- }
32
+ export type JavaScriptRunInput = EvalKernelRunInput;
37
33
 
38
34
  export type KernelOperation = "run" | "reset" | "interrupt";
39
35
  export type LifecycleState = "open" | "closing" | "closed";
@@ -10,7 +10,7 @@ export const JAVASCRIPT_KERNEL_PRELUDE = [
10
10
  "tool(fn, metadata?): register a named JavaScript function as a fenced kernel tool for in-process children.",
11
11
  "completion(prompt, options?): request a host completion bridge call.",
12
12
  "output(...ids, options?): retrieve task output through the reserved output bridge.",
13
- "agent(prompt, options?): delegate work through the reserved agent bridge.",
13
+ 'agent(prompt, options?): delegate work; isolated/apply/merge 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.',
14
14
  "workpool(agent, name, options?): await a host-owned pool adapter with pool_id, push, close, inspect, and cancel; options only accept mode.",
15
15
  "parallel(thunks): run async thunks through the configured bounded pool; preserves order and rethrows the lowest-index error after all settle.",
16
16
  "pipeline(items, ...stages): map items through staged async transforms with a barrier between stages.",
@@ -49,21 +49,31 @@ export class JavaScriptRunQueue {
49
49
  const next = this.#queue.shift() ?? null;
50
50
  if (next) next.startedAtMs = startedAtMs;
51
51
  this.#active = next;
52
+ next?.input.onStarted?.();
52
53
  return next;
53
54
  }
54
55
 
56
+ remove(cellId: string, reason = "interrupted"): boolean {
57
+ const index = this.#queue.findIndex((run) => run.input.cellId === cellId);
58
+ if (index < 0) return false;
59
+ const [run] = this.#queue.splice(index, 1);
60
+ if (!run) return false;
61
+ this.settle(run, stoppedResult(cellId, reason));
62
+ return true;
63
+ }
64
+
65
+ snapshot(): { activeCellId: string | null; queuedCellIds: readonly string[] } {
66
+ return {
67
+ activeCellId: this.#active?.input.cellId ?? null,
68
+ queuedCellIds: this.#queue.map((run) => run.input.cellId),
69
+ };
70
+ }
71
+
55
72
  durationMs(run: PendingJavaScriptRun, finishedAtMs: number): number {
56
73
  if (run.startedAtMs === null) return 0;
57
74
  return Math.max(0, Math.round(finishedAtMs - run.startedAtMs));
58
75
  }
59
76
 
60
- takeInterruptTarget(): PendingJavaScriptRun | null {
61
- if (!this.#active) return this.#queue.shift() ?? null;
62
- const active = this.#active;
63
- this.#active = null;
64
- return active;
65
- }
66
-
67
77
  releaseActive(run: PendingJavaScriptRun): boolean {
68
78
  if (this.#active !== run) return false;
69
79
  this.#active = null;
@@ -305,7 +305,9 @@ export class JsWorkerRuntime {
305
305
  : JSON.parse(String(text))
306
306
  : text;
307
307
  if (!handle) return output;
308
- const details = isPlainObject(responseRecord.details) ? responseRecord.details : responseRecord;
308
+ const details = Object.hasOwn(responseRecord, "id")
309
+ ? responseRecord
310
+ : isPlainObject(responseRecord.details) ? responseRecord.details : responseRecord;
309
311
  const id = details.id;
310
312
  if (id === undefined || id === null) return { text, output: text, handle: null, id: null, agent: null };
311
313
  const node = {
@@ -317,6 +319,9 @@ export class JsWorkerRuntime {
317
319
  agent: details.agent ?? callArgs.agent ?? null,
318
320
  };
319
321
  if (Object.hasOwn(callArgs, "schema")) node.data = output;
322
+ if (isPlainObject(responseRecord.details) && Object.hasOwn(responseRecord.details, "isolation")) {
323
+ node.details = { isolation: responseRecord.details.isolation };
324
+ }
320
325
  for (const key of ["isolated", "patchPath", "branchName", "nestedPatches", "changesApplied", "isolationSummary"]) {
321
326
  if (details[key] !== undefined) node[key] = details[key];
322
327
  }
@@ -1,4 +1,5 @@
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 { KernelSpawnProcess } from "./process.ts";
4
5
  import type { PythonTransportResult } from "./transport.ts";
@@ -16,11 +17,7 @@ export interface PythonKernelStartOptions {
16
17
  readonly spawnProcess?: KernelSpawnProcess;
17
18
  }
18
19
 
19
- export interface PythonKernelRunOptions {
20
- readonly cellId: string;
21
- readonly code: string;
22
- readonly timeoutMs?: number;
23
- }
20
+ export type PythonKernelRunOptions = EvalKernelRunInput;
24
21
 
25
22
  export type ResultMessage = PythonTransportResult;
26
23