@code-yeongyu/senpi 2026.7.11 → 2026.7.14-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/CHANGELOG.md +48 -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 +86 -26
  8. package/dist/core/extensions/builtin/prompt-preset/gpt-5.6.js.map +1 -1
  9. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +1 -1
  10. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
  11. package/dist/core/extensions/builtin/terminal/runtime-session.js +3 -2
  12. package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
  13. package/dist/core/extensions/builtin/websearch/websearch/native.d.ts +1 -1
  14. package/dist/core/extensions/builtin/websearch/websearch/native.d.ts.map +1 -1
  15. package/dist/core/extensions/builtin/websearch/websearch/native.js +83 -33
  16. package/dist/core/extensions/builtin/websearch/websearch/native.js.map +1 -1
  17. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.d.ts.map +1 -1
  18. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js +2 -1
  19. package/dist/core/extensions/builtin/websearch/websearch/provider-endpoints.js.map +1 -1
  20. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -3
  22. package/dist/core/extensions/builtin/websearch/websearch/tool.js.map +1 -1
  23. package/dist/core/model-registry.d.ts.map +1 -1
  24. package/dist/core/model-registry.js +1 -0
  25. package/dist/core/model-registry.js.map +1 -1
  26. package/dist/core/resource-loader.d.ts +1 -0
  27. package/dist/core/resource-loader.d.ts.map +1 -1
  28. package/dist/core/resource-loader.js +20 -2
  29. package/dist/core/resource-loader.js.map +1 -1
  30. package/dist/modes/interactive/compaction-queue-transfer.d.ts +22 -0
  31. package/dist/modes/interactive/compaction-queue-transfer.d.ts.map +1 -0
  32. package/dist/modes/interactive/compaction-queue-transfer.js +82 -0
  33. package/dist/modes/interactive/compaction-queue-transfer.js.map +1 -0
  34. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  35. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  36. package/dist/modes/interactive/interactive-mode.js +83 -69
  37. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  38. package/node_modules/@babel/helper-string-parser/LICENSE +22 -0
  39. package/node_modules/@babel/helper-string-parser/README.md +19 -0
  40. package/node_modules/@babel/helper-string-parser/lib/index.js +295 -0
  41. package/node_modules/@babel/helper-string-parser/lib/index.js.map +1 -0
  42. package/node_modules/@babel/helper-string-parser/package.json +31 -0
  43. package/node_modules/@babel/helper-validator-identifier/LICENSE +22 -0
  44. package/node_modules/@babel/helper-validator-identifier/README.md +19 -0
  45. package/node_modules/@babel/helper-validator-identifier/lib/identifier.js +70 -0
  46. package/node_modules/@babel/helper-validator-identifier/lib/identifier.js.map +1 -0
  47. package/node_modules/@babel/helper-validator-identifier/lib/index.js +57 -0
  48. package/node_modules/@babel/helper-validator-identifier/lib/index.js.map +1 -0
  49. package/node_modules/@babel/helper-validator-identifier/lib/keyword.js +35 -0
  50. package/node_modules/@babel/helper-validator-identifier/lib/keyword.js.map +1 -0
  51. package/node_modules/@babel/helper-validator-identifier/package.json +31 -0
  52. package/node_modules/@babel/parser/LICENSE +19 -0
  53. package/node_modules/@babel/parser/README.md +19 -0
  54. package/node_modules/@babel/parser/bin/babel-parser.js +15 -0
  55. package/node_modules/@babel/parser/lib/index.js +14599 -0
  56. package/node_modules/@babel/parser/lib/index.js.map +1 -0
  57. package/node_modules/@babel/parser/package.json +50 -0
  58. package/node_modules/@babel/parser/typings/babel-parser.d.ts +262 -0
  59. package/node_modules/@babel/types/LICENSE +22 -0
  60. package/node_modules/@babel/types/README.md +19 -0
  61. package/node_modules/@babel/types/lib/asserts/assertNode.js +16 -0
  62. package/node_modules/@babel/types/lib/asserts/assertNode.js.map +1 -0
  63. package/node_modules/@babel/types/lib/asserts/generated/index.js +1251 -0
  64. package/node_modules/@babel/types/lib/asserts/generated/index.js.map +1 -0
  65. package/node_modules/@babel/types/lib/ast-types/generated/index.js +3 -0
  66. package/node_modules/@babel/types/lib/ast-types/generated/index.js.map +1 -0
  67. package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js +18 -0
  68. package/node_modules/@babel/types/lib/builders/flow/createFlowUnionType.js.map +1 -0
  69. package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js +31 -0
  70. package/node_modules/@babel/types/lib/builders/flow/createTypeAnnotationBasedOnTypeof.js.map +1 -0
  71. package/node_modules/@babel/types/lib/builders/generated/index.js +29 -0
  72. package/node_modules/@babel/types/lib/builders/generated/index.js.map +1 -0
  73. package/node_modules/@babel/types/lib/builders/generated/lowercase.js +2902 -0
  74. package/node_modules/@babel/types/lib/builders/generated/lowercase.js.map +1 -0
  75. package/node_modules/@babel/types/lib/builders/generated/uppercase.js +272 -0
  76. package/node_modules/@babel/types/lib/builders/generated/uppercase.js.map +1 -0
  77. package/node_modules/@babel/types/lib/builders/productions.js +12 -0
  78. package/node_modules/@babel/types/lib/builders/productions.js.map +1 -0
  79. package/node_modules/@babel/types/lib/builders/react/buildChildren.js +24 -0
  80. package/node_modules/@babel/types/lib/builders/react/buildChildren.js.map +1 -0
  81. package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js +22 -0
  82. package/node_modules/@babel/types/lib/builders/typescript/createTSUnionType.js.map +1 -0
  83. package/node_modules/@babel/types/lib/builders/validateNode.js +21 -0
  84. package/node_modules/@babel/types/lib/builders/validateNode.js.map +1 -0
  85. package/node_modules/@babel/types/lib/clone/clone.js +12 -0
  86. package/node_modules/@babel/types/lib/clone/clone.js.map +1 -0
  87. package/node_modules/@babel/types/lib/clone/cloneDeep.js +12 -0
  88. package/node_modules/@babel/types/lib/clone/cloneDeep.js.map +1 -0
  89. package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js +12 -0
  90. package/node_modules/@babel/types/lib/clone/cloneDeepWithoutLoc.js.map +1 -0
  91. package/node_modules/@babel/types/lib/clone/cloneNode.js +107 -0
  92. package/node_modules/@babel/types/lib/clone/cloneNode.js.map +1 -0
  93. package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js +12 -0
  94. package/node_modules/@babel/types/lib/clone/cloneWithoutLoc.js.map +1 -0
  95. package/node_modules/@babel/types/lib/comments/addComment.js +15 -0
  96. package/node_modules/@babel/types/lib/comments/addComment.js.map +1 -0
  97. package/node_modules/@babel/types/lib/comments/addComments.js +22 -0
  98. package/node_modules/@babel/types/lib/comments/addComments.js.map +1 -0
  99. package/node_modules/@babel/types/lib/comments/inheritInnerComments.js +12 -0
  100. package/node_modules/@babel/types/lib/comments/inheritInnerComments.js.map +1 -0
  101. package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js +12 -0
  102. package/node_modules/@babel/types/lib/comments/inheritLeadingComments.js.map +1 -0
  103. package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js +12 -0
  104. package/node_modules/@babel/types/lib/comments/inheritTrailingComments.js.map +1 -0
  105. package/node_modules/@babel/types/lib/comments/inheritsComments.js +17 -0
  106. package/node_modules/@babel/types/lib/comments/inheritsComments.js.map +1 -0
  107. package/node_modules/@babel/types/lib/comments/removeComments.js +15 -0
  108. package/node_modules/@babel/types/lib/comments/removeComments.js.map +1 -0
  109. package/node_modules/@babel/types/lib/constants/generated/index.js +60 -0
  110. package/node_modules/@babel/types/lib/constants/generated/index.js.map +1 -0
  111. package/node_modules/@babel/types/lib/constants/index.js +31 -0
  112. package/node_modules/@babel/types/lib/constants/index.js.map +1 -0
  113. package/node_modules/@babel/types/lib/converters/ensureBlock.js +14 -0
  114. package/node_modules/@babel/types/lib/converters/ensureBlock.js.map +1 -0
  115. package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js +65 -0
  116. package/node_modules/@babel/types/lib/converters/gatherSequenceExpressions.js.map +1 -0
  117. package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js +14 -0
  118. package/node_modules/@babel/types/lib/converters/toBindingIdentifierName.js.map +1 -0
  119. package/node_modules/@babel/types/lib/converters/toBlock.js +29 -0
  120. package/node_modules/@babel/types/lib/converters/toBlock.js.map +1 -0
  121. package/node_modules/@babel/types/lib/converters/toComputedKey.js +14 -0
  122. package/node_modules/@babel/types/lib/converters/toComputedKey.js.map +1 -0
  123. package/node_modules/@babel/types/lib/converters/toExpression.js +28 -0
  124. package/node_modules/@babel/types/lib/converters/toExpression.js.map +1 -0
  125. package/node_modules/@babel/types/lib/converters/toIdentifier.js +25 -0
  126. package/node_modules/@babel/types/lib/converters/toIdentifier.js.map +1 -0
  127. package/node_modules/@babel/types/lib/converters/toKeyAlias.js +38 -0
  128. package/node_modules/@babel/types/lib/converters/toKeyAlias.js.map +1 -0
  129. package/node_modules/@babel/types/lib/converters/toSequenceExpression.js +19 -0
  130. package/node_modules/@babel/types/lib/converters/toSequenceExpression.js.map +1 -0
  131. package/node_modules/@babel/types/lib/converters/toStatement.js +39 -0
  132. package/node_modules/@babel/types/lib/converters/toStatement.js.map +1 -0
  133. package/node_modules/@babel/types/lib/converters/valueToNode.js +89 -0
  134. package/node_modules/@babel/types/lib/converters/valueToNode.js.map +1 -0
  135. package/node_modules/@babel/types/lib/definitions/core.js +1725 -0
  136. package/node_modules/@babel/types/lib/definitions/core.js.map +1 -0
  137. package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js +11 -0
  138. package/node_modules/@babel/types/lib/definitions/deprecated-aliases.js.map +1 -0
  139. package/node_modules/@babel/types/lib/definitions/experimental.js +124 -0
  140. package/node_modules/@babel/types/lib/definitions/experimental.js.map +1 -0
  141. package/node_modules/@babel/types/lib/definitions/flow.js +495 -0
  142. package/node_modules/@babel/types/lib/definitions/flow.js.map +1 -0
  143. package/node_modules/@babel/types/lib/definitions/index.js +106 -0
  144. package/node_modules/@babel/types/lib/definitions/index.js.map +1 -0
  145. package/node_modules/@babel/types/lib/definitions/jsx.js +157 -0
  146. package/node_modules/@babel/types/lib/definitions/jsx.js.map +1 -0
  147. package/node_modules/@babel/types/lib/definitions/misc.js +31 -0
  148. package/node_modules/@babel/types/lib/definitions/misc.js.map +1 -0
  149. package/node_modules/@babel/types/lib/definitions/placeholders.js +27 -0
  150. package/node_modules/@babel/types/lib/definitions/placeholders.js.map +1 -0
  151. package/node_modules/@babel/types/lib/definitions/typescript.js +528 -0
  152. package/node_modules/@babel/types/lib/definitions/typescript.js.map +1 -0
  153. package/node_modules/@babel/types/lib/definitions/utils.js +296 -0
  154. package/node_modules/@babel/types/lib/definitions/utils.js.map +1 -0
  155. package/node_modules/@babel/types/lib/index-legacy.d.ts +2797 -0
  156. package/node_modules/@babel/types/lib/index.d.ts +3617 -0
  157. package/node_modules/@babel/types/lib/index.js +582 -0
  158. package/node_modules/@babel/types/lib/index.js.flow +2650 -0
  159. package/node_modules/@babel/types/lib/index.js.map +1 -0
  160. package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js +15 -0
  161. package/node_modules/@babel/types/lib/modifications/appendToMemberExpression.js.map +1 -0
  162. package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js +65 -0
  163. package/node_modules/@babel/types/lib/modifications/flow/removeTypeDuplicates.js.map +1 -0
  164. package/node_modules/@babel/types/lib/modifications/inherits.js +28 -0
  165. package/node_modules/@babel/types/lib/modifications/inherits.js.map +1 -0
  166. package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js +17 -0
  167. package/node_modules/@babel/types/lib/modifications/prependToMemberExpression.js.map +1 -0
  168. package/node_modules/@babel/types/lib/modifications/removeProperties.js +24 -0
  169. package/node_modules/@babel/types/lib/modifications/removeProperties.js.map +1 -0
  170. package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js +14 -0
  171. package/node_modules/@babel/types/lib/modifications/removePropertiesDeep.js.map +1 -0
  172. package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js +66 -0
  173. package/node_modules/@babel/types/lib/modifications/typescript/removeTypeDuplicates.js.map +1 -0
  174. package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js +48 -0
  175. package/node_modules/@babel/types/lib/retrievers/getAssignmentIdentifiers.js.map +1 -0
  176. package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js +102 -0
  177. package/node_modules/@babel/types/lib/retrievers/getBindingIdentifiers.js.map +1 -0
  178. package/node_modules/@babel/types/lib/retrievers/getFunctionName.js +63 -0
  179. package/node_modules/@babel/types/lib/retrievers/getFunctionName.js.map +1 -0
  180. package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js +13 -0
  181. package/node_modules/@babel/types/lib/retrievers/getOuterBindingIdentifiers.js.map +1 -0
  182. package/node_modules/@babel/types/lib/traverse/traverse.js +50 -0
  183. package/node_modules/@babel/types/lib/traverse/traverse.js.map +1 -0
  184. package/node_modules/@babel/types/lib/traverse/traverseFast.js +40 -0
  185. package/node_modules/@babel/types/lib/traverse/traverseFast.js.map +1 -0
  186. package/node_modules/@babel/types/lib/utils/deprecationWarning.js +44 -0
  187. package/node_modules/@babel/types/lib/utils/deprecationWarning.js.map +1 -0
  188. package/node_modules/@babel/types/lib/utils/inherit.js +13 -0
  189. package/node_modules/@babel/types/lib/utils/inherit.js.map +1 -0
  190. package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js +40 -0
  191. package/node_modules/@babel/types/lib/utils/react/cleanJSXElementLiteralChild.js.map +1 -0
  192. package/node_modules/@babel/types/lib/utils/shallowEqual.js +17 -0
  193. package/node_modules/@babel/types/lib/utils/shallowEqual.js.map +1 -0
  194. package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js +13 -0
  195. package/node_modules/@babel/types/lib/validators/buildMatchMemberExpression.js.map +1 -0
  196. package/node_modules/@babel/types/lib/validators/generated/index.js +2797 -0
  197. package/node_modules/@babel/types/lib/validators/generated/index.js.map +1 -0
  198. package/node_modules/@babel/types/lib/validators/is.js +27 -0
  199. package/node_modules/@babel/types/lib/validators/is.js.map +1 -0
  200. package/node_modules/@babel/types/lib/validators/isBinding.js +27 -0
  201. package/node_modules/@babel/types/lib/validators/isBinding.js.map +1 -0
  202. package/node_modules/@babel/types/lib/validators/isBlockScoped.js +13 -0
  203. package/node_modules/@babel/types/lib/validators/isBlockScoped.js.map +1 -0
  204. package/node_modules/@babel/types/lib/validators/isImmutable.js +21 -0
  205. package/node_modules/@babel/types/lib/validators/isImmutable.js.map +1 -0
  206. package/node_modules/@babel/types/lib/validators/isLet.js +13 -0
  207. package/node_modules/@babel/types/lib/validators/isLet.js.map +1 -0
  208. package/node_modules/@babel/types/lib/validators/isNode.js +12 -0
  209. package/node_modules/@babel/types/lib/validators/isNode.js.map +1 -0
  210. package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js +57 -0
  211. package/node_modules/@babel/types/lib/validators/isNodesEquivalent.js.map +1 -0
  212. package/node_modules/@babel/types/lib/validators/isPlaceholderType.js +15 -0
  213. package/node_modules/@babel/types/lib/validators/isPlaceholderType.js.map +1 -0
  214. package/node_modules/@babel/types/lib/validators/isReferenced.js +96 -0
  215. package/node_modules/@babel/types/lib/validators/isReferenced.js.map +1 -0
  216. package/node_modules/@babel/types/lib/validators/isScope.js +18 -0
  217. package/node_modules/@babel/types/lib/validators/isScope.js.map +1 -0
  218. package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js +14 -0
  219. package/node_modules/@babel/types/lib/validators/isSpecifierDefault.js.map +1 -0
  220. package/node_modules/@babel/types/lib/validators/isType.js +17 -0
  221. package/node_modules/@babel/types/lib/validators/isType.js.map +1 -0
  222. package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js +13 -0
  223. package/node_modules/@babel/types/lib/validators/isValidES3Identifier.js.map +1 -0
  224. package/node_modules/@babel/types/lib/validators/isValidIdentifier.js +18 -0
  225. package/node_modules/@babel/types/lib/validators/isValidIdentifier.js.map +1 -0
  226. package/node_modules/@babel/types/lib/validators/isVar.js +15 -0
  227. package/node_modules/@babel/types/lib/validators/isVar.js.map +1 -0
  228. package/node_modules/@babel/types/lib/validators/matchesPattern.js +44 -0
  229. package/node_modules/@babel/types/lib/validators/matchesPattern.js.map +1 -0
  230. package/node_modules/@babel/types/lib/validators/react/isCompatTag.js +11 -0
  231. package/node_modules/@babel/types/lib/validators/react/isCompatTag.js.map +1 -0
  232. package/node_modules/@babel/types/lib/validators/react/isReactComponent.js +11 -0
  233. package/node_modules/@babel/types/lib/validators/react/isReactComponent.js.map +1 -0
  234. package/node_modules/@babel/types/lib/validators/validate.js +42 -0
  235. package/node_modules/@babel/types/lib/validators/validate.js.map +1 -0
  236. package/node_modules/@babel/types/package.json +39 -0
  237. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +28 -2
  238. package/node_modules/@code-yeongyu/senpi-codemode/README.md +128 -78
  239. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -3
  240. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/protocol.ts +15 -2
  241. package/node_modules/@code-yeongyu/senpi-codemode/src/bridge/reserved.ts +9 -0
  242. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/agent-bridge.ts +197 -0
  243. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/output-bridge.ts +96 -0
  244. package/node_modules/@code-yeongyu/senpi-codemode/src/bridges/schema-injection.ts +3 -0
  245. package/node_modules/@code-yeongyu/senpi-codemode/src/completion/handler.ts +95 -26
  246. package/node_modules/@code-yeongyu/senpi-codemode/src/completion/tool-bridge.ts +11 -2
  247. package/node_modules/@code-yeongyu/senpi-codemode/src/config/settings.ts +96 -8
  248. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +24 -3
  249. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +155 -21
  250. package/node_modules/@code-yeongyu/senpi-codemode/src/interpreters/detect.ts +1 -1
  251. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/prelude.jl +252 -48
  252. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/jl/runner.jl +263 -83
  253. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/context-manager.ts +11 -5
  254. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/local-module-loader.ts +108 -0
  255. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +8 -6
  256. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/rewrite-imports.ts +164 -0
  257. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-core.js +6 -1
  258. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +307 -41
  259. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/kernel.ts +3 -2
  260. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +792 -79
  261. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/prelude.rb +234 -21
  262. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/rb/runner.rb +154 -51
  263. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/shared/subprocess-queue.ts +1 -0
  264. package/node_modules/@code-yeongyu/senpi-codemode/src/output/output-meta.ts +89 -0
  265. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +296 -0
  266. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +101 -31
  267. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/bridge-timeout.ts +2 -0
  268. package/node_modules/@code-yeongyu/senpi-codemode/src/timeouts/idle-timeout.ts +8 -19
  269. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/cell-handler.ts +175 -113
  270. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/eval-tool.ts +130 -120
  271. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/image.ts +274 -0
  272. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/json-tree.ts +247 -0
  273. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +641 -38
  274. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/status-events.ts +12 -0
  275. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +29 -1
  276. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  277. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +2 -23
  279. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +175 -158
  281. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts +60 -0
  283. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +54 -0
  285. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/cerebras.models.js.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts +92 -0
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js +72 -0
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +23 -22
  293. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +63 -63
  295. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +0 -136
  297. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +6 -142
  299. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.d.ts.map +1 -1
  301. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js +9 -0
  302. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/context-transformer.js.map +1 -1
  303. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts +1 -1
  304. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.d.ts.map +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js +6 -2
  306. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/index.js.map +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts +8 -0
  308. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.d.ts.map +1 -0
  309. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js +92 -0
  310. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/coerce-parameters.js.map +1 -0
  311. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts +6 -0
  312. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.d.ts.map +1 -0
  313. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js +54 -0
  314. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/format.js.map +1 -0
  315. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.d.ts +4 -0
  316. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.d.ts.map +1 -0
  317. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.js +4 -0
  318. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/index.js.map +1 -0
  319. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.d.ts +7 -0
  320. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.d.ts.map +1 -0
  321. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.js +16 -0
  322. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-match.js.map +1 -0
  323. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts +19 -0
  324. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.d.ts.map +1 -0
  325. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js +217 -0
  326. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/invoke-tag-scanner.js.map +1 -0
  327. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts +4 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.d.ts.map +1 -0
  329. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js +46 -0
  330. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/parse.js.map +1 -0
  331. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts +13 -0
  332. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.d.ts.map +1 -0
  333. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js +144 -0
  334. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream-boundary.js.map +1 -0
  335. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts +5 -0
  336. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.d.ts.map +1 -0
  337. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js +208 -0
  338. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/stream.js.map +1 -0
  339. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.d.ts +4 -0
  340. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.d.ts.map +1 -0
  341. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.js +17 -0
  342. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/tool-resolver.js.map +1 -0
  343. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.d.ts +5 -0
  344. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.d.ts.map +1 -0
  345. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.js +34 -0
  346. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/protocols/anthropic-xml/xml-entities.js.map +1 -0
  347. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts +3 -1
  348. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.d.ts.map +1 -1
  349. package/node_modules/@earendil-works/pi-ai/dist/tool-call-middleware/types.js.map +1 -1
  350. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  351. package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
  352. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  353. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  354. package/package.json +6 -6
@@ -1,5 +1,7 @@
1
+ // allow: SIZE_OK — one eval render pipeline avoids the runtime/render TDZ that motivated this module boundary.
1
2
  import {
2
3
  type AgentToolResult,
4
+ highlightCode,
3
5
  sanitizeTerminalLabel,
4
6
  type Theme,
5
7
  type ThemeColor,
@@ -7,12 +9,34 @@ import {
7
9
  type ToolRenderResultOptions,
8
10
  truncateToVisualLines,
9
11
  } from "@code-yeongyu/senpi";
10
- import type { createEvalInputSchema, EvalToolDetails, EvalToolInput } from "./types.ts";
12
+ import { formatTruncationWarning, stripOutputNotice, type TruncationMeta } from "../output/output-meta.ts";
13
+ import {
14
+ JSON_TREE_MAX_DEPTH_COLLAPSED,
15
+ JSON_TREE_MAX_DEPTH_EXPANDED,
16
+ JSON_TREE_MAX_LINES_COLLAPSED,
17
+ JSON_TREE_MAX_LINES_EXPANDED,
18
+ JSON_TREE_SCALAR_LEN_COLLAPSED,
19
+ JSON_TREE_SCALAR_LEN_EXPANDED,
20
+ renderJsonTreeLines,
21
+ } from "./json-tree.ts";
22
+ import type {
23
+ EvalCellResult,
24
+ EvalInputSchema,
25
+ EvalLanguage,
26
+ EvalStatusEvent,
27
+ EvalToolDetails,
28
+ EvalToolInput,
29
+ } from "./types.ts";
11
30
 
12
- type EvalToolDefinition = ToolDefinition<ReturnType<typeof createEvalInputSchema>, EvalToolDetails>;
31
+ type EvalToolDefinition = ToolDefinition<EvalInputSchema, EvalToolDetails>;
13
32
  type RenderContext = Parameters<NonNullable<EvalToolDefinition["renderCall"]>>[2];
14
- type Component = ReturnType<NonNullable<EvalToolDefinition["renderCall"]>>;
33
+ type ResultRenderContext = Parameters<NonNullable<EvalToolDefinition["renderResult"]>>[3];
15
34
  type CollapsibleKind = "code" | "output";
35
+
36
+ export interface EvalRenderComponent {
37
+ render(width: number): string[];
38
+ invalidate(): void;
39
+ }
16
40
  type ToolCallRow = {
17
41
  readonly summary: string;
18
42
  readonly error?: string;
@@ -32,16 +56,19 @@ type RenderBlock =
32
56
  readonly calls: readonly ToolCallRow[];
33
57
  readonly expanded: boolean;
34
58
  readonly theme?: Theme;
35
- };
59
+ }
60
+ | { readonly kind: "dynamic"; readonly render: (width: number) => readonly string[] };
36
61
 
37
62
  const CODE_PREVIEW_LINES = 4;
38
63
  const OUTPUT_PREVIEW_LINES = 8;
64
+ const STATUS_PREVIEW_COUNT = 3;
65
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"] as const;
39
66
  const TOOL_CALL_PREVIEW_COUNT = 5;
40
67
  const TOOL_CALL_COLLAPSED_VISUAL_LINES = 4;
41
68
  const TOOL_CALL_COLLAPSED_ERROR_CODE_POINTS = 512;
42
69
  const TOOL_ERROR_OMISSION_MARKER = "[tool error omitted]";
43
70
 
44
- class PlainTextComponent {
71
+ class PlainTextComponent implements EvalRenderComponent {
45
72
  #blocks: readonly RenderBlock[] = [];
46
73
 
47
74
  setBlocks(blocks: readonly RenderBlock[]): void {
@@ -51,12 +78,21 @@ class PlainTextComponent {
51
78
  render(width: number): string[] {
52
79
  const lines: string[] = [];
53
80
  for (const block of this.#blocks) {
54
- if (block.kind === "blank") {
55
- lines.push("");
56
- } else if (block.kind === "toolCalls") {
57
- appendLines(lines, renderToolCallBlock(block, width));
58
- } else {
59
- appendLines(lines, renderTextBlock(block, width));
81
+ switch (block.kind) {
82
+ case "blank":
83
+ lines.push("");
84
+ break;
85
+ case "toolCalls":
86
+ appendLines(lines, renderToolCallBlock(block, width));
87
+ break;
88
+ case "text":
89
+ appendLines(lines, renderTextBlock(block, width));
90
+ break;
91
+ case "dynamic":
92
+ appendLines(lines, block.render(width));
93
+ break;
94
+ default:
95
+ assertNever(block);
60
96
  }
61
97
  }
62
98
  return lines;
@@ -65,7 +101,7 @@ class PlainTextComponent {
65
101
  invalidate(): void {}
66
102
  }
67
103
 
68
- function componentFor(context: RenderContext): PlainTextComponent {
104
+ function componentFor(context: RenderContext | ResultRenderContext): PlainTextComponent {
69
105
  const existing = context.lastComponent;
70
106
  if (existing instanceof PlainTextComponent) return existing;
71
107
  return new PlainTextComponent();
@@ -152,8 +188,473 @@ function renderToolCallBlock(block: Extract<RenderBlock, { kind: "toolCalls" }>,
152
188
  return lines;
153
189
  }
154
190
 
155
- function callCode(code: string): string {
156
- return code.trim().length > 0 ? code : "...";
191
+ type CellStatus = EvalCellResult["status"];
192
+ type AgentStatus = "pending" | "running" | "completed" | "failed" | "aborted";
193
+ type StatusPresentation = { readonly label: string; readonly icon: string; readonly color: ThemeColor };
194
+ type RenderEnvironment = {
195
+ readonly expanded: boolean;
196
+ readonly theme: Theme | undefined;
197
+ readonly spinnerFrame: number | undefined;
198
+ readonly width: number;
199
+ readonly meta: TruncationMeta | undefined;
200
+ };
201
+ type CellBadges = { readonly reset: boolean; readonly timeout: number | undefined };
202
+ type PrefixStyle = { readonly prefix: string; readonly continuation: string; readonly color: ThemeColor };
203
+ type DetailedRenderContext = {
204
+ readonly environment: RenderEnvironment;
205
+ readonly args: EvalToolInput;
206
+ readonly showImageFallback: boolean;
207
+ };
208
+
209
+ function assertNever(value: never): never {
210
+ throw new TypeError(`Unhandled eval render variant: ${String(value)}`);
211
+ }
212
+
213
+ function languageForHighlighter(language: EvalLanguage): "python" | "javascript" | "ruby" | "julia" {
214
+ switch (language) {
215
+ case "py":
216
+ return "python";
217
+ case "js":
218
+ return "javascript";
219
+ case "rb":
220
+ return "ruby";
221
+ case "jl":
222
+ return "julia";
223
+ default:
224
+ return assertNever(language);
225
+ }
226
+ }
227
+
228
+ function highlightedCode(code: string, language: EvalLanguage, theme: Theme | undefined): string {
229
+ const normalizedCode = code.trim().length > 0 ? code : "...";
230
+ const lines = highlightCode(normalizedCode, languageForHighlighter(language));
231
+ return (theme === undefined ? lines.map((line) => line.replace(/\u001b\[[0-9;]*m/gu, "")) : lines).join("\n");
232
+ }
233
+
234
+ function formatDuration(milliseconds: number): string {
235
+ const totalSeconds = Math.floor(Math.max(0, milliseconds) / 1_000);
236
+ if (totalSeconds < 1) return "<1s";
237
+ const seconds = totalSeconds % 60;
238
+ const totalMinutes = Math.floor(totalSeconds / 60);
239
+ if (totalMinutes < 1) return `${seconds}s`;
240
+ const minutes = totalMinutes % 60;
241
+ const hours = Math.floor(totalMinutes / 60);
242
+ if (hours < 1) return seconds === 0 ? `${minutes}m` : `${minutes}m ${seconds}s`;
243
+ return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}m`;
244
+ }
245
+
246
+ function spinner(frame: number | undefined): string {
247
+ return SPINNER_FRAMES.at((frame ?? 0) % SPINNER_FRAMES.length) ?? SPINNER_FRAMES[0];
248
+ }
249
+
250
+ function cellPresentation(status: CellStatus, spinnerFrame: number | undefined): StatusPresentation {
251
+ switch (status) {
252
+ case "pending":
253
+ return { label: "pending", icon: "○", color: "muted" };
254
+ case "running":
255
+ return { label: "running", icon: spinner(spinnerFrame), color: "warning" };
256
+ case "complete":
257
+ return { label: "done", icon: "✓", color: "success" };
258
+ case "error":
259
+ return { label: "error", icon: "✗", color: "error" };
260
+ default:
261
+ return assertNever(status);
262
+ }
263
+ }
264
+
265
+ function renderPrefixed(text: string, environment: RenderEnvironment, prefixStyle: PrefixStyle): string[] {
266
+ const bodyLines = renderAllVisualLines(text, Math.max(1, environment.width - prefixStyle.prefix.length));
267
+ if (bodyLines.length === 0) return [style(environment.theme, prefixStyle.color, prefixStyle.prefix.trimEnd())];
268
+ return bodyLines.map(
269
+ (line, index) =>
270
+ `${style(environment.theme, prefixStyle.color, index === 0 ? prefixStyle.prefix : prefixStyle.continuation)}${line}`,
271
+ );
272
+ }
273
+
274
+ function cellHeader(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string {
275
+ const presentation = cellPresentation(cell.status, environment.spinnerFrame);
276
+ const title = cell.title === undefined ? "" : ` ${cell.title}`;
277
+ let header = `eval ${cell.language}${title} ${presentation.label} ${presentation.icon}`;
278
+ if (cell.durationMs !== undefined) header += ` · ${formatDuration(cell.durationMs)}`;
279
+ if (badges.reset) header += " · reset";
280
+ if (badges.timeout !== undefined) header += ` · timeout ${badges.timeout}s`;
281
+ return style(environment.theme, presentation.color, header);
282
+ }
283
+
284
+ function previewText(
285
+ text: string,
286
+ maxLines: number,
287
+ width: number,
288
+ ): { readonly lines: string[]; readonly skipped: number } {
289
+ const preview = truncateToVisualLines(text, maxLines, Math.max(1, width));
290
+ return { lines: preview.visualLines.map((line) => line.trimEnd()), skipped: preview.skippedCount };
291
+ }
292
+
293
+ function eventString(value: unknown): string | undefined {
294
+ return typeof value === "string" && value.length > 0 ? value : undefined;
295
+ }
296
+
297
+ function eventNumber(value: unknown): number {
298
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
299
+ }
300
+
301
+ function plural(count: number, singular: string, pluralNoun: string): string {
302
+ return `${count} ${count === 1 ? singular : pluralNoun}`;
303
+ }
304
+
305
+ function statusIcon(op: string): string {
306
+ if (op.startsWith("git_")) return "⌁";
307
+ switch (op) {
308
+ case "read":
309
+ case "write":
310
+ case "cat":
311
+ case "touch":
312
+ return "▣";
313
+ case "ls":
314
+ case "cd":
315
+ case "pwd":
316
+ case "mkdir":
317
+ return "▤";
318
+ case "run":
319
+ case "sh":
320
+ return "▶";
321
+ case "completion":
322
+ return "◇";
323
+ case "phase":
324
+ return "◆";
325
+ default:
326
+ return "•";
327
+ }
328
+ }
329
+
330
+ function formatStatusEvent(event: EvalStatusEvent, theme: Theme | undefined): string {
331
+ const op = event.op;
332
+ const icon = style(theme, "muted", statusIcon(op));
333
+ const error = eventString(event["error"]);
334
+ if (error !== undefined) return `${icon} ${style(theme, "warning", op)}: ${style(theme, "dim", error)}`;
335
+ const parts: string[] = [];
336
+ switch (op) {
337
+ case "read": {
338
+ parts.push(`${eventNumber(event["chars"] ?? event["bytes"])} chars`);
339
+ const path = eventString(event["path"]);
340
+ if (path !== undefined) parts.push(`from ${path}`);
341
+ break;
342
+ }
343
+ case "write": {
344
+ parts.push(`${eventNumber(event["chars"] ?? event["bytes"])} chars`);
345
+ const path = eventString(event["path"]);
346
+ if (path !== undefined) parts.push(`to ${path}`);
347
+ break;
348
+ }
349
+ case "cat":
350
+ parts.push(plural(eventNumber(event["files"]), "file", "files"));
351
+ parts.push(`${eventNumber(event["chars"])} chars`);
352
+ break;
353
+ case "ls":
354
+ parts.push(plural(eventNumber(event["count"]), "entry", "entries"));
355
+ break;
356
+ case "env": {
357
+ const action = eventString(event["action"]);
358
+ const key = eventString(event["key"]);
359
+ const value = eventString(event["value"]) ?? "";
360
+ if (action === "set" && key !== undefined) parts.push(`set ${key}=${value.slice(0, 30)}`);
361
+ else if (action === "get" && key !== undefined) parts.push(`${key}=${value.slice(0, 30)}`);
362
+ else parts.push(plural(eventNumber(event["count"]), "variable", "variables"));
363
+ break;
364
+ }
365
+ case "git_status": {
366
+ if (event["clean"] === true) parts.push("clean");
367
+ else {
368
+ const changes: string[] = [];
369
+ for (const key of ["staged", "modified", "untracked"] as const) {
370
+ const count = eventNumber(event[key]);
371
+ if (count > 0) changes.push(`${count} ${key}`);
372
+ }
373
+ parts.push(changes.join(", ") || "unknown");
374
+ }
375
+ const branch = eventString(event["branch"]);
376
+ if (branch !== undefined) parts.push(`on ${branch}`);
377
+ break;
378
+ }
379
+ case "git_diff":
380
+ parts.push(plural(eventNumber(event["lines"]), "line", "lines"));
381
+ if (event["staged"] === true) parts.push("staged");
382
+ break;
383
+ case "git_log":
384
+ parts.push(plural(eventNumber(event["commits"]), "commit", "commits"));
385
+ break;
386
+ case "run":
387
+ case "sh": {
388
+ const command = eventString(event["command"] ?? event["cmd"]);
389
+ if (command !== undefined) parts.push(command);
390
+ if (typeof event["exitCode"] === "number") parts.push(`exit ${event["exitCode"]}`);
391
+ break;
392
+ }
393
+ case "completion": {
394
+ const model = eventString(event["model"]);
395
+ const tier = eventString(event["tier"]);
396
+ if (model !== undefined) parts.push(model);
397
+ if (tier !== undefined && tier !== model) parts.push(tier);
398
+ parts.push(`${eventNumber(event["chars"])} chars`);
399
+ break;
400
+ }
401
+ case "log":
402
+ parts.push(eventString(event["message"]) ?? "");
403
+ break;
404
+ case "phase":
405
+ parts.push(eventString(event["title"]) ?? "");
406
+ break;
407
+ default: {
408
+ if (event["count"] !== undefined) parts.push(String(event["count"]));
409
+ const path = eventString(event["path"]);
410
+ if (path !== undefined) parts.push(path);
411
+ }
412
+ }
413
+ const description = parts.filter((part) => part.length > 0).join(" · ");
414
+ return `${icon} ${style(theme, "muted", op)}${description.length > 0 ? ` ${style(theme, "dim", description)}` : ""}`;
415
+ }
416
+
417
+ function renderStatusEvents(events: readonly EvalStatusEvent[], environment: RenderEnvironment): string[] {
418
+ const retained = environment.expanded ? events : events.slice(-STATUS_PREVIEW_COUNT);
419
+ const skipped = events.length - retained.length;
420
+ const lines: string[] = [];
421
+ if (skipped > 0) lines.push(style(environment.theme, "dim", `├ … ${skipped} earlier status events`));
422
+ for (const [index, event] of retained.entries()) {
423
+ const branch = index === retained.length - 1 ? "└" : "├";
424
+ lines.push(`${style(environment.theme, "dim", branch)} ${formatStatusEvent(event, environment.theme)}`);
425
+ }
426
+ return lines;
427
+ }
428
+
429
+ function agentStatus(value: unknown): AgentStatus {
430
+ switch (value) {
431
+ case "pending":
432
+ case "running":
433
+ case "completed":
434
+ case "failed":
435
+ case "aborted":
436
+ return value;
437
+ default:
438
+ return "running";
439
+ }
440
+ }
441
+
442
+ function coalesceAgentEvents(events: readonly EvalStatusEvent[]): EvalStatusEvent[] {
443
+ const rows: EvalStatusEvent[] = [];
444
+ const indexes = new Map<string, number>();
445
+ for (const event of events) {
446
+ const id = eventString(event["id"]);
447
+ if (id === undefined) {
448
+ rows.push(event);
449
+ continue;
450
+ }
451
+ const index = indexes.get(id);
452
+ if (index === undefined) {
453
+ indexes.set(id, rows.length);
454
+ rows.push(event);
455
+ } else rows[index] = event;
456
+ }
457
+ return rows;
458
+ }
459
+
460
+ function agentPresentation(status: AgentStatus, spinnerFrame: number | undefined): StatusPresentation {
461
+ switch (status) {
462
+ case "pending":
463
+ return { label: "pending", icon: "○", color: "muted" };
464
+ case "running":
465
+ return { label: "running", icon: spinner(spinnerFrame), color: "warning" };
466
+ case "completed":
467
+ return { label: "done", icon: "✓", color: "success" };
468
+ case "failed":
469
+ return { label: "failed", icon: "✗", color: "error" };
470
+ case "aborted":
471
+ return { label: "aborted", icon: "×", color: "error" };
472
+ default:
473
+ return assertNever(status);
474
+ }
475
+ }
476
+
477
+ function renderAgentProgressEvents(events: readonly EvalStatusEvent[], environment: RenderEnvironment): string[] {
478
+ const rows = coalesceAgentEvents(events);
479
+ const lines: string[] = [];
480
+ // Senpi Theme has no tree-token API; fixed ├/└/│ glyphs intentionally mirror omp.
481
+ for (const [index, event] of rows.entries()) {
482
+ const isLast = index === rows.length - 1;
483
+ const status = agentStatus(event["status"]);
484
+ const presentation = agentPresentation(status, environment.spinnerFrame);
485
+ const id = eventString(event["id"]) ?? "agent";
486
+ const styledId = environment.theme === undefined ? id : environment.theme.bold(id);
487
+ let body = `${style(environment.theme, presentation.color, presentation.icon)} ${styledId} ${presentation.label}`;
488
+ if (status === "completed" || status === "failed" || status === "aborted") {
489
+ const duration = eventNumber(event["durationMs"]);
490
+ if (duration > 0) body += ` · ${style(environment.theme, "dim", formatDuration(duration))}`;
491
+ }
492
+ const branch = isLast ? "└ " : "├ ";
493
+ const continuation = isLast ? " " : "│ ";
494
+ appendLines(
495
+ lines,
496
+ renderPrefixed(body, environment, { prefix: branch, continuation: continuation, color: "dim" }),
497
+ );
498
+ if (status !== "running") continue;
499
+ const currentTool = eventString(event["currentTool"]);
500
+ const lastIntent = eventString(event["lastIntent"]);
501
+ if (currentTool === undefined && lastIntent === undefined) continue;
502
+ const detail =
503
+ currentTool === undefined
504
+ ? (lastIntent ?? "")
505
+ : `${currentTool}${lastIntent === undefined ? "" : `: ${lastIntent}`}`;
506
+ appendLines(
507
+ lines,
508
+ renderPrefixed(detail, environment, {
509
+ prefix: `${continuation}└ `,
510
+ continuation: `${continuation} `,
511
+ color: "dim",
512
+ }),
513
+ );
514
+ }
515
+ return lines;
516
+ }
517
+
518
+ function renderCell(cell: EvalCellResult, environment: RenderEnvironment, badges: CellBadges): string[] {
519
+ const lines = renderPrefixed(cellHeader(cell, environment, badges), environment, {
520
+ prefix: "╭─ ",
521
+ continuation: "│ ",
522
+ color: "borderAccent",
523
+ });
524
+ const innerWidth = Math.max(1, environment.width - 2);
525
+ const codePreview = previewText(
526
+ highlightedCode(cell.code, cell.language, environment.theme),
527
+ environment.expanded ? Number.POSITIVE_INFINITY : CODE_PREVIEW_LINES,
528
+ innerWidth,
529
+ );
530
+ if (codePreview.skipped > 0) {
531
+ appendLines(
532
+ lines,
533
+ renderPrefixed(`${codePreview.skipped} earlier code lines`, environment, {
534
+ prefix: "│ ",
535
+ continuation: "│ ",
536
+ color: "muted",
537
+ }),
538
+ );
539
+ }
540
+ for (const line of codePreview.lines) {
541
+ appendLines(lines, renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }));
542
+ }
543
+ const output = stripOutputNotice(cell.output, environment.meta).trimEnd();
544
+ if (output.length > 0) {
545
+ appendLines(lines, renderPrefixed("output", environment, { prefix: "├─ ", continuation: "│ ", color: "dim" }));
546
+ const outputColor: ThemeColor = cell.status === "error" ? "error" : "toolOutput";
547
+ const styledOutput = output
548
+ .split("\n")
549
+ .map((line) => style(environment.theme, outputColor, line))
550
+ .join("\n");
551
+ const outputPreview = previewText(
552
+ styledOutput,
553
+ environment.expanded ? Number.POSITIVE_INFINITY : OUTPUT_PREVIEW_LINES,
554
+ innerWidth,
555
+ );
556
+ if (outputPreview.skipped > 0) {
557
+ appendLines(
558
+ lines,
559
+ renderPrefixed(`${outputPreview.skipped} earlier output lines`, environment, {
560
+ prefix: "│ ",
561
+ continuation: "│ ",
562
+ color: "muted",
563
+ }),
564
+ );
565
+ }
566
+ for (const line of outputPreview.lines) {
567
+ appendLines(
568
+ lines,
569
+ renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }),
570
+ );
571
+ }
572
+ }
573
+ const allEvents = cell.statusEvents ?? [];
574
+ const statusEvents = allEvents.filter((event) => event.op !== "agent");
575
+ if (statusEvents.length > 0) {
576
+ appendLines(lines, renderPrefixed("status", environment, { prefix: "├─ ", continuation: "│ ", color: "dim" }));
577
+ for (const line of renderStatusEvents(statusEvents, environment)) {
578
+ appendLines(
579
+ lines,
580
+ renderPrefixed(line, environment, { prefix: "│ ", continuation: "│ ", color: "borderMuted" }),
581
+ );
582
+ }
583
+ }
584
+ lines.push(style(environment.theme, "borderMuted", "╰─"));
585
+ const agentEvents = allEvents.filter((event) => event.op === "agent");
586
+ if (agentEvents.length > 0) appendLines(lines, renderAgentProgressEvents(agentEvents, environment));
587
+ return lines;
588
+ }
589
+
590
+ function renderJsonOutputs(values: readonly unknown[], environment: RenderEnvironment): string[] {
591
+ const lines: string[] = [];
592
+ const depth = environment.expanded ? JSON_TREE_MAX_DEPTH_EXPANDED : JSON_TREE_MAX_DEPTH_COLLAPSED;
593
+ const lineCap = environment.expanded ? JSON_TREE_MAX_LINES_EXPANDED : JSON_TREE_MAX_LINES_COLLAPSED;
594
+ const scalarLen = environment.expanded ? JSON_TREE_SCALAR_LEN_EXPANDED : JSON_TREE_SCALAR_LEN_COLLAPSED;
595
+ for (const [index, value] of values.entries()) {
596
+ appendLines(
597
+ lines,
598
+ renderAllVisualLines(style(environment.theme, "dim", `display[${index + 1}]`), environment.width),
599
+ );
600
+ const tree = renderJsonTreeLines(value, environment.theme, depth, lineCap, scalarLen);
601
+ for (const line of tree.lines) appendLines(lines, renderAllVisualLines(line, environment.width));
602
+ if (tree.truncated)
603
+ appendLines(lines, renderAllVisualLines(style(environment.theme, "dim", "…"), environment.width));
604
+ }
605
+ return lines;
606
+ }
607
+
608
+ function renderDetailedLines(
609
+ details: EvalToolDetails,
610
+ result: AgentToolResult<EvalToolDetails>,
611
+ context: DetailedRenderContext,
612
+ ): string[] {
613
+ const lines: string[] = [];
614
+ const cells = details.cells ?? [];
615
+ for (const [index, cell] of cells.entries()) {
616
+ const badges = {
617
+ reset: index === 0 && context.args.reset === true,
618
+ timeout: index === 0 ? context.args.timeout : undefined,
619
+ };
620
+ appendLines(lines, renderCell(cell, context.environment, badges));
621
+ if (index < cells.length - 1) lines.push("");
622
+ }
623
+ const jsonOutputs = details.jsonOutputs ?? [];
624
+ if (jsonOutputs.length > 0) {
625
+ if (lines.length > 0) lines.push("");
626
+ appendLines(lines, renderJsonOutputs(jsonOutputs, context.environment));
627
+ }
628
+ if (context.showImageFallback) {
629
+ for (const part of result.content) {
630
+ if (part.type !== "image") continue;
631
+ if (lines.length > 0) lines.push("");
632
+ appendLines(
633
+ lines,
634
+ renderAllVisualLines(`[image: ${sanitizeTerminalLabel(part.mimeType)}]`, context.environment.width),
635
+ );
636
+ }
637
+ }
638
+ if (details.phase !== undefined)
639
+ appendLines(
640
+ lines,
641
+ renderAllVisualLines(
642
+ style(context.environment.theme, "muted", `phase ${details.phase}`),
643
+ context.environment.width,
644
+ ),
645
+ );
646
+ if (details.notice !== undefined)
647
+ appendLines(
648
+ lines,
649
+ renderAllVisualLines(style(context.environment.theme, "dim", details.notice), context.environment.width),
650
+ );
651
+ const warning = formatTruncationWarning(details.meta) ?? (details.truncated ? "[eval output truncated]" : null);
652
+ if (warning !== null)
653
+ appendLines(
654
+ lines,
655
+ renderAllVisualLines(style(context.environment.theme, "warning", warning), context.environment.width),
656
+ );
657
+ return lines;
157
658
  }
158
659
 
159
660
  function textOutput(result: AgentToolResult<EvalToolDetails>, showImageFallback: boolean): string {
@@ -190,12 +691,20 @@ function resultHeader(
190
691
  status: "running" | "done" | "error",
191
692
  theme: Theme | undefined,
192
693
  ): string {
193
- const title = details?.title ? ` ${details.title}` : "";
194
- return style(
195
- theme,
196
- status === "running" ? "warning" : status === "done" ? "success" : "error",
197
- `eval ${details?.language ?? "?"}${title} ${status}`,
198
- );
694
+ const title = details?.title === undefined ? "" : ` ${details.title}`;
695
+ let color: ThemeColor;
696
+ switch (status) {
697
+ case "running":
698
+ color = "warning";
699
+ break;
700
+ case "done":
701
+ color = "success";
702
+ break;
703
+ case "error":
704
+ color = "error";
705
+ break;
706
+ }
707
+ return style(theme, color, `eval ${details?.language ?? "?"}${title} ${status}`);
199
708
  }
200
709
 
201
710
  function resultMetadata(
@@ -210,19 +719,49 @@ function resultMetadata(
210
719
  return [{ kind: "text", text: style(theme, "muted", metadata.join(" | ")) }];
211
720
  }
212
721
 
213
- export function renderEvalCall(args: EvalToolInput, theme: Theme | undefined, context: RenderContext): Component {
722
+ export function renderEvalCall(
723
+ args: EvalToolInput,
724
+ theme: Theme | undefined,
725
+ context: RenderContext,
726
+ ): EvalRenderComponent {
214
727
  const component = componentFor(context);
215
- const title = args.title ? ` ${args.title}` : "";
216
- const reset = args.reset ? " reset" : "";
217
- const timeout = args.timeout ? ` timeout ${args.timeout}s` : "";
728
+ if (theme === undefined && context.spinnerFrame === undefined) {
729
+ const title = args.title === undefined ? "" : ` ${args.title}`;
730
+ const reset = args.reset === true ? " reset" : "";
731
+ const timeout = args.timeout === undefined ? "" : ` timeout ${args.timeout}s`;
732
+ component.setBlocks([
733
+ { kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${title}${reset}${timeout}`) },
734
+ {
735
+ kind: "text",
736
+ text: style(theme, "mdCodeBlock", args.code.trim().length > 0 ? args.code : "..."),
737
+ maxVisualLines: context.expanded ? undefined : CODE_PREVIEW_LINES,
738
+ collapseKind: "code",
739
+ theme,
740
+ },
741
+ ]);
742
+ return component;
743
+ }
218
744
  component.setBlocks([
219
- { kind: "text", text: style(theme, "toolTitle", `eval ${args.language}${title}${reset}${timeout}`) },
220
745
  {
221
- kind: "text",
222
- text: style(theme, "mdCodeBlock", callCode(args.code)),
223
- maxVisualLines: context.expanded ? undefined : CODE_PREVIEW_LINES,
224
- collapseKind: "code",
225
- theme,
746
+ kind: "dynamic",
747
+ render: (width) => {
748
+ const environment: RenderEnvironment = {
749
+ expanded: context.expanded,
750
+ theme,
751
+ spinnerFrame: context.spinnerFrame,
752
+ width,
753
+ meta: undefined,
754
+ };
755
+ const cell: EvalCellResult = {
756
+ index: 0,
757
+ ...(args.title === undefined ? {} : { title: args.title }),
758
+ code: args.code,
759
+ language: args.language,
760
+ output: "",
761
+ status: context.spinnerFrame === undefined ? "pending" : "running",
762
+ };
763
+ return renderCell(cell, environment, { reset: args.reset === true, timeout: args.timeout });
764
+ },
226
765
  },
227
766
  ]);
228
767
  return component;
@@ -232,22 +771,46 @@ export function renderEvalResult(
232
771
  result: AgentToolResult<EvalToolDetails>,
233
772
  options: ToolRenderResultOptions,
234
773
  theme: Theme | undefined,
235
- context: Parameters<NonNullable<EvalToolDefinition["renderResult"]>>[3],
236
- ): Component {
774
+ context: ResultRenderContext,
775
+ ): EvalRenderComponent {
237
776
  const component = componentFor(context);
238
777
  const details = result.details;
239
778
  const expanded = options.expanded || context.expanded;
240
779
  const imageProtocol = context.imageProtocol ?? null;
780
+ if (details?.cells !== undefined && details.cells.length > 0) {
781
+ const blocks: RenderBlock[] = [
782
+ {
783
+ kind: "dynamic",
784
+ render: (width) =>
785
+ renderDetailedLines(details, result, {
786
+ environment: {
787
+ expanded,
788
+ theme,
789
+ spinnerFrame: context.spinnerFrame,
790
+ width,
791
+ meta: details.meta,
792
+ },
793
+ args: context.args,
794
+ showImageFallback: context.showImages && imageProtocol === null,
795
+ }),
796
+ },
797
+ ];
798
+ const calls = toolCallRows(details);
799
+ if (calls.length > 0) blocks.push({ kind: "blank" }, { kind: "toolCalls", calls, expanded, theme });
800
+ component.setBlocks(blocks);
801
+ return component;
802
+ }
241
803
  const status = resultStatus(details, options, context.isError);
242
804
  const blocks: RenderBlock[] = [
243
805
  { kind: "text", text: resultHeader(details, status, theme) },
244
806
  ...resultMetadata(details, options, theme),
245
807
  { kind: "blank" },
246
808
  ];
247
- const output = textOutput(result, context.showImages && imageProtocol === null).trimEnd();
809
+ const rawOutput = textOutput(result, context.showImages && imageProtocol === null);
810
+ const output = stripOutputNotice(rawOutput, details?.meta).trimEnd();
248
811
  const hasRenderedImage =
249
812
  context.showImages && imageProtocol !== null && result.content.some((part) => part.type === "image");
250
- if (output) {
813
+ if (output.length > 0) {
251
814
  blocks.push({
252
815
  kind: "text",
253
816
  text: style(theme, "toolOutput", output),
@@ -255,13 +818,53 @@ export function renderEvalResult(
255
818
  collapseKind: "output",
256
819
  theme,
257
820
  });
258
- } else if (!hasRenderedImage) {
259
- blocks.push({ kind: "text", text: style(theme, "muted", "(no output)") });
821
+ } else if (!hasRenderedImage) blocks.push({ kind: "text", text: style(theme, "muted", "(no output)") });
822
+ const statusEvents = details?.statusEvents ?? [];
823
+ const nonAgentEvents = statusEvents.filter((event) => event.op !== "agent");
824
+ const agentEvents = statusEvents.filter((event) => event.op === "agent");
825
+ if (nonAgentEvents.length > 0 || agentEvents.length > 0) {
826
+ blocks.push(
827
+ { kind: "blank" },
828
+ {
829
+ kind: "dynamic",
830
+ render: (width) => {
831
+ const environment: RenderEnvironment = {
832
+ expanded,
833
+ theme,
834
+ spinnerFrame: context.spinnerFrame,
835
+ width,
836
+ meta: details?.meta,
837
+ };
838
+ return [
839
+ ...renderStatusEvents(nonAgentEvents, environment),
840
+ ...renderAgentProgressEvents(agentEvents, environment),
841
+ ];
842
+ },
843
+ },
844
+ );
845
+ }
846
+ if ((details?.jsonOutputs?.length ?? 0) > 0) {
847
+ blocks.push(
848
+ { kind: "blank" },
849
+ {
850
+ kind: "dynamic",
851
+ render: (width) =>
852
+ renderJsonOutputs(details?.jsonOutputs ?? [], {
853
+ expanded,
854
+ theme,
855
+ spinnerFrame: context.spinnerFrame,
856
+ width,
857
+ meta: details?.meta,
858
+ }),
859
+ },
860
+ );
260
861
  }
261
862
  const calls = toolCallRows(details);
262
863
  if (calls.length > 0) blocks.push({ kind: "blank" }, { kind: "toolCalls", calls, expanded, theme });
263
- if (details?.truncated)
264
- blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "warning", "[eval output truncated]") });
864
+ if (details?.notice !== undefined)
865
+ blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "dim", details.notice) });
866
+ const warning = formatTruncationWarning(details?.meta) ?? (details?.truncated ? "[eval output truncated]" : null);
867
+ if (warning !== null) blocks.push({ kind: "blank" }, { kind: "text", text: style(theme, "warning", warning) });
265
868
  component.setBlocks(blocks);
266
869
  return component;
267
870
  }