@code-yeongyu/senpi 2026.7.31 → 2026.8.1

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 (491) hide show
  1. package/CHANGELOG.md +237 -0
  2. package/dist/core/agent-session.d.ts +49 -13
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +120 -37
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/dynamic-prompt/build.d.ts.map +1 -1
  7. package/dist/core/dynamic-prompt/build.js +4 -0
  8. package/dist/core/dynamic-prompt/build.js.map +1 -1
  9. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-command.d.ts +2 -2
  10. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-command.d.ts.map +1 -1
  11. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-command.js +25 -25
  12. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-command.js.map +1 -1
  13. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-events.d.ts.map +1 -1
  14. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-events.js.map +1 -1
  15. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-management.d.ts +1 -1
  16. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-management.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-management.js +2 -2
  18. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-management.js.map +1 -1
  19. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/accounts.d.ts +9 -9
  20. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/accounts.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/accounts.js +2 -2
  22. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/accounts.js.map +1 -1
  23. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/affinity.d.ts +1 -1
  24. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/affinity.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/affinity.js +3 -3
  26. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/affinity.js.map +1 -1
  27. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-attempt.d.ts +21 -0
  28. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-attempt.d.ts.map +1 -0
  29. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-attempt.js +30 -0
  30. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-attempt.js.map +1 -0
  31. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/auth-lane.d.ts +8 -4
  32. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-lane.d.ts.map +1 -0
  33. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/auth-lane.js +34 -25
  34. package/dist/core/extensions/builtin/claude-sdk-oauth/auth-lane.js.map +1 -0
  35. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools-schema.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools-schema.js.map +1 -1
  37. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools.js.map +1 -1
  39. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/errors.d.ts +1 -1
  40. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/errors.d.ts.map +1 -1
  41. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/errors.js +1 -1
  42. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/errors.js.map +1 -1
  43. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/executable.d.ts.map +1 -1
  44. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/executable.js.map +1 -1
  45. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/failover.d.ts.map +1 -1
  46. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/failover.js +1 -1
  47. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/failover.js.map +1 -1
  48. package/dist/core/extensions/builtin/claude-sdk-oauth/guidance.d.ts +14 -0
  49. package/dist/core/extensions/builtin/claude-sdk-oauth/guidance.d.ts.map +1 -0
  50. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/guidance.js +37 -1
  51. package/dist/core/extensions/builtin/claude-sdk-oauth/guidance.js.map +1 -0
  52. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts +4 -0
  53. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts.map +1 -0
  54. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/index.js +12 -10
  55. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js.map +1 -0
  56. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/oauth-login.d.ts +3 -3
  57. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/oauth-login.d.ts.map +1 -1
  58. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/oauth-login.js +2 -2
  59. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.js.map +1 -0
  60. package/dist/core/extensions/builtin/claude-sdk-oauth/options.d.ts +18 -0
  61. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/options.d.ts.map +1 -1
  62. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/options.js +70 -10
  63. package/dist/core/extensions/builtin/claude-sdk-oauth/options.js.map +1 -0
  64. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/prompt-bridge.d.ts.map +1 -1
  65. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/prompt-bridge.js +32 -19
  66. package/dist/core/extensions/builtin/claude-sdk-oauth/prompt-bridge.js.map +1 -0
  67. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/sdk-boundary.d.ts +1 -0
  68. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/sdk-boundary.d.ts.map +1 -1
  69. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/sdk-boundary.js.map +1 -1
  70. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-pump.d.ts +30 -0
  71. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-pump.d.ts.map +1 -0
  72. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-pump.js +197 -0
  73. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-pump.js.map +1 -0
  74. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-state.d.ts +18 -0
  75. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-state.d.ts.map +1 -0
  76. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-state.js +33 -0
  77. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-state.js.map +1 -0
  78. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.d.ts +3 -0
  79. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.d.ts.map +1 -0
  80. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js +134 -0
  81. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry-wiring.js.map +1 -0
  82. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts +85 -0
  83. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.d.ts.map +1 -0
  84. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js +270 -0
  85. package/dist/core/extensions/builtin/claude-sdk-oauth/session-registry.js.map +1 -0
  86. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.d.ts +17 -0
  87. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.d.ts.map +1 -0
  88. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js +217 -0
  89. package/dist/core/extensions/builtin/claude-sdk-oauth/session-stream.js.map +1 -0
  90. package/dist/core/extensions/builtin/claude-sdk-oauth/session-sync.d.ts +49 -0
  91. package/dist/core/extensions/builtin/claude-sdk-oauth/session-sync.d.ts.map +1 -0
  92. package/dist/core/extensions/builtin/claude-sdk-oauth/session-sync.js +204 -0
  93. package/dist/core/extensions/builtin/claude-sdk-oauth/session-sync.js.map +1 -0
  94. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts +28 -0
  95. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -0
  96. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +107 -0
  97. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -0
  98. package/dist/core/extensions/builtin/claude-sdk-oauth/stream-guidance.d.ts +2 -0
  99. package/dist/core/extensions/builtin/claude-sdk-oauth/stream-guidance.d.ts.map +1 -0
  100. package/dist/core/extensions/builtin/claude-sdk-oauth/stream-guidance.js +10 -0
  101. package/dist/core/extensions/builtin/claude-sdk-oauth/stream-guidance.js.map +1 -0
  102. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream-protocol.d.ts.map +1 -1
  103. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream-protocol.js.map +1 -1
  104. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream.d.ts +1 -1
  105. package/dist/core/extensions/builtin/claude-sdk-oauth/stream.d.ts.map +1 -0
  106. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream.js +72 -53
  107. package/dist/core/extensions/builtin/claude-sdk-oauth/stream.js.map +1 -0
  108. package/dist/core/extensions/builtin/claude-sdk-oauth/system-prompt.d.ts +3 -0
  109. package/dist/core/extensions/builtin/claude-sdk-oauth/system-prompt.d.ts.map +1 -0
  110. package/dist/core/extensions/builtin/claude-sdk-oauth/system-prompt.js +25 -0
  111. package/dist/core/extensions/builtin/claude-sdk-oauth/system-prompt.js.map +1 -0
  112. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tool-watch.d.ts +1 -1
  113. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tool-watch.d.ts.map +1 -1
  114. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tool-watch.js +2 -2
  115. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tool-watch.js.map +1 -1
  116. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tools.d.ts.map +1 -1
  117. package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tools.js.map +1 -1
  118. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts +18 -0
  119. package/dist/core/extensions/builtin/compaction/deterministic-fallback.d.ts.map +1 -0
  120. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js +69 -0
  121. package/dist/core/extensions/builtin/compaction/deterministic-fallback.js.map +1 -0
  122. package/dist/core/extensions/builtin/compaction/index.d.ts.map +1 -1
  123. package/dist/core/extensions/builtin/compaction/index.js +28 -2
  124. package/dist/core/extensions/builtin/compaction/index.js.map +1 -1
  125. package/dist/core/extensions/builtin/compaction/speculative.d.ts +4 -1
  126. package/dist/core/extensions/builtin/compaction/speculative.d.ts.map +1 -1
  127. package/dist/core/extensions/builtin/compaction/speculative.js +22 -17
  128. package/dist/core/extensions/builtin/compaction/speculative.js.map +1 -1
  129. package/dist/core/extensions/builtin/compaction/task-intent.d.ts +2 -6
  130. package/dist/core/extensions/builtin/compaction/task-intent.d.ts.map +1 -1
  131. package/dist/core/extensions/builtin/compaction/task-intent.js +10 -9
  132. package/dist/core/extensions/builtin/compaction/task-intent.js.map +1 -1
  133. package/dist/core/extensions/builtin/goal/continuation-recovery.d.ts +6 -0
  134. package/dist/core/extensions/builtin/goal/continuation-recovery.d.ts.map +1 -0
  135. package/dist/core/extensions/builtin/goal/continuation-recovery.js +20 -0
  136. package/dist/core/extensions/builtin/goal/continuation-recovery.js.map +1 -0
  137. package/dist/core/extensions/builtin/goal/continuation.d.ts +2 -4
  138. package/dist/core/extensions/builtin/goal/continuation.d.ts.map +1 -1
  139. package/dist/core/extensions/builtin/goal/continuation.js +2 -8
  140. package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
  141. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.d.ts +19 -0
  142. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.d.ts.map +1 -0
  143. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js +48 -0
  144. package/dist/core/extensions/builtin/goal/direct-input-lifecycle.js.map +1 -0
  145. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  146. package/dist/core/extensions/builtin/goal/index.js +17 -15
  147. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  148. package/dist/core/extensions/builtin/goal/lifecycle-helpers.d.ts.map +1 -1
  149. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js +12 -10
  150. package/dist/core/extensions/builtin/goal/lifecycle-helpers.js.map +1 -1
  151. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts +5 -1
  152. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  153. package/dist/core/extensions/builtin/goal/monitor-continuation.js +94 -52
  154. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  155. package/dist/core/extensions/builtin/goal/persistence.d.ts +16 -0
  156. package/dist/core/extensions/builtin/goal/persistence.d.ts.map +1 -1
  157. package/dist/core/extensions/builtin/goal/persistence.js +185 -11
  158. package/dist/core/extensions/builtin/goal/persistence.js.map +1 -1
  159. package/dist/core/extensions/builtin/goal/ui.d.ts +1 -0
  160. package/dist/core/extensions/builtin/goal/ui.d.ts.map +1 -1
  161. package/dist/core/extensions/builtin/goal/ui.js +11 -2
  162. package/dist/core/extensions/builtin/goal/ui.js.map +1 -1
  163. package/dist/core/extensions/builtin/gpt-apply-patch/extension.d.ts.map +1 -1
  164. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js +15 -0
  165. package/dist/core/extensions/builtin/gpt-apply-patch/extension.js.map +1 -1
  166. package/dist/core/extensions/builtin/gpt-apply-patch/tool.d.ts.map +1 -1
  167. package/dist/core/extensions/builtin/gpt-apply-patch/tool.js +30 -3
  168. package/dist/core/extensions/builtin/gpt-apply-patch/tool.js.map +1 -1
  169. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  170. package/dist/core/extensions/builtin/index.js +5 -2
  171. package/dist/core/extensions/builtin/index.js.map +1 -1
  172. package/dist/core/extensions/builtin/loop-guard/detectors.d.ts +31 -0
  173. package/dist/core/extensions/builtin/loop-guard/detectors.d.ts.map +1 -0
  174. package/dist/core/extensions/builtin/loop-guard/detectors.js +111 -0
  175. package/dist/core/extensions/builtin/loop-guard/detectors.js.map +1 -0
  176. package/dist/core/extensions/builtin/loop-guard/index.d.ts +3 -0
  177. package/dist/core/extensions/builtin/loop-guard/index.d.ts.map +1 -0
  178. package/dist/core/extensions/builtin/loop-guard/index.js +31 -0
  179. package/dist/core/extensions/builtin/loop-guard/index.js.map +1 -0
  180. package/dist/core/extensions/builtin/loop-guard/notice.d.ts +5 -0
  181. package/dist/core/extensions/builtin/loop-guard/notice.d.ts.map +1 -0
  182. package/dist/core/extensions/builtin/loop-guard/notice.js +42 -0
  183. package/dist/core/extensions/builtin/loop-guard/notice.js.map +1 -0
  184. package/dist/core/extensions/builtin/loop-guard/policy.d.ts +30 -0
  185. package/dist/core/extensions/builtin/loop-guard/policy.d.ts.map +1 -0
  186. package/dist/core/extensions/builtin/loop-guard/policy.js +30 -0
  187. package/dist/core/extensions/builtin/loop-guard/policy.js.map +1 -0
  188. package/dist/core/extensions/builtin/loop-guard/renderer.d.ts +4 -0
  189. package/dist/core/extensions/builtin/loop-guard/renderer.d.ts.map +1 -0
  190. package/dist/core/extensions/builtin/loop-guard/renderer.js +50 -0
  191. package/dist/core/extensions/builtin/loop-guard/renderer.js.map +1 -0
  192. package/dist/core/extensions/builtin/loop-guard/similarity.d.ts +13 -0
  193. package/dist/core/extensions/builtin/loop-guard/similarity.d.ts.map +1 -0
  194. package/dist/core/extensions/builtin/loop-guard/similarity.js +51 -0
  195. package/dist/core/extensions/builtin/loop-guard/similarity.js.map +1 -0
  196. package/dist/core/extensions/builtin/loop-guard/tracker.d.ts +13 -0
  197. package/dist/core/extensions/builtin/loop-guard/tracker.d.ts.map +1 -0
  198. package/dist/core/extensions/builtin/loop-guard/tracker.js +39 -0
  199. package/dist/core/extensions/builtin/loop-guard/tracker.js.map +1 -0
  200. package/dist/core/extensions/builtin/monitor-state-event.d.ts +10 -0
  201. package/dist/core/extensions/builtin/monitor-state-event.d.ts.map +1 -1
  202. package/dist/core/extensions/builtin/monitor-state-event.js.map +1 -1
  203. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash-0731.d.ts +3 -0
  204. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash-0731.d.ts.map +1 -0
  205. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash-0731.js +10 -0
  206. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash-0731.js.map +1 -0
  207. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash.d.ts +3 -0
  208. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash.d.ts.map +1 -0
  209. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash.js +10 -0
  210. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-flash.js.map +1 -0
  211. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-pro.d.ts +3 -0
  212. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-pro.d.ts.map +1 -0
  213. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-pro.js +11 -0
  214. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-pro.js.map +1 -0
  215. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4.d.ts +13 -0
  216. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4.d.ts.map +1 -0
  217. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4.js +60 -0
  218. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4.js.map +1 -0
  219. package/dist/core/extensions/builtin/prompt-preset/index.d.ts.map +1 -1
  220. package/dist/core/extensions/builtin/prompt-preset/index.js +8 -4
  221. package/dist/core/extensions/builtin/prompt-preset/index.js.map +1 -1
  222. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  223. package/dist/core/extensions/builtin/prompt-preset/presets.js +42 -0
  224. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  225. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  226. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  227. package/dist/core/extensions/builtin/prompt-preset/settings.js +3 -0
  228. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  229. package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
  230. package/dist/core/extensions/builtin/recommended-models/index.js +2 -1
  231. package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
  232. package/dist/core/extensions/builtin/rules/index.js +4 -3
  233. package/dist/core/extensions/builtin/rules/index.js.map +1 -1
  234. package/dist/core/extensions/builtin/rules/rules/constants.d.ts +11 -0
  235. package/dist/core/extensions/builtin/rules/rules/constants.d.ts.map +1 -1
  236. package/dist/core/extensions/builtin/rules/rules/constants.js +11 -0
  237. package/dist/core/extensions/builtin/rules/rules/constants.js.map +1 -1
  238. package/dist/core/extensions/builtin/rules/rules/formatter.d.ts.map +1 -1
  239. package/dist/core/extensions/builtin/rules/rules/formatter.js +15 -1
  240. package/dist/core/extensions/builtin/rules/rules/formatter.js.map +1 -1
  241. package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
  242. package/dist/core/extensions/builtin/service-tier.js +23 -21
  243. package/dist/core/extensions/builtin/service-tier.js.map +1 -1
  244. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  245. package/dist/core/extensions/builtin/terminal/extension.js +21 -7
  246. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  247. package/dist/core/extensions/builtin/terminal/monitor-notify.d.ts.map +1 -1
  248. package/dist/core/extensions/builtin/terminal/monitor-notify.js +42 -5
  249. package/dist/core/extensions/builtin/terminal/monitor-notify.js.map +1 -1
  250. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +2 -0
  251. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
  252. package/dist/core/extensions/builtin/terminal/monitor-registry.js +2 -0
  253. package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
  254. package/dist/core/extensions/builtin/terminal/monitor-status-ticker.d.ts +37 -0
  255. package/dist/core/extensions/builtin/terminal/monitor-status-ticker.d.ts.map +1 -0
  256. package/dist/core/extensions/builtin/terminal/monitor-status-ticker.js +61 -0
  257. package/dist/core/extensions/builtin/terminal/monitor-status-ticker.js.map +1 -0
  258. package/dist/core/extensions/builtin/terminal/monitor-status.d.ts +9 -1
  259. package/dist/core/extensions/builtin/terminal/monitor-status.d.ts.map +1 -1
  260. package/dist/core/extensions/builtin/terminal/monitor-status.js +35 -2
  261. package/dist/core/extensions/builtin/terminal/monitor-status.js.map +1 -1
  262. package/dist/core/extensions/builtin/terminal/tools/monitor.js +1 -1
  263. package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
  264. package/dist/core/extensions/builtin/todotools/commands.d.ts +2 -2
  265. package/dist/core/extensions/builtin/todotools/commands.d.ts.map +1 -1
  266. package/dist/core/extensions/builtin/todotools/commands.js.map +1 -1
  267. package/dist/core/extensions/builtin/todotools/index.d.ts.map +1 -1
  268. package/dist/core/extensions/builtin/todotools/index.js +6 -3
  269. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  270. package/dist/core/extensions/builtin/todotools/state.d.ts +1 -1
  271. package/dist/core/extensions/builtin/todotools/state.d.ts.map +1 -1
  272. package/dist/core/extensions/builtin/todotools/state.js +1 -1
  273. package/dist/core/extensions/builtin/todotools/state.js.map +1 -1
  274. package/dist/core/extensions/builtin/todotools/todo-widget-component.d.ts +19 -0
  275. package/dist/core/extensions/builtin/todotools/todo-widget-component.d.ts.map +1 -0
  276. package/dist/core/extensions/builtin/todotools/todo-widget-component.js +78 -0
  277. package/dist/core/extensions/builtin/todotools/todo-widget-component.js.map +1 -0
  278. package/dist/core/extensions/builtin/todotools/todo-widget.d.ts +13 -1
  279. package/dist/core/extensions/builtin/todotools/todo-widget.d.ts.map +1 -1
  280. package/dist/core/extensions/builtin/todotools/todo-widget.js +32 -14
  281. package/dist/core/extensions/builtin/todotools/todo-widget.js.map +1 -1
  282. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts +2 -2
  283. package/dist/core/extensions/builtin/todotools/tools/todo.d.ts.map +1 -1
  284. package/dist/core/extensions/builtin/todotools/tools/todo.js +1 -1
  285. package/dist/core/extensions/builtin/todotools/tools/todo.js.map +1 -1
  286. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-anthropic-payload.d.ts +1 -1
  287. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-anthropic-payload.d.ts.map +1 -1
  288. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-anthropic-payload.js +88 -29
  289. package/dist/core/extensions/builtin/tool-pair-guard/sanitize-anthropic-payload.js.map +1 -1
  290. package/dist/core/extensions/builtin/tps.d.ts.map +1 -1
  291. package/dist/core/extensions/builtin/tps.js +5 -2
  292. package/dist/core/extensions/builtin/tps.js.map +1 -1
  293. package/dist/core/extensions/builtin/ttsr/builtin-rules.d.ts +4 -0
  294. package/dist/core/extensions/builtin/ttsr/builtin-rules.d.ts.map +1 -0
  295. package/dist/core/extensions/builtin/ttsr/builtin-rules.js +20 -0
  296. package/dist/core/extensions/builtin/ttsr/builtin-rules.js.map +1 -0
  297. package/dist/core/extensions/builtin/ttsr/commands.js +9 -1
  298. package/dist/core/extensions/builtin/ttsr/commands.js.map +1 -1
  299. package/dist/core/extensions/builtin/ttsr/index.d.ts.map +1 -1
  300. package/dist/core/extensions/builtin/ttsr/index.js +4 -3
  301. package/dist/core/extensions/builtin/ttsr/index.js.map +1 -1
  302. package/dist/core/extensions/builtin/ttsr/manager.js +1 -1
  303. package/dist/core/extensions/builtin/ttsr/manager.js.map +1 -1
  304. package/dist/core/extensions/builtin/websearch/websearch/config.d.ts.map +1 -1
  305. package/dist/core/extensions/builtin/websearch/websearch/config.js +1 -0
  306. package/dist/core/extensions/builtin/websearch/websearch/config.js.map +1 -1
  307. package/dist/core/extensions/builtin/websearch/websearch/native.d.ts.map +1 -1
  308. package/dist/core/extensions/builtin/websearch/websearch/native.js +16 -5
  309. package/dist/core/extensions/builtin/websearch/websearch/native.js.map +1 -1
  310. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.d.ts.map +1 -1
  311. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js +1 -0
  312. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js.map +1 -1
  313. package/dist/core/extensions/builtin/websearch/websearch/providers/anthropic.d.ts +4 -1
  314. package/dist/core/extensions/builtin/websearch/websearch/providers/anthropic.d.ts.map +1 -1
  315. package/dist/core/extensions/builtin/websearch/websearch/providers/anthropic.js +44 -37
  316. package/dist/core/extensions/builtin/websearch/websearch/providers/anthropic.js.map +1 -1
  317. package/dist/core/extensions/builtin/websearch/websearch/providers/deepseek.d.ts +3 -0
  318. package/dist/core/extensions/builtin/websearch/websearch/providers/deepseek.d.ts.map +1 -0
  319. package/dist/core/extensions/builtin/websearch/websearch/providers/deepseek.js +12 -0
  320. package/dist/core/extensions/builtin/websearch/websearch/providers/deepseek.js.map +1 -0
  321. package/dist/core/extensions/builtin/websearch/websearch/providers.d.ts.map +1 -1
  322. package/dist/core/extensions/builtin/websearch/websearch/providers.js +2 -0
  323. package/dist/core/extensions/builtin/websearch/websearch/providers.js.map +1 -1
  324. package/dist/core/extensions/builtin/websearch/websearch/renderers.d.ts.map +1 -1
  325. package/dist/core/extensions/builtin/websearch/websearch/renderers.js +3 -3
  326. package/dist/core/extensions/builtin/websearch/websearch/renderers.js.map +1 -1
  327. package/dist/core/extensions/builtin/websearch/websearch/search.d.ts.map +1 -1
  328. package/dist/core/extensions/builtin/websearch/websearch/search.js +1 -3
  329. package/dist/core/extensions/builtin/websearch/websearch/search.js.map +1 -1
  330. package/dist/core/extensions/builtin/websearch/websearch/tool.js +2 -2
  331. package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
  332. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts +1 -1
  333. package/dist/core/extensions/builtin/websearch/websearch/types.d.ts.map +1 -1
  334. package/dist/core/extensions/builtin/websearch/websearch/types.js.map +1 -1
  335. package/dist/core/extensions/index.d.ts +1 -1
  336. package/dist/core/extensions/index.d.ts.map +1 -1
  337. package/dist/core/extensions/index.js.map +1 -1
  338. package/dist/core/extensions/loader.d.ts.map +1 -1
  339. package/dist/core/extensions/loader.js +5 -0
  340. package/dist/core/extensions/loader.js.map +1 -1
  341. package/dist/core/extensions/runner.d.ts +1 -1
  342. package/dist/core/extensions/runner.d.ts.map +1 -1
  343. package/dist/core/extensions/runner.js +3 -1
  344. package/dist/core/extensions/runner.js.map +1 -1
  345. package/dist/core/extensions/types.d.ts +22 -1
  346. package/dist/core/extensions/types.d.ts.map +1 -1
  347. package/dist/core/extensions/types.js.map +1 -1
  348. package/dist/core/model-resolver.js +2 -2
  349. package/dist/core/model-resolver.js.map +1 -1
  350. package/dist/core/thinking-levels.d.ts +5 -0
  351. package/dist/core/thinking-levels.d.ts.map +1 -1
  352. package/dist/core/thinking-levels.js +9 -39
  353. package/dist/core/thinking-levels.js.map +1 -1
  354. package/dist/index.d.ts +1 -1
  355. package/dist/index.d.ts.map +1 -1
  356. package/dist/index.js.map +1 -1
  357. package/dist/modes/app-server/server/account.d.ts +1 -1
  358. package/dist/modes/app-server/server/account.js +1 -1
  359. package/dist/modes/app-server/server/account.js.map +1 -1
  360. package/dist/modes/app-server/server/server-core.js +1 -1
  361. package/dist/modes/app-server/server/server-core.js.map +1 -1
  362. package/dist/modes/interactive/compaction-queue-transfer.d.ts +2 -0
  363. package/dist/modes/interactive/compaction-queue-transfer.d.ts.map +1 -1
  364. package/dist/modes/interactive/compaction-queue-transfer.js.map +1 -1
  365. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  366. package/dist/modes/interactive/components/footer.js +9 -5
  367. package/dist/modes/interactive/components/footer.js.map +1 -1
  368. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  369. package/dist/modes/interactive/interactive-mode.js +38 -12
  370. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  371. package/dist/modes/interactive/risky-main-model-warning.d.ts +1 -1
  372. package/dist/modes/interactive/risky-main-model-warning.d.ts.map +1 -1
  373. package/dist/modes/interactive/risky-main-model-warning.js +1 -1
  374. package/dist/modes/interactive/risky-main-model-warning.js.map +1 -1
  375. package/dist/modes/rpc/connection-handler.js +3 -3
  376. package/dist/modes/rpc/connection-handler.js.map +1 -1
  377. package/docs/extensions.md +10 -0
  378. package/docs/providers.md +21 -5
  379. package/docs/release-guide.md +2 -2
  380. package/docs/settings.md +1 -1
  381. package/examples/extensions/overlay-test.ts +1 -1
  382. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +33 -0
  383. package/node_modules/@code-yeongyu/senpi-codemode/README.md +6 -3
  384. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  385. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-status-ticker.ts +79 -0
  386. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/eval-status.ts +36 -3
  387. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +26 -12
  388. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-execution.ts +146 -0
  389. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +21 -119
  390. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-runtime.ts +157 -0
  391. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +62 -208
  392. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-notification.ts +98 -0
  393. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-snapshot.ts +81 -0
  394. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-state.ts +24 -0
  395. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-eval-result.ts +140 -0
  396. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-notification-queue.ts +53 -0
  397. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-request.ts +45 -0
  398. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool-options.ts +45 -0
  399. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +20 -342
  400. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  401. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +1 -0
  402. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  403. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  404. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  405. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +10 -15
  406. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  407. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +2 -2
  408. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
  409. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses/fallback-state.d.ts +24 -0
  410. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses/fallback-state.d.ts.map +1 -0
  411. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses/fallback-state.js +70 -0
  412. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses/fallback-state.js.map +1 -0
  413. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts +2 -16
  414. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  415. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +10 -58
  416. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  417. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +2 -2
  418. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  419. package/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.d.ts +1 -0
  420. package/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.d.ts.map +1 -1
  421. package/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.js +7 -0
  422. package/node_modules/@earendil-works/pi-ai/dist/api/openai-prompt-cache.js.map +1 -1
  423. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +2 -2
  424. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  425. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts +2 -1
  426. package/node_modules/@earendil-works/pi-ai/dist/model.d.ts.map +1 -1
  427. package/node_modules/@earendil-works/pi-ai/dist/model.js.map +1 -1
  428. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +14 -0
  429. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  430. package/node_modules/@earendil-works/pi-ai/dist/models.js +95 -19
  431. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  432. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  433. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  434. package/node_modules/@earendil-works/pi-ai/dist/providers/data/azure-openai-responses.json +1 -1
  435. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
  436. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  437. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  438. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  439. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  440. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
  441. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
  442. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +5 -0
  443. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  444. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  445. package/node_modules/@earendil-works/pi-ai/dist/utils/unavailable-tool-text.d.ts +3 -0
  446. package/node_modules/@earendil-works/pi-ai/dist/utils/unavailable-tool-text.d.ts.map +1 -0
  447. package/node_modules/@earendil-works/pi-ai/dist/utils/unavailable-tool-text.js +36 -0
  448. package/node_modules/@earendil-works/pi-ai/dist/utils/unavailable-tool-text.js.map +1 -0
  449. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  450. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  451. package/node_modules/@earendil-works/pi-tui/dist/mux.js +1 -1
  452. package/node_modules/@earendil-works/pi-tui/dist/mux.js.map +1 -1
  453. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts +1 -0
  454. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  455. package/node_modules/@earendil-works/pi-tui/dist/tui.js +17 -3
  456. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  457. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  458. package/package.json +6 -6
  459. package/dist/core/extensions/builtin/claude-agent-sdk/auth-lane.d.ts.map +0 -1
  460. package/dist/core/extensions/builtin/claude-agent-sdk/auth-lane.js.map +0 -1
  461. package/dist/core/extensions/builtin/claude-agent-sdk/guidance.d.ts +0 -6
  462. package/dist/core/extensions/builtin/claude-agent-sdk/guidance.d.ts.map +0 -1
  463. package/dist/core/extensions/builtin/claude-agent-sdk/guidance.js.map +0 -1
  464. package/dist/core/extensions/builtin/claude-agent-sdk/index.d.ts +0 -4
  465. package/dist/core/extensions/builtin/claude-agent-sdk/index.d.ts.map +0 -1
  466. package/dist/core/extensions/builtin/claude-agent-sdk/index.js.map +0 -1
  467. package/dist/core/extensions/builtin/claude-agent-sdk/oauth-login.js.map +0 -1
  468. package/dist/core/extensions/builtin/claude-agent-sdk/options.d.ts +0 -16
  469. package/dist/core/extensions/builtin/claude-agent-sdk/options.js.map +0 -1
  470. package/dist/core/extensions/builtin/claude-agent-sdk/prompt-bridge.js.map +0 -1
  471. package/dist/core/extensions/builtin/claude-agent-sdk/settings.d.ts +0 -15
  472. package/dist/core/extensions/builtin/claude-agent-sdk/settings.d.ts.map +0 -1
  473. package/dist/core/extensions/builtin/claude-agent-sdk/settings.js +0 -41
  474. package/dist/core/extensions/builtin/claude-agent-sdk/settings.js.map +0 -1
  475. package/dist/core/extensions/builtin/claude-agent-sdk/stream.d.ts.map +0 -1
  476. package/dist/core/extensions/builtin/claude-agent-sdk/stream.js.map +0 -1
  477. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-events.d.ts +0 -0
  478. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/account-events.js +0 -0
  479. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools-schema.d.ts +0 -0
  480. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools-schema.js +0 -0
  481. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools.d.ts +0 -0
  482. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/custom-tools.js +0 -0
  483. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/executable.d.ts +0 -0
  484. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/executable.js +0 -0
  485. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/failover.d.ts +0 -0
  486. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/prompt-bridge.d.ts +0 -0
  487. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/sdk-boundary.js +0 -0
  488. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream-protocol.d.ts +0 -0
  489. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/stream-protocol.js +0 -0
  490. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tools.d.ts +0 -0
  491. /package/dist/core/extensions/builtin/{claude-agent-sdk → claude-sdk-oauth}/tools.js +0 -0
@@ -0,0 +1,157 @@
1
+ import type { AgentToolResult, AgentToolUpdateCallback, ExtensionContext } from "@code-yeongyu/senpi";
2
+ import type { KernelToHostMessage } from "../bridge/protocol.ts";
3
+ import { type EvalImageResizer, EvalOutputCollector, type EvalOutputResult } from "./image.ts";
4
+ import type { EvalStatusEvent, EvalToolDetails, EvalToolInput } from "./types.ts";
5
+
6
+ type KernelResult = Extract<KernelToHostMessage, { type: "result" }>;
7
+ type DisplayMessage = Extract<KernelToHostMessage, { type: "display" }>;
8
+ type ToolCall = EvalToolDetails["toolCalls"] extends readonly (infer Item)[] ? Item : never;
9
+
10
+ export interface CellState {
11
+ readonly input: EvalToolInput;
12
+ readonly signal: AbortSignal;
13
+ readonly onUpdate: AgentToolUpdateCallback<EvalToolDetails> | undefined;
14
+ readonly toolCalls: ToolCall[];
15
+ readonly pendingBridgeCalls: Promise<void>[];
16
+ readonly statusEvents: EvalStatusEvent[];
17
+ active: boolean;
18
+ output: string;
19
+ phase: string | undefined;
20
+ durationMs: number;
21
+ status: "pending" | "running" | "complete" | "error";
22
+ }
23
+
24
+ export interface CellResultBuilderOptions {
25
+ readonly artifactPath?: string;
26
+ readonly headBytes: number;
27
+ readonly imageResizer?: EvalImageResizer;
28
+ readonly maxColumns: number;
29
+ readonly model: ExtensionContext["model"];
30
+ readonly state: CellState;
31
+ }
32
+
33
+ export class CellResultBuilder {
34
+ readonly #output: EvalOutputCollector;
35
+ readonly #state: CellState;
36
+
37
+ constructor(options: CellResultBuilderOptions) {
38
+ this.#state = options.state;
39
+ this.#output = new EvalOutputCollector({
40
+ headBytes: options.headBytes,
41
+ maxColumns: options.maxColumns,
42
+ model: options.model,
43
+ ...(options.artifactPath === undefined ? {} : { artifactPath: options.artifactPath }),
44
+ ...(options.imageResizer === undefined ? {} : { imageResizer: options.imageResizer }),
45
+ onChunk: (_aggregate, cell) => {
46
+ options.state.output = cell;
47
+ this.emitUpdate(false);
48
+ },
49
+ });
50
+ options.state.status = "running";
51
+ this.emitUpdate(false);
52
+ }
53
+
54
+ push(text: string): void {
55
+ this.#output.push(text);
56
+ }
57
+
58
+ display(message: DisplayMessage): void {
59
+ this.#output.display(message);
60
+ }
61
+
62
+ setPhase(title: string): void {
63
+ this.#state.phase = title;
64
+ this.emitUpdate(false);
65
+ }
66
+
67
+ async finalize(result: KernelResult): Promise<AgentToolResult<EvalToolDetails>> {
68
+ this.#state.durationMs = result.durationMs;
69
+ if (result.ok) {
70
+ if (result.valueRepr) this.#output.push(`${result.valueRepr}\n`);
71
+ this.#state.status = "complete";
72
+ } else {
73
+ this.#output.push(`${result.error.message}\n`);
74
+ this.#state.status = "error";
75
+ }
76
+ return await this.#finish(!result.ok);
77
+ }
78
+
79
+ async finalizeCancellation(error: Error): Promise<AgentToolResult<EvalToolDetails>> {
80
+ this.#output.push(`${error.message}\n`);
81
+ this.#state.status = "error";
82
+ return await this.#finish(true);
83
+ }
84
+
85
+ async flushOutput(): Promise<void> {
86
+ await this.#output.flush();
87
+ }
88
+
89
+ liveResult(): AgentToolResult<EvalToolDetails> {
90
+ return {
91
+ content: [{ type: "text", text: this.#liveUpdateText() }],
92
+ details: this.#details(undefined, this.#state.status === "error"),
93
+ };
94
+ }
95
+
96
+ emitUpdate(isError: boolean): void {
97
+ if (!this.#state.active) return;
98
+ this.#state.onUpdate?.({
99
+ content: [{ type: "text", text: this.#liveUpdateText() }],
100
+ details: this.#details(undefined, isError),
101
+ });
102
+ }
103
+
104
+ async #finish(isError: boolean): Promise<AgentToolResult<EvalToolDetails>> {
105
+ const output = await this.#output.finish();
106
+ this.#state.output = output.output;
107
+ const details = this.#details(output, isError);
108
+ this.emitUpdate(isError);
109
+ const text =
110
+ output.output ||
111
+ (output.images.length > 0
112
+ ? `(displayed ${output.images.length} image${output.images.length === 1 ? "" : "s"}; no text output)`
113
+ : "(no output)");
114
+ return { content: [{ type: "text", text }, ...output.images], details };
115
+ }
116
+
117
+ #details(output: EvalOutputResult | undefined, isError: boolean): EvalToolDetails {
118
+ const statusEvents = this.#state.statusEvents.length > 0 ? [...this.#state.statusEvents] : undefined;
119
+ return {
120
+ language: this.#state.input.language,
121
+ languages: [this.#state.input.language],
122
+ ...(this.#state.input.title === undefined ? {} : { title: this.#state.input.title }),
123
+ durationMs: this.#state.durationMs,
124
+ toolCalls: [...this.#state.toolCalls],
125
+ truncated: output?.truncated ?? false,
126
+ ...(isError ? { isError: true } : {}),
127
+ ...(this.#state.phase === undefined ? {} : { phase: this.#state.phase }),
128
+ cells: [
129
+ {
130
+ index: 0,
131
+ ...(this.#state.input.title === undefined ? {} : { title: this.#state.input.title }),
132
+ code: this.#state.input.code,
133
+ language: this.#state.input.language,
134
+ output: this.#state.output,
135
+ status: this.#state.status,
136
+ durationMs: this.#state.durationMs,
137
+ ...(statusEvents === undefined ? {} : { statusEvents }),
138
+ ...(output?.hasMarkdown ? { hasMarkdown: true } : {}),
139
+ },
140
+ ],
141
+ ...(statusEvents === undefined ? {} : { statusEvents }),
142
+ ...(output === undefined || output.jsonOutputs.length === 0 ? {} : { jsonOutputs: output.jsonOutputs }),
143
+ ...(output?.notice === undefined ? {} : { notice: output.notice }),
144
+ ...(output?.meta === undefined ? {} : { meta: output.meta }),
145
+ };
146
+ }
147
+
148
+ #liveUpdateText(): string {
149
+ const title = this.#state.input.title === undefined ? "" : ` ${this.#state.input.title}`;
150
+ const aggregateOutput = this.#output.aggregateText();
151
+ const outputLines = aggregateOutput.split("\n");
152
+ const hasTrailingNewline = aggregateOutput.endsWith("\n");
153
+ if (hasTrailingNewline) outputLines.pop();
154
+ const output = `${outputLines.slice(-8).join("\n")}${hasTrailingNewline ? "\n" : ""}`;
155
+ return `1/1 cells ${this.#state.status}\n[1] ${this.#state.input.language}${title} ${this.#state.status}${output.length === 0 ? "" : `\n${output}`}`;
156
+ }
157
+ }
@@ -1,26 +1,32 @@
1
- import { mkdir, writeFile } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
1
  import type { AgentToolResult } from "@code-yeongyu/senpi";
2
+ import { detachedNotificationSpillPath } from "./detached-cell-notification.ts";
3
+ import { currentDetachedResult, detachedErrorResult, snapshotDetachedCell } from "./detached-cell-snapshot.ts";
4
+ import {
5
+ activeDetachedCellReuseError,
6
+ allowsDetachedCellTransition,
7
+ detachedCellIsActive,
8
+ } from "./detached-cell-state.ts";
9
+ import { DetachedNotificationQueue } from "./detached-notification-queue.ts";
4
10
  import type { EvalKernel, EvalLanguage, EvalToolDetails, EvalToolInput } from "./types.ts";
5
11
 
6
- const NOTIFICATION_TAIL_BYTES = 512;
7
-
8
12
  export type EvalDetachedCellState = "running" | "detached" | "completed" | "failed" | "cancelled";
9
13
 
14
+ type LiveResultProvider = () => AgentToolResult<EvalToolDetails>;
15
+
10
16
  type ManagedCell = {
11
17
  readonly cellId: string;
12
18
  readonly input: EvalToolInput;
13
19
  readonly spillPath: string | undefined;
20
+ readonly startedAtMs: number;
21
+ readonly terminal: PromiseWithResolvers<EvalDetachedCellSnapshot>;
14
22
  state: EvalDetachedCellState;
15
23
  canDetach: boolean;
16
24
  wasDetached: boolean;
17
25
  kernel: EvalKernel | undefined;
18
- /** Set after an interrupt-driven stop; undefined until the kernel reports its fate. */
19
26
  stateRetained: boolean | undefined;
20
- outputTail: (() => string) | undefined;
21
- result: AgentToolResult<EvalToolDetails> | undefined;
27
+ liveResult: LiveResultProvider | undefined;
28
+ terminalResult: AgentToolResult<EvalToolDetails> | undefined;
22
29
  notificationQueued: boolean;
23
- readonly terminal: PromiseWithResolvers<EvalDetachedCellSnapshot>;
24
30
  };
25
31
 
26
32
  export interface EvalDetachedCellSnapshot {
@@ -28,7 +34,7 @@ export interface EvalDetachedCellSnapshot {
28
34
  readonly language: EvalLanguage;
29
35
  readonly state: EvalDetachedCellState;
30
36
  readonly outputTail: string;
31
- readonly result: AgentToolResult<EvalToolDetails> | undefined;
37
+ readonly result: AgentToolResult<EvalToolDetails>;
32
38
  readonly stateRetained: boolean | undefined;
33
39
  }
34
40
 
@@ -41,63 +47,53 @@ export interface EvalDetachedCellNotifier {
41
47
  notify(cells: readonly EvalDetachedCellNotification[]): void;
42
48
  }
43
49
 
44
- /** One live detached cell, as shown in the footer status line. */
45
50
  export interface EvalDetachedCellStatusEntry {
46
51
  readonly cellId: string;
47
52
  readonly language: EvalLanguage;
48
53
  readonly title?: string;
54
+ readonly startedAtMs: number;
49
55
  }
50
56
 
51
57
  export interface EvalDetachedCellManagerOptions {
52
58
  readonly artifactsDir?: string;
53
59
  readonly notifier?: EvalDetachedCellNotifier;
54
- /** Called with every detached cell whenever that set changes; empty clears the status. */
55
60
  readonly onStatusChange?: (entries: readonly EvalDetachedCellStatusEntry[]) => void;
61
+ readonly now?: () => number;
56
62
  }
57
63
 
58
- /**
59
- * Session-owned lifecycle owner for eval cells that outlive their tool call.
60
- *
61
- * All state changes are synchronous and funnel through #transition. That is the
62
- * atomic boundary for timeout, kernel completion, explicit stop, and session
63
- * disposal races; exactly one path can release a language's detached busy mark.
64
- */
65
64
  export class EvalDetachedCellManager {
66
65
  readonly #artifactsDir: string | undefined;
67
- readonly #notifier: EvalDetachedCellNotifier | undefined;
68
66
  readonly #onStatusChange: ((entries: readonly EvalDetachedCellStatusEntry[]) => void) | undefined;
69
67
  readonly #cells = new Map<string, ManagedCell>();
70
68
  readonly #detachedByLanguage = new Map<EvalLanguage, ManagedCell>();
71
- #notificationQueue: ManagedCell[] = [];
72
- #notificationFlush: Promise<void> | undefined;
69
+ readonly #notificationQueue: DetachedNotificationQueue;
70
+ readonly #now: () => number;
73
71
 
74
72
  constructor(options: EvalDetachedCellManagerOptions = {}) {
75
73
  this.#artifactsDir = options.artifactsDir;
76
- this.#notifier = options.notifier;
77
74
  this.#onStatusChange = options.onStatusChange;
75
+ this.#notificationQueue = new DetachedNotificationQueue(options.notifier, options.artifactsDir);
76
+ this.#now = options.now ?? Date.now;
78
77
  }
79
78
 
80
79
  create(cellId: string, input: EvalToolInput): ManagedCell {
81
80
  const existing = this.#cells.get(cellId);
82
81
  if (existing !== undefined) {
83
- if (existing.state === "running" || existing.state === "detached") throw activeCellReuseError(existing);
82
+ if (detachedCellIsActive(existing.state)) throw activeDetachedCellReuseError(existing);
84
83
  this.#cells.delete(cellId);
85
84
  }
86
- const spillPath =
87
- this.#artifactsDir === undefined
88
- ? undefined
89
- : join(this.#artifactsDir, "local", `detached-eval-${safeCellId(cellId)}.log`);
90
85
  const cell: ManagedCell = {
91
86
  cellId,
92
87
  input,
93
- spillPath,
88
+ spillPath: detachedNotificationSpillPath(this.#artifactsDir, cellId),
89
+ startedAtMs: this.#now(),
94
90
  state: "running",
95
91
  canDetach: false,
96
92
  wasDetached: false,
97
93
  kernel: undefined,
98
94
  stateRetained: undefined,
99
- outputTail: undefined,
100
- result: undefined,
95
+ liveResult: undefined,
96
+ terminalResult: undefined,
101
97
  notificationQueued: false,
102
98
  terminal: Promise.withResolvers<EvalDetachedCellSnapshot>(),
103
99
  };
@@ -105,15 +101,16 @@ export class EvalDetachedCellManager {
105
101
  return cell;
106
102
  }
107
103
 
108
- markRunning(cell: ManagedCell, kernel: EvalKernel, outputTail: () => string): void {
104
+ markRunning(cell: ManagedCell, kernel: EvalKernel, liveResult: LiveResultProvider): void {
109
105
  if (cell.state !== "running") return;
110
106
  cell.kernel = kernel;
111
- cell.outputTail = outputTail;
107
+ cell.liveResult = liveResult;
112
108
  cell.canDetach = true;
113
109
  }
114
110
 
115
111
  detach(cell: ManagedCell): boolean {
116
- if (!cell.canDetach || !this.#transition(cell, "detached")) return false;
112
+ if (!cell.canDetach || !allowsDetachedCellTransition(cell.state, "detached")) return false;
113
+ cell.state = "detached";
117
114
  cell.wasDetached = true;
118
115
  this.#detachedByLanguage.set(cell.input.language, cell);
119
116
  this.#emitStatus();
@@ -121,22 +118,19 @@ export class EvalDetachedCellManager {
121
118
  }
122
119
 
123
120
  complete(cell: ManagedCell, result: AgentToolResult<EvalToolDetails>): boolean {
124
- cell.result = result;
125
- return this.#transition(cell, result.details.isError === true ? "failed" : "completed");
121
+ return this.#settle(cell, result.details.isError === true ? "failed" : "completed", result);
126
122
  }
127
123
 
128
124
  fail(cell: ManagedCell, error: Error): boolean {
129
- const result = errorResult(cell, error);
130
- cell.result = result;
131
- return this.#transition(cell, "failed");
125
+ return this.#settle(cell, "failed", detachedErrorResult(cell, error));
132
126
  }
133
127
 
134
128
  async stop(cellId: string, reason = "Stopped detached eval cell"): Promise<EvalDetachedCellSnapshot> {
135
129
  const cell = this.#get(cellId);
136
- if (cell.state === "detached" && this.#transition(cell, "cancelled")) {
137
- const kernel = cell.kernel;
138
- if (kernel !== undefined) {
139
- const handle = await kernel.interrupt(reason);
130
+ if (cell.state === "detached") {
131
+ const claimed = this.#settle(cell, "cancelled", currentDetachedResult(cell));
132
+ if (claimed && cell.kernel !== undefined) {
133
+ const handle = await cell.kernel.interrupt(reason);
140
134
  cell.stateRetained = await handle.stateRetained;
141
135
  }
142
136
  }
@@ -161,85 +155,51 @@ export class EvalDetachedCellManager {
161
155
  await Promise.allSettled(
162
156
  detached.map(async (cell) => await this.stop(cell.cellId, "Session ended; detached eval cell cancelled")),
163
157
  );
164
- await this.flushNotifications();
158
+ await this.#notificationQueue.flush();
165
159
  }
166
160
 
167
161
  async flushNotifications(): Promise<void> {
168
- const flush = this.#notificationFlush;
169
- if (flush !== undefined) await flush;
170
- }
171
-
172
- #transition(cell: ManagedCell, next: EvalDetachedCellState): boolean {
173
- if (!allowsTransition(cell.state, next)) return false;
174
- cell.state = next;
175
- if (next !== "running" && next !== "detached") cell.terminal.resolve(this.#snapshot(cell));
176
- if (cell.wasDetached && next !== "detached") {
162
+ await this.#notificationQueue.flush();
163
+ }
164
+
165
+ #settle(
166
+ cell: ManagedCell,
167
+ state: "completed" | "failed" | "cancelled",
168
+ result: AgentToolResult<EvalToolDetails>,
169
+ ): boolean {
170
+ if (!allowsDetachedCellTransition(cell.state, state)) return false;
171
+ cell.state = state;
172
+ cell.terminalResult = result;
173
+ cell.liveResult = undefined;
174
+ cell.terminal.resolve(this.#snapshot(cell));
175
+ if (cell.wasDetached) {
177
176
  if (this.#detachedByLanguage.get(cell.input.language) === cell)
178
177
  this.#detachedByLanguage.delete(cell.input.language);
179
178
  this.#emitStatus();
180
- this.#queueNotification(cell);
179
+ if (!cell.notificationQueued) {
180
+ cell.notificationQueued = true;
181
+ this.#notificationQueue.enqueue({
182
+ snapshot: () => this.#snapshot(cell),
183
+ spillPath: cell.spillPath,
184
+ });
185
+ }
181
186
  }
182
187
  return true;
183
188
  }
184
189
 
185
190
  #emitStatus(): void {
186
- const emit = this.#onStatusChange;
187
- if (emit === undefined) return;
188
- emit(
191
+ this.#onStatusChange?.(
189
192
  [...this.#detachedByLanguage.values()].map((cell) => ({
190
193
  cellId: cell.cellId,
191
194
  language: cell.input.language,
195
+ startedAtMs: cell.startedAtMs,
192
196
  ...(cell.input.title === undefined ? {} : { title: cell.input.title }),
193
197
  })),
194
198
  );
195
199
  }
196
200
 
197
- #queueNotification(cell: ManagedCell): void {
198
- if (cell.notificationQueued) return;
199
- cell.notificationQueued = true;
200
- this.#notificationQueue.push(cell);
201
- this.#scheduleNotificationFlush();
202
- }
203
-
204
- #scheduleNotificationFlush(): void {
205
- if (this.#notificationFlush !== undefined) return;
206
- const flush = Promise.resolve().then(async () => {
207
- const cells = this.#notificationQueue.splice(0);
208
- const notifications = await Promise.all(cells.map(async (candidate) => await this.#notification(candidate)));
209
- this.#notifier?.notify(notifications);
210
- });
211
- this.#notificationFlush = flush;
212
- void flush.then(
213
- () => this.#finishNotificationFlush(flush),
214
- () => this.#finishNotificationFlush(flush),
215
- );
216
- }
217
-
218
- #finishNotificationFlush(flush: Promise<void>): void {
219
- if (this.#notificationFlush !== flush) return;
220
- this.#notificationFlush = undefined;
221
- if (this.#notificationQueue.length > 0) this.#scheduleNotificationFlush();
222
- }
223
-
224
- async #notification(cell: ManagedCell): Promise<EvalDetachedCellNotification> {
225
- const snapshot = this.#snapshot(cell);
226
- const body = notificationBody(snapshot);
227
- const overflow = Buffer.byteLength(body, "utf8") > NOTIFICATION_TAIL_BYTES;
228
- let spillNotice = "";
229
- if (overflow && cell.spillPath !== undefined) {
230
- try {
231
- await mkdir(dirname(cell.spillPath), { recursive: true });
232
- await writeFile(cell.spillPath, body, "utf8");
233
- spillNotice = `\nBuffered output overflowed; full output: ${localUri(cell.spillPath, this.#artifactsDir)}`;
234
- } catch (error) {
235
- const message = error instanceof Error ? error.message : String(error);
236
- spillNotice = `\nBuffered output overflow could not be spilled: ${message}`;
237
- }
238
- }
239
- return {
240
- cellId: cell.cellId,
241
- content: `${overflow ? notificationPreview(snapshot) : body}${overflow ? "\n[…notification tail capped…]" : ""}${spillNotice}`,
242
- };
201
+ #snapshot(cell: ManagedCell): EvalDetachedCellSnapshot {
202
+ return snapshotDetachedCell(cell, this.#now());
243
203
  }
244
204
 
245
205
  #get(cellId: string): ManagedCell {
@@ -247,110 +207,4 @@ export class EvalDetachedCellManager {
247
207
  if (cell === undefined) throw new Error(`Unknown detached eval cell "${cellId}"`);
248
208
  return cell;
249
209
  }
250
-
251
- #snapshot(cell: ManagedCell): EvalDetachedCellSnapshot {
252
- return {
253
- cellId: cell.cellId,
254
- language: cell.input.language,
255
- state: cell.state,
256
- outputTail: cell.outputTail?.() ?? "",
257
- result: cell.result,
258
- stateRetained: cell.stateRetained,
259
- };
260
- }
261
- }
262
-
263
- function activeCellReuseError(cell: ManagedCell): Error {
264
- return new Error(
265
- `Eval cell ${cell.cellId} from a previous call is still ${cell.state} in the ${cell.input.language} kernel. Use eval({ action: "peek", cell_id: "${cell.cellId}" }) to read it or eval({ action: "stop", cell_id: "${cell.cellId}" }) to end it before its id can be reused.`,
266
- );
267
- }
268
-
269
- function allowsTransition(from: EvalDetachedCellState, to: EvalDetachedCellState): boolean {
270
- if (from === "running") return to === "detached" || to === "completed" || to === "failed" || to === "cancelled";
271
- if (from === "detached") return to === "completed" || to === "failed" || to === "cancelled";
272
- return false;
273
- }
274
-
275
- function errorResult(cell: ManagedCell, error: Error): AgentToolResult<EvalToolDetails> {
276
- const output = cell.outputTail?.() ?? "";
277
- return {
278
- content: [{ type: "text", text: output.length > 0 ? `${output}\n${error.message}` : error.message }],
279
- details: {
280
- language: cell.input.language,
281
- languages: [cell.input.language],
282
- durationMs: 0,
283
- toolCalls: [],
284
- truncated: false,
285
- isError: true,
286
- cells: [
287
- {
288
- index: 0,
289
- code: cell.input.code,
290
- language: cell.input.language,
291
- output,
292
- status: "error",
293
- },
294
- ],
295
- },
296
- };
297
- }
298
-
299
- function notificationBody(cell: EvalDetachedCellSnapshot): string {
300
- const outcome = cell.state === "completed" ? "completed" : cell.state === "cancelled" ? "cancelled" : "failed";
301
- const resultText =
302
- cell.result?.content
303
- .filter((part) => part.type === "text")
304
- .map((part) => part.text)
305
- .join("\n") ?? cell.outputTail;
306
- const stateNote =
307
- cell.state === "cancelled" && cell.language === "js"
308
- ? "JavaScript worker was restarted; VM state was lost."
309
- : cell.state === "cancelled" && cell.language === "py"
310
- ? "Python kernel was interrupted; its existing variables are preserved."
311
- : "Kernel state updated - variables are available to the next eval cell.";
312
- return [
313
- `<system-reminder>Detached eval cell ${cell.cellId} (${cell.language}) ${outcome}.`,
314
- resultText.length === 0 ? "(no output)" : resultText,
315
- `${stateNote}</system-reminder>`,
316
- ].join("\n");
317
- }
318
-
319
- function notificationPreview(cell: EvalDetachedCellSnapshot): string {
320
- const outcome = cell.state === "completed" ? "completed" : cell.state === "cancelled" ? "cancelled" : "failed";
321
- const resultText =
322
- cell.result?.content
323
- .filter((part) => part.type === "text")
324
- .map((part) => part.text)
325
- .join("\n") ?? cell.outputTail;
326
- const stateNote =
327
- cell.state === "cancelled" && cell.language === "js"
328
- ? "JavaScript worker was restarted; VM state was lost."
329
- : cell.state === "cancelled" && cell.language === "py"
330
- ? "Python kernel was interrupted; its existing variables are preserved."
331
- : "Kernel state updated - variables are available to the next eval cell.";
332
- return [
333
- `<system-reminder>Detached eval cell ${cell.cellId} (${cell.language}) ${outcome}.`,
334
- "Buffered output tail:",
335
- truncateTailUtf8(resultText, NOTIFICATION_TAIL_BYTES),
336
- `${stateNote}</system-reminder>`,
337
- ].join("\n");
338
- }
339
-
340
- function safeCellId(cellId: string): string {
341
- return cellId.replace(/[^a-zA-Z0-9_-]/gu, "_");
342
- }
343
-
344
- function localUri(path: string, artifactsDir: string | undefined): string {
345
- if (artifactsDir === undefined) return `local://${path}`;
346
- const root = join(artifactsDir, "local");
347
- return path.startsWith(`${root}/`) ? `local://${path.slice(root.length + 1)}` : `local://${path}`;
348
- }
349
-
350
- function truncateTailUtf8(text: string, maxBytes: number): string {
351
- if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
352
- const bytes = Buffer.from(text, "utf8");
353
- let start = bytes.length - maxBytes;
354
- while (start < bytes.length && (bytes[start] & 0xc0) === 0x80) start++;
355
- return bytes.subarray(start).toString("utf8");
356
210
  }
@@ -0,0 +1,98 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { dirname, join } from "node:path";
3
+ import type { EvalDetachedCellNotification, EvalDetachedCellSnapshot } from "./detached-cell-manager.ts";
4
+
5
+ const NOTIFICATION_TAIL_BYTES = 512;
6
+
7
+ export function detachedNotificationSpillPath(artifactsDir: string | undefined, cellId: string): string | undefined {
8
+ if (artifactsDir === undefined) return undefined;
9
+ return join(artifactsDir, "local", `detached-eval-${safeCellId(cellId)}.log`);
10
+ }
11
+
12
+ export async function buildDetachedCellNotification(
13
+ snapshot: EvalDetachedCellSnapshot,
14
+ spillPath: string | undefined,
15
+ artifactsDir: string | undefined,
16
+ ): Promise<EvalDetachedCellNotification> {
17
+ const body = notificationBody(snapshot);
18
+ const overflow = Buffer.byteLength(body, "utf8") > NOTIFICATION_TAIL_BYTES;
19
+ let spillNotice = "";
20
+ if (overflow && spillPath !== undefined) {
21
+ try {
22
+ await mkdir(dirname(spillPath), { recursive: true });
23
+ await writeFile(spillPath, body, "utf8");
24
+ spillNotice = `\nBuffered output overflowed; full output: ${localUri(spillPath, artifactsDir)}`;
25
+ } catch (error) {
26
+ const message = error instanceof Error ? error.message : String(error);
27
+ spillNotice = `\nBuffered output overflow could not be spilled: ${message}`;
28
+ }
29
+ }
30
+ return {
31
+ cellId: snapshot.cellId,
32
+ content: `${overflow ? notificationPreview(snapshot) : body}${overflow ? "\n[…notification tail capped…]" : ""}${spillNotice}`,
33
+ };
34
+ }
35
+
36
+ function notificationBody(cell: EvalDetachedCellSnapshot): string {
37
+ const outcome = outcomeOf(cell);
38
+ const resultText = textContent(cell);
39
+ const stateNote = stateNoteOf(cell);
40
+ return [
41
+ `<system-reminder>Detached eval cell ${cell.cellId} (${cell.language}) ${outcome}.`,
42
+ resultText.length === 0 ? "(no output)" : resultText,
43
+ `${stateNote}</system-reminder>`,
44
+ ].join("\n");
45
+ }
46
+
47
+ function notificationPreview(cell: EvalDetachedCellSnapshot): string {
48
+ const outcome = outcomeOf(cell);
49
+ const resultText = textContent(cell);
50
+ const stateNote = stateNoteOf(cell);
51
+ return [
52
+ `<system-reminder>Detached eval cell ${cell.cellId} (${cell.language}) ${outcome}.`,
53
+ "Buffered output tail:",
54
+ truncateTailUtf8(resultText, NOTIFICATION_TAIL_BYTES),
55
+ `${stateNote}</system-reminder>`,
56
+ ].join("\n");
57
+ }
58
+
59
+ function textContent(cell: EvalDetachedCellSnapshot): string {
60
+ return (
61
+ cell.result.content
62
+ .filter((part) => part.type === "text")
63
+ .map((part) => part.text)
64
+ .join("\n") || cell.outputTail
65
+ );
66
+ }
67
+
68
+ function outcomeOf(cell: EvalDetachedCellSnapshot): string {
69
+ if (cell.state === "completed") return "completed";
70
+ if (cell.state === "cancelled") return "cancelled";
71
+ return "failed";
72
+ }
73
+
74
+ function stateNoteOf(cell: EvalDetachedCellSnapshot): string {
75
+ if (cell.state === "cancelled" && cell.language === "js")
76
+ return "JavaScript worker was restarted; VM state was lost.";
77
+ if (cell.state === "cancelled" && cell.language === "py")
78
+ return "Python kernel was interrupted; its existing variables are preserved.";
79
+ return "Kernel state updated - variables are available to the next eval cell.";
80
+ }
81
+
82
+ function safeCellId(cellId: string): string {
83
+ return cellId.replace(/[^a-zA-Z0-9_-]/gu, "_");
84
+ }
85
+
86
+ function localUri(path: string, artifactsDir: string | undefined): string {
87
+ if (artifactsDir === undefined) return `local://${path}`;
88
+ const root = join(artifactsDir, "local");
89
+ return path.startsWith(`${root}/`) ? `local://${path.slice(root.length + 1)}` : `local://${path}`;
90
+ }
91
+
92
+ function truncateTailUtf8(text: string, maxBytes: number): string {
93
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
94
+ const bytes = Buffer.from(text, "utf8");
95
+ let start = bytes.length - maxBytes;
96
+ while (start < bytes.length && (bytes[start] & 0xc0) === 0x80) start++;
97
+ return bytes.subarray(start).toString("utf8");
98
+ }