@code-yeongyu/senpi 2026.9.15 → 2026.9.16-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 (333) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +1 -1
  3. package/dist/core/agent-session.d.ts +28 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +111 -13
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/compaction/compaction.d.ts.map +1 -1
  8. package/dist/core/compaction/compaction.js +4 -2
  9. package/dist/core/compaction/compaction.js.map +1 -1
  10. package/dist/core/compaction/stream-watchdog.d.ts +56 -2
  11. package/dist/core/compaction/stream-watchdog.d.ts.map +1 -1
  12. package/dist/core/compaction/stream-watchdog.js +93 -15
  13. package/dist/core/compaction/stream-watchdog.js.map +1 -1
  14. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts +6 -0
  15. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +17 -0
  17. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  18. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts +4 -1
  19. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.d.ts.map +1 -1
  20. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js +31 -0
  21. package/dist/core/extensions/builtin/claude-sdk-oauth/session-continuity.js.map +1 -1
  22. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts +2 -0
  23. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  24. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +16 -0
  25. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  26. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js +19 -8
  28. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js.map +1 -1
  29. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js +2 -1
  31. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js.map +1 -1
  32. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +13 -1
  33. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +66 -2
  35. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -1
  36. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  37. package/dist/core/extensions/builtin/compaction/index.js +16 -10
  38. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  39. package/dist/core/extensions/builtin/compaction/speculative-summary.d.ts.map +1 -1
  40. package/dist/core/extensions/builtin/compaction/speculative-summary.js +4 -2
  41. package/dist/core/extensions/builtin/compaction/speculative-summary.js.map +1 -1
  42. package/dist/core/extensions/builtin/compaction/speculative.d.ts +8 -1
  43. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/compaction/speculative.js +31 -7
  45. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  46. package/dist/core/extensions/builtin/compaction/transient-failure.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/compaction/transient-failure.js +6 -3
  48. package/dist/core/extensions/builtin/compaction/transient-failure.js.map +1 -1
  49. package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -1
  50. package/dist/core/extensions/builtin/config-reload/index.js +25 -8
  51. package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
  52. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +4 -5
  53. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -1
  54. package/dist/core/extensions/builtin/config-reload/watch-engine.js +14 -18
  55. package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -1
  56. package/dist/core/extensions/builtin/config-reload/watch-event-source.d.ts.map +1 -1
  57. package/dist/core/extensions/builtin/config-reload/watch-event-source.js +32 -9
  58. package/dist/core/extensions/builtin/config-reload/watch-event-source.js.map +1 -1
  59. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts +23 -0
  60. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts.map +1 -0
  61. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js +48 -0
  62. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js.map +1 -0
  63. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts +13 -0
  64. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts.map +1 -0
  65. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js +24 -0
  66. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js.map +1 -0
  67. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts +1 -0
  68. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts.map +1 -1
  69. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js +7 -1
  70. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js.map +1 -1
  71. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts +2 -0
  72. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
  73. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +11 -9
  74. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
  75. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts +18 -0
  76. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts.map +1 -0
  77. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js +61 -0
  78. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js.map +1 -0
  79. package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts +4 -1
  80. package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
  81. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +1 -44
  82. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
  83. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +22 -0
  84. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
  85. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +1 -1
  86. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
  87. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.d.ts.map +1 -1
  88. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js +2 -13
  89. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js.map +1 -1
  90. package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts +3 -0
  91. package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts.map +1 -0
  92. package/dist/core/extensions/builtin/terminal/monitor-file-digest.js +25 -0
  93. package/dist/core/extensions/builtin/terminal/monitor-file-digest.js.map +1 -0
  94. package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts +9 -0
  95. package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts.map +1 -0
  96. package/dist/core/extensions/builtin/terminal/monitor-file-watch.js +33 -0
  97. package/dist/core/extensions/builtin/terminal/monitor-file-watch.js.map +1 -0
  98. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts +6 -0
  99. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts.map +1 -0
  100. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js +22 -0
  101. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js.map +1 -0
  102. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
  103. package/dist/core/extensions/builtin/terminal/monitor-registry.js +14 -35
  104. package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
  105. package/dist/core/extensions/kernel-tools-context.d.ts +13 -0
  106. package/dist/core/extensions/kernel-tools-context.d.ts.map +1 -0
  107. package/dist/core/extensions/kernel-tools-context.js +3 -0
  108. package/dist/core/extensions/kernel-tools-context.js.map +1 -0
  109. package/dist/core/extensions/runner.d.ts +19 -0
  110. package/dist/core/extensions/runner.d.ts.map +1 -1
  111. package/dist/core/extensions/runner.js +103 -1
  112. package/dist/core/extensions/runner.js.map +1 -1
  113. package/dist/core/extensions/types.d.ts +21 -0
  114. package/dist/core/extensions/types.d.ts.map +1 -1
  115. package/dist/core/extensions/types.js.map +1 -1
  116. package/dist/core/keybindings.d.ts +5 -0
  117. package/dist/core/keybindings.d.ts.map +1 -1
  118. package/dist/core/keybindings.js +1 -0
  119. package/dist/core/keybindings.js.map +1 -1
  120. package/dist/core/resource-loader.d.ts.map +1 -1
  121. package/dist/core/resource-loader.js +9 -17
  122. package/dist/core/resource-loader.js.map +1 -1
  123. package/dist/core/retry-fallback/settings.d.ts +3 -0
  124. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  125. package/dist/core/retry-fallback/settings.js.map +1 -1
  126. package/dist/core/sdk.d.ts.map +1 -1
  127. package/dist/core/sdk.js +1 -0
  128. package/dist/core/sdk.js.map +1 -1
  129. package/dist/core/session-manager.d.ts +30 -1
  130. package/dist/core/session-manager.d.ts.map +1 -1
  131. package/dist/core/session-manager.js +92 -5
  132. package/dist/core/session-manager.js.map +1 -1
  133. package/dist/core/session-resident-store.d.ts +33 -7
  134. package/dist/core/session-resident-store.d.ts.map +1 -1
  135. package/dist/core/session-resident-store.js +163 -14
  136. package/dist/core/session-resident-store.js.map +1 -1
  137. package/dist/core/session-write-reservation.d.ts +6 -0
  138. package/dist/core/session-write-reservation.d.ts.map +1 -1
  139. package/dist/core/session-write-reservation.js +19 -0
  140. package/dist/core/session-write-reservation.js.map +1 -1
  141. package/dist/core/settings-manager.d.ts +35 -1
  142. package/dist/core/settings-manager.d.ts.map +1 -1
  143. package/dist/core/settings-manager.js +62 -0
  144. package/dist/core/settings-manager.js.map +1 -1
  145. package/dist/core/slash-commands.d.ts.map +1 -1
  146. package/dist/core/slash-commands.js +2 -1
  147. package/dist/core/slash-commands.js.map +1 -1
  148. package/dist/core/tools/index.d.ts +1 -1
  149. package/dist/core/tools/index.d.ts.map +1 -1
  150. package/dist/core/tools/index.js +4 -3
  151. package/dist/core/tools/index.js.map +1 -1
  152. package/dist/core/tools/read.d.ts +3 -1
  153. package/dist/core/tools/read.d.ts.map +1 -1
  154. package/dist/core/tools/read.js +16 -2
  155. package/dist/core/tools/read.js.map +1 -1
  156. package/dist/index.d.ts +1 -0
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +1 -0
  159. package/dist/index.js.map +1 -1
  160. package/dist/modes/interactive/components/assistant-render-descriptors.d.ts.map +1 -1
  161. package/dist/modes/interactive/components/assistant-render-descriptors.js +12 -5
  162. package/dist/modes/interactive/components/assistant-render-descriptors.js.map +1 -1
  163. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  164. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  165. package/dist/modes/interactive/components/extension-input.js +5 -0
  166. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +19 -2
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +69 -17
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/tips/catalog/session-tips.js +1 -1
  172. package/dist/modes/interactive/tips/catalog/session-tips.js.map +1 -1
  173. package/dist/modes/interactive/working-status.d.ts +3 -2
  174. package/dist/modes/interactive/working-status.d.ts.map +1 -1
  175. package/dist/modes/interactive/working-status.js +17 -4
  176. package/dist/modes/interactive/working-status.js.map +1 -1
  177. package/dist/modes/print-mode.d.ts +1 -1
  178. package/dist/modes/print-mode.d.ts.map +1 -1
  179. package/dist/modes/print-mode.js +5 -1
  180. package/dist/modes/print-mode.js.map +1 -1
  181. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
  182. package/dist/modes/rpc/host-watchdog.js +5 -24
  183. package/dist/modes/rpc/host-watchdog.js.map +1 -1
  184. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  185. package/dist/modes/rpc/rpc-mode.js +3 -8
  186. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  187. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  188. package/dist/modes/rpc/session-command-router.js +3 -0
  189. package/dist/modes/rpc/session-command-router.js.map +1 -1
  190. package/dist/modes/rpc/session-worker-client.d.ts +3 -0
  191. package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
  192. package/dist/modes/rpc/session-worker-client.js +17 -6
  193. package/dist/modes/rpc/session-worker-client.js.map +1 -1
  194. package/dist/modes/rpc/shutdown.d.ts +3 -0
  195. package/dist/modes/rpc/shutdown.d.ts.map +1 -0
  196. package/dist/modes/rpc/shutdown.js +17 -0
  197. package/dist/modes/rpc/shutdown.js.map +1 -0
  198. package/docs/extensions.md +5 -2
  199. package/docs/keybindings.md +1 -0
  200. package/docs/session-format.md +1 -1
  201. package/docs/sessions.md +3 -3
  202. package/docs/settings.md +31 -1
  203. package/docs/usage.md +1 -1
  204. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +50 -0
  205. package/node_modules/@code-yeongyu/senpi-codemode/README.md +24 -0
  206. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  207. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/http-server.ts +7 -1
  208. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/kernel-tools-protocol.ts +85 -0
  209. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +6 -0
  210. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +30 -11
  211. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +11 -0
  212. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
  213. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +46 -0
  214. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +1 -1
  215. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +58 -10
  216. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +12 -0
  217. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.d.ts +13 -0
  218. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.js +7 -0
  219. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.d.ts +10 -0
  220. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.js +12 -0
  221. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.js +22 -0
  222. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.ts +26 -0
  223. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-host.ts +134 -0
  224. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-naming.js +28 -0
  225. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.d.ts +5 -0
  226. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.js +255 -0
  227. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-pump.js +105 -0
  228. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.d.ts +27 -0
  229. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.js +127 -0
  230. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-schema.js +69 -0
  231. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-types.ts +42 -0
  232. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -0
  233. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +26 -3
  234. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +20 -8
  235. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-slot.ts +6 -1
  236. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-startup.ts +9 -7
  237. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/workpool.js +37 -0
  238. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/kernel-tools-unavailable.ts +5 -0
  239. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +13 -0
  240. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +57 -3
  241. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +13 -2
  242. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/workpool.rb +38 -0
  243. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +13 -0
  244. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +9 -1
  245. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +4 -2
  246. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +31 -3
  247. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +36 -71
  248. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image-resize.ts +52 -0
  249. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +37 -72
  250. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +78 -0
  251. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +30 -5
  252. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +52 -30
  253. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +35 -0
  254. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/tool-result-marshal.ts +23 -0
  255. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -0
  256. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  257. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +30 -3
  258. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  259. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +5 -0
  260. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  261. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +2 -0
  262. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  263. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
  264. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +51 -12
  265. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
  266. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts +3 -0
  267. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js +18 -3
  269. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts +4 -0
  271. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts.map +1 -0
  272. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js +268 -0
  273. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js.map +1 -0
  274. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts +18 -0
  275. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts.map +1 -0
  276. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js +69 -0
  277. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js.map +1 -0
  278. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts +27 -0
  279. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts.map +1 -0
  280. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js +118 -0
  281. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js.map +1 -0
  282. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts +21 -0
  283. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts.map +1 -0
  284. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js +24 -0
  285. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js.map +1 -0
  286. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts +12 -0
  287. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts.map +1 -0
  288. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js +92 -0
  289. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js.map +1 -0
  290. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts +47 -0
  291. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts.map +1 -0
  292. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js +8 -0
  293. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js.map +1 -0
  294. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts +52 -0
  295. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts.map +1 -0
  296. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js +155 -0
  297. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js.map +1 -0
  298. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +4 -0
  299. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-agent-core/dist/index.js +3 -0
  301. package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.d.ts +101 -0
  303. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.d.ts.map +1 -0
  304. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.js +178 -0
  305. package/node_modules/@earendil-works/pi-agent-core/dist/stream-throughput-watchdog.js.map +1 -0
  306. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +9 -0
  307. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  308. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  309. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  310. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  311. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  313. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  315. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
  316. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  317. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  318. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  319. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
  320. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  321. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts +15 -0
  322. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts.map +1 -0
  323. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js +15 -0
  324. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js.map +1 -0
  325. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +24 -0
  326. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  327. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +92 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  329. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  330. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  331. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  332. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  333. package/package.json +7 -7
@@ -12,6 +12,56 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.9.16-2] - 2026-09-16
16
+
17
+ ### Breaking Changes
18
+
19
+ ### Added
20
+
21
+ ### Changed
22
+
23
+ ### Fixed
24
+
25
+ - The JavaScript kernel-tool capability now reaches host tools called from inside a running eval cell. A cell that registers `tool(fn)` can hand those functions to its in-process children through `task`/`agent`/`workpool`, because `ExtensionContext.kernelTools` resolves for the duration of each host tool call the cell makes. It was undefined at the dispatch point — the worker's message loop ran outside the `kernelToolsStorage` scope that only covered the awaited run chain — so every grant was refused with `tools_unavailable` and the capability shipped in the previous release could not be used ([#1754](https://github.com/code-yeongyu/senpi/issues/1754)).
26
+
27
+ ### Removed
28
+
29
+ ## [2026.9.16] - 2026-09-16
30
+
31
+ ### Breaking Changes
32
+
33
+ - Background `agent(..., handle=true)` now requires the host task tool to return structured `details.task_id` (`st_` plus lowercase hex) and an integer `details.run_epoch >= 0`. The result gains a `run_epoch` field next to `id` and `handle`, in every kernel language. A host that returns an error, or only a prose task id in its text, raises `invalid_task_handle`; the old regex scrape of the text is gone. Extra producer fields in `details` are accepted. Foreground text and JSON results are unchanged ([#1646](https://github.com/code-yeongyu/senpi/issues/1646)).
34
+
35
+ ### Added
36
+
37
+ - Added `workpool(agent, name, mode?)` to the JS, Python, Ruby and Julia preludes as a thin adapter over the host `workpool` tool. `agent` is a plain-data spec with one of `category` or `subagent_type` plus `prompt` and optional `model`; `mode` is `fresh` or `keep_alive` and is forwarded only when given. The adapter exposes `pool_id`, `push(items)`, `close()`, `inspect()` and `cancel()`, each returning the same `{text, details, images?, hasError?}` envelope as a direct tool call, and holds no worker, queue or admission state, so a kernel reset drops only the variable and the pool survives. A missing or inactive host tool raises `workpool_unavailable`; a host error at creation is raised instead of returning a broken adapter. Kernel tools may not call `workpool()` (`kernel_tool_recursion`) ([#1646](https://github.com/code-yeongyu/senpi/issues/1646)).
38
+ - Added JavaScript kernel tools. `tool(fn, metadata?)` registers a named `function` or `async function` declaration as a fenced tool for in-process children while `tool.<name>(args)` host calls keep working. The parser reads only the declaration head: anonymous functions, classes, generators, native functions and non-identifier parameters are rejected with `invalid_tool_definition`; unicode identifiers are kept as written. Names must already fit the MCP grammar (`[A-Za-z0-9_-]`, at most 64 characters) and are checked against reserved bridge names, live host tools (including tools attached after the worker started) and tools registered by the session's Python, Ruby or Julia kernels, raising `reserved_tool_name` or `tool_name_collision`. Each descriptor carries `name`, a JSON input schema, `kernel_generation` and `definition_revision`; a stale generation or revision is refused with `kernel_tool_stale`, redefining a function bumps its revision, and a kernel reset clears every registered tool and bumps the generation. `agent()` accepts `tools: string[]` to hand a child those tool names. Kernel-tool requests against Python, Ruby or Julia kernels fail with `tools_unavailable` ([#1647](https://github.com/code-yeongyu/senpi/issues/1647)).
39
+ - The JS worker answers kernel-tool `describe` and `invoke` requests on a separate pump from the top-level run queue, so a parent cell can stay pending on `agent()` while an in-process child calls one of the parent's registered functions. Interrupting the parent settles every nested invoke, and a worker reset, crash or close rejects the pending ones with `kernel_tool_stale` ([#1647](https://github.com/code-yeongyu/senpi/issues/1647)).
40
+ - `CodemodeExtensionAPI.kernelTools` exposes the parent cell's kernel-tool `describe`/`invoke` capability to extensions while a JavaScript eval is live; `KernelToolDescriptor`, `KernelToolsCapability`, `KernelToolsDescribeResult`, `KernelToolsInvokeRequest` and `KERNEL_TOOLS_UNSUPPORTED` are exported. Kernels may implement `EvalKernel.listKernelToolNames()` so the session manager can detect cross-language name collisions ([#1647](https://github.com/code-yeongyu/senpi/issues/1647)).
41
+
42
+ ### Changed
43
+
44
+ - The eval prompt documents `workpool()` and the `run_epoch` field on background `agent()` handles, and the JS prelude describes `tool(fn, metadata?)` and `workpool()` ([#1646](https://github.com/code-yeongyu/senpi/issues/1646), [#1647](https://github.com/code-yeongyu/senpi/issues/1647)).
45
+
46
+ ### Fixed
47
+
48
+ ### Removed
49
+
50
+ ## [2026.9.15-2] - 2026-09-15
51
+
52
+ ### Breaking Changes
53
+
54
+ ### Added
55
+
56
+ ### Changed
57
+
58
+ ### Fixed
59
+
60
+ - Detached eval result cards no longer arm the 1 Hz repaint ticker (they render static with frozen elapsed time), and a live ticker whose row stops rendering now stops itself after 60 idle ticks and rearms on the next render, so transcript rebuilds and session switches cannot accumulate intervals on idle sessions ([#1696](https://github.com/code-yeongyu/senpi/issues/1696)).
61
+ - Bounded three unbounded retentions that grew long-lived session heaps without limit: settled eval cells now leave the live registry into a 32-entry terminal snapshot LRU, the JS kernel's unconsumed tool-call queue is capped at 256 and cleared on interrupt/reset/close/crash (mirroring the subprocess kernel), and per-cell display buffers cap at 8 images / 24 MB / 64 JSON outputs with elision notes ([#1695](https://github.com/code-yeongyu/senpi/issues/1695)).
62
+
63
+ ### Removed
64
+
15
65
  ## [2026.9.15] - 2026-09-15
16
66
 
17
67
  ### Breaking Changes
@@ -144,6 +144,7 @@ options object and asynchronous helpers are `await`-able.
144
144
  | `tool_schema(name?)` | Returns a tool's parameter schema without calling it; omit `name` to list tool names. |
145
145
  | `completion(prompt, model?, system?, schema?)` | Requests a one-shot host completion; `schema` asks the host to parse structured output. |
146
146
  | `agent(prompt, ...)` | Delegates to the configured active `taskTools.task` tool. Supports background handles and structured JSON results. |
147
+ | `workpool(agent, name, mode?)` | Creates a thin adapter over the normal host `workpool` tool; exposes `pool_id`, `push(items)`, `close()`, `inspect()`, and `cancel()`. JS awaits creation and operations. |
147
148
  | `output(ids, format?, offset?, limit?)` | Delegates transcript retrieval to the configured active `taskTools.output` tool. |
148
149
  | `parallel(thunks)` | Runs thunks through the configured bounded pool while preserving input order. |
149
150
  | `pipeline(items, ...stages)` | Applies stages left to right with a barrier between stages. |
@@ -164,6 +165,29 @@ updates, and transcripts remain owned by that engine.
164
165
  `isolated`, `apply`, and `merge` are accepted for compatibility but emit a
165
166
  warning because this task-engine integration has no isolation model.
166
167
 
168
+ Background `agent()` handles retain `id` and `agent://<id>` and include `run_epoch`.
169
+ The host must return structured `details.task_id` (`st_` plus lowercase hex) and
170
+ 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.
172
+
173
+ `workpool` takes exactly one of `{category, prompt, model?}` or
174
+ `{subagent_type, prompt, model?}` as its plain-data agent spec. Mode is `fresh`
175
+ or `keep_alive`: pass `{mode: "fresh"}` in JS, `mode="fresh"` in Python/Julia,
176
+ or `mode: "fresh"` in Ruby. Omission is forwarded unchanged to the engine;
177
+ hosts without an approved default still require an explicit mode. Custom tool
178
+ names are not enabled by this adapter.
179
+
180
+ `push` forwards `[{key, input}]` and returns the host receipt without waiting
181
+ for admission. Operations return the same `{text, details, images?, hasError?}`
182
+ envelope as direct tool calls. Creation refuses host errors instead of returning
183
+ a broken adapter; a missing host raises `workpool_unavailable`. The host owns
184
+ workers, keyed yields, cancellation, and aggregate delivery after explicit
185
+ `close()`; none is implemented in a kernel. Aggregate support requires a host
186
+ that implements it. Reset only removes kernel variables: save `pool_id` and use
187
+ `tool.workpool({op: "inspect", pool_id})` from a new JS cell (equivalent keyword
188
+ arguments in other languages). An open pool's adapter can be recreated with the
189
+ same name/spec/mode; no worker state is reconstructed in the prelude.
190
+
167
191
  ## Required summary
168
192
 
169
193
  Every `eval` run call MUST include a `summary` — one line in the user's
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi-codemode",
3
- "version": "2026.9.15",
3
+ "version": "2026.9.16-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.15",
34
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.16-2",
35
35
  "typebox": "1.3.27"
36
36
  },
37
37
  "peerDependencies": {
38
- "@code-yeongyu/senpi": "2026.9.15"
38
+ "@code-yeongyu/senpi": "2026.9.16-2"
39
39
  },
40
40
  "devDependencies": {
41
- "@code-yeongyu/senpi": "2026.9.15"
41
+ "@code-yeongyu/senpi": "2026.9.16-2"
42
42
  },
43
43
  "keywords": [
44
44
  "senpi",
@@ -217,7 +217,13 @@ function sendJson(response: ServerResponse, status: number, body: JsonReply): vo
217
217
  }
218
218
 
219
219
  function bridgeError(error: unknown): BridgeError {
220
- if (error instanceof Error) return { name: error.name, message: error.message, stack: error.stack };
220
+ if (error instanceof Error)
221
+ return {
222
+ name: error.name,
223
+ message: error.message,
224
+ stack: error.stack,
225
+ ...("code" in error && typeof error.code === "string" ? { code: error.code } : {}),
226
+ };
221
227
  return { message: String(error) };
222
228
  }
223
229
 
@@ -0,0 +1,85 @@
1
+ import { type Static, Type } from "typebox";
2
+
3
+ const kernelToolErrorSchema = Type.Object({
4
+ message: Type.String(),
5
+ name: Type.Optional(Type.String()),
6
+ stack: Type.Optional(Type.String()),
7
+ code: Type.Optional(Type.String()),
8
+ });
9
+
10
+ export const kernelToolDescriptorSchema = Type.Object({
11
+ name: Type.String({ minLength: 1 }),
12
+ description: Type.String(),
13
+ input_schema: Type.Unknown(),
14
+ language: Type.Literal("js"),
15
+ kernel_generation: Type.Integer({ minimum: 0 }),
16
+ definition_revision: Type.Integer({ minimum: 1 }),
17
+ });
18
+
19
+ const describeResultSchema = Type.Union([
20
+ Type.Object({
21
+ name: Type.String({ minLength: 1 }),
22
+ ok: Type.Literal(true),
23
+ descriptor: kernelToolDescriptorSchema,
24
+ }),
25
+ Type.Object({
26
+ name: Type.String({ minLength: 1 }),
27
+ ok: Type.Literal(false),
28
+ error: kernelToolErrorSchema,
29
+ }),
30
+ ]);
31
+
32
+ export const kernelToolHostToKernelSchemas = [
33
+ Type.Object({
34
+ type: Type.Literal("kernel-tool-describe"),
35
+ requestId: Type.String({ minLength: 1 }),
36
+ names: Type.Array(Type.String({ minLength: 1 })),
37
+ }),
38
+ Type.Object({
39
+ type: Type.Literal("kernel-tool-invoke"),
40
+ requestId: Type.String({ minLength: 1 }),
41
+ name: Type.String({ minLength: 1 }),
42
+ kernel_generation: Type.Integer({ minimum: 0 }),
43
+ definition_revision: Type.Integer({ minimum: 1 }),
44
+ args: Type.Unknown(),
45
+ call_id: Type.String({ minLength: 1 }),
46
+ }),
47
+ Type.Object({
48
+ type: Type.Literal("kernel-tool-cancel"),
49
+ requestId: Type.String({ minLength: 1 }),
50
+ }),
51
+ Type.Object({
52
+ type: Type.Literal("kernel-tools-names"),
53
+ hostToolNames: Type.Array(Type.String({ minLength: 1 })),
54
+ foreignLanguageNames: Type.Array(Type.String({ minLength: 1 })),
55
+ }),
56
+ ] as const;
57
+
58
+ export const kernelToolKernelToHostSchemas = [
59
+ Type.Object({
60
+ type: Type.Literal("kernel-tool-describe-reply"),
61
+ requestId: Type.String({ minLength: 1 }),
62
+ ok: Type.Literal(true),
63
+ results: Type.Array(describeResultSchema),
64
+ }),
65
+ Type.Object({
66
+ type: Type.Literal("kernel-tool-describe-reply"),
67
+ requestId: Type.String({ minLength: 1 }),
68
+ ok: Type.Literal(false),
69
+ error: kernelToolErrorSchema,
70
+ }),
71
+ Type.Object({
72
+ type: Type.Literal("kernel-tool-invoke-reply"),
73
+ requestId: Type.String({ minLength: 1 }),
74
+ ok: Type.Literal(true),
75
+ value: Type.Unknown(),
76
+ }),
77
+ Type.Object({
78
+ type: Type.Literal("kernel-tool-invoke-reply"),
79
+ requestId: Type.String({ minLength: 1 }),
80
+ ok: Type.Literal(false),
81
+ error: kernelToolErrorSchema,
82
+ }),
83
+ ] as const;
84
+
85
+ export type KernelToolDescriptorMessage = Static<typeof kernelToolDescriptorSchema>;
@@ -1,6 +1,7 @@
1
1
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
2
2
  import { type Static, Type } from "typebox";
3
3
  import { Value } from "typebox/value";
4
+ import { kernelToolHostToKernelSchemas, kernelToolKernelToHostSchemas } from "./kernel-tools-protocol.ts";
4
5
 
5
6
  export const BRIDGE_FRAME_MAX_BYTES = 10 * 1024 * 1024;
6
7
 
@@ -27,6 +28,9 @@ const hostToKernelMessageSchema = Type.Union([
27
28
  sessionId: Type.String({ minLength: 1 }),
28
29
  connection: connectionConfigSchema,
29
30
  sessionEnv: Type.Optional(Type.Record(Type.String(), Type.String())),
31
+ kernelGeneration: Type.Optional(Type.Integer({ minimum: 1 })),
32
+ hostToolNames: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
33
+ foreignLanguageNames: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
30
34
  }),
31
35
  Type.Object({
32
36
  type: Type.Literal("run"),
@@ -53,6 +57,7 @@ const hostToKernelMessageSchema = Type.Union([
53
57
  Type.Object({
54
58
  type: Type.Literal("close"),
55
59
  }),
60
+ ...kernelToolHostToKernelSchemas,
56
61
  ]);
57
62
 
58
63
  const kernelToHostMessageSchema = Type.Union([
@@ -92,6 +97,7 @@ const kernelToHostMessageSchema = Type.Union([
92
97
  durationMs: Type.Integer({ minimum: 0 }),
93
98
  }),
94
99
  Type.Object({ type: Type.Literal("closed") }),
100
+ ...kernelToolKernelToHostSchemas,
95
101
  ]);
96
102
 
97
103
  const bridgeMessageSchema = Type.Union([hostToKernelMessageSchema, kernelToHostMessageSchema]);
@@ -11,6 +11,7 @@ const agentArgsSchema = Type.Object(
11
11
  label: Type.Optional(Type.String()),
12
12
  schema: Type.Optional(Type.Unknown()),
13
13
  handle: Type.Optional(Type.Boolean()),
14
+ tools: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
14
15
  isolated: Type.Optional(Type.Boolean()),
15
16
  apply: Type.Optional(Type.Boolean()),
16
17
  merge: Type.Optional(Type.Boolean()),
@@ -19,7 +20,19 @@ const agentArgsSchema = Type.Object(
19
20
  );
20
21
 
21
22
  const unsupportedIsolationWarning = "isolated/apply/merge unsupported (no isolation in task engine)";
22
- const taskIdPattern = /\bst_[A-Za-z0-9_-]+\b/;
23
+ const taskHandleSchema = Type.Object(
24
+ {
25
+ task_id: Type.String({ pattern: "^st_[0-9a-f]+$" }),
26
+ run_epoch: Type.Integer({ minimum: 0 }),
27
+ },
28
+ { additionalProperties: true },
29
+ );
30
+
31
+ /** Structural host contract; no orchestration package dependency. */
32
+ export type TaskHandleDetails = {
33
+ readonly task_id: string;
34
+ readonly run_epoch: number;
35
+ };
23
36
  const droppedOptionNames = ["isolated", "apply", "merge"] as const;
24
37
 
25
38
  type AgentArgs = Static<typeof agentArgsSchema>;
@@ -29,6 +42,7 @@ type TaskParams = {
29
42
  readonly model?: string;
30
43
  readonly name?: string;
31
44
  readonly run_in_background: boolean;
45
+ readonly tools?: readonly string[];
32
46
  };
33
47
  type ProgressContext = { readonly fallbackId: string; readonly warning?: string };
34
48
 
@@ -48,7 +62,7 @@ export type EvalAgentResult =
48
62
  | { readonly text: string }
49
63
  | { readonly text: string; readonly data: unknown }
50
64
  | { readonly text: string; readonly parseError: string }
51
- | { readonly text: string; readonly id: string; readonly handle: string };
65
+ | { readonly text: string; readonly id: string; readonly handle: string; readonly run_epoch: number };
52
66
 
53
67
  class AgentArgumentsError extends Error {
54
68
  readonly name = "AgentArgumentsError";
@@ -68,9 +82,10 @@ class AgentUnavailableError extends Error {
68
82
 
69
83
  class AgentHandleError extends Error {
70
84
  readonly name = "AgentHandleError";
85
+ readonly code = "invalid_task_handle";
71
86
 
72
87
  constructor() {
73
- super("agent() background task result did not include a task id");
88
+ super("agent() requires successful task details with a valid task_id and nonnegative integer run_epoch");
74
89
  }
75
90
  }
76
91
 
@@ -105,9 +120,8 @@ export async function runEvalAgent(args: unknown, options: RunEvalAgentOptions):
105
120
 
106
121
  const text = resultText(result);
107
122
  if (parsed.handle === true) {
108
- const id = resultTaskId(result, text);
109
- if (!id) throw new AgentHandleError();
110
- return { text, id, handle: `agent://${id}` };
123
+ const { task_id: id, run_epoch } = resultTaskHandle(result);
124
+ return { text, id, handle: `agent://${id}`, run_epoch };
111
125
  }
112
126
  if (!structured) return { text };
113
127
  return parseStructuredText(text);
@@ -130,6 +144,7 @@ function toTaskParams(args: AgentArgs, structured: boolean): TaskParams {
130
144
  ...(args.model === undefined ? {} : { model: args.model }),
131
145
  ...(args.label === undefined ? {} : { name: args.label }),
132
146
  run_in_background: args.handle === true,
147
+ ...(args.tools === undefined ? {} : { tools: args.tools }),
133
148
  };
134
149
  }
135
150
 
@@ -168,11 +183,15 @@ function resultText(result: AgentToolResult<unknown>): string {
168
183
  .join("\n");
169
184
  }
170
185
 
171
- function resultTaskId(result: AgentToolResult<unknown>, text: string): string | undefined {
172
- const details = isRecord(result.details) ? result.details : undefined;
173
- const detailId = firstString(details, ["task_id", "taskId", "id"]);
174
- if (detailId) return detailId;
175
- return text.match(taskIdPattern)?.[0];
186
+ function resultTaskHandle(result: AgentToolResult<unknown>): TaskHandleDetails {
187
+ const details = result.details;
188
+ if (
189
+ ("isError" in result && result.isError === true) ||
190
+ (isRecord(details) && (details.isError === true || details.error !== undefined)) ||
191
+ !Check(taskHandleSchema, details)
192
+ )
193
+ throw new AgentHandleError();
194
+ return details;
176
195
  }
177
196
 
178
197
  function firstString(
@@ -215,6 +215,8 @@ class DefaultCodemodeSessionManager implements CodemodeSessionManager {
215
215
  cwd: this.#options.cwd,
216
216
  parallelPoolWidth,
217
217
  onMessage,
218
+ hostToolNames: () => this.#options.listTools?.().map((tool) => tool.name) ?? [],
219
+ foreignLanguageNames: () => this.#foreignKernelToolNames(),
218
220
  ...(this.#options.sessionEnv ? { sessionEnv: this.#options.sessionEnv } : {}),
219
221
  ...(localRoots ? { localRoots: { ...localRoots } } : {}),
220
222
  ...(this.#options.artifactsDir ? { artifactsDir: this.#options.artifactsDir } : {}),
@@ -259,6 +261,15 @@ class DefaultCodemodeSessionManager implements CodemodeSessionManager {
259
261
  });
260
262
  }
261
263
 
264
+ #foreignKernelToolNames(): string[] {
265
+ const names: string[] = [];
266
+ for (const [language, kernel] of this.#kernels) {
267
+ if (language === "js") continue;
268
+ names.push(...(kernel.listKernelToolNames?.() ?? []));
269
+ }
270
+ return names;
271
+ }
272
+
262
273
  #contextFor(signal: AbortSignal): ExtensionContext {
263
274
  const ctx = this.#context;
264
275
  if (!ctx) throw new CodemodeContextUnavailableError();
@@ -23,6 +23,7 @@ import type { CodemodeSessionManager, CreateCodemodeSessionManagerOptions } from
23
23
  import { SessionManagerProxy } from "./extension/session-manager-proxy.ts";
24
24
  import { activeBunSkillPath, registerBunSkillContribution } from "./extension/skill-contribution.ts";
25
25
  import { WAKE_SOURCE_STATE_EVENT, type WakeSourceState } from "./extension/wake-source-state.ts";
26
+ import type { KernelToolsCapability } from "./kernels/js/kernel-tools-types.ts";
26
27
  import { EvalDetachedCellManager, type EvalDetachedCellStatusEntry } from "./tool/detached-cell-manager.ts";
27
28
  import {
28
29
  EVAL_EXECUTION_EVENT,
@@ -48,6 +49,8 @@ export interface CodemodeExtensionAPI {
48
49
  registerRemovedToolHint(name: string, hint: string): void;
49
50
  on(event: CodemodeEvent | "resources_discover", handler: (event: unknown, ctx: ExtensionContext) => unknown): void;
50
51
  executeTool: AgentExecuteTool;
52
+ /** Present only while a live JavaScript eval owns the host-tool context. */
53
+ kernelTools?: KernelToolsCapability;
51
54
  getActiveTools(): string[];
52
55
  getAllTools(): readonly EvalSchemaToolInfo[];
53
56
  sendMessage(
@@ -259,4 +262,11 @@ function modelIdFrom(event: unknown): string | undefined {
259
262
  return typeof model.id === "string" ? model.id : undefined;
260
263
  }
261
264
 
265
+ export {
266
+ KERNEL_TOOLS_UNSUPPORTED,
267
+ type KernelToolDescriptor,
268
+ type KernelToolsCapability,
269
+ type KernelToolsDescribeResult,
270
+ type KernelToolsInvokeRequest,
271
+ } from "./kernels/js/kernel-tools-types.ts";
262
272
  export { enabledLanguagesFrom };
@@ -181,6 +181,51 @@ end
181
181
  Base.getproperty(::SenpiToolProxy, name::Symbol) = SenpiToolCallable(string(name))
182
182
  const tool = SenpiToolProxy()
183
183
 
184
+ struct SenpiBridgeError <: Exception
185
+ message::String
186
+ code::Union{String, Nothing}
187
+ end
188
+ Base.showerror(io::IO, error::SenpiBridgeError) = Base.print(io, error.message)
189
+
190
+ function senpi_workpool_call(args)
191
+ try
192
+ return tool.workpool(args)
193
+ catch error
194
+ if error isa SenpiBridgeError && error.code in ("unknown_tool", "inactive_tool")
195
+ throw(SenpiBridgeError("No active host workpool tool", "workpool_unavailable"))
196
+ end
197
+ rethrow()
198
+ end
199
+ end
200
+
201
+ struct SenpiWorkpool
202
+ pool_id::String
203
+ end
204
+
205
+ function Base.getproperty(pool::SenpiWorkpool, name::Symbol)
206
+ pool_id = getfield(pool, :pool_id)
207
+ name === :pool_id && return pool_id
208
+ name === :push && return items -> senpi_workpool_call(Dict("op" => "push", "pool_id" => pool_id, "items" => items))
209
+ name in (:close, :inspect, :cancel) && return () -> senpi_workpool_call(Dict("op" => string(name), "pool_id" => pool_id))
210
+ getfield(pool, name)
211
+ end
212
+
213
+ function workpool(agent::AbstractDict, name::AbstractString; mode=nothing)
214
+ args = Dict{String, Any}("op" => "create", "agent" => agent, "name" => name)
215
+ mode !== nothing && (args["mode"] = mode)
216
+ result = senpi_workpool_call(args)
217
+ details = get(result, "details", nothing)
218
+ if details isa AbstractDict
219
+ error = get(details, "error", nothing)
220
+ error isa AbstractDict && throw(SenpiBridgeError(error["message"], error["code"]))
221
+ pool_id = get(details, "pool_id", nothing)
222
+ if get(result, "hasError", false) !== true && pool_id isa AbstractString && occursin(r"^wp_[0-9a-f]{32}$", pool_id)
223
+ return SenpiWorkpool(pool_id)
224
+ end
225
+ end
226
+ throw(SenpiBridgeError("Host did not return a workpool identity", "workpool_unavailable"))
227
+ end
228
+
184
229
  function completion(prompt::AbstractString; model="default", system=nothing, schema=nothing, kwargs...)
185
230
  options = Dict{String, Any}("model" => model)
186
231
  system !== nothing && (options["system"] = system)
@@ -225,6 +270,7 @@ function agent(prompt::AbstractString; agent="task", model=nothing, label=nothin
225
270
  handle || return parsed
226
271
  result = Dict{String, Any}("text" => text_value, "output" => text_value, "id" => get(record, "id", nothing), "agent" => get(record, "agent", agent))
227
272
  result["handle"] = get(record, "handle", result["id"] === nothing ? nothing : "agent://" * string(result["id"]))
273
+ result["run_epoch"] = get(record, "run_epoch", nothing)
228
274
  schema !== nothing && (result["data"] = parsed)
229
275
  result
230
276
  end
@@ -244,7 +244,7 @@ function senpi_bridge_request(path::String, payload)
244
244
  parsed isa AbstractDict || error("Bridge returned invalid JSON")
245
245
  get(parsed, "ok", false) === true && return get(parsed, "value", nothing)
246
246
  failure = get(parsed, "error", parsed)
247
- error(failure isa AbstractDict ? string(get(failure, "message", failure)) : string(failure))
247
+ throw(SenpiBridgeError(failure isa AbstractDict ? string(get(failure, "message", failure)) : string(failure), failure isa AbstractDict ? get(failure, "code", nothing) : nothing))
248
248
  finally
249
249
  close(socket)
250
250
  end
@@ -8,8 +8,12 @@ import {
8
8
  type JavaScriptRunInput,
9
9
  type LifecycleState,
10
10
  type ResultMessage,
11
+ resolveKernelToolNameSource,
11
12
  type ToolCallMessage,
12
13
  } from "./kernel-contract.ts";
14
+ import { kernelToolError } from "./kernel-tools-errors.ts";
15
+ import { KernelToolHostPump } from "./kernel-tools-host.ts";
16
+ import type { KernelToolsDescribeResult, KernelToolsInvokeRequest } from "./kernel-tools-types.ts";
13
17
  import { type JavaScriptKernelOptions, LocalModuleLoader } from "./local-module-loader.ts";
14
18
  import { terminateProcessTrees } from "./process-tree-host.ts";
15
19
  import { JavaScriptRunQueue, type PendingJavaScriptRun, stoppedResult } from "./run-queue.ts";
@@ -23,6 +27,10 @@ export { type JavaScriptWorkerEntryUrlOptions, resolveJsWorkerEntryUrl } from ".
23
27
  /** How long a lost worker's children get to honour SIGTERM before the host sends SIGKILL. */
24
28
  const WORKER_LOSS_CHILD_GRACE_MS = 1_000;
25
29
 
30
+ // Pull-API fallback queue bound: a nextToolCall consumer this far behind is already stalled, and the
31
+ // normal push path (onMessage) never reads the queue, so unbounded growth only pins tool args (#1695).
32
+ const MAX_PENDING_TOOL_CALLS = 256;
33
+
26
34
  export class JavaScriptKernel {
27
35
  readonly #options: JavaScriptKernelOptions;
28
36
  readonly #moduleLoader: LocalModuleLoader;
@@ -32,6 +40,10 @@ export class JavaScriptKernel {
32
40
  #recovery: Promise<void> | null = null;
33
41
  #closePromise: Promise<void> | null = null;
34
42
  readonly #runs = new JavaScriptRunQueue();
43
+ readonly #kernelTools = new KernelToolHostPump(
44
+ (message) => this.#slot.postMessage(message),
45
+ () => this.#lifecycle === "open" && this.#slot.present,
46
+ );
35
47
  #timeout: NodeJS.Timeout | null = null;
36
48
  #toolWaiters: Array<(message: ToolCallMessage) => void> = [];
37
49
  #pendingToolCalls: ToolCallMessage[] = [];
@@ -52,6 +64,18 @@ export class JavaScriptKernel {
52
64
  return this.#slot.mode;
53
65
  }
54
66
 
67
+ get kernelToolEvents(): EventTarget {
68
+ return this.#kernelTools.events;
69
+ }
70
+
71
+ describeKernelTools(names: readonly string[]): Promise<KernelToolsDescribeResult> {
72
+ return this.#kernelTools.describe(names);
73
+ }
74
+
75
+ invokeKernelTool(request: KernelToolsInvokeRequest, signal?: AbortSignal): Promise<unknown> {
76
+ return this.#kernelTools.invoke(request, signal);
77
+ }
78
+
55
79
  async run(input: JavaScriptRunInput): Promise<ResultMessage> {
56
80
  assertJavaScriptKernelOpen(this.#lifecycle, "run");
57
81
  const promise = this.#runs.enqueue(input);
@@ -77,6 +101,7 @@ export class JavaScriptKernel {
77
101
  async reset(): Promise<void> {
78
102
  assertJavaScriptKernelOpen(this.#lifecycle, "reset");
79
103
  await this.#terminate();
104
+ this.#clearToolCalls();
80
105
  assertJavaScriptKernelOpen(this.#lifecycle, "reset");
81
106
  await this.#ensureReady();
82
107
  this.#startNext();
@@ -97,6 +122,8 @@ export class JavaScriptKernel {
97
122
  this.#slot.postMessage({ type: "close" });
98
123
  this.#lifecycle = "closing";
99
124
  this.#runs.settleAll("JS kernel closed");
125
+ this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JS kernel closed"));
126
+ this.#clearToolCalls();
100
127
  const recovery = this.#recovery;
101
128
  const closePromise = (async () => {
102
129
  if (recovery) await recovery;
@@ -140,6 +167,11 @@ export class JavaScriptKernel {
140
167
  if (next.input.timeoutMs) {
141
168
  this.#timeout = setTimeout(() => void this.#timeoutActive(next), next.input.timeoutMs);
142
169
  }
170
+ this.#slot.postMessage({
171
+ type: "kernel-tools-names",
172
+ hostToolNames: resolveKernelToolNameSource(this.#options.hostToolNames),
173
+ foreignLanguageNames: resolveKernelToolNameSource(this.#options.foreignLanguageNames),
174
+ });
143
175
  this.#slot.postMessage({
144
176
  type: "run",
145
177
  cellId: next.input.cellId,
@@ -170,15 +202,19 @@ export class JavaScriptKernel {
170
202
  message: string,
171
203
  durationMs = 0,
172
204
  ): Promise<{ readonly retained: boolean; readonly note?: string }> {
173
- run.interruptResult = { type: "result", cellId: run.input.cellId, ok: false, error: { message }, durationMs };
174
- run.interruptAck ??= Promise.withResolvers<void>();
175
- this.#slot.postMessage({ type: "interrupt", reason });
176
- if ((await awaitCooperativeSettlement(run)) === "settled") return { retained: run.settledByWorker };
177
- if (!this.#runs.releaseActive(run)) return { retained: run.settledByWorker };
178
- const retirement = await this.#terminate();
179
- this.#runs.settle(run, run.interruptResult ?? stoppedResult(run.input.cellId, message));
180
- void this.#recover(() => Promise.resolve());
181
- return retirement === "abandoned" ? { retained: false, note: abandonedWorkerNote() } : { retained: false };
205
+ try {
206
+ run.interruptResult = { type: "result", cellId: run.input.cellId, ok: false, error: { message }, durationMs };
207
+ run.interruptAck ??= Promise.withResolvers<void>();
208
+ this.#slot.postMessage({ type: "interrupt", reason });
209
+ if ((await awaitCooperativeSettlement(run)) === "settled") return { retained: run.settledByWorker };
210
+ if (!this.#runs.releaseActive(run)) return { retained: run.settledByWorker };
211
+ const retirement = await this.#terminate();
212
+ this.#runs.settle(run, run.interruptResult ?? stoppedResult(run.input.cellId, message));
213
+ void this.#recover(() => Promise.resolve());
214
+ return retirement === "abandoned" ? { retained: false, note: abandonedWorkerNote() } : { retained: false };
215
+ } finally {
216
+ this.#clearToolCalls();
217
+ }
182
218
  }
183
219
 
184
220
  async #restartAfterStop(): Promise<void> {
@@ -210,6 +246,7 @@ export class JavaScriptKernel {
210
246
  }
211
247
 
212
248
  #handleMessage(message: KernelToHostMessage): void {
249
+ if (this.#kernelTools.consume(message) && message.type !== "tool-call") return;
213
250
  if (message.type === "status" && message.event.op === INTERRUPT_ACK_OP) {
214
251
  this.#runs.active?.interruptAck?.resolve();
215
252
  return;
@@ -223,7 +260,10 @@ export class JavaScriptKernel {
223
260
  if (message.type === "tool-call") {
224
261
  const waiter = this.#toolWaiters.shift();
225
262
  if (waiter) waiter(message);
226
- else this.#pendingToolCalls.push(message);
263
+ else {
264
+ this.#pendingToolCalls.push(message);
265
+ if (this.#pendingToolCalls.length > MAX_PENDING_TOOL_CALLS) this.#pendingToolCalls.shift();
266
+ }
227
267
  return;
228
268
  }
229
269
  if (message.type !== "result") return;
@@ -240,6 +280,7 @@ export class JavaScriptKernel {
240
280
  const active = this.#runs.active;
241
281
  if (!active && this.#slot.startingUp) return;
242
282
  this.#clearTimeout();
283
+ this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", error.message));
243
284
  if (active) {
244
285
  this.#runs.releaseActive(active);
245
286
  this.#runs.settle(active, {
@@ -250,9 +291,15 @@ export class JavaScriptKernel {
250
291
  durationMs: this.#runs.durationMs(active, performance.now()),
251
292
  });
252
293
  }
294
+ this.#clearToolCalls();
253
295
  void this.#restartAfterStop();
254
296
  }
255
297
 
298
+ #clearToolCalls(): void {
299
+ this.#pendingToolCalls.length = 0;
300
+ this.#toolWaiters.length = 0;
301
+ }
302
+
256
303
  #clearTimeout(): void {
257
304
  if (this.#timeout) clearTimeout(this.#timeout);
258
305
  this.#timeout = null;
@@ -271,6 +318,7 @@ export class JavaScriptKernel {
271
318
  */
272
319
  async #terminate(): Promise<WorkerRetirement> {
273
320
  this.#clearTimeout();
321
+ this.#kernelTools.rejectAll(kernelToolError("kernel_tool_stale", "JavaScript worker reset"));
274
322
  const retirement = await this.#slot.retire();
275
323
  await this.#retireWorkerChildren();
276
324
  return retirement;