@code-yeongyu/senpi 2026.9.15 → 2026.9.16

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 (227) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/core/extensions/builtin/config-reload/index.d.ts.map +1 -1
  3. package/dist/core/extensions/builtin/config-reload/index.js +25 -8
  4. package/dist/core/extensions/builtin/config-reload/index.js.map +1 -1
  5. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts +4 -5
  6. package/dist/core/extensions/builtin/config-reload/watch-engine.d.ts.map +1 -1
  7. package/dist/core/extensions/builtin/config-reload/watch-engine.js +14 -18
  8. package/dist/core/extensions/builtin/config-reload/watch-engine.js.map +1 -1
  9. package/dist/core/extensions/builtin/config-reload/watch-event-source.d.ts.map +1 -1
  10. package/dist/core/extensions/builtin/config-reload/watch-event-source.js +32 -9
  11. package/dist/core/extensions/builtin/config-reload/watch-event-source.js.map +1 -1
  12. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts +23 -0
  13. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.d.ts.map +1 -0
  14. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js +48 -0
  15. package/dist/core/extensions/builtin/cursor-cli-oauth/catalog-refresh.js.map +1 -0
  16. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts +13 -0
  17. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.d.ts.map +1 -0
  18. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js +24 -0
  19. package/dist/core/extensions/builtin/cursor-cli-oauth/environment.js.map +1 -0
  20. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts +1 -0
  21. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.d.ts.map +1 -1
  22. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js +7 -1
  23. package/dist/core/extensions/builtin/cursor-cli-oauth/executable.js.map +1 -1
  24. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts +2 -0
  25. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
  26. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +11 -9
  27. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
  28. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts +18 -0
  29. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.d.ts.map +1 -0
  30. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js +61 -0
  31. package/dist/core/extensions/builtin/cursor-cli-oauth/models-probe.js.map +1 -0
  32. package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts +4 -1
  33. package/dist/core/extensions/builtin/cursor-cli-oauth/models.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js +1 -44
  35. package/dist/core/extensions/builtin/cursor-cli-oauth/models.js.map +1 -1
  36. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +22 -0
  37. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +1 -1
  39. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
  40. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js +2 -13
  42. package/dist/core/extensions/builtin/cursor-cli-oauth/transport.js.map +1 -1
  43. package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts +3 -0
  44. package/dist/core/extensions/builtin/terminal/monitor-file-digest.d.ts.map +1 -0
  45. package/dist/core/extensions/builtin/terminal/monitor-file-digest.js +25 -0
  46. package/dist/core/extensions/builtin/terminal/monitor-file-digest.js.map +1 -0
  47. package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts +9 -0
  48. package/dist/core/extensions/builtin/terminal/monitor-file-watch.d.ts.map +1 -0
  49. package/dist/core/extensions/builtin/terminal/monitor-file-watch.js +33 -0
  50. package/dist/core/extensions/builtin/terminal/monitor-file-watch.js.map +1 -0
  51. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts +6 -0
  52. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.d.ts.map +1 -0
  53. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js +22 -0
  54. package/dist/core/extensions/builtin/terminal/monitor-line-buffer.js.map +1 -0
  55. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
  56. package/dist/core/extensions/builtin/terminal/monitor-registry.js +14 -35
  57. package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
  58. package/dist/core/extensions/kernel-tools-context.d.ts +13 -0
  59. package/dist/core/extensions/kernel-tools-context.d.ts.map +1 -0
  60. package/dist/core/extensions/kernel-tools-context.js +3 -0
  61. package/dist/core/extensions/kernel-tools-context.js.map +1 -0
  62. package/dist/core/extensions/runner.d.ts +19 -0
  63. package/dist/core/extensions/runner.d.ts.map +1 -1
  64. package/dist/core/extensions/runner.js +103 -1
  65. package/dist/core/extensions/runner.js.map +1 -1
  66. package/dist/core/extensions/types.d.ts +21 -0
  67. package/dist/core/extensions/types.d.ts.map +1 -1
  68. package/dist/core/extensions/types.js.map +1 -1
  69. package/dist/core/resource-loader.d.ts.map +1 -1
  70. package/dist/core/resource-loader.js +9 -17
  71. package/dist/core/resource-loader.js.map +1 -1
  72. package/dist/core/session-manager.d.ts +3 -0
  73. package/dist/core/session-manager.d.ts.map +1 -1
  74. package/dist/core/session-manager.js +14 -0
  75. package/dist/core/session-manager.js.map +1 -1
  76. package/dist/core/settings-manager.d.ts +23 -0
  77. package/dist/core/settings-manager.d.ts.map +1 -1
  78. package/dist/core/settings-manager.js +41 -0
  79. package/dist/core/settings-manager.js.map +1 -1
  80. package/dist/core/tools/index.d.ts +1 -1
  81. package/dist/core/tools/index.d.ts.map +1 -1
  82. package/dist/core/tools/index.js +4 -3
  83. package/dist/core/tools/index.js.map +1 -1
  84. package/dist/core/tools/read.d.ts +3 -1
  85. package/dist/core/tools/read.d.ts.map +1 -1
  86. package/dist/core/tools/read.js +16 -2
  87. package/dist/core/tools/read.js.map +1 -1
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +1 -0
  91. package/dist/index.js.map +1 -1
  92. package/dist/modes/interactive/interactive-mode.js +3 -3
  93. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  94. package/dist/modes/rpc/host-watchdog.d.ts.map +1 -1
  95. package/dist/modes/rpc/host-watchdog.js +5 -24
  96. package/dist/modes/rpc/host-watchdog.js.map +1 -1
  97. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  98. package/dist/modes/rpc/rpc-mode.js +3 -8
  99. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  100. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  101. package/dist/modes/rpc/session-command-router.js +3 -0
  102. package/dist/modes/rpc/session-command-router.js.map +1 -1
  103. package/dist/modes/rpc/session-worker-client.d.ts +3 -0
  104. package/dist/modes/rpc/session-worker-client.d.ts.map +1 -1
  105. package/dist/modes/rpc/session-worker-client.js +17 -6
  106. package/dist/modes/rpc/session-worker-client.js.map +1 -1
  107. package/dist/modes/rpc/shutdown.d.ts +3 -0
  108. package/dist/modes/rpc/shutdown.d.ts.map +1 -0
  109. package/dist/modes/rpc/shutdown.js +17 -0
  110. package/dist/modes/rpc/shutdown.js.map +1 -0
  111. package/docs/extensions.md +3 -0
  112. package/docs/settings.md +12 -0
  113. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +36 -0
  114. package/node_modules/@code-yeongyu/senpi-codemode/README.md +24 -0
  115. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  116. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/http-server.ts +7 -1
  117. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/kernel-tools-protocol.ts +85 -0
  118. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +6 -0
  119. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +30 -11
  120. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +11 -0
  121. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
  122. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +46 -0
  123. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +1 -1
  124. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +58 -10
  125. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-contract.ts +12 -0
  126. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.d.ts +13 -0
  127. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-context.js +7 -0
  128. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.d.ts +10 -0
  129. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-define.js +12 -0
  130. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.js +22 -0
  131. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-errors.ts +26 -0
  132. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-host.ts +134 -0
  133. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-naming.js +28 -0
  134. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.d.ts +5 -0
  135. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-parse.js +255 -0
  136. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-pump.js +105 -0
  137. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.d.ts +27 -0
  138. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-registry.js +127 -0
  139. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-schema.js +69 -0
  140. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/kernel-tools-types.ts +42 -0
  141. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -0
  142. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +26 -3
  143. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +20 -8
  144. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-slot.ts +6 -1
  145. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-startup.ts +9 -7
  146. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/workpool.js +37 -0
  147. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/kernel-tools-unavailable.ts +5 -0
  148. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +13 -0
  149. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +57 -3
  150. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +13 -2
  151. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/workpool.rb +38 -0
  152. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-kernel.ts +13 -0
  153. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +9 -1
  154. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +4 -2
  155. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +8 -1
  156. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +36 -71
  157. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image-resize.ts +52 -0
  158. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +37 -72
  159. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/managed-cell.ts +78 -0
  160. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +30 -5
  161. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/run-eval-cell.ts +49 -30
  162. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/terminal-snapshot-store.ts +35 -0
  163. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/tool-result-marshal.ts +23 -0
  164. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -0
  165. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
  166. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +51 -12
  167. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
  168. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts +3 -0
  169. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.d.ts.map +1 -1
  170. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js +18 -3
  171. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/read.js.map +1 -1
  172. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts +4 -0
  173. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.d.ts.map +1 -0
  174. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js +268 -0
  175. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/brace-scanner.js.map +1 -0
  176. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts +18 -0
  177. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.d.ts.map +1 -0
  178. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js +69 -0
  179. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/header-protection.js.map +1 -0
  180. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts +27 -0
  181. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.d.ts.map +1 -0
  182. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js +118 -0
  183. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/index.js.map +1 -0
  184. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts +21 -0
  185. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.d.ts.map +1 -0
  186. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js +24 -0
  187. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-context.js.map +1 -0
  188. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts +12 -0
  189. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.d.ts.map +1 -0
  190. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js +92 -0
  191. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/lexical-spans.js.map +1 -0
  192. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts +47 -0
  193. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.d.ts.map +1 -0
  194. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js +8 -0
  195. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/read-folders/types.js.map +1 -0
  196. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts +52 -0
  197. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.d.ts.map +1 -0
  198. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js +155 -0
  199. package/node_modules/@earendil-works/pi-agent-core/dist/harness/utils/segmented-read-view.js.map +1 -0
  200. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +2 -0
  201. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
  202. package/node_modules/@earendil-works/pi-agent-core/dist/index.js +2 -0
  203. package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
  204. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  205. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  206. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  207. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  208. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/data/alibaba-token-plan.json +1 -1
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan.json +1 -1
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  216. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts +15 -0
  217. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.d.ts.map +1 -0
  218. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js +15 -0
  219. package/node_modules/@earendil-works/pi-ai/dist/utils/empty-response-errors.js.map +1 -0
  220. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  221. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +10 -0
  222. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  223. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  224. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  225. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  226. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  227. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"session-worker-client.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-worker-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport { isBunBinary } from \"../../config.ts\";\nimport type { CliRuntimeConfiguration } from \"../../main.ts\";\nimport type { RpcConnectionOptions } from \"./connection-handler.ts\";\nimport type { RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type { RpcSessionLaunchProfile } from \"./session-registry.ts\";\nimport type {\n\tHostToSessionWorker,\n\tSessionWorkerToHost,\n\tSessionWriteGrant,\n\tWorkerDisplay,\n\tWorkerSnapshot,\n} from \"./session-worker-protocol.ts\";\n\nimport { SessionWorkerRequests, type WorkerRequestInput } from \"./session-worker-requests.ts\";\nimport { acknowledge, acknowledgeGrant, respondDisplay } from \"./session-worker-signals.ts\";\n\n/** Lifecycle hooks the owning registry installs on every worker it allocates. */\nexport interface SessionWorkerCallbacks {\n\treserve: (path: string) => SessionWriteGrant;\n\t/** Every snapshot republishes which paths this worker still writes. */\n\treconcile: (livePaths: readonly string[]) => void;\n\texit: () => void;\n\tfailure: (error: string) => void;\n}\n\n/** Bun wrapper builders define the worker entry name relative to their explicit --root. */\ndeclare const SENPI_RPC_SESSION_WORKER_ENTRY: string | undefined;\nconst compiledWorkerEntry =\n\ttypeof SENPI_RPC_SESSION_WORKER_ENTRY === \"string\"\n\t\t? SENPI_RPC_SESSION_WORKER_ENTRY\n\t\t: \"./src/modes/rpc/session-worker.ts\";\n\nexport class SessionWorkerClient {\n\treadonly worker = new Worker(\n\t\tisBunBinary\n\t\t\t? fileURLToPath(new URL(compiledWorkerEntry, import.meta.url)).replaceAll(\"\\\\\", \"/\")\n\t\t\t: new URL(import.meta.url.endsWith(\".ts\") ? \"./session-worker.ts\" : \"./session-worker.js\", import.meta.url),\n\t);\n\treadonly exited: Promise<void>;\n\tsnapshot?: WorkerSnapshot;\n\t/** Main marks this only after installing the unique routing binding. */\n\tbindingReady = false;\n\tprivate readonly requests = new SessionWorkerRequests(\n\t\t(message) => this.worker.postMessage(message),\n\t\t() => this.fail(\"session_worker_request_timeout\"),\n\t);\n\tprivate stopped = false;\n\tprivate displayRevision = 0;\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\tprivate writer?: SessionEventWriter;\n\tprivate sessionId?: string;\n\tprivate requestClose?: () => void;\n\tprivate options: Pick<RpcConnectionOptions, \"capabilities\" | \"sharedWidth\"> = {};\n\tprivate readonly listeners = new Set<() => void>();\n\tprivate readonly controls = new Set<\"display\" | \"cancel_ui\">();\n\tprivate latestDisplay?: Extract<HostToSessionWorker, { type: \"display\" }>;\n\n\tprivate readonly callbacks: SessionWorkerCallbacks;\n\n\tconstructor(callbacks: SessionWorkerCallbacks) {\n\t\tthis.callbacks = callbacks;\n\t\tthis.exited = new Promise((resolve) => {\n\t\t\tthis.worker.once(\"exit\", () => {\n\t\t\t\tif (!this.stopped && !this.closeTimer) this.fail(\"session_worker_exited\");\n\t\t\t\tthis.stopped = true;\n\t\t\t\tif (this.closeTimer) clearTimeout(this.closeTimer);\n\t\t\t\tthis.requests.close(new Error(\"session_worker_exited\"));\n\t\t\t\tthis.listeners.clear();\n\t\t\t\tcallbacks.exit();\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t\tthis.worker.on(\"message\", (message: SessionWorkerToHost) => this.receive(message));\n\t\tthis.worker.on(\"error\", (error: unknown) => this.fail(error instanceof Error ? error.message : String(error)));\n\t}\n\n\tasync prepare(configuration: CliRuntimeConfiguration, profile: RpcSessionLaunchProfile): Promise<string> {\n\t\tconst result = await this.request({ type: \"prepare\", configuration, profile });\n\t\tif (result.type !== \"prepared\") throw new Error(\"Invalid worker prepare response\");\n\t\treturn result.sessionPath;\n\t}\n\n\tasync commit(): Promise<WorkerSnapshot> {\n\t\tconst result = await this.request({ type: \"commit\" });\n\t\tif (result.type !== \"ready\") throw new Error(\"Invalid worker commit response\");\n\t\tthis.snapshot = result.snapshot;\n\t\treturn result.snapshot;\n\t}\n\n\tasync bind(\n\t\tsessionId: string,\n\t\twriter: SessionEventWriter,\n\t\trequestClose: () => void,\n\t\toptions: Pick<RpcConnectionOptions, \"capabilities\" | \"sharedWidth\">,\n\t): Promise<RpcSessionBinding> {\n\t\tthis.sessionId = sessionId;\n\t\tthis.writer = writer;\n\t\tthis.requestClose = requestClose;\n\t\tthis.options = options;\n\t\tawait this.request({ type: \"bind\", sessionId, display: this.display(), connection: writer.currentConnection() });\n\t\treturn {\n\t\t\thandle: async (command) => {\n\t\t\t\tawait this.request({\n\t\t\t\t\ttype: \"command\",\n\t\t\t\t\tcommand,\n\t\t\t\t\tconnection: writer.currentConnection(),\n\t\t\t\t\tdisplay: this.display(),\n\t\t\t\t});\n\t\t\t},\n\t\t\tcancelPendingExtensionUiRequests: () => this.post({ type: \"cancel_ui\" }),\n\t\t\trerenderComponents: () => this.post({ type: \"display\", display: this.display() }),\n\t\t\tdispose: async () => {\n\t\t\t\tthis.post({ type: \"cancel_ui\" });\n\t\t\t},\n\t\t};\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.requests.activeCount > 0 || this.snapshot?.busy === true;\n\t}\n\n\tsubscribeSettled(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/** Deadline requests termination, but only the actual exit callback releases ownership. */\n\tclose(graceMs: number): Promise<void> {\n\t\tif (this.stopped || this.closeTimer) return this.exited;\n\t\tthis.post({ type: \"close\" });\n\t\tthis.closeTimer = setTimeout(() => this.quarantine(), graceMs);\n\t\treturn this.exited;\n\t}\n\n\tquarantine(): void {\n\t\tthis.stopped = true;\n\t\tthis.requests.close(new Error(\"session_closing\"));\n\t\tvoid this.worker.terminate();\n\t}\n\n\tprivate display(): WorkerDisplay {\n\t\treturn {\n\t\t\trevision: ++this.displayRevision,\n\t\t\twidth: this.options.sharedWidth?.getWidth() ?? 80,\n\t\t\trendered: this.options.sharedWidth?.hasRenderedComponents?.(this.sessionId ?? \"\") ?? false,\n\t\t\tcapabilities: this.options.capabilities ?? [],\n\t\t};\n\t}\n\n\tprivate request(message: WorkerRequestInput): ReturnType<SessionWorkerRequests[\"request\"]> {\n\t\treturn this.requests.request(message);\n\t}\n\n\tprivate post(message: HostToSessionWorker): void {\n\t\tif (this.stopped) return;\n\t\tif (message.type === \"display\" || message.type === \"cancel_ui\") {\n\t\t\tif (this.controls.has(message.type)) {\n\t\t\t\tif (message.type === \"display\") this.latestDisplay = message;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.controls.add(message.type);\n\t\t}\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tprivate receive(message: SessionWorkerToHost): void {\n\t\tif (this.stopped) {\n\t\t\tif (\"signal\" in message) acknowledge(message.signal, false);\n\t\t\treturn;\n\t\t}\n\t\tswitch (message.type) {\n\t\t\tcase \"prepared\":\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tthis.requests.receive(message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"reserve\":\n\t\t\t\tacknowledgeGrant(message.signal, this.callbacks.reserve(message.path));\n\t\t\t\treturn;\n\t\t\tcase \"snapshot\":\n\t\t\t\tthis.snapshot = message.snapshot;\n\t\t\t\tthis.callbacks.reconcile(message.snapshot.liveSessionPaths);\n\t\t\t\tacknowledge(message.signal, true);\n\t\t\t\tif (message.settled) for (const listener of [...this.listeners]) listener();\n\t\t\t\treturn;\n\t\t\tcase \"control_done\": {\n\t\t\t\tthis.controls.delete(message.control);\n\t\t\t\tif (message.control === \"display\" && this.latestDisplay) {\n\t\t\t\t\tconst latest = this.latestDisplay;\n\t\t\t\t\tthis.latestDisplay = undefined;\n\t\t\t\t\tthis.post(latest);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"output\": {\n\t\t\t\tconst writer = this.writer;\n\t\t\t\tconst sessionId = this.sessionId;\n\t\t\t\tif (!writer || !sessionId || this.stopped) {\n\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Identity and activity commit before publication; clients may attach or disconnect on that event.\n\t\t\t\tif (message.snapshot) {\n\t\t\t\t\tthis.snapshot = message.snapshot;\n\t\t\t\t\tthis.callbacks.reconcile(message.snapshot.liveSessionPaths);\n\t\t\t\t} else if (this.snapshot)\n\t\t\t\t\tthis.snapshot = {\n\t\t\t\t\t\t...this.snapshot,\n\t\t\t\t\t\t...message.activity,\n\t\t\t\t\t\tstate: { ...this.snapshot.state, isStreaming: message.activity.streaming },\n\t\t\t\t\t};\n\t\t\t\tconst enqueue = () => {\n\t\t\t\t\tif (!writer.enqueue(sessionId, message.record)) {\n\t\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\t\tthis.fail(\"session_output_overflow_or_closed\");\n\t\t\t\t\t\treturn Promise.reject(new Error(\"session_output_overflow_or_closed\"));\n\t\t\t\t\t}\n\t\t\t\t\treturn writer.waitForSessionBackpressure(sessionId);\n\t\t\t\t};\n\t\t\t\tconst consumed =\n\t\t\t\t\tmessage.connection === undefined ? enqueue() : writer.withConnection(message.connection, enqueue);\n\t\t\t\tvoid consumed.then(\n\t\t\t\t\t() => acknowledge(message.signal, true),\n\t\t\t\t\t(cause: unknown) => {\n\t\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\t\tthis.fail(cause instanceof Error ? cause.message : String(cause));\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"width\":\n\t\t\t\tthis.options.sharedWidth?.setWidth(message.connection, message.width);\n\t\t\t\tthis.options.sharedWidth?.onChange?.();\n\t\t\t\trespondDisplay(message.signal, this.display());\n\t\t\t\treturn;\n\t\t\tcase \"capabilities\":\n\t\t\t\tthis.options.sharedWidth?.setCapabilities?.(message.connection, message.capabilities);\n\t\t\t\trespondDisplay(message.signal, this.display());\n\t\t\t\treturn;\n\t\t\tcase \"request_close\":\n\t\t\t\tthis.requestClose?.();\n\t\t\t\treturn;\n\t\t\tcase \"failure\":\n\t\t\t\tthis.fail(message.error);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate fail(error: string): void {\n\t\tif (this.stopped) return;\n\t\tthis.callbacks.failure(error);\n\t\tif (this.writer && this.sessionId) {\n\t\t\tthis.writer.enqueue(this.sessionId, { type: \"session_error\", error });\n\t\t\tthis.writer.closeSession(this.sessionId, {\n\t\t\t\ttype: \"response\",\n\t\t\t\tcommand: \"close_session\",\n\t\t\t\tsuccess: false,\n\t\t\t\terror,\n\t\t\t});\n\t\t}\n\t\tthis.quarantine();\n\t}\n}\n"]}
1
+ {"version":3,"file":"session-worker-client.js","sourceRoot":"","sources":["../../../src/modes/rpc/session-worker-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { fileURLToPath } from \"node:url\";\nimport { Worker } from \"node:worker_threads\";\nimport { isBunBinary } from \"../../config.ts\";\nimport type { CliRuntimeConfiguration } from \"../../main.ts\";\nimport type { RpcConnectionOptions } from \"./connection-handler.ts\";\nimport type { RpcSessionBinding } from \"./session-binding.ts\";\nimport type { SessionEventWriter } from \"./session-event-writer.ts\";\nimport type { RpcSessionLaunchProfile } from \"./session-registry.ts\";\nimport type {\n\tHostToSessionWorker,\n\tSessionWorkerToHost,\n\tSessionWriteGrant,\n\tWorkerDisplay,\n\tWorkerSnapshot,\n} from \"./session-worker-protocol.ts\";\n\nimport { SessionWorkerRequests, type WorkerRequestInput } from \"./session-worker-requests.ts\";\nimport { acknowledge, acknowledgeGrant, respondDisplay } from \"./session-worker-signals.ts\";\n\n/** Lifecycle hooks the owning registry installs on every worker it allocates. */\nexport interface SessionWorkerCallbacks {\n\treserve: (path: string) => SessionWriteGrant;\n\t/** Every snapshot republishes which paths this worker still writes. */\n\treconcile: (livePaths: readonly string[]) => void;\n\texit: () => void;\n\tfailure: (error: string) => void;\n}\n\n/** Bun wrapper builders define the worker entry name relative to their explicit --root. */\ndeclare const SENPI_RPC_SESSION_WORKER_ENTRY: string | undefined;\nconst compiledWorkerEntry =\n\ttypeof SENPI_RPC_SESSION_WORKER_ENTRY === \"string\"\n\t\t? SENPI_RPC_SESSION_WORKER_ENTRY\n\t\t: \"./src/modes/rpc/session-worker.ts\";\n\nexport class SessionWorkerClient {\n\treadonly worker = new Worker(\n\t\tisBunBinary\n\t\t\t? fileURLToPath(new URL(compiledWorkerEntry, import.meta.url)).replaceAll(\"\\\\\", \"/\")\n\t\t\t: new URL(import.meta.url.endsWith(\".ts\") ? \"./session-worker.ts\" : \"./session-worker.js\", import.meta.url),\n\t);\n\treadonly exited: Promise<void>;\n\tsnapshot?: WorkerSnapshot;\n\t/** Main marks this only after installing the unique routing binding. */\n\tbindingReady = false;\n\tprivate readonly requests = new SessionWorkerRequests(\n\t\t(message) => this.worker.postMessage(message),\n\t\t() => this.fail(\"session_worker_request_timeout\"),\n\t);\n\tprivate stopped = false;\n\tprivate displayRevision = 0;\n\tprivate closeTimer?: ReturnType<typeof setTimeout>;\n\tprivate writer?: SessionEventWriter;\n\tprivate sessionId?: string;\n\tprivate requestClose?: () => void;\n\tprivate options: Pick<RpcConnectionOptions, \"capabilities\" | \"sharedWidth\"> = {};\n\tprivate readonly listeners = new Set<() => void>();\n\tprivate readonly controls = new Set<\"display\" | \"cancel_ui\">();\n\tprivate latestDisplay?: Extract<HostToSessionWorker, { type: \"display\" }>;\n\tprivate terminalFailure?: string;\n\n\tprivate readonly callbacks: SessionWorkerCallbacks;\n\n\tconstructor(callbacks: SessionWorkerCallbacks) {\n\t\tthis.callbacks = callbacks;\n\t\tthis.exited = new Promise((resolve) => {\n\t\t\tthis.worker.once(\"exit\", () => {\n\t\t\t\tif (!this.stopped && !this.closeTimer) this.fail(\"session_worker_exited\");\n\t\t\t\tthis.stopped = true;\n\t\t\t\tif (this.closeTimer) clearTimeout(this.closeTimer);\n\t\t\t\tthis.requests.close(new Error(\"session_worker_exited\"));\n\t\t\t\tthis.listeners.clear();\n\t\t\t\tcallbacks.exit();\n\t\t\t\tthis.publishTerminalFailure();\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t\tthis.worker.on(\"message\", (message: SessionWorkerToHost) => this.receive(message));\n\t\tthis.worker.on(\"error\", (error: unknown) => this.fail(error instanceof Error ? error.message : String(error)));\n\t}\n\n\tasync prepare(configuration: CliRuntimeConfiguration, profile: RpcSessionLaunchProfile): Promise<string> {\n\t\tconst result = await this.request({ type: \"prepare\", configuration, profile });\n\t\tif (result.type !== \"prepared\") throw new Error(\"Invalid worker prepare response\");\n\t\treturn result.sessionPath;\n\t}\n\n\tasync commit(): Promise<WorkerSnapshot> {\n\t\tconst result = await this.request({ type: \"commit\" });\n\t\tif (result.type !== \"ready\") throw new Error(\"Invalid worker commit response\");\n\t\tthis.snapshot = result.snapshot;\n\t\treturn result.snapshot;\n\t}\n\n\tasync bind(\n\t\tsessionId: string,\n\t\twriter: SessionEventWriter,\n\t\trequestClose: () => void,\n\t\toptions: Pick<RpcConnectionOptions, \"capabilities\" | \"sharedWidth\">,\n\t): Promise<RpcSessionBinding> {\n\t\tthis.sessionId = sessionId;\n\t\tthis.writer = writer;\n\t\tthis.requestClose = requestClose;\n\t\tthis.options = options;\n\t\tawait this.request({ type: \"bind\", sessionId, display: this.display(), connection: writer.currentConnection() });\n\t\treturn {\n\t\t\thandle: async (command) => {\n\t\t\t\tawait this.request({\n\t\t\t\t\ttype: \"command\",\n\t\t\t\t\tcommand,\n\t\t\t\t\tconnection: writer.currentConnection(),\n\t\t\t\t\tdisplay: this.display(),\n\t\t\t\t});\n\t\t\t},\n\t\t\tcancelPendingExtensionUiRequests: () => this.post({ type: \"cancel_ui\" }),\n\t\t\trerenderComponents: () => this.post({ type: \"display\", display: this.display() }),\n\t\t\tdispose: async () => {\n\t\t\t\tthis.post({ type: \"cancel_ui\" });\n\t\t\t},\n\t\t};\n\t}\n\n\tget busy(): boolean {\n\t\treturn this.requests.activeCount > 0 || this.snapshot?.busy === true;\n\t}\n\n\tsubscribeSettled(listener: () => void): () => void {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t}\n\n\t/** Deadline requests termination, but only the actual exit callback releases ownership. */\n\tclose(graceMs: number): Promise<void> {\n\t\tif (this.stopped || this.closeTimer) return this.exited;\n\t\tthis.post({ type: \"close\" });\n\t\tthis.closeTimer = setTimeout(() => this.quarantine(), graceMs);\n\t\treturn this.exited;\n\t}\n\n\tquarantine(): void {\n\t\tthis.stopped = true;\n\t\tthis.requests.close(new Error(\"session_closing\"));\n\t\tvoid this.worker.terminate();\n\t}\n\n\tprivate display(): WorkerDisplay {\n\t\treturn {\n\t\t\trevision: ++this.displayRevision,\n\t\t\twidth: this.options.sharedWidth?.getWidth() ?? 80,\n\t\t\trendered: this.options.sharedWidth?.hasRenderedComponents?.(this.sessionId ?? \"\") ?? false,\n\t\t\tcapabilities: this.options.capabilities ?? [],\n\t\t};\n\t}\n\n\tprivate request(message: WorkerRequestInput): ReturnType<SessionWorkerRequests[\"request\"]> {\n\t\treturn this.requests.request(message);\n\t}\n\n\tprivate post(message: HostToSessionWorker): void {\n\t\tif (this.stopped) return;\n\t\tif (message.type === \"display\" || message.type === \"cancel_ui\") {\n\t\t\tif (this.controls.has(message.type)) {\n\t\t\t\tif (message.type === \"display\") this.latestDisplay = message;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.controls.add(message.type);\n\t\t}\n\t\tthis.worker.postMessage(message);\n\t}\n\n\tprivate receive(message: SessionWorkerToHost): void {\n\t\tif (this.stopped) {\n\t\t\tif (\"signal\" in message) acknowledge(message.signal, false);\n\t\t\treturn;\n\t\t}\n\t\tswitch (message.type) {\n\t\t\tcase \"prepared\":\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tthis.requests.receive(message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"reserve\":\n\t\t\t\tacknowledgeGrant(message.signal, this.callbacks.reserve(message.path));\n\t\t\t\treturn;\n\t\t\tcase \"snapshot\":\n\t\t\t\tthis.snapshot = message.snapshot;\n\t\t\t\tthis.callbacks.reconcile(message.snapshot.liveSessionPaths);\n\t\t\t\tacknowledge(message.signal, true);\n\t\t\t\tif (message.settled) for (const listener of [...this.listeners]) listener();\n\t\t\t\treturn;\n\t\t\tcase \"control_done\": {\n\t\t\t\tthis.controls.delete(message.control);\n\t\t\t\tif (message.control === \"display\" && this.latestDisplay) {\n\t\t\t\t\tconst latest = this.latestDisplay;\n\t\t\t\t\tthis.latestDisplay = undefined;\n\t\t\t\t\tthis.post(latest);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"output\": {\n\t\t\t\tconst writer = this.writer;\n\t\t\t\tconst sessionId = this.sessionId;\n\t\t\t\tif (!writer || !sessionId || this.stopped) {\n\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// Identity and activity commit before publication; clients may attach or disconnect on that event.\n\t\t\t\tif (message.snapshot) {\n\t\t\t\t\tthis.snapshot = message.snapshot;\n\t\t\t\t\tthis.callbacks.reconcile(message.snapshot.liveSessionPaths);\n\t\t\t\t} else if (this.snapshot)\n\t\t\t\t\tthis.snapshot = {\n\t\t\t\t\t\t...this.snapshot,\n\t\t\t\t\t\t...message.activity,\n\t\t\t\t\t\tstate: { ...this.snapshot.state, isStreaming: message.activity.streaming },\n\t\t\t\t\t};\n\t\t\t\tconst enqueue = () => {\n\t\t\t\t\tif (!writer.enqueue(sessionId, message.record)) {\n\t\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\t\tthis.fail(\"session_output_overflow_or_closed\");\n\t\t\t\t\t\treturn Promise.reject(new Error(\"session_output_overflow_or_closed\"));\n\t\t\t\t\t}\n\t\t\t\t\treturn writer.waitForSessionBackpressure(sessionId);\n\t\t\t\t};\n\t\t\t\tconst consumed =\n\t\t\t\t\tmessage.connection === undefined ? enqueue() : writer.withConnection(message.connection, enqueue);\n\t\t\t\tvoid consumed.then(\n\t\t\t\t\t() => acknowledge(message.signal, true),\n\t\t\t\t\t(cause: unknown) => {\n\t\t\t\t\t\tacknowledge(message.signal, false);\n\t\t\t\t\t\tthis.fail(cause instanceof Error ? cause.message : String(cause));\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcase \"width\":\n\t\t\t\tthis.options.sharedWidth?.setWidth(message.connection, message.width);\n\t\t\t\tthis.options.sharedWidth?.onChange?.();\n\t\t\t\trespondDisplay(message.signal, this.display());\n\t\t\t\treturn;\n\t\t\tcase \"capabilities\":\n\t\t\t\tthis.options.sharedWidth?.setCapabilities?.(message.connection, message.capabilities);\n\t\t\t\trespondDisplay(message.signal, this.display());\n\t\t\t\treturn;\n\t\t\tcase \"request_close\":\n\t\t\t\tthis.requestClose?.();\n\t\t\t\treturn;\n\t\t\tcase \"failure\":\n\t\t\t\tthis.fail(message.error);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprivate fail(error: string): void {\n\t\tif (this.stopped) return;\n\t\tthis.callbacks.failure(error);\n\t\tthis.terminalFailure = error;\n\t\tif (this.writer && this.sessionId) {\n\t\t\tthis.writer.enqueue(this.sessionId, { type: \"session_error\", error });\n\t\t}\n\t\tthis.quarantine();\n\t}\n\n\t/** Terminal close records observe completed registry removal, including worker failure. */\n\tprivate publishTerminalFailure(): void {\n\t\tconst error = this.terminalFailure;\n\t\tconst writer = this.writer;\n\t\tconst sessionId = this.sessionId;\n\t\tif (error === undefined || !writer || !sessionId) return;\n\t\tthis.terminalFailure = undefined;\n\t\twriter.closeSession(sessionId, {\n\t\t\ttype: \"response\",\n\t\t\tcommand: \"close_session\",\n\t\t\tsuccess: false,\n\t\t\terror,\n\t\t});\n\t}\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /** Process shutdown entry shared by EOF, signals and transport failures. */
2
+ export declare function createRpcShutdown(dispose: (signal?: NodeJS.Signals) => Promise<void>, exit: (code: number) => never): (exitCode?: number, signal?: NodeJS.Signals) => Promise<never>;
3
+ //# sourceMappingURL=shutdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.d.ts","sourceRoot":"","sources":["../../../src/modes/rpc/shutdown.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,EACnD,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,GAC3B,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,CAYhE"}
@@ -0,0 +1,17 @@
1
+ /** Process shutdown entry shared by EOF, signals and transport failures. */
2
+ export function createRpcShutdown(dispose, exit) {
3
+ let pending;
4
+ let code = 0;
5
+ return (exitCode = 0, signal) => {
6
+ if (code === 0)
7
+ code = exitCode;
8
+ if (pending)
9
+ return pending;
10
+ pending = (async () => {
11
+ await dispose(signal);
12
+ return exit(code);
13
+ })();
14
+ return pending;
15
+ };
16
+ }
17
+ //# sourceMappingURL=shutdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shutdown.js","sourceRoot":"","sources":["../../../src/modes/rpc/shutdown.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,UAAU,iBAAiB,CAChC,OAAmD,EACnD,IAA6B;IAE7B,IAAI,OAAmC,CAAC;IACxC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,MAAuB,EAAkB,EAAE;QAChE,IAAI,IAAI,KAAK,CAAC;YAAE,IAAI,GAAG,QAAQ,CAAC;QAChC,IAAI,OAAO;YAAE,OAAO,OAAO,CAAC;QAC5B,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YACrB,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;YACtB,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,OAAO,CAAC;IAChB,CAAC,CAAC;AACH,CAAC","sourcesContent":["/** Process shutdown entry shared by EOF, signals and transport failures. */\nexport function createRpcShutdown(\n\tdispose: (signal?: NodeJS.Signals) => Promise<void>,\n\texit: (code: number) => never,\n): (exitCode?: number, signal?: NodeJS.Signals) => Promise<never> {\n\tlet pending: Promise<never> | undefined;\n\tlet code = 0;\n\treturn (exitCode = 0, signal?: NodeJS.Signals): Promise<never> => {\n\t\tif (code === 0) code = exitCode;\n\t\tif (pending) return pending;\n\t\tpending = (async () => {\n\t\t\tawait dispose(signal);\n\t\t\treturn exit(code);\n\t\t})();\n\t\treturn pending;\n\t};\n}\n"]}
@@ -619,10 +619,13 @@ Fired before a started session runtime is torn down. Use this to clean up resour
619
619
  pi.on("session_shutdown", async (event, ctx) => {
620
620
  // event.reason - "quit" | "reload" | "new" | "resume" | "fork"
621
621
  // event.targetSessionFile - destination session for session replacement flows
622
+ // event.signal - aborted when this handler exceeds the host's shutdown budget
622
623
  // Cleanup, save state, etc.
623
624
  });
624
625
  ```
625
626
 
627
+ The host budgets each handler separately: a handler still running after `sessionShutdownHandlerWarnMs` (default 2000) logs a warning naming the extension, and at `sessionShutdownHandlerTimeoutMs` (default 10000) senpi aborts that handler's `event.signal`, reports an extension error, and continues teardown with the remaining handlers. Keep shutdown work short, and pass `event.signal` to anything that can block (subprocess waits, network calls, lock acquisition) so it stops when the host gives up on it. Both thresholds are settings; `0` disables either half. See [settings.md](settings.md#shutdown-handler-budget).
628
+
626
629
  ### Agent Events
627
630
 
628
631
  #### before_agent_start
package/docs/settings.md CHANGED
@@ -505,6 +505,8 @@ While a question is pending, the terminal title shows `? <header>` unless an act
505
505
  | Setting | Type | Default | Description |
506
506
  |---------|------|---------|-------------|
507
507
  | `sessionDir` | string | - | Directory where session files are stored. Accepts absolute or relative paths, plus `~`. |
508
+ | `sessionShutdownHandlerWarnMs` | number | `2000` | Warn when a single extension's `session_shutdown` handler has run this long. Set to `0` to disable the warning. |
509
+ | `sessionShutdownHandlerTimeoutMs` | number | `10000` | Hard cap for a single extension's `session_shutdown` handler. Set to `0` to disable the cap. |
508
510
 
509
511
  ```json
510
512
  { "sessionDir": ".senpi/sessions" }
@@ -512,6 +514,16 @@ While a question is pending, the terminal title shows `? <header>` unless an act
512
514
 
513
515
  When multiple sources specify a session directory, precedence is `--session-dir`, `SENPI_CODING_AGENT_SESSION_DIR`, then `sessionDir` in settings.json.
514
516
 
517
+ #### Shutdown handler budget
518
+
519
+ senpi bounds each extension's `session_shutdown` handler so one slow extension cannot hold quit, `/reload`, `/new`, `/resume` or a fork hostage. Past `sessionShutdownHandlerWarnMs` it logs one warning naming the extension; at `sessionShutdownHandlerTimeoutMs` it aborts the `signal` that handler received on the event, reports an extension error, and continues teardown with the next handler. The handler itself is not killed - it keeps running until the process exits - so extensions that persist durable state should observe `event.signal`.
520
+
521
+ ```json
522
+ { "sessionShutdownHandlerWarnMs": 2000, "sessionShutdownHandlerTimeoutMs": 10000 }
523
+ ```
524
+
525
+ Only `session_shutdown` is bounded; other extension events (including ask-user and approval dialogs, which may legitimately wait for minutes) are unaffected.
526
+
515
527
  ### Model Cycling
516
528
 
517
529
  | Setting | Type | Default | Description |
@@ -12,6 +12,42 @@
12
12
 
13
13
  ### Removed
14
14
 
15
+ ## [2026.9.16] - 2026-09-16
16
+
17
+ ### Breaking Changes
18
+
19
+ - 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)).
20
+
21
+ ### Added
22
+
23
+ - 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)).
24
+ - 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)).
25
+ - 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)).
26
+ - `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)).
27
+
28
+ ### Changed
29
+
30
+ - 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)).
31
+
32
+ ### Fixed
33
+
34
+ ### Removed
35
+
36
+ ## [2026.9.15-2] - 2026-09-15
37
+
38
+ ### Breaking Changes
39
+
40
+ ### Added
41
+
42
+ ### Changed
43
+
44
+ ### Fixed
45
+
46
+ - 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)).
47
+ - 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)).
48
+
49
+ ### Removed
50
+
15
51
  ## [2026.9.15] - 2026-09-15
16
52
 
17
53
  ### 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",
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",
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"
39
39
  },
40
40
  "devDependencies": {
41
- "@code-yeongyu/senpi": "2026.9.15"
41
+ "@code-yeongyu/senpi": "2026.9.16"
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