@code-yeongyu/senpi 2026.7.11 → 2026.7.13

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 (267) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/core/agent-session.d.ts +9 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +56 -15
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.d.ts.map +1 -1
  7. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js +76 -25
  8. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  9. package/dist/core/resource-loader.d.ts +1 -0
  10. package/dist/core/resource-loader.d.ts.map +1 -1
  11. package/dist/core/resource-loader.js +20 -2
  12. package/dist/core/resource-loader.js.map +1 -1
  13. package/dist/modes/interactive/compaction-queue-transfer.d.ts +22 -0
  14. package/dist/modes/interactive/compaction-queue-transfer.d.ts.map +1 -0
  15. package/dist/modes/interactive/compaction-queue-transfer.js +82 -0
  16. package/dist/modes/interactive/compaction-queue-transfer.js.map +1 -0
  17. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  18. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  19. package/dist/modes/interactive/interactive-mode.js +83 -69
  20. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  21. package/node_modules/@babel/helper-string-parser/LICENSE +22 -0
  22. package/node_modules/@babel/helper-string-parser/README.md +19 -0
  23. package/node_modules/@babel/helper-string-parser/lib/index.js +295 -0
  24. package/node_modules/@babel/helper-string-parser/lib/index.js.map +1 -0
  25. package/node_modules/@babel/helper-string-parser/package.json +31 -0
  26. package/node_modules/@babel/helper-validator-identifier/LICENSE +22 -0
  27. package/node_modules/@babel/helper-validator-identifier/README.md +19 -0
  28. package/node_modules/@babel/helper-validator-identifier/lib/identifier.js +70 -0
  29. package/node_modules/@babel/helper-validator-identifier/lib/identifier.js.map +1 -0
  30. package/node_modules/@babel/helper-validator-identifier/lib/index.js +57 -0
  31. package/node_modules/@babel/helper-validator-identifier/lib/index.js.map +1 -0
  32. package/node_modules/@babel/helper-validator-identifier/lib/keyword.js +35 -0
  33. package/node_modules/@babel/helper-validator-identifier/lib/keyword.js.map +1 -0
  34. package/node_modules/@babel/helper-validator-identifier/package.json +31 -0
  35. package/node_modules/@babel/parser/LICENSE +19 -0
  36. package/node_modules/@babel/parser/README.md +19 -0
  37. package/node_modules/@babel/parser/bin/babel-parser.js +15 -0
  38. package/node_modules/@babel/parser/lib/index.js +14599 -0
  39. package/node_modules/@babel/parser/lib/index.js.map +1 -0
  40. package/node_modules/@babel/parser/package.json +50 -0
  41. package/node_modules/@babel/parser/typings/babel-parser.d.ts +262 -0
  42. package/node_modules/@babel/types/LICENSE +22 -0
  43. package/node_modules/@babel/types/README.md +19 -0
  44. package/node_modules/@babel/types/lib/asserts/assertNode.js +16 -0
  45. package/node_modules/@babel/types/lib/asserts/assertNode.js.map +1 -0
  46. package/node_modules/@babel/types/lib/asserts/generated/index.js +1251 -0
  47. package/node_modules/@babel/types/lib/asserts/generated/index.js.map +1 -0
  48. package/node_modules/@babel/types/lib/ast-types/generated/index.js +3 -0
  49. package/node_modules/@babel/types/lib/ast-types/generated/index.js.map +1 -0
  50. package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js +18 -0
  51. package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js.map +1 -0
  52. package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js +31 -0
  53. package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js.map +1 -0
  54. package/node_modules/@babel/types/lib/builders/generated/index.js +29 -0
  55. package/node_modules/@babel/types/lib/builders/generated/index.js.map +1 -0
  56. package/node_modules/@babel/types/lib/builders/generated/lowercase.js +2902 -0
  57. package/node_modules/@babel/types/lib/builders/generated/lowercase.js.map +1 -0
  58. package/node_modules/@babel/types/lib/builders/generated/uppercase.js +272 -0
  59. package/node_modules/@babel/types/lib/builders/generated/uppercase.js.map +1 -0
  60. package/node_modules/@babel/types/lib/builders/productions.js +12 -0
  61. package/node_modules/@babel/types/lib/builders/productions.js.map +1 -0
  62. package/node_modules/@babel/types/lib/builders/react/buildChildren.js +24 -0
  63. package/node_modules/@babel/types/lib/builders/react/buildChildren.js.map +1 -0
  64. package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js +22 -0
  65. package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js.map +1 -0
  66. package/node_modules/@babel/types/lib/builders/validateNode.js +21 -0
  67. package/node_modules/@babel/types/lib/builders/validateNode.js.map +1 -0
  68. package/node_modules/@babel/types/lib/clone/clone.js +12 -0
  69. package/node_modules/@babel/types/lib/clone/clone.js.map +1 -0
  70. package/node_modules/@babel/types/lib/clone/cloneDeep.js +12 -0
  71. package/node_modules/@babel/types/lib/clone/cloneDeep.js.map +1 -0
  72. package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js +12 -0
  73. package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js.map +1 -0
  74. package/node_modules/@babel/types/lib/clone/cloneNode.js +107 -0
  75. package/node_modules/@babel/types/lib/clone/cloneNode.js.map +1 -0
  76. package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js +12 -0
  77. package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js.map +1 -0
  78. package/node_modules/@babel/types/lib/comments/addComment.js +15 -0
  79. package/node_modules/@babel/types/lib/comments/addComment.js.map +1 -0
  80. package/node_modules/@babel/types/lib/comments/addComments.js +22 -0
  81. package/node_modules/@babel/types/lib/comments/addComments.js.map +1 -0
  82. package/node_modules/@babel/types/lib/comments/inheritInnerComments.js +12 -0
  83. package/node_modules/@babel/types/lib/comments/inheritInnerComments.js.map +1 -0
  84. package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js +12 -0
  85. package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js.map +1 -0
  86. package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js +12 -0
  87. package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js.map +1 -0
  88. package/node_modules/@babel/types/lib/comments/inheritsComments.js +17 -0
  89. package/node_modules/@babel/types/lib/comments/inheritsComments.js.map +1 -0
  90. package/node_modules/@babel/types/lib/comments/removeComments.js +15 -0
  91. package/node_modules/@babel/types/lib/comments/removeComments.js.map +1 -0
  92. package/node_modules/@babel/types/lib/constants/generated/index.js +60 -0
  93. package/node_modules/@babel/types/lib/constants/generated/index.js.map +1 -0
  94. package/node_modules/@babel/types/lib/constants/index.js +31 -0
  95. package/node_modules/@babel/types/lib/constants/index.js.map +1 -0
  96. package/node_modules/@babel/types/lib/converters/ensureBlock.js +14 -0
  97. package/node_modules/@babel/types/lib/converters/ensureBlock.js.map +1 -0
  98. package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js +65 -0
  99. package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js.map +1 -0
  100. package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js +14 -0
  101. package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js.map +1 -0
  102. package/node_modules/@babel/types/lib/converters/toBlock.js +29 -0
  103. package/node_modules/@babel/types/lib/converters/toBlock.js.map +1 -0
  104. package/node_modules/@babel/types/lib/converters/toComputedKey.js +14 -0
  105. package/node_modules/@babel/types/lib/converters/toComputedKey.js.map +1 -0
  106. package/node_modules/@babel/types/lib/converters/toExpression.js +28 -0
  107. package/node_modules/@babel/types/lib/converters/toExpression.js.map +1 -0
  108. package/node_modules/@babel/types/lib/converters/toIdentifier.js +25 -0
  109. package/node_modules/@babel/types/lib/converters/toIdentifier.js.map +1 -0
  110. package/node_modules/@babel/types/lib/converters/toKeyAlias.js +38 -0
  111. package/node_modules/@babel/types/lib/converters/toKeyAlias.js.map +1 -0
  112. package/node_modules/@babel/types/lib/converters/toSequenceExpression.js +19 -0
  113. package/node_modules/@babel/types/lib/converters/toSequenceExpression.js.map +1 -0
  114. package/node_modules/@babel/types/lib/converters/toStatement.js +39 -0
  115. package/node_modules/@babel/types/lib/converters/toStatement.js.map +1 -0
  116. package/node_modules/@babel/types/lib/converters/valueToNode.js +89 -0
  117. package/node_modules/@babel/types/lib/converters/valueToNode.js.map +1 -0
  118. package/node_modules/@babel/types/lib/definitions/core.js +1725 -0
  119. package/node_modules/@babel/types/lib/definitions/core.js.map +1 -0
  120. package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js +11 -0
  121. package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js.map +1 -0
  122. package/node_modules/@babel/types/lib/definitions/experimental.js +124 -0
  123. package/node_modules/@babel/types/lib/definitions/experimental.js.map +1 -0
  124. package/node_modules/@babel/types/lib/definitions/flow.js +495 -0
  125. package/node_modules/@babel/types/lib/definitions/flow.js.map +1 -0
  126. package/node_modules/@babel/types/lib/definitions/index.js +106 -0
  127. package/node_modules/@babel/types/lib/definitions/index.js.map +1 -0
  128. package/node_modules/@babel/types/lib/definitions/jsx.js +157 -0
  129. package/node_modules/@babel/types/lib/definitions/jsx.js.map +1 -0
  130. package/node_modules/@babel/types/lib/definitions/misc.js +31 -0
  131. package/node_modules/@babel/types/lib/definitions/misc.js.map +1 -0
  132. package/node_modules/@babel/types/lib/definitions/placeholders.js +27 -0
  133. package/node_modules/@babel/types/lib/definitions/placeholders.js.map +1 -0
  134. package/node_modules/@babel/types/lib/definitions/typescript.js +528 -0
  135. package/node_modules/@babel/types/lib/definitions/typescript.js.map +1 -0
  136. package/node_modules/@babel/types/lib/definitions/utils.js +296 -0
  137. package/node_modules/@babel/types/lib/definitions/utils.js.map +1 -0
  138. package/node_modules/@babel/types/lib/index-legacy.d.ts +2797 -0
  139. package/node_modules/@babel/types/lib/index.d.ts +3617 -0
  140. package/node_modules/@babel/types/lib/index.js +582 -0
  141. package/node_modules/@babel/types/lib/index.js.flow +2650 -0
  142. package/node_modules/@babel/types/lib/index.js.map +1 -0
  143. package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js +15 -0
  144. package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js.map +1 -0
  145. package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js +65 -0
  146. package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js.map +1 -0
  147. package/node_modules/@babel/types/lib/modifications/inherits.js +28 -0
  148. package/node_modules/@babel/types/lib/modifications/inherits.js.map +1 -0
  149. package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js +17 -0
  150. package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js.map +1 -0
  151. package/node_modules/@babel/types/lib/modifications/removeProperties.js +24 -0
  152. package/node_modules/@babel/types/lib/modifications/removeProperties.js.map +1 -0
  153. package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js +14 -0
  154. package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js.map +1 -0
  155. package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js +66 -0
  156. package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js.map +1 -0
  157. package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js +48 -0
  158. package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js.map +1 -0
  159. package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js +102 -0
  160. package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js.map +1 -0
  161. package/node_modules/@babel/types/lib/retrievers/getFunctionName.js +63 -0
  162. package/node_modules/@babel/types/lib/retrievers/getFunctionName.js.map +1 -0
  163. package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js +13 -0
  164. package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js.map +1 -0
  165. package/node_modules/@babel/types/lib/traverse/traverse.js +50 -0
  166. package/node_modules/@babel/types/lib/traverse/traverse.js.map +1 -0
  167. package/node_modules/@babel/types/lib/traverse/traverseFast.js +40 -0
  168. package/node_modules/@babel/types/lib/traverse/traverseFast.js.map +1 -0
  169. package/node_modules/@babel/types/lib/utils/deprecationWarning.js +44 -0
  170. package/node_modules/@babel/types/lib/utils/deprecationWarning.js.map +1 -0
  171. package/node_modules/@babel/types/lib/utils/inherit.js +13 -0
  172. package/node_modules/@babel/types/lib/utils/inherit.js.map +1 -0
  173. package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js +40 -0
  174. package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js.map +1 -0
  175. package/node_modules/@babel/types/lib/utils/shallowEqual.js +17 -0
  176. package/node_modules/@babel/types/lib/utils/shallowEqual.js.map +1 -0
  177. package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js +13 -0
  178. package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js.map +1 -0
  179. package/node_modules/@babel/types/lib/validators/generated/index.js +2797 -0
  180. package/node_modules/@babel/types/lib/validators/generated/index.js.map +1 -0
  181. package/node_modules/@babel/types/lib/validators/is.js +27 -0
  182. package/node_modules/@babel/types/lib/validators/is.js.map +1 -0
  183. package/node_modules/@babel/types/lib/validators/isBinding.js +27 -0
  184. package/node_modules/@babel/types/lib/validators/isBinding.js.map +1 -0
  185. package/node_modules/@babel/types/lib/validators/isBlockScoped.js +13 -0
  186. package/node_modules/@babel/types/lib/validators/isBlockScoped.js.map +1 -0
  187. package/node_modules/@babel/types/lib/validators/isImmutable.js +21 -0
  188. package/node_modules/@babel/types/lib/validators/isImmutable.js.map +1 -0
  189. package/node_modules/@babel/types/lib/validators/isLet.js +13 -0
  190. package/node_modules/@babel/types/lib/validators/isLet.js.map +1 -0
  191. package/node_modules/@babel/types/lib/validators/isNode.js +12 -0
  192. package/node_modules/@babel/types/lib/validators/isNode.js.map +1 -0
  193. package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js +57 -0
  194. package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js.map +1 -0
  195. package/node_modules/@babel/types/lib/validators/isPlaceholderType.js +15 -0
  196. package/node_modules/@babel/types/lib/validators/isPlaceholderType.js.map +1 -0
  197. package/node_modules/@babel/types/lib/validators/isReferenced.js +96 -0
  198. package/node_modules/@babel/types/lib/validators/isReferenced.js.map +1 -0
  199. package/node_modules/@babel/types/lib/validators/isScope.js +18 -0
  200. package/node_modules/@babel/types/lib/validators/isScope.js.map +1 -0
  201. package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js +14 -0
  202. package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js.map +1 -0
  203. package/node_modules/@babel/types/lib/validators/isType.js +17 -0
  204. package/node_modules/@babel/types/lib/validators/isType.js.map +1 -0
  205. package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js +13 -0
  206. package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js.map +1 -0
  207. package/node_modules/@babel/types/lib/validators/isValidIdentifier.js +18 -0
  208. package/node_modules/@babel/types/lib/validators/isValidIdentifier.js.map +1 -0
  209. package/node_modules/@babel/types/lib/validators/isVar.js +15 -0
  210. package/node_modules/@babel/types/lib/validators/isVar.js.map +1 -0
  211. package/node_modules/@babel/types/lib/validators/matchesPattern.js +44 -0
  212. package/node_modules/@babel/types/lib/validators/matchesPattern.js.map +1 -0
  213. package/node_modules/@babel/types/lib/validators/react/isCompatTag.js +11 -0
  214. package/node_modules/@babel/types/lib/validators/react/isCompatTag.js.map +1 -0
  215. package/node_modules/@babel/types/lib/validators/react/isReactComponent.js +11 -0
  216. package/node_modules/@babel/types/lib/validators/react/isReactComponent.js.map +1 -0
  217. package/node_modules/@babel/types/lib/validators/validate.js +42 -0
  218. package/node_modules/@babel/types/lib/validators/validate.js.map +1 -0
  219. package/node_modules/@babel/types/package.json +39 -0
  220. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +10 -2
  221. package/node_modules/@code-yeongyu/senpi-codemode/README.md +128 -78
  222. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -3
  223. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +15 -2
  224. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/reserved.ts +9 -0
  225. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +197 -0
  226. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/output-bridge.ts +96 -0
  227. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/schema-injection.ts +3 -0
  228. package/node_modules/@code-yeongyu/senpi-codemode/src/completion/handler.ts +95 -26
  229. package/node_modules/@code-yeongyu/senpi-codemode/src/completion/tool-bridge.ts +11 -2
  230. package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +96 -8
  231. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +24 -3
  232. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +155 -21
  233. package/node_modules/@code-yeongyu/senpi-codemode/src/interpreters/detect.ts +1 -1
  234. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +252 -48
  235. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +263 -83
  236. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +11 -5
  237. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/local-module-loader.ts +108 -0
  238. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +8 -6
  239. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/rewrite-imports.ts +164 -0
  240. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +6 -1
  241. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +307 -41
  242. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +3 -2
  243. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +792 -79
  244. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +234 -21
  245. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/runner.rb +154 -51
  246. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +1 -0
  247. package/node_modules/@code-yeongyu/senpi-codemode/src/output/output-meta.ts +89 -0
  248. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +296 -0
  249. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +107 -30
  250. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/bridge-timeout.ts +2 -0
  251. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +8 -19
  252. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +175 -113
  253. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +130 -120
  254. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +274 -0
  255. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/json-tree.ts +247 -0
  256. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +641 -38
  257. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/status-events.ts +12 -0
  258. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +29 -1
  259. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  260. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +16 -16
  261. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +6 -6
  263. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  264. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  265. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  266. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  267. package/package.json +6 -6
@@ -0,0 +1,164 @@
1
+ import { parse } from "@babel/parser";
2
+ import type { ImportDeclaration } from "@babel/types";
3
+
4
+ const DYNAMIC_IMPORT_CALLEE =
5
+ '(typeof __senpi_import__ === "function" ? __senpi_import__ : (specifier, options) => import(specifier, options))';
6
+
7
+ type AstNode = {
8
+ readonly type: string;
9
+ readonly start: number;
10
+ readonly end: number;
11
+ readonly value: Readonly<Record<string, unknown>>;
12
+ };
13
+
14
+ type TextEdit = {
15
+ readonly start: number;
16
+ readonly end: number;
17
+ readonly text: string;
18
+ };
19
+
20
+ class UnexpectedImportSpecifierError extends Error {
21
+ readonly name = "UnexpectedImportSpecifierError";
22
+ }
23
+
24
+ function assertNever(_value: never): never {
25
+ throw new UnexpectedImportSpecifierError("Unsupported import specifier");
26
+ }
27
+
28
+ function isRecord(value: unknown): value is Readonly<Record<string, unknown>> {
29
+ return value !== null && typeof value === "object" && !Array.isArray(value);
30
+ }
31
+
32
+ function nodeFrom(value: unknown): AstNode | undefined {
33
+ if (!isRecord(value)) return undefined;
34
+ const type = value["type"];
35
+ const start = value["start"];
36
+ const end = value["end"];
37
+ if (typeof type !== "string" || typeof start !== "number" || typeof end !== "number") return undefined;
38
+ return { type, start, end, value };
39
+ }
40
+
41
+ function parseProgram(code: string): ReturnType<typeof parse> | undefined {
42
+ try {
43
+ return parse(code, {
44
+ sourceType: "module",
45
+ allowAwaitOutsideFunction: true,
46
+ allowReturnOutsideFunction: true,
47
+ allowImportExportEverywhere: true,
48
+ allowNewTargetOutsideFunction: true,
49
+ allowSuperOutsideMethod: true,
50
+ allowUndeclaredExports: true,
51
+ errorRecovery: true,
52
+ plugins: ["typescript", "importAttributes"],
53
+ });
54
+ } catch (error) {
55
+ if (error instanceof SyntaxError) return undefined;
56
+ throw error;
57
+ }
58
+ }
59
+
60
+ function walkNodes(root: unknown, visit: (node: AstNode) => void): void {
61
+ const stack: unknown[] = [root];
62
+ while (stack.length > 0) {
63
+ const current = stack.pop();
64
+ if (Array.isArray(current)) {
65
+ for (let index = current.length - 1; index >= 0; index -= 1) stack.push(current[index]);
66
+ continue;
67
+ }
68
+ if (!isRecord(current)) continue;
69
+ const node = nodeFrom(current);
70
+ if (node) visit(node);
71
+ for (const [key, value] of Object.entries(current)) {
72
+ if (key === "loc" || key === "extra" || key === "range" || key.endsWith("Comments")) continue;
73
+ if (value !== null && typeof value === "object") stack.push(value);
74
+ }
75
+ }
76
+ }
77
+
78
+ function importOptions(node: ImportDeclaration): string | undefined {
79
+ if (!node.attributes || node.attributes.length === 0) return undefined;
80
+ const pairs = node.attributes.map((attribute) => {
81
+ const key = attribute.key.type === "Identifier" ? attribute.key.name : JSON.stringify(attribute.key.value);
82
+ return `${key}: ${JSON.stringify(attribute.value.value)}`;
83
+ });
84
+ return `{ with: { ${pairs.join(", ")} } }`;
85
+ }
86
+
87
+ function importCall(source: string, options: string | undefined): string {
88
+ const sourceLiteral = JSON.stringify(source);
89
+ return options ? `__senpi_import__(${sourceLiteral}, ${options})` : `__senpi_import__(${sourceLiteral})`;
90
+ }
91
+
92
+ function rewriteImportDeclaration(node: ImportDeclaration): string {
93
+ const call = importCall(node.source.value, importOptions(node));
94
+ let defaultName: string | undefined;
95
+ let namespaceName: string | undefined;
96
+ const namedBindings: Array<readonly [imported: string, local: string]> = [];
97
+
98
+ for (const specifier of node.specifiers) {
99
+ switch (specifier.type) {
100
+ case "ImportDefaultSpecifier":
101
+ defaultName = specifier.local.name;
102
+ break;
103
+ case "ImportNamespaceSpecifier":
104
+ namespaceName = specifier.local.name;
105
+ break;
106
+ case "ImportSpecifier": {
107
+ const imported =
108
+ specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
109
+ namedBindings.push([imported, specifier.local.name]);
110
+ break;
111
+ }
112
+ default:
113
+ assertNever(specifier);
114
+ }
115
+ }
116
+
117
+ if (namedBindings.length > 0) {
118
+ const named = namedBindings
119
+ .map(([imported, local]) => (imported === local ? imported : `${imported}: ${local}`))
120
+ .join(", ");
121
+ const bindings = defaultName ? `default: ${defaultName}, ${named}` : named;
122
+ return `const { ${bindings} } = await ${call};`;
123
+ }
124
+ if (namespaceName && defaultName) {
125
+ return `const ${namespaceName} = await ${call}; const ${defaultName} = ${namespaceName}.default;`;
126
+ }
127
+ if (namespaceName) return `const ${namespaceName} = await ${call};`;
128
+ if (defaultName) return `const ${defaultName} = (await ${call}).default;`;
129
+ return `await ${call};`;
130
+ }
131
+
132
+ function dynamicImportEdit(node: AstNode): TextEdit | undefined {
133
+ if (node.type !== "CallExpression") return undefined;
134
+ const callee = nodeFrom(node.value["callee"]);
135
+ if (callee?.type !== "Import") return undefined;
136
+ return { start: callee.start, end: callee.end, text: DYNAMIC_IMPORT_CALLEE };
137
+ }
138
+
139
+ function applyEdits(code: string, edits: readonly TextEdit[]): string {
140
+ if (edits.length === 0) return code;
141
+ const descending = edits.toSorted((left, right) => right.start - left.start);
142
+ let output = code;
143
+ for (const edit of descending) {
144
+ output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
145
+ }
146
+ return output;
147
+ }
148
+
149
+ export function rewriteImports(code: string): string {
150
+ if (!code.includes("import")) return code;
151
+ const ast = parseProgram(code);
152
+ if (!ast) return code;
153
+ const edits: TextEdit[] = [];
154
+
155
+ for (const node of ast.program.body) {
156
+ if (node.type !== "ImportDeclaration" || typeof node.start !== "number" || typeof node.end !== "number") continue;
157
+ edits.push({ start: node.start, end: node.end, text: rewriteImportDeclaration(node) });
158
+ }
159
+ walkNodes(ast.program, (node) => {
160
+ const edit = dynamicImportEdit(node);
161
+ if (edit) edits.push(edit);
162
+ });
163
+ return applyEdits(code, edits);
164
+ }
@@ -34,7 +34,12 @@ export function createWorkerCore(transport, options) {
34
34
 
35
35
  function onMessage(message) {
36
36
  if (message.type === "init") {
37
- runtime = new JsWorkerRuntime({ cwd: options.cwd, parallelPoolWidth: options.parallelPoolWidth });
37
+ runtime = new JsWorkerRuntime({
38
+ cwd: options.cwd,
39
+ parallelPoolWidth: options.parallelPoolWidth,
40
+ localRoots: message.connection.localRoots,
41
+ artifactsDir: message.connection.artifactsDir,
42
+ });
38
43
  emit({ type: "ready" });
39
44
  return;
40
45
  }
@@ -1,24 +1,41 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
2
- import { dirname, isAbsolute, resolve } from "node:path";
1
+ // allow: SIZE_OK private runtime state and installed globals must stay in one worker module.
2
+ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
3
+ import { dirname, isAbsolute, join, normalize, resolve, sep } from "node:path";
3
4
  import { inspect } from "node:util";
4
5
  import { awaitMaybePromise, indirectEval, wrapUserCode } from "./worker-indirect-eval.js";
5
6
 
7
+ const PREPARED_CELL_PREFIX = "/*senpi:prepared-cell*/";
8
+ const INTERNAL_URL = /^([a-z][a-z0-9+.-]*):\/\/(.*)$/iu;
9
+ const BASE64_STRICT_RE = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/u;
10
+ const DECIMAL_CSV_RE = /^\d{1,3}(?:,\d{1,3})*$/u;
11
+
6
12
  export class JsWorkerRuntime {
7
13
  #cwd;
8
14
  #parallelPoolWidth;
15
+ #localRoots;
9
16
  #env = new Map();
10
17
  #hooks = null;
11
18
 
12
19
  constructor(options) {
13
20
  this.#cwd = options.cwd;
14
21
  this.#parallelPoolWidth = options.parallelPoolWidth;
22
+ this.#localRoots = { ...(options.localRoots ?? {}) };
23
+ if (options.artifactsDir && !this.#localRoots.local) this.#localRoots.local = join(options.artifactsDir, "local");
15
24
  this.#installGlobals();
16
25
  }
17
26
 
18
27
  async run(code, cellId, hooks) {
19
28
  this.#hooks = hooks;
20
29
  try {
21
- return await awaitMaybePromise(indirectEval(wrapUserCode(code), cellId));
30
+ let prelude = "";
31
+ let cellCode = code;
32
+ if (code.startsWith(PREPARED_CELL_PREFIX)) {
33
+ const prepared = JSON.parse(code.slice(PREPARED_CELL_PREFIX.length));
34
+ if (!isPlainObject(prepared) || typeof prepared.prelude !== "string" || typeof prepared.code !== "string") throw new Error("Invalid prepared JavaScript cell payload");
35
+ ({ prelude, code: cellCode } = prepared);
36
+ }
37
+ if (prelude) indirectEval(prelude, `${cellId}:prelude`);
38
+ return await awaitMaybePromise(indirectEval(wrapUserCode(cellCode), cellId));
22
39
  } finally {
23
40
  this.#hooks = null;
24
41
  }
@@ -30,8 +47,10 @@ export class JsWorkerRuntime {
30
47
  globalThis.log = message => this.#hooks?.emit({ type: "log", message: String(message) });
31
48
  globalThis.phase = title => this.#hooks?.emit({ type: "phase", title: String(title) });
32
49
  globalThis.env = (key, value) => this.#envHelper(key, value);
33
- globalThis.read = async (path, offset = 1, limit) => await this.#read(path, offset, limit);
50
+ globalThis.read = async (path, options, ...rest) => await this.#read(path, helperOptions("read", options, rest));
34
51
  globalThis.write = async (path, content) => await this.#write(path, content);
52
+ globalThis.output = async (...args) => await this.#output(args);
53
+ globalThis.agent = async (prompt, options, ...rest) => await this.#agent(prompt, options, rest);
35
54
  globalThis.parallel = async thunks => await this.#parallel(thunks);
36
55
  globalThis.pipeline = async (items, ...stages) => await this.#pipeline(items, stages);
37
56
  globalThis.completion = async (prompt, opts) => await this.#callTool("completion", { prompt, opts });
@@ -40,21 +59,34 @@ export class JsWorkerRuntime {
40
59
  {
41
60
  get: (_target, prop) => {
42
61
  if (typeof prop !== "string") return undefined;
43
- return async args => await this.#callTool(prop, args);
62
+ return async args => await this.#callTool(prop, args ?? {});
44
63
  },
45
64
  },
46
65
  );
47
66
  const originalLog = console.log.bind(console);
48
67
  const originalError = console.error.bind(console);
49
- console.log = (...values) => {
50
- this.#emitText("stdout", `${values.map(formatValue).join(" ")}\n`);
51
- };
52
- console.error = (...values) => {
53
- this.#emitText("stderr", `${values.map(formatValue).join(" ")}\n`);
68
+ const originalStdoutWrite = process.stdout.write;
69
+ const originalStderrWrite = process.stderr.write;
70
+ const routeWrite = (stream, originalWrite, streamName) => {
71
+ const write = originalWrite.bind(stream);
72
+ return (chunk, encoding, callback) => {
73
+ if (!this.#hooks) return write(chunk, encoding, callback);
74
+ const callbackValue = typeof encoding === "function" ? encoding : callback;
75
+ const encodingValue = typeof encoding === "string" ? encoding : undefined;
76
+ this.#emitText(streamName, chunkToString(chunk, encodingValue));
77
+ if (typeof callbackValue === "function") callbackValue();
78
+ return true;
79
+ };
54
80
  };
81
+ process.stdout.write = routeWrite(process.stdout, originalStdoutWrite, "stdout");
82
+ process.stderr.write = routeWrite(process.stderr, originalStderrWrite, "stderr");
83
+ console.log = (...values) => this.#emitText("stdout", `${values.map(formatValue).join(" ")}\n`);
84
+ console.error = (...values) => this.#emitText("stderr", `${values.map(formatValue).join(" ")}\n`);
55
85
  globalThis.__senpi_restore_console__ = () => {
56
86
  console.log = originalLog;
57
87
  console.error = originalError;
88
+ process.stdout.write = originalStdoutWrite;
89
+ process.stderr.write = originalStderrWrite;
58
90
  };
59
91
  }
60
92
 
@@ -62,73 +94,307 @@ export class JsWorkerRuntime {
62
94
  this.#hooks?.emit({ type: "text", stream, data });
63
95
  }
64
96
 
97
+ #emitStatus(event) {
98
+ this.#hooks?.emit({ type: "status", event });
99
+ }
100
+
65
101
  #display(value) {
66
- if (value && typeof value === "object" && typeof value.mimeType === "string" && typeof value.dataBase64 === "string") {
67
- this.#hooks?.emit({ type: "display", mimeType: value.mimeType, dataBase64: value.dataBase64 });
102
+ if (value && typeof value === "object") {
103
+ if (value.type === "markdown" && typeof value.text === "string") {
104
+ this.#hooks?.emit({ type: "display", mimeType: "text/markdown", dataBase64: encodeBase64(value.text) });
105
+ return;
106
+ }
107
+ if (value.type === "image" && typeof value.mimeType === "string") {
108
+ const dataBase64 = imageBase64(value.data);
109
+ if (dataBase64 !== undefined) {
110
+ this.#hooks?.emit({ type: "display", mimeType: value.mimeType, dataBase64 });
111
+ return;
112
+ }
113
+ this.#emitText(
114
+ "stdout",
115
+ `[display: image dropped — \`data\` must be a base64 string, Uint8Array/Buffer, or ArrayBuffer; got ${describeImageData(value.data)}]\n`,
116
+ );
117
+ return;
118
+ }
119
+ if (typeof value.mimeType === "string" && typeof value.dataBase64 === "string") {
120
+ this.#hooks?.emit({ type: "display", mimeType: value.mimeType, dataBase64: value.dataBase64 });
121
+ return;
122
+ }
123
+ try {
124
+ this.#hooks?.emit({ type: "display", mimeType: "application/json", dataBase64: encodeBase64(JSON.stringify(value)) });
125
+ } catch (error) {
126
+ if (!(error instanceof TypeError)) throw error;
127
+ this.#emitText("stdout", `${inspect(value, { colors: false, depth: 5 })}\n`);
128
+ }
68
129
  return;
69
130
  }
70
- this.#hooks?.emit({
71
- type: "display",
72
- mimeType: "application/json",
73
- dataBase64: Buffer.from(JSON.stringify(value), "utf8").toString("base64"),
74
- });
131
+ this.#emitText("stdout", `${String(value)}\n`);
75
132
  }
76
133
 
77
134
  #envHelper(key, value) {
78
- if (key === undefined) return { ...process.env, ...Object.fromEntries(this.#env) };
135
+ if (key === undefined || key === null || key === "") {
136
+ const merged = Object.fromEntries(Object.entries({ ...process.env, ...Object.fromEntries(this.#env) }).sort());
137
+ this.#emitStatus({ op: "env", count: Object.keys(merged).length, keys: Object.keys(merged).slice(0, 20) });
138
+ return merged;
139
+ }
140
+ const name = String(key);
79
141
  if (value !== undefined) {
80
142
  const stringValue = String(value);
81
- this.#env.set(String(key), stringValue);
143
+ this.#env.set(name, stringValue);
144
+ this.#emitStatus({ op: "env", key: name, value: stringValue, action: "set" });
82
145
  return stringValue;
83
146
  }
84
- return this.#env.get(String(key)) ?? process.env[String(key)];
147
+ const result = this.#env.get(name) ?? process.env[name];
148
+ this.#emitStatus({ op: "env", key: name, value: result, action: "get" });
149
+ return result;
85
150
  }
86
151
 
87
- async #read(rawPath, offset, limit) {
88
- const text = await readFile(this.#resolvePath(String(rawPath)), "utf8");
89
- if (offset <= 1 && limit === undefined) return text;
90
- const lines = text.split(/\r?\n/u);
91
- return lines.slice(Math.max(0, offset - 1), limit === undefined ? undefined : offset - 1 + limit).join("\n");
152
+ async #read(rawPath, options) {
153
+ const path = this.#resolvePath(String(rawPath), "read");
154
+ const info = await stat(path);
155
+ if (info.isDirectory()) throw new Error(`Directory paths are not supported by read(): ${path}`);
156
+ let text = await readFile(path, "utf8");
157
+ const offset = typeof options.offset === "number" ? options.offset : 1;
158
+ const limit = typeof options.limit === "number" ? options.limit : undefined;
159
+ if (offset > 1 || limit !== undefined) {
160
+ const lines = text.split(/\r?\n/u);
161
+ const start = Math.max(0, offset - 1);
162
+ text = lines.slice(start, limit === undefined ? undefined : start + limit).join("\n");
163
+ }
164
+ this.#emitStatus({ op: "read", path, bytes: info.size, chars: text.length });
165
+ return text;
92
166
  }
93
167
 
94
168
  async #write(rawPath, content) {
95
- const path = this.#resolvePath(String(rawPath));
169
+ const path = this.#resolvePath(String(rawPath), "write");
170
+ const data = await writeData(content);
96
171
  await mkdir(dirname(path), { recursive: true });
97
- await writeFile(path, String(content));
172
+ await writeFile(path, data);
173
+ this.#emitStatus({ op: "write", path, bytes: typeof data === "string" ? Buffer.byteLength(data) : data.byteLength });
174
+ return path;
175
+ }
176
+
177
+ #resolvePath(rawPath, operation) {
178
+ const match = INTERNAL_URL.exec(rawPath);
179
+ if (!match) return isAbsolute(rawPath) ? normalize(rawPath) : resolve(this.#cwd, rawPath);
180
+ const scheme = match[1].toLowerCase();
181
+ const root = this.#localRoots[scheme];
182
+ if (!root) throw new Error(`Protocol paths are not supported by ${operation}(): ${rawPath}`);
183
+ let relative;
184
+ try {
185
+ relative = decodeURIComponent(match[2].replaceAll("\\", "/"));
186
+ } catch (error) {
187
+ if (error instanceof URIError) throw new Error(`Invalid URL encoding in ${scheme}:// path: ${rawPath}`);
188
+ throw error;
189
+ }
190
+ if (isAbsolute(relative) || relative.split("/").includes("..")) {
191
+ throw new Error(`Path traversal is not allowed in ${scheme}:// URLs: ${rawPath}`);
192
+ }
193
+ const rootPath = resolve(root);
194
+ const path = resolve(rootPath, relative);
195
+ if (path !== rootPath && !path.startsWith(`${rootPath}${sep}`)) throw new Error(`${scheme}:// path escapes its root`);
98
196
  return path;
99
197
  }
100
198
 
101
- #resolvePath(path) {
102
- return isAbsolute(path) ? path : resolve(this.#cwd, path);
199
+ async #output(args) {
200
+ let ids = args;
201
+ let options = {};
202
+ const last = args.at(-1);
203
+ if (isPlainObject(last)) {
204
+ ids = args.slice(0, -1);
205
+ options = last;
206
+ }
207
+ return await this.#callTool(reservedTool("__senpi_reserved_output_tool__", "output"), {
208
+ ids: ids.map(String),
209
+ ...options,
210
+ });
211
+ }
212
+
213
+ async #agent(prompt, options, rest) {
214
+ const parsed = optionsArg({
215
+ name: "agent",
216
+ value: options,
217
+ rest,
218
+ keys: ["agent", "model", "label", "schema", "isolated", "apply", "merge"],
219
+ example: "{ agent, model, label, schema, isolated, apply, merge, handle }",
220
+ });
221
+ const { handle, ...callArgs } = parsed;
222
+ const response = await this.#callTool(reservedTool("__senpi_reserved_agent_tool__", "agent"), {
223
+ prompt: String(prompt),
224
+ ...callArgs,
225
+ handle: Boolean(handle),
226
+ });
227
+ const responseRecord = isPlainObject(response) ? response : {};
228
+ const text = Object.hasOwn(responseRecord, "text") ? responseRecord.text : response;
229
+ const output = Object.hasOwn(callArgs, "schema")
230
+ ? Object.hasOwn(responseRecord, "data")
231
+ ? responseRecord.data
232
+ : JSON.parse(String(text))
233
+ : text;
234
+ if (!handle) return output;
235
+ const details = isPlainObject(responseRecord.details) ? responseRecord.details : responseRecord;
236
+ const id = details.id;
237
+ if (id === undefined || id === null) return { text, output: text, handle: null, id: null, agent: null };
238
+ const node = {
239
+ text,
240
+ output: text,
241
+ handle: details.handle ?? `agent://${id}`,
242
+ id,
243
+ agent: details.agent ?? callArgs.agent ?? null,
244
+ };
245
+ if (Object.hasOwn(callArgs, "schema")) node.data = output;
246
+ for (const key of ["isolated", "patchPath", "branchName", "nestedPatches", "changesApplied", "isolationSummary"]) {
247
+ if (details[key] !== undefined) node[key] = details[key];
248
+ }
249
+ return node;
103
250
  }
104
251
 
105
252
  async #callTool(toolName, args) {
106
- if (!this.#hooks) throw new Error("tool call outside active JS cell");
107
- return await this.#hooks.callTool(toolName, args);
253
+ const hooks = this.#hooks;
254
+ if (!hooks) throw new Error("tool call outside active JS cell");
255
+ if (
256
+ typeof globalThis.__senpi_timeout_pause_op__ !== "string" ||
257
+ typeof globalThis.__senpi_timeout_resume_op__ !== "string"
258
+ ) {
259
+ throw new Error("timeout bridge is unavailable");
260
+ }
261
+ this.#emitStatus({ op: globalThis.__senpi_timeout_pause_op__ });
262
+ try {
263
+ return await hooks.callTool(toolName, args);
264
+ } finally {
265
+ this.#emitStatus({ op: globalThis.__senpi_timeout_resume_op__ });
266
+ }
108
267
  }
109
268
 
110
269
  async #parallel(thunks) {
111
- const results = new Array(thunks.length);
270
+ const list = Array.from(thunks ?? []);
271
+ if (list.length === 0) return [];
272
+ const configuredWidth = Number.isFinite(this.#parallelPoolWidth) ? Math.trunc(this.#parallelPoolWidth) : 1;
273
+ const workerCount = Math.min(Math.max(1, configuredWidth), list.length);
274
+ const results = new Array(list.length);
112
275
  let next = 0;
113
- const workers = Array.from({ length: Math.min(this.#parallelPoolWidth, thunks.length) }, async () => {
114
- while (next < thunks.length) {
276
+ let firstError;
277
+ let firstErrorIndex = list.length;
278
+ let hasError = false;
279
+ const worker = async () => {
280
+ while (true) {
115
281
  const index = next;
116
282
  next += 1;
117
- results[index] = await thunks[index]();
283
+ if (index >= list.length) return;
284
+ try {
285
+ const thunk = list[index];
286
+ if (typeof thunk !== "function") throw new TypeError("parallel() expects an iterable of functions");
287
+ results[index] = await thunk(index);
288
+ } catch (error) {
289
+ if (!hasError || index < firstErrorIndex) {
290
+ hasError = true;
291
+ firstErrorIndex = index;
292
+ firstError = error;
293
+ }
294
+ }
118
295
  }
119
- });
120
- await Promise.all(workers);
296
+ };
297
+ await Promise.all(Array.from({ length: workerCount }, worker));
298
+ if (hasError) throw firstError;
121
299
  return results;
122
300
  }
123
301
 
124
302
  async #pipeline(items, stages) {
125
- let current = items;
126
- for (const stage of stages) current = await this.#parallel(current.map(item => async () => await stage(item)));
303
+ let current = Array.from(items ?? []);
304
+ for (const stage of stages) {
305
+ if (typeof stage !== "function") throw new TypeError("pipeline() stages must be functions");
306
+ current = await this.#parallel(current.map(item => async () => await stage(item)));
307
+ }
127
308
  return current;
128
309
  }
129
310
  }
130
311
 
312
+ function isPlainObject(value) {
313
+ return value !== null && typeof value === "object" && !Array.isArray(value);
314
+ }
315
+
316
+ function optionsArg(options) {
317
+ const { name, value, rest, keys, example } = options;
318
+ if (isPlainObject(value)) {
319
+ if (rest.some(item => item !== undefined && item !== null)) throw new TypeError(`${name}() options cannot mix object and positional forms`);
320
+ return value;
321
+ }
322
+ const values = [value, ...rest];
323
+ for (let index = keys.length; index < values.length; index += 1) {
324
+ if (values[index] !== undefined && values[index] !== null) throw new TypeError(`${name}() accepts ${example}`);
325
+ }
326
+ return Object.fromEntries(keys.flatMap((key, index) => values[index] === undefined || values[index] === null ? [] : [[key, values[index]]]));
327
+ }
328
+
329
+ function helperOptions(name, value, rest) {
330
+ return optionsArg({ name, value, rest, keys: ["offset", "limit"], example: "{ offset, limit }" });
331
+ }
332
+
333
+ function reservedTool(globalName, helperName) {
334
+ const value = globalThis[globalName];
335
+ if (typeof value !== "string") throw new Error(`${helperName}() bridge is unavailable`);
336
+ return value;
337
+ }
338
+
339
+ async function writeData(value) {
340
+ if (typeof value === "string" || value instanceof Uint8Array) return value;
341
+ if (value instanceof Blob) return new Uint8Array(await value.arrayBuffer());
342
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
343
+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
344
+ throw new TypeError("write() expects string, Blob, ArrayBuffer, or TypedArray data");
345
+ }
346
+
347
+ function imageBase64(data) {
348
+ if (typeof data === "string") {
349
+ if (isStrictBase64(data)) return data;
350
+ if (!DECIMAL_CSV_RE.test(data)) return undefined;
351
+ const parts = data.split(",");
352
+ const bytes = new Uint8Array(parts.length);
353
+ for (let index = 0; index < parts.length; index += 1) {
354
+ const byte = Number(parts[index]);
355
+ if (!Number.isInteger(byte) || byte < 0 || byte > 255) return undefined;
356
+ bytes[index] = byte;
357
+ }
358
+ return Buffer.from(bytes).toString("base64");
359
+ }
360
+ if (data instanceof Uint8Array) return Buffer.from(data).toString("base64");
361
+ if (data instanceof ArrayBuffer) return Buffer.from(data).toString("base64");
362
+ if (ArrayBuffer.isView(data)) return Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("base64");
363
+ if (isPlainObject(data) && data.type === "Buffer" && Array.isArray(data.data)) {
364
+ const bytes = new Uint8Array(data.data.length);
365
+ for (let index = 0; index < data.data.length; index += 1) {
366
+ const byte = data.data[index];
367
+ if (typeof byte !== "number" || !Number.isInteger(byte) || byte < 0 || byte > 255) return undefined;
368
+ bytes[index] = byte;
369
+ }
370
+ return Buffer.from(bytes).toString("base64");
371
+ }
372
+ return undefined;
373
+ }
374
+
375
+ function isStrictBase64(value) {
376
+ return value.length > 0 && value.length % 4 === 0 && BASE64_STRICT_RE.test(value);
377
+ }
378
+
379
+ function describeImageData(data) {
380
+ if (data === null) return "null";
381
+ if (data instanceof Uint8Array) return "Uint8Array";
382
+ if (data instanceof ArrayBuffer) return "ArrayBuffer";
383
+ if (ArrayBuffer.isView(data)) return data.constructor.name;
384
+ if (typeof data === "string") return `string(${data.length})`;
385
+ return typeof data;
386
+ }
387
+
388
+ function chunkToString(chunk, encoding) {
389
+ if (typeof chunk === "string") return chunk;
390
+ if (chunk instanceof Uint8Array) return Buffer.from(chunk).toString(encoding ?? "utf8");
391
+ return String(chunk);
392
+ }
393
+
394
+ function encodeBase64(value) {
395
+ return Buffer.from(value, "utf8").toString("base64");
396
+ }
397
+
131
398
  function formatValue(value) {
132
- if (typeof value === "string") return value;
133
- return inspect(value, { colors: false, depth: 5 });
399
+ return typeof value === "string" ? value : inspect(value, { colors: false, depth: 5 });
134
400
  }
@@ -135,8 +135,9 @@ export class PythonKernel {
135
135
  if (!pending || !this.#pending.has(pending.input.cellId)) return;
136
136
  this.#active = pending;
137
137
  pending.startedAt = performance.now();
138
- const timeoutMs = pending.input.timeoutMs ?? 30_000;
139
- pending.timeoutTimer = setTimeout(() => this.#timeoutRun(pending, timeoutMs), timeoutMs);
138
+ const timeoutMs = pending.input.timeoutMs;
139
+ if (timeoutMs !== undefined)
140
+ pending.timeoutTimer = setTimeout(() => this.#timeoutRun(pending, timeoutMs), timeoutMs);
140
141
  try {
141
142
  this.#transport?.run(pending.input);
142
143
  } catch (error) {