@ebowwa/coder 0.7.63 → 0.7.65

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 (364) hide show
  1. package/dist/core/__tests__/permissions.test.d.ts +12 -0
  2. package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
  3. package/dist/core/__tests__/permissions.test.js +851 -0
  4. package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
  5. package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
  6. package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
  7. package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
  8. package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
  9. package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
  10. package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
  11. package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
  12. package/dist/core/agent-loop/__tests__/index.test.js +121 -0
  13. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
  14. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
  15. package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
  16. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
  17. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
  18. package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
  19. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
  20. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
  21. package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
  22. package/dist/core/agent-loop/compaction.d.ts +39 -0
  23. package/dist/core/agent-loop/compaction.d.ts.map +1 -0
  24. package/dist/core/agent-loop/compaction.js +51 -0
  25. package/dist/core/agent-loop/formatters.d.ts +21 -0
  26. package/dist/core/agent-loop/formatters.d.ts.map +1 -0
  27. package/dist/core/agent-loop/formatters.js +42 -0
  28. package/dist/core/agent-loop/index.d.ts +25 -0
  29. package/dist/core/agent-loop/index.d.ts.map +1 -0
  30. package/dist/core/agent-loop/index.js +83 -0
  31. package/dist/core/agent-loop/loop-state.d.ts +74 -0
  32. package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
  33. package/dist/core/agent-loop/loop-state.js +147 -0
  34. package/dist/core/agent-loop/message-builder.d.ts +13 -0
  35. package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
  36. package/dist/core/agent-loop/message-builder.js +49 -0
  37. package/dist/core/agent-loop/tool-executor.d.ts +23 -0
  38. package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
  39. package/dist/core/agent-loop/tool-executor.js +152 -0
  40. package/dist/core/agent-loop/turn-executor.d.ts +57 -0
  41. package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
  42. package/dist/core/agent-loop/turn-executor.js +124 -0
  43. package/dist/core/agent-loop/types.d.ts +141 -0
  44. package/dist/core/agent-loop/types.d.ts.map +1 -0
  45. package/dist/core/agent-loop/types.js +4 -0
  46. package/dist/core/agent-loop.d.ts +17 -0
  47. package/dist/core/agent-loop.d.ts.map +1 -0
  48. package/dist/core/agent-loop.js +16 -0
  49. package/dist/core/api-client-impl.d.ts +62 -0
  50. package/dist/core/api-client-impl.d.ts.map +1 -0
  51. package/dist/core/api-client-impl.js +479 -0
  52. package/dist/core/api-client.d.ts +6 -0
  53. package/dist/core/api-client.d.ts.map +1 -0
  54. package/dist/core/api-client.js +5 -0
  55. package/dist/core/checkpoints.d.ts +128 -0
  56. package/dist/core/checkpoints.d.ts.map +1 -0
  57. package/dist/core/checkpoints.js +438 -0
  58. package/dist/core/claude-md.d.ts +71 -0
  59. package/dist/core/claude-md.d.ts.map +1 -0
  60. package/dist/core/claude-md.js +198 -0
  61. package/dist/core/cognitive-security/hooks.d.ts +138 -0
  62. package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
  63. package/dist/core/cognitive-security/hooks.js +389 -0
  64. package/dist/core/cognitive-security/index.d.ts +751 -0
  65. package/dist/core/cognitive-security/index.d.ts.map +1 -0
  66. package/dist/core/cognitive-security/index.js +1123 -0
  67. package/dist/core/cognitive-security/middleware.d.ts +136 -0
  68. package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
  69. package/dist/core/cognitive-security/middleware.js +376 -0
  70. package/dist/core/config-loader.d.ts +127 -0
  71. package/dist/core/config-loader.d.ts.map +1 -0
  72. package/dist/core/config-loader.js +219 -0
  73. package/dist/core/context-compaction.d.ts +87 -0
  74. package/dist/core/context-compaction.d.ts.map +1 -0
  75. package/dist/core/context-compaction.js +428 -0
  76. package/dist/core/git-status.d.ts +25 -0
  77. package/dist/core/git-status.d.ts.map +1 -0
  78. package/dist/core/git-status.js +204 -0
  79. package/dist/core/image.d.ts +69 -0
  80. package/dist/core/image.d.ts.map +1 -0
  81. package/dist/core/image.js +290 -0
  82. package/dist/core/image.test.d.ts +2 -0
  83. package/dist/core/image.test.d.ts.map +1 -0
  84. package/dist/core/image.test.js +149 -0
  85. package/dist/core/models.d.ts +123 -0
  86. package/dist/core/models.d.ts.map +1 -0
  87. package/dist/core/models.js +325 -0
  88. package/dist/core/permissions.d.ts +81 -0
  89. package/dist/core/permissions.d.ts.map +1 -0
  90. package/dist/core/permissions.js +327 -0
  91. package/dist/core/retry.d.ts +25 -0
  92. package/dist/core/retry.d.ts.map +1 -0
  93. package/dist/core/retry.js +121 -0
  94. package/dist/core/session-store.d.ts +9 -0
  95. package/dist/core/session-store.d.ts.map +1 -0
  96. package/dist/core/session-store.js +10 -0
  97. package/dist/core/sessions/export.d.ts +47 -0
  98. package/dist/core/sessions/export.d.ts.map +1 -0
  99. package/dist/core/sessions/export.js +256 -0
  100. package/dist/core/sessions/index.d.ts +132 -0
  101. package/dist/core/sessions/index.d.ts.map +1 -0
  102. package/dist/core/sessions/index.js +442 -0
  103. package/dist/core/sessions/metadata.d.ts +77 -0
  104. package/dist/core/sessions/metadata.d.ts.map +1 -0
  105. package/dist/core/sessions/metadata.js +233 -0
  106. package/dist/core/sessions/persistence.d.ts +72 -0
  107. package/dist/core/sessions/persistence.d.ts.map +1 -0
  108. package/dist/core/sessions/persistence.js +201 -0
  109. package/dist/core/sessions/types.d.ts +110 -0
  110. package/dist/core/sessions/types.d.ts.map +1 -0
  111. package/dist/core/sessions/types.js +4 -0
  112. package/dist/core/stream-highlighter.d.ts +18 -0
  113. package/dist/core/stream-highlighter.d.ts.map +1 -0
  114. package/dist/core/stream-highlighter.js +916 -0
  115. package/dist/core/system-reminders.d.ts +89 -0
  116. package/dist/core/system-reminders.d.ts.map +1 -0
  117. package/dist/core/system-reminders.js +285 -0
  118. package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
  119. package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
  120. package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
  121. package/dist/ecosystem/hooks/index.d.ts +59 -0
  122. package/dist/ecosystem/hooks/index.d.ts.map +1 -0
  123. package/dist/ecosystem/hooks/index.js +294 -0
  124. package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
  125. package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
  126. package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
  127. package/dist/ecosystem/skills/index.d.ts +55 -0
  128. package/dist/ecosystem/skills/index.d.ts.map +1 -0
  129. package/dist/ecosystem/skills/index.js +258 -0
  130. package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
  131. package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
  132. package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
  133. package/dist/ecosystem/tools/index.d.ts +24 -0
  134. package/dist/ecosystem/tools/index.d.ts.map +1 -0
  135. package/dist/ecosystem/tools/index.js +1709 -0
  136. package/dist/index.d.ts +24 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +33688 -49712
  139. package/dist/interfaces/mcp/client.d.ts +40 -0
  140. package/dist/interfaces/mcp/client.d.ts.map +1 -0
  141. package/dist/interfaces/mcp/client.js +309 -0
  142. package/dist/interfaces/ui/index.d.ts +36 -0
  143. package/dist/interfaces/ui/index.d.ts.map +1 -0
  144. package/dist/interfaces/ui/index.js +61 -0
  145. package/dist/interfaces/ui/spinner.d.ts +140 -0
  146. package/dist/interfaces/ui/spinner.d.ts.map +1 -0
  147. package/dist/interfaces/ui/spinner.js +342 -0
  148. package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
  149. package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
  150. package/dist/interfaces/ui/terminal/cli/index.js +32012 -50526
  151. package/dist/interfaces/ui/terminal/native/README.md +53 -0
  152. package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
  153. package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
  154. package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
  155. package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
  156. package/dist/interfaces/ui/terminal/native/index.js +43 -0
  157. package/dist/interfaces/ui/terminal/native/index.node +0 -0
  158. package/dist/interfaces/ui/terminal/native/package.json +34 -0
  159. package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
  160. package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
  161. package/dist/interfaces/ui/terminal/shared/args.js +176 -0
  162. package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
  163. package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
  164. package/dist/interfaces/ui/terminal/shared/index.js +16 -0
  165. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
  166. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
  167. package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
  168. package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
  169. package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
  170. package/dist/interfaces/ui/terminal/shared/query.js +100 -0
  171. package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
  172. package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
  173. package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
  174. package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
  175. package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
  176. package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
  177. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
  178. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
  179. package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
  180. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
  181. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
  182. package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
  183. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
  184. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
  185. package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
  186. package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
  187. package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
  188. package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
  189. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
  190. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
  191. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
  192. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
  193. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
  194. package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
  195. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
  196. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
  197. package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
  198. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
  199. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
  200. package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
  201. package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
  202. package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
  203. package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
  204. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
  205. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
  206. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
  207. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
  208. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
  209. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
  210. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
  211. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
  212. package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
  213. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
  214. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
  215. package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
  216. package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
  217. package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
  218. package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
  219. package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
  220. package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
  221. package/dist/interfaces/ui/terminal/tui/console.js +46 -0
  222. package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
  223. package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
  224. package/dist/interfaces/ui/terminal/tui/index.js +28 -0
  225. package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
  226. package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
  227. package/dist/interfaces/ui/terminal/tui/run.js +31 -0
  228. package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
  229. package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
  230. package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
  231. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
  232. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
  233. package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
  234. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
  235. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
  236. package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
  237. package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
  238. package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
  239. package/dist/interfaces/ui/terminal/tui/types.js +5 -0
  240. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
  241. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
  242. package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
  243. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
  244. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
  245. package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
  246. package/dist/native/README.md +53 -0
  247. package/dist/native/claude_code_native.darwin-x64.node +0 -0
  248. package/dist/native/claude_code_native.dylib +0 -0
  249. package/dist/native/index.d.ts +0 -0
  250. package/dist/native/index.d.ts.map +1 -0
  251. package/dist/native/index.darwin-arm64.node +0 -0
  252. package/dist/native/index.js +43 -0
  253. package/dist/native/index.node +0 -0
  254. package/dist/native/package.json +34 -0
  255. package/dist/teammates/index.d.ts +161 -0
  256. package/dist/teammates/index.d.ts.map +1 -0
  257. package/dist/teammates/index.js +827 -0
  258. package/dist/types/index.d.ts +482 -0
  259. package/dist/types/index.d.ts.map +1 -0
  260. package/dist/types/index.js +52 -0
  261. package/native/index.darwin-arm64.node +0 -0
  262. package/native/index.js +33 -19
  263. package/package.json +6 -3
  264. package/packages/src/core/__tests__/permissions.test.ts +1091 -0
  265. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +283 -0
  266. package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
  267. package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
  268. package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
  269. package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
  270. package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
  271. package/packages/src/core/agent-loop/compaction.ts +92 -0
  272. package/packages/src/core/agent-loop/formatters.ts +50 -0
  273. package/packages/src/core/agent-loop/index.ts +137 -0
  274. package/packages/src/core/agent-loop/loop-state.ts +187 -0
  275. package/packages/src/core/agent-loop/message-builder.ts +62 -0
  276. package/packages/src/core/agent-loop/tool-executor.ts +211 -0
  277. package/packages/src/core/agent-loop/turn-executor.ts +226 -0
  278. package/packages/src/core/agent-loop/types.ts +152 -0
  279. package/packages/src/core/agent-loop.ts +18 -0
  280. package/packages/src/core/api-client-impl.ts +729 -0
  281. package/packages/src/core/api-client.ts +6 -0
  282. package/packages/src/core/checkpoints.ts +606 -0
  283. package/packages/src/core/claude-md.ts +272 -0
  284. package/packages/src/core/cognitive-security/hooks.ts +591 -0
  285. package/packages/src/core/cognitive-security/index.ts +2041 -0
  286. package/packages/src/core/cognitive-security/middleware.ts +536 -0
  287. package/packages/src/core/config/todo +7 -0
  288. package/packages/src/core/config-loader.ts +324 -0
  289. package/packages/src/core/context/__tests__/integration.test.ts +334 -0
  290. package/packages/src/core/context/compaction.ts +170 -0
  291. package/packages/src/core/context/constants.ts +58 -0
  292. package/packages/src/core/context/extraction.ts +85 -0
  293. package/packages/src/core/context/index.ts +66 -0
  294. package/packages/src/core/context/summarization.ts +251 -0
  295. package/packages/src/core/context/token-estimation.ts +98 -0
  296. package/packages/src/core/context/types.ts +59 -0
  297. package/packages/src/core/git-status.ts +262 -0
  298. package/packages/src/core/image.test.ts +180 -0
  299. package/packages/src/core/image.ts +350 -0
  300. package/packages/src/core/lmdb.db +0 -0
  301. package/packages/src/core/lmdb.db-lock +0 -0
  302. package/packages/src/core/models.ts +507 -0
  303. package/packages/src/core/normalizers/todo +8 -0
  304. package/packages/src/core/permissions.ts +431 -0
  305. package/packages/src/core/providers/README.md +230 -0
  306. package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
  307. package/packages/src/core/providers/index.ts +419 -0
  308. package/packages/src/core/providers/types.ts +132 -0
  309. package/packages/src/core/retry.ts +180 -0
  310. package/packages/src/core/session-store.ts +36 -0
  311. package/packages/src/core/sessions/export.ts +329 -0
  312. package/packages/src/core/sessions/index.ts +587 -0
  313. package/packages/src/core/sessions/metadata.ts +309 -0
  314. package/packages/src/core/sessions/persistence.ts +244 -0
  315. package/packages/src/core/sessions/types.ts +169 -0
  316. package/packages/src/core/stream-highlighter.ts +1123 -0
  317. package/packages/src/core/system-reminders.ts +402 -0
  318. package/packages/src/core/todo +8 -0
  319. package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
  320. package/packages/src/ecosystem/hooks/index.ts +341 -0
  321. package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
  322. package/packages/src/ecosystem/skills/index.ts +295 -0
  323. package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
  324. package/packages/src/ecosystem/tools/index.ts +2051 -0
  325. package/packages/src/index.ts +141 -0
  326. package/packages/src/interfaces/mcp/client.ts +389 -0
  327. package/packages/src/interfaces/ui/index.ts +158 -0
  328. package/packages/src/interfaces/ui/lmdb.db +0 -0
  329. package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
  330. package/packages/src/interfaces/ui/spinner.ts +451 -0
  331. package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
  332. package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
  333. package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
  334. package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
  335. package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
  336. package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
  337. package/packages/src/interfaces/ui/terminal/cli/index.ts +415 -0
  338. package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
  339. package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +393 -0
  340. package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
  341. package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
  342. package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
  343. package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
  344. package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
  345. package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
  346. package/packages/src/interfaces/ui/terminal/shared/index.ts +84 -0
  347. package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
  348. package/packages/src/interfaces/ui/terminal/shared/query.ts +152 -0
  349. package/packages/src/interfaces/ui/terminal/shared/setup.ts +299 -0
  350. package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
  351. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +366 -0
  352. package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
  353. package/packages/src/lmdb.db +0 -0
  354. package/packages/src/lmdb.db-lock +0 -0
  355. package/packages/src/native/index.ts +2722 -0
  356. package/packages/src/native/tui_v2_types.ts +39 -0
  357. package/packages/src/teammates/coordination.test.ts +279 -0
  358. package/packages/src/teammates/coordination.ts +646 -0
  359. package/packages/src/teammates/index.ts +1052 -0
  360. package/packages/src/teammates/integration.test.ts +272 -0
  361. package/packages/src/teammates/runner.test.ts +235 -0
  362. package/packages/src/teammates/runner.ts +750 -0
  363. package/packages/src/teammates/schemas.ts +673 -0
  364. package/packages/src/types/index.ts +723 -0
@@ -0,0 +1,916 @@
1
+ /**
2
+ * Streaming text highlighter for code blocks and diffs
3
+ * Buffers text and highlights as content completes during streaming output
4
+ */
5
+ import { highlight_code, highlight_diff } from "../native/index.js";
6
+ // ANSI color codes - Base16 Ocean color scheme
7
+ const COLORS = {
8
+ reset: "\x1b[0m",
9
+ bold: "\x1b[1m",
10
+ dim: "\x1b[2m",
11
+ italic: "\x1b[3m",
12
+ underline: "\x1b[4m",
13
+ strikethrough: "\x1b[9m",
14
+ // Syntax colors
15
+ purple: "\x1b[38;2;180;142;173m", // keywords
16
+ blue: "\x1b[38;2;143;161;179m", // functions
17
+ green: "\x1b[38;2;163;190;140m", // strings, additions
18
+ orange: "\x1b[38;2;208;135;112m", // numbers
19
+ red: "\x1b[38;2;191;97;106m", // types, deletions
20
+ cyan: "\x1b[38;2;150;181;180m", // builtins
21
+ gray: "\x1b[38;2;192;197;206m", // default
22
+ yellow: "\x1b[38;2;235;203;139m", // warnings, highlights
23
+ comment: "\x1b[38;2;101;115;126m", // comments
24
+ // Markdown specific
25
+ header: "\x1b[38;2;143;161;179m\x1b[1m", // bold blue
26
+ link: "\x1b[38;2;150;181;180m\x1b[4m", // cyan underline
27
+ list: "\x1b[38;2;180;142;173m", // purple bullet
28
+ blockquote: "\x1b[38;2;101;115;126m\x1b[3m", // dim italic gray
29
+ hr: "\x1b[38;2;101;115;126m", // dim gray
30
+ tableBorder: "\x1b[38;2;143;161;179m", // blue for table borders
31
+ tableHeader: "\x1b[38;2;180;142;173m\x1b[1m", // bold purple for table headers
32
+ // Financial/Trading colors
33
+ money: "\x1b[38;2;163;190;140m", // green for money amounts
34
+ moneyLoss: "\x1b[38;2;191;97;106m", // red for losses
35
+ moneyGain: "\x1b[38;2;140;190;140m\x1b[1m", // bold green for gains
36
+ percentUp: "\x1b[38;2;163;190;140m", // green for positive %
37
+ percentDown: "\x1b[38;2;191;97;106m", // red for negative %
38
+ ticker: "\x1b[38;2;235;203;139m\x1b[1m", // bold yellow for stock tickers
39
+ crypto: "\x1b[38;2;247;140;108m", // orange for crypto
40
+ timestamp: "\x1b[38;2;101;115;126m", // dim gray for timestamps
41
+ math: "\x1b[38;2;180;142;173m", // purple for math operators
42
+ bullish: "\x1b[38;2;163;190;140m\x1b[1m", // bold green for bullish terms
43
+ bearish: "\x1b[38;2;191;97;106m\x1b[1m", // bold red for bearish terms
44
+ neutral: "\x1b[38;2;235;203;139m", // yellow for neutral terms
45
+ priceTarget: "\x1b[38;2;143;161;179m\x1b[4m", // blue underline for price targets
46
+ };
47
+ // Currency symbols and their names
48
+ const CURRENCY_SYMBOLS = {
49
+ '$': 'USD', '€': 'EUR', '£': 'GBP', '¥': 'JPY', '₹': 'INR',
50
+ '₽': 'RUB', '₩': 'KRW', '₿': 'BTC', 'Ξ': 'ETH', '₮': 'USDT',
51
+ '₳': 'ADA', '₴': 'UAH', '₸': 'KZT', '₺': 'TRY', '₼': 'AZN',
52
+ '₪': 'ILS', '₫': 'VND', '₭': 'LAK', '₱': 'PHP', '₲': 'PYG',
53
+ '₵': 'GHS', '₡': 'CRC', '₦': 'NGN', '₣': 'CHF', '₤': 'TRY',
54
+ };
55
+ // Crypto symbols
56
+ const CRYPTO_SYMBOLS = new Set([
57
+ 'BTC', 'ETH', 'USDT', 'BNB', 'XRP', 'SOL', 'USDC', 'ADA', 'DOGE', 'DOT',
58
+ 'MATIC', 'LTC', 'SHIB', 'TRX', 'AVAX', 'LINK', 'ATOM', 'UNI', 'XMR', 'ETC',
59
+ 'XLM', 'BCH', 'APT', 'NEAR', 'FIL', 'LDO', 'ARB', 'OP', 'HBAR', 'VET',
60
+ 'ICP', 'QNT', 'AAVE', 'GRT', 'ALGO', 'SAND', 'MANA', 'AXS', 'FTM', 'EGLD',
61
+ 'SUSHI', 'THETA', 'XTZ', 'EOS', 'FLOW', 'CHZ', 'SNX', 'LUNC', 'RUNE', 'KAVA',
62
+ 'CRV', 'COMP', 'YFI', 'MKR', 'ZEC', 'DASH', 'NEO', 'WAVES', 'ENJ', 'BAT',
63
+ '1INCH', 'ANKR', 'CELO', 'CVC', 'DIA', 'GNO', 'KNC', 'OCEAN', 'OMG', 'REN',
64
+ 'RLC', 'STORJ', 'SYN', 'UMA', 'ZRX', 'BLUR', 'DYDX', 'GMX', 'PEPE', 'BONK',
65
+ 'WIF', 'FLOKI', 'INJ', 'SUI', 'SEI', 'TIA', 'IMX', 'ORDI', 'JUP', 'W',
66
+ ]);
67
+ // Stock ticker pattern (1-5 uppercase letters)
68
+ const TICKER_PATTERN = /\$?([A-Z]{1,5})(?=\s|\.|,|:|;|!|\?|$|\(|\)|\[|\]|-)/g;
69
+ // Trading terms
70
+ const BULLISH_TERMS = new Set([
71
+ 'bull', 'bullish', 'long', 'buy', 'call', 'pump', 'moon', 'rocket', 'lambo',
72
+ 'hold', 'hodl', 'diamond', 'hands', 'gains', 'profit', 'rally', 'surge',
73
+ 'breakout', 'uptrend', 'accumulation', 'support', 'bounce', 'recovery',
74
+ 'all-time high', 'ath', 'bagholder', 'whale buy', 'accumulation', 'undervalued',
75
+ ]);
76
+ const BEARISH_TERMS = new Set([
77
+ 'bear', 'bearish', 'short', 'sell', 'put', 'dump', 'crash', 'dump', 'rekt',
78
+ 'liquidated', 'loss', 'bleed', 'downtrend', 'breakdown', 'resistance',
79
+ 'correction', 'dip', ' capitulation', 'panic sell', 'overvalued', 'bubble',
80
+ ]);
81
+ const NEUTRAL_TERMS = new Set([
82
+ 'position', 'entry', 'exit', 'stop', 'limit', 'market', 'order', 'trade',
83
+ 'volume', 'liquidity', 'spread', 'slippage', 'leverage', 'margin', 'futures',
84
+ 'options', 'perpetual', 'funding', 'basis', 'arbitrage', 'hedge', 'delta',
85
+ 'gamma', 'theta', 'vega', 'iv', 'hv', 'volatility', 'oi', 'open interest',
86
+ ]);
87
+ // Math operators and symbols
88
+ const MATH_PATTERNS = [
89
+ { pattern: /[+\-×÷*\/%^=<>≤≥≠≈±√∫∑∏∂∆∇]/g, color: 'math' },
90
+ { pattern: /\b(pi|π|e|phi|inf|infinity|NaN|null)\b/gi, color: 'orange' },
91
+ ];
92
+ /**
93
+ * Detects if content looks like a diff (unified diff format)
94
+ */
95
+ function isDiffContent(content) {
96
+ const lines = content.split('\n').filter(l => l.length > 0);
97
+ if (lines.length < 3)
98
+ return false;
99
+ // Check for diff markers
100
+ let diffMarkers = 0;
101
+ for (const line of lines.slice(0, 10)) {
102
+ if (line.startsWith('+++') || line.startsWith('---') ||
103
+ line.startsWith('@@') || line.startsWith('diff ') ||
104
+ line.startsWith('index ')) {
105
+ diffMarkers++;
106
+ }
107
+ }
108
+ // Also check for +/- lines
109
+ let plusLines = 0;
110
+ let minusLines = 0;
111
+ for (const line of lines) {
112
+ if (line.startsWith('+') && !line.startsWith('+++'))
113
+ plusLines++;
114
+ if (line.startsWith('-') && !line.startsWith('---'))
115
+ minusLines++;
116
+ }
117
+ return diffMarkers >= 2 || (plusLines > 0 && minusLines > 0);
118
+ }
119
+ /**
120
+ * Highlight diff content with ANSI colors
121
+ * Supports unified diff, git diff, and context diff formats
122
+ */
123
+ function highlightDiffContent(content) {
124
+ const lines = content.split('\n');
125
+ const result = [];
126
+ for (const line of lines) {
127
+ if (line.startsWith('@@')) {
128
+ // Hunk header - cyan with function context
129
+ // Format: @@ -start,count +start,count @@ optional_function_name
130
+ const match = line.match(/^(@@ -\d+(?:,\d+)? \+\d+(?:,\d+)? @@)(.*)$/);
131
+ if (match) {
132
+ result.push(`${COLORS.cyan}${match[1]}${COLORS.reset}${COLORS.dim}${match[2]}${COLORS.reset}`);
133
+ }
134
+ else {
135
+ result.push(`${COLORS.cyan}${line}${COLORS.reset}`);
136
+ }
137
+ }
138
+ else if (line.startsWith('+++') || line.startsWith('---')) {
139
+ // File headers - bold
140
+ const prefix = line.startsWith('+++') ? '+' : '-';
141
+ const rest = line.slice(3);
142
+ result.push(`${COLORS.bold}${prefix}${prefix}${prefix}${COLORS.reset}${COLORS.cyan}${rest}${COLORS.reset}`);
143
+ }
144
+ else if (line.startsWith('diff --git')) {
145
+ // Git diff header
146
+ result.push(`${COLORS.dim}${line}${COLORS.reset}`);
147
+ }
148
+ else if (line.startsWith('index ')) {
149
+ // Index line
150
+ result.push(`${COLORS.dim}${line}${COLORS.reset}`);
151
+ }
152
+ else if (line.startsWith('new file') || line.startsWith('deleted file')) {
153
+ // New/deleted file markers
154
+ result.push(`${COLORS.yellow}${line}${COLORS.reset}`);
155
+ }
156
+ else if (line.startsWith('Binary files')) {
157
+ // Binary file markers
158
+ result.push(`${COLORS.yellow}${line}${COLORS.reset}`);
159
+ }
160
+ else if (line.startsWith('rename from') || line.startsWith('rename to')) {
161
+ // Rename markers
162
+ result.push(`${COLORS.purple}${line}${COLORS.reset}`);
163
+ }
164
+ else if (line.startsWith('similarity index')) {
165
+ // Similarity index
166
+ result.push(`${COLORS.dim}${line}${COLORS.reset}`);
167
+ }
168
+ else if (line.startsWith('+')) {
169
+ // Additions - green with brighter first char
170
+ if (line === '+') {
171
+ result.push(`${COLORS.green}+${COLORS.reset}`);
172
+ }
173
+ else {
174
+ result.push(`${COLORS.green}+${line.slice(1)}${COLORS.reset}`);
175
+ }
176
+ }
177
+ else if (line.startsWith('-')) {
178
+ // Deletions - red
179
+ if (line === '-') {
180
+ result.push(`${COLORS.red}-${COLORS.reset}`);
181
+ }
182
+ else {
183
+ result.push(`${COLORS.red}-${line.slice(1)}${COLORS.reset}`);
184
+ }
185
+ }
186
+ else if (line.startsWith(' ') || line === '') {
187
+ // Context lines - dim
188
+ result.push(`${COLORS.dim}${line}${COLORS.reset}`);
189
+ }
190
+ else if (line.match(/^(={67}|>{67}|<{67})/)) {
191
+ // Context diff separators
192
+ result.push(`${COLORS.dim}${line}${COLORS.reset}`);
193
+ }
194
+ else if (line.startsWith('***************')) {
195
+ // Context diff hunk marker
196
+ result.push(`${COLORS.cyan}${line}${COLORS.reset}`);
197
+ }
198
+ else if (line.startsWith('*** ') || line.startsWith('--- ')) {
199
+ // Context diff file markers (at line start, not diff markers)
200
+ result.push(`${COLORS.cyan}${line}${COLORS.reset}`);
201
+ }
202
+ else {
203
+ result.push(line);
204
+ }
205
+ }
206
+ return result.join('\n');
207
+ }
208
+ /**
209
+ * Highlight inline code with a subtle color
210
+ */
211
+ function highlightInlineCode(text) {
212
+ // Skip if we're inside a code block
213
+ if (text.includes('```')) {
214
+ return text;
215
+ }
216
+ // Match inline code with single backticks
217
+ // Also handle escaped backticks and nested code
218
+ return text
219
+ // Single backtick inline code
220
+ .replace(/`([^`\n]+)`/g, (_, code) => {
221
+ return `${COLORS.dim}\`${COLORS.orange}${code}${COLORS.dim}\`${COLORS.reset}`;
222
+ })
223
+ // Double backtick inline code (allows single backticks inside)
224
+ .replace(/``([^`\n]+)``/g, (_, code) => {
225
+ return `${COLORS.dim}\`\`${COLORS.orange}${code}${COLORS.dim}\`\`${COLORS.reset}`;
226
+ });
227
+ }
228
+ /**
229
+ * Highlight URLs that aren't already part of markdown links
230
+ */
231
+ function highlightUrls(text) {
232
+ // Skip if already in a markdown link
233
+ if (/\[[^\]]+\]\([^)]+\)/.test(text)) {
234
+ return text;
235
+ }
236
+ // Match bare URLs (http:// or https://)
237
+ return text.replace(/(https?:\/\/[^\s<>\[\]()]+)/g, `${COLORS.link}$1${COLORS.reset}`);
238
+ }
239
+ /**
240
+ * Highlight emoji shortcodes :emoji:
241
+ */
242
+ function highlightEmoji(text) {
243
+ return text.replace(/:([a-z0-9_+-]+):/g, (_, name) => {
244
+ return `${COLORS.yellow}:${name}:${COLORS.reset}`;
245
+ });
246
+ }
247
+ // ===== Financial/Trading Highlighting =====
248
+ /**
249
+ * Format large numbers with K, M, B, T suffixes
250
+ */
251
+ function formatLargeNumber(num) {
252
+ if (num >= 1e12)
253
+ return (num / 1e12).toFixed(1) + 'T';
254
+ if (num >= 1e9)
255
+ return (num / 1e9).toFixed(1) + 'B';
256
+ if (num >= 1e6)
257
+ return (num / 1e6).toFixed(1) + 'M';
258
+ if (num >= 1e3)
259
+ return (num / 1e3).toFixed(1) + 'K';
260
+ return num.toString();
261
+ }
262
+ /**
263
+ * Highlight currency amounts ($100, €50, ¥1000, etc.)
264
+ */
265
+ function highlightCurrency(text) {
266
+ // Skip if inside code block or has ANSI codes
267
+ if (text.includes('```') || text.includes('\x1b['))
268
+ return text;
269
+ // Currency symbols pattern - match currency symbol followed by number
270
+ const currencyPattern = new RegExp(`([${Object.keys(CURRENCY_SYMBOLS).join('')}])\\s?([\\d,]+(?:\\.\\d{1,8})?)`, 'g');
271
+ let result = text.replace(currencyPattern, (_, symbol, amount) => {
272
+ const currency = CURRENCY_SYMBOLS[symbol] || '';
273
+ return `${COLORS.money}${symbol}${amount}${COLORS.reset}`;
274
+ });
275
+ // Named currency formats (USD 100, EUR 50)
276
+ result = result.replace(/\b(USD|EUR|GBP|JPY|CAD|AUD|CHF|CNY|INR|MXN|BRL|KRW|SGD|HKD|NOK|SEK|DKK|NZD|ZAR|RUB|TRY|PLN|THB|IDR|MYR|PHP|VND)\s+([\d,]+(?:\.\d{1,8})?)/gi, (_, currency, amount) => `${COLORS.money}${currency} ${amount}${COLORS.reset}`);
277
+ return result;
278
+ }
279
+ /**
280
+ * Highlight cryptocurrency amounts and symbols
281
+ */
282
+ function highlightCrypto(text) {
283
+ // Skip if inside code block
284
+ if (text.includes('```'))
285
+ return text;
286
+ let result = text;
287
+ // Crypto amounts with symbol (0.5 BTC, 10 ETH, etc.)
288
+ const cryptoPattern = new RegExp(`([\\d,]+(?:\\.\\d{1,8})?)\\s*(${Array.from(CRYPTO_SYMBOLS).join('|')})(?=\\s|\\.|\,|:|;|!|\\?|$)`, 'gi');
289
+ result = result.replace(cryptoPattern, (_, amount, symbol) => {
290
+ const upperSymbol = symbol.toUpperCase();
291
+ return `${COLORS.crypto}${amount} ${upperSymbol}${COLORS.reset}`;
292
+ });
293
+ // Satoshi amounts
294
+ result = result.replace(/([\d,]+(?:\.\d{1,8})?)\s*(sats?|satoshis?)(?=\s|\.|,|:|;|!|\?|$)/gi, (_, amount, unit) => {
295
+ return `${COLORS.crypto}${amount} ${unit.toLowerCase()}${COLORS.reset}`;
296
+ });
297
+ // Gwei amounts (gas prices)
298
+ result = result.replace(/([\d,]+(?:\.\d{1,2})?)\s*gwei(?=\s|\.|,|:|;|!|\?|$)/gi, (_, amount) => {
299
+ return `${COLORS.crypto}${amount} gwei${COLORS.reset}`;
300
+ });
301
+ // Wei amounts
302
+ result = result.replace(/([\d,]+)\s*wei(?=\s|\.|,|:|;|!|\?|$)/gi, (_, amount) => {
303
+ return `${COLORS.dim}${amount} wei${COLORS.reset}`;
304
+ });
305
+ return result;
306
+ }
307
+ /**
308
+ * Highlight percentages with color based on positive/negative
309
+ */
310
+ function highlightPercentages(text) {
311
+ // Skip if inside code block or already has ANSI codes
312
+ if (text.includes('```') || text.includes('\x1b['))
313
+ return text;
314
+ let result = text;
315
+ // Positive percentages (+5.2%, +10%) - must have space or start before
316
+ result = result.replace(/(^|\s)\+([\d,]+(?:\.\d{1,4})?)\s*%/gm, (_, prefix, num) => `${prefix}${COLORS.percentUp}+${num}%${COLORS.reset}`);
317
+ // Negative percentages (-5.2%, -10%) - must have space or start before
318
+ result = result.replace(/(^|\s)-([\d,]+(?:\.\d{1,4})?)\s*%/gm, (_, prefix, num) => `${prefix}${COLORS.percentDown}-${num}%${COLORS.reset}`);
319
+ // Neutral percentages (5.2%, 10%) - must not be part of +/-
320
+ result = result.replace(/(^|\s)([\d,]+(?:\.\d{1,4})?)\s*%/gm, (_, prefix, num) => `${prefix}${COLORS.orange}${num}%${COLORS.reset}`);
321
+ return result;
322
+ }
323
+ /**
324
+ * Highlight stock tickers ($AAPL, $TSLA, etc.)
325
+ */
326
+ function highlightTickers(text) {
327
+ // Skip if inside code block or already has ANSI codes
328
+ if (text.includes('```') || text.includes('\x1b['))
329
+ return text;
330
+ // Match $TICKER with word boundaries - must have $ prefix and be 1-5 uppercase letters
331
+ return text.replace(/(?<![a-zA-Z0-9])\$([A-Z]{1,5})(?![a-zA-Z0-9])/g, (_, ticker) => `${COLORS.ticker}$${ticker}${COLORS.reset}`);
332
+ }
333
+ /**
334
+ * Highlight trading terms (bullish/bearish/neutral)
335
+ */
336
+ function highlightTradingTerms(text) {
337
+ // Skip if inside code block or already has ANSI codes
338
+ if (text.includes('```') || text.includes('\x1b['))
339
+ return text;
340
+ let result = text;
341
+ // Bullish terms - whole word matches only
342
+ const bullishRegex = new RegExp(`\\b(${Array.from(BULLISH_TERMS).join('|')})\\b`, 'gi');
343
+ result = result.replace(bullishRegex, (match) => {
344
+ return `${COLORS.bullish}${match}${COLORS.reset}`;
345
+ });
346
+ // Bearish terms - whole word matches only
347
+ const bearishRegex = new RegExp(`\\b(${Array.from(BEARISH_TERMS).join('|')})\\b`, 'gi');
348
+ result = result.replace(bearishRegex, (match) => {
349
+ return `${COLORS.bearish}${match}${COLORS.reset}`;
350
+ });
351
+ return result;
352
+ }
353
+ /**
354
+ * Highlight price targets and ranges
355
+ */
356
+ function highlightPriceTargets(text) {
357
+ // Skip if inside code block
358
+ if (text.includes('```'))
359
+ return text;
360
+ let result = text;
361
+ // Price targets ($100 target, PT: $150, etc.)
362
+ result = result.replace(/\b(?:PT|price target|target|TP|take profit)\s*:?\s*([\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/gi, (_, price) => `${COLORS.priceTarget}PT: ${price}${COLORS.reset}`);
363
+ // Stop loss levels
364
+ result = result.replace(/\b(?:SL|stop loss|stop)\s*:?\s*([\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/gi, (_, price) => `${COLORS.red}SL: ${price}${COLORS.reset}`);
365
+ // Entry levels
366
+ result = result.replace(/\b(?:entry|enter|buy in)\s*:?\s*([\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/gi, (_, price) => `${COLORS.green}Entry: ${price}${COLORS.reset}`);
367
+ // Price ranges ($100-$150, 50-75)
368
+ result = result.replace(/([\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)\s*[-–]\s*([\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/g, (_, low, high) => `${COLORS.money}${low}-${high}${COLORS.reset}`);
369
+ return result;
370
+ }
371
+ /**
372
+ * Highlight timestamps and dates
373
+ */
374
+ function highlightTimestamps(text) {
375
+ // Skip if inside code block or already has ANSI codes
376
+ if (text.includes('```') || text.includes('\x1b['))
377
+ return text;
378
+ let result = text;
379
+ // ISO dates (2024-01-15) - specific pattern
380
+ result = result.replace(/\b(\d{4}-\d{2}-\d{2})\b/g, (_, date) => `${COLORS.timestamp}${date}${COLORS.reset}`);
381
+ // ISO datetime with T (2024-01-15T14:30:00Z)
382
+ result = result.replace(/\b(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(Z)?\b/g, (_, datetime, z) => `${COLORS.timestamp}${datetime}${z || ''}${COLORS.reset}`);
383
+ // Time only (14:30:00) - must have word boundary
384
+ result = result.replace(/\b(\d{2}:\d{2}:\d{2})\b/g, (_, time) => `${COLORS.timestamp}${time}${COLORS.reset}`);
385
+ // Relative times (1h ago, 2d ago, etc.)
386
+ result = result.replace(/\b(\d+)\s*(second|minute|hour|day|week|month|year)s?\s+ago\b/gi, (_, num, unit) => `${COLORS.timestamp}${num} ${unit}s ago${COLORS.reset}`);
387
+ return result;
388
+ }
389
+ /**
390
+ * Highlight mathematical expressions
391
+ */
392
+ function highlightMath(text) {
393
+ // Skip if inside code block or has ANSI codes
394
+ if (text.includes('```') || text.includes('\x1b['))
395
+ return text;
396
+ let result = text;
397
+ // Mathematical constants - be specific with word boundaries
398
+ result = result.replace(/\b(pi|π|euler|infinity|inf)\b/gi, (_, constant) => `${COLORS.orange}${constant}${COLORS.reset}`);
399
+ // Exponents (x^2, 10^6) - only in math contexts
400
+ result = result.replace(/(\d)\^(\d+)/g, (_, base, exp) => `${COLORS.math}${base}^${exp}${COLORS.reset}`);
401
+ // Scientific notation (1.5e10, 2E-5)
402
+ result = result.replace(/(\d+\.\d+)[eE]([+-]?\d+)/g, (_, mantissa, exp) => `${COLORS.orange}${mantissa}e${exp}${COLORS.reset}`);
403
+ return result;
404
+ }
405
+ /**
406
+ * Highlight P/L (profit/loss) statements
407
+ */
408
+ function highlightPL(text) {
409
+ // Skip if inside code block
410
+ if (text.includes('```'))
411
+ return text;
412
+ let result = text;
413
+ // P/L with amounts
414
+ result = result.replace(/\b(?:P\/L|PnL|profit\/loss|PL)\s*:?\s*([+\-]?[\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/gi, (_, amount) => {
415
+ const isPositive = !amount.startsWith('-');
416
+ const color = isPositive ? COLORS.moneyGain : COLORS.moneyLoss;
417
+ return `${color}P/L: ${amount}${COLORS.reset}`;
418
+ });
419
+ // ROI percentages
420
+ result = result.replace(/\b(?:ROI|return)\s*:?\s*([+\-]?[\d,]+(?:\.\d{1,2})?\s*%)/gi, (_, percent) => {
421
+ const isPositive = !percent.startsWith('-');
422
+ const color = isPositive ? COLORS.percentUp : COLORS.percentDown;
423
+ return `${color}ROI: ${percent}${COLORS.reset}`;
424
+ });
425
+ // Unrealized/Realized P/L
426
+ result = result.replace(/\b(unrealized|realized)\s+(p\/l|pnl|profit|loss)\s*:?\s*([+\-]?[\$€£¥]?\s*[\d,]+(?:\.\d{1,4})?)/gi, (_, status, _type, amount) => {
427
+ const isPositive = !amount.startsWith('-');
428
+ const color = isPositive ? COLORS.moneyGain : COLORS.moneyLoss;
429
+ return `${color}${status} P/L: ${amount}${COLORS.reset}`;
430
+ });
431
+ return result;
432
+ }
433
+ /**
434
+ * Highlight OHLC (Open, High, Low, Close) values
435
+ */
436
+ function highlightOHLC(text) {
437
+ // Skip if inside code block
438
+ if (text.includes('```'))
439
+ return text;
440
+ let result = text;
441
+ // OHLC pattern
442
+ result = result.replace(/\b(?:O|Open)\s*:?\s*([\d,]+(?:\.\d{1,8})?)/gi, (_, val) => `${COLORS.neutral}O: ${val}${COLORS.reset}`);
443
+ result = result.replace(/\b(?:H|High)\s*:?\s*([\d,]+(?:\.\d{1,8})?)/gi, (_, val) => `${COLORS.moneyGain}H: ${val}${COLORS.reset}`);
444
+ result = result.replace(/\b(?:L|Low)\s*:?\s*([\d,]+(?:\.\d{1,8})?)/gi, (_, val) => `${COLORS.moneyLoss}L: ${val}${COLORS.reset}`);
445
+ result = result.replace(/\b(?:C|Close)\s*:?\s*([\d,]+(?:\.\d{1,8})?)/gi, (_, val) => `${COLORS.neutral}C: ${val}${COLORS.reset}`);
446
+ // Volume
447
+ result = result.replace(/\b(?:V|Vol|Volume)\s*:?\s*([\d,]+(?:\.\d{1,2})?[KkMmBb]?)/gi, (_, val) => `${COLORS.cyan}Vol: ${val}${COLORS.reset}`);
448
+ // Market Cap
449
+ result = result.replace(/\b(?:MCap|Market Cap|Market Capitalization)\s*:?\s*([\$€£¥]?\s*[\d,]+(?:\.\d{1,2})?[KkMmBbTt]?)/gi, (_, val) => `${COLORS.money}MCap: ${val}${COLORS.reset}`);
450
+ return result;
451
+ }
452
+ /**
453
+ * Apply all financial highlighting - runs FIRST before any other highlighting
454
+ */
455
+ function highlightFinancial(text) {
456
+ // Skip if already has ANSI codes or inside code block
457
+ if (text.includes('\x1b[') || text.includes('```'))
458
+ return text;
459
+ let result = text;
460
+ // Order matters - most specific patterns first
461
+ // 1. Crypto (specific symbols)
462
+ result = highlightCrypto(result);
463
+ // 2. Currency (specific symbols)
464
+ result = highlightCurrency(result);
465
+ // 3. Percentages (with +/-)
466
+ result = highlightPercentages(result);
467
+ // 4. P/L statements
468
+ result = highlightPL(result);
469
+ // 5. Price targets (PT:, SL:)
470
+ result = highlightPriceTargets(result);
471
+ // 6. OHLC values
472
+ result = highlightOHLC(result);
473
+ // 7. Stock tickers ($AAPL)
474
+ result = highlightTickers(result);
475
+ // 8. Trading terms (bullish/bearish)
476
+ result = highlightTradingTerms(result);
477
+ // 9. Timestamps
478
+ result = highlightTimestamps(result);
479
+ // 10. Math expressions
480
+ result = highlightMath(result);
481
+ return result;
482
+ }
483
+ /**
484
+ * Highlight markdown formatting in plain text
485
+ */
486
+ function highlightMarkdown(text) {
487
+ let result = text;
488
+ // Skip processing if we're inside a code block (basic check)
489
+ if (text.includes('```')) {
490
+ return result;
491
+ }
492
+ // Horizontal rules (---, ***, ___) - must be on own line
493
+ result = result.replace(/^( {0,3})([-*_])( {0,2}\2){2,}$/gm, `${COLORS.hr}$1$2$2$2${COLORS.reset}`);
494
+ // Headers (# ## ### etc) - with setext style support
495
+ result = result.replace(/^(#{1,6})\s+(.+)$/gm, (_, hashes, content) => {
496
+ // Color the header level differently based on depth
497
+ const level = hashes.length;
498
+ if (level === 1) {
499
+ return `${COLORS.bold}${COLORS.blue}${hashes} ${content}${COLORS.reset}`;
500
+ }
501
+ else if (level === 2) {
502
+ return `${COLORS.bold}${COLORS.cyan}${hashes} ${content}${COLORS.reset}`;
503
+ }
504
+ return `${COLORS.header}${hashes} ${content}${COLORS.reset}`;
505
+ });
506
+ // Setext-style headers (underlined with === or ---)
507
+ result = result.replace(/^(.+)\n([=]+)$/gm, (_, content, line) => {
508
+ return `${COLORS.bold}${COLORS.blue}${content}${COLORS.reset}\n${COLORS.hr}${line}${COLORS.reset}`;
509
+ });
510
+ result = result.replace(/^(.+)\n([-]+)$/gm, (_, content, line) => {
511
+ return `${COLORS.bold}${COLORS.cyan}${content}${COLORS.reset}\n${COLORS.hr}${line}${COLORS.reset}`;
512
+ });
513
+ // Blockquotes (> at start of line)
514
+ result = result.replace(/^(>{1,})\s?(.*)$/gm, (_, markers, content) => {
515
+ const depth = markers.length;
516
+ // Different color for nested quotes
517
+ const color = depth > 1 ? COLORS.dim : COLORS.blockquote;
518
+ return `${COLORS.green}${markers}${COLORS.reset} ${color}${content}${COLORS.reset}`;
519
+ });
520
+ // Tables - simple detection and formatting
521
+ result = result.replace(/^\|(.+)\|\s*$/gm, (match, content) => {
522
+ // Table row
523
+ const cells = content.split('|');
524
+ const formattedCells = cells.map((cell) => {
525
+ const trimmed = cell.trim();
526
+ if (trimmed) {
527
+ return ` ${COLORS.gray}${trimmed}${COLORS.reset} `;
528
+ }
529
+ return cell;
530
+ }).join(`${COLORS.tableBorder}|${COLORS.reset}`);
531
+ return `${COLORS.tableBorder}|${COLORS.reset}${formattedCells}${COLORS.tableBorder}|${COLORS.reset}`;
532
+ });
533
+ // Table separator line (|---|---|)
534
+ result = result.replace(/^\|([-:\s|]+)\|\s*$/gm, (_, content) => {
535
+ return `${COLORS.tableBorder}|${content}|${COLORS.reset}`;
536
+ });
537
+ // Bold (**text** or __text__)
538
+ result = result.replace(/\*\*([^*]+)\*\*/g, `${COLORS.bold}$1${COLORS.reset}`);
539
+ result = result.replace(/__([^_]+)__/g, `${COLORS.bold}$1${COLORS.reset}`);
540
+ // Strikethrough (~~text~~)
541
+ result = result.replace(/~~([^~]+)~~/g, `${COLORS.strikethrough}${COLORS.dim}$1${COLORS.reset}`);
542
+ // Italic (*text* or _text_) - be careful not to match inside words
543
+ result = result.replace(/(?<![a-zA-Z\*])\*([^*]+)\*(?![a-zA-Z\*])/g, `${COLORS.italic}$1${COLORS.reset}`);
544
+ result = result.replace(/(?<![a-zA-Z_])_([^_]+)_(?![a-zA-Z_])/g, `${COLORS.italic}$1${COLORS.reset}`);
545
+ // Bold+Italic (***text*** or ___text___)
546
+ result = result.replace(/\*\*\*([^*]+)\*\*\*/g, `${COLORS.bold}${COLORS.italic}$1${COLORS.reset}`);
547
+ result = result.replace(/___([^_]+)___/g, `${COLORS.bold}${COLORS.italic}$1${COLORS.reset}`);
548
+ // Task lists (- [ ] or - [x])
549
+ result = result.replace(/^(\s*)[-*]\s\[([ xX])\]/gm, (_, indent, checked) => {
550
+ const mark = checked.toLowerCase() === 'x' ? '✓' : ' ';
551
+ const color = checked.toLowerCase() === 'x' ? COLORS.green : COLORS.dim;
552
+ return `${indent}${COLORS.list}-${COLORS.reset} ${color}[${mark}]${COLORS.reset}`;
553
+ });
554
+ // Regular list items (- or * at start of line)
555
+ result = result.replace(/^(\s*)([-*])\s(?!\[)/gm, `$1${COLORS.list}$2${COLORS.reset} `);
556
+ // Numbered lists
557
+ result = result.replace(/^(\s*)(\d+\.)(?=\s)/gm, `$1${COLORS.list}$2${COLORS.reset}`);
558
+ // Definition lists (term : definition)
559
+ result = result.replace(/^([^:\n]+):\s{2,}(.+)$/gm, `${COLORS.bold}$1${COLORS.reset}:${COLORS.dim} $2${COLORS.reset}`);
560
+ // Links [text](url)
561
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, `${COLORS.link}[$1]${COLORS.reset}${COLORS.dim}($2)${COLORS.reset}`);
562
+ // Reference-style links [text][ref]
563
+ result = result.replace(/\[([^\]]+)\]\[([^\]]*)\]/g, `${COLORS.link}[$1]${COLORS.reset}${COLORS.dim}[$2]${COLORS.reset}`);
564
+ // Images ![alt](url)
565
+ result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, `${COLORS.yellow}![${COLORS.reset}${COLORS.dim}$1${COLORS.reset}${COLORS.yellow}]${COLORS.reset}${COLORS.dim}($2)${COLORS.reset}`);
566
+ // Footnotes [^1] and [^1]: definition
567
+ result = result.replace(/\[\^([^\]]+)\]/g, `${COLORS.yellow}[^$1]${COLORS.reset}`);
568
+ result = result.replace(/^\[\^([^\]]+)\]:\s*(.+)$/gm, `${COLORS.yellow}[^$1]${COLORS.reset}:${COLORS.dim} $2${COLORS.reset}`);
569
+ // HTML tags (basic detection)
570
+ result = result.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)(\s[^>]*)?>/g, `${COLORS.dim}<${COLORS.purple}$1${COLORS.reset}$2${COLORS.dim}>${COLORS.reset}`);
571
+ // Highlight/mark (==text==)
572
+ result = result.replace(/==([^=]+)==/g, `${COLORS.yellow}$1${COLORS.reset}`);
573
+ // Keyboard shortcuts (<kbd>text</kbd> - if not already handled by HTML)
574
+ result = result.replace(/<kbd>([^<]+)<\/kbd>/gi, `${COLORS.dim}[${COLORS.orange}$1${COLORS.dim}]${COLORS.reset}`);
575
+ return result;
576
+ }
577
+ /**
578
+ * Extract language and optional file path from fence info
579
+ * Examples: "typescript", "typescript path/to/file.ts", "ts {linenos=true}"
580
+ */
581
+ function parseFenceInfo(fenceInfo) {
582
+ const parts = fenceInfo.split(/\s+/);
583
+ const language = parts[0] || "";
584
+ let filePath;
585
+ let attrs = "";
586
+ for (let i = 1; i < parts.length; i++) {
587
+ const part = parts[i];
588
+ if (!part)
589
+ continue;
590
+ if (part.includes('=')) {
591
+ attrs += (attrs ? ' ' : '') + part;
592
+ }
593
+ else if (part.includes('.') || part.includes('/')) {
594
+ // Looks like a file path
595
+ filePath = part;
596
+ }
597
+ }
598
+ return { language, filePath, attrs };
599
+ }
600
+ /**
601
+ * Map file extensions to languages
602
+ */
603
+ const EXT_TO_LANG = {
604
+ '.ts': 'typescript',
605
+ '.tsx': 'typescript',
606
+ '.js': 'javascript',
607
+ '.jsx': 'javascript',
608
+ '.mjs': 'javascript',
609
+ '.cjs': 'javascript',
610
+ '.py': 'python',
611
+ '.rb': 'ruby',
612
+ '.rs': 'rust',
613
+ '.go': 'go',
614
+ '.java': 'java',
615
+ '.kt': 'kotlin',
616
+ '.swift': 'swift',
617
+ '.c': 'c',
618
+ '.cpp': 'cpp',
619
+ '.cc': 'cpp',
620
+ '.cxx': 'cpp',
621
+ '.h': 'c',
622
+ '.hpp': 'cpp',
623
+ '.cs': 'csharp',
624
+ '.php': 'php',
625
+ '.sh': 'bash',
626
+ '.bash': 'bash',
627
+ '.zsh': 'bash',
628
+ '.ps1': 'powershell',
629
+ '.json': 'json',
630
+ '.yaml': 'yaml',
631
+ '.yml': 'yaml',
632
+ '.toml': 'toml',
633
+ '.md': 'markdown',
634
+ '.html': 'html',
635
+ '.htm': 'html',
636
+ '.css': 'css',
637
+ '.scss': 'css',
638
+ '.less': 'css',
639
+ '.sql': 'sql',
640
+ '.xml': 'xml',
641
+ '.svg': 'xml',
642
+ '.vue': 'vue',
643
+ '.svelte': 'svelte',
644
+ '.dockerfile': 'dockerfile',
645
+ '.makefile': 'makefile',
646
+ '.cmake': 'cmake',
647
+ '.lua': 'lua',
648
+ '.r': 'r',
649
+ '.ex': 'elixir',
650
+ '.exs': 'elixir',
651
+ '.erl': 'erlang',
652
+ '.hs': 'haskell',
653
+ '.ml': 'ocaml',
654
+ '.clj': 'clojure',
655
+ '.scala': 'scala',
656
+ '.groovy': 'groovy',
657
+ '.pl': 'perl',
658
+ '.pm': 'perl',
659
+ };
660
+ /**
661
+ * Detect language from file path
662
+ */
663
+ function detectLanguageFromPath(filePath) {
664
+ const ext = filePath.toLowerCase().slice(filePath.lastIndexOf('.'));
665
+ return EXT_TO_LANG[ext];
666
+ }
667
+ /**
668
+ * Apply all text highlighting (markdown, inline code, urls, emoji)
669
+ */
670
+ function highlightAllText(text) {
671
+ // Skip if text already has ANSI codes (already processed)
672
+ if (text.includes('\x1b[')) {
673
+ return text;
674
+ }
675
+ let result = text;
676
+ // Apply in order - more specific patterns should come first
677
+ // Financial highlighting first since it has specific patterns
678
+ result = highlightFinancial(result);
679
+ // Then inline code (but skip if in code blocks)
680
+ result = highlightInlineCode(result);
681
+ // Markdown formatting
682
+ result = highlightMarkdown(result);
683
+ // URLs and emoji last
684
+ result = highlightUrls(result);
685
+ result = highlightEmoji(result);
686
+ return result;
687
+ }
688
+ /**
689
+ * Creates a streaming highlighter that detects and highlights code blocks
690
+ * and diffs as they complete during streaming output.
691
+ */
692
+ export function createStreamHighlighter() {
693
+ let buffer = "";
694
+ let state = 'text';
695
+ let codeBlockLang = "";
696
+ let blockContent = "";
697
+ let blockFilePath = "";
698
+ function process(text) {
699
+ buffer += text;
700
+ let output = "";
701
+ while (true) {
702
+ if (state === 'code' || state === 'diff') {
703
+ // Look for closing fence (``` at start of line)
704
+ const closeMatch = buffer.match(/\n```/);
705
+ if (!closeMatch) {
706
+ // No closing fence yet, keep buffering
707
+ // But output most of the buffer to avoid memory issues
708
+ if (buffer.length > 2000) {
709
+ const safeChunk = buffer.slice(0, -200); // Keep last 200 chars in case fence is partial
710
+ blockContent += safeChunk;
711
+ // For diffs, we can output as we go with line-by-line highlighting
712
+ if (state === 'diff') {
713
+ output += highlightDiffContent(safeChunk);
714
+ }
715
+ else {
716
+ output += safeChunk; // Code gets highlighted at end for proper syntax
717
+ }
718
+ buffer = buffer.slice(-200);
719
+ }
720
+ break;
721
+ }
722
+ const closeIndex = closeMatch.index;
723
+ // Found closing fence - extract remaining content
724
+ blockContent += buffer.slice(0, closeIndex);
725
+ // Highlight based on block type
726
+ let highlighted;
727
+ const effectiveLang = codeBlockLang || (blockFilePath ? detectLanguageFromPath(blockFilePath) : '');
728
+ if (state === 'diff' || (codeBlockLang === 'diff' || isDiffContent(blockContent))) {
729
+ highlighted = highlightDiffContent(blockContent);
730
+ }
731
+ else if (effectiveLang) {
732
+ try {
733
+ highlighted = highlight_code(blockContent, effectiveLang).html;
734
+ }
735
+ catch {
736
+ highlighted = blockContent;
737
+ }
738
+ }
739
+ else {
740
+ highlighted = blockContent;
741
+ }
742
+ // Remove trailing reset and whitespace from highlighted code
743
+ const trimmed = highlighted
744
+ .replace(/\x1b\[0m$/, '')
745
+ .trimEnd();
746
+ output += trimmed;
747
+ output += `\n${COLORS.reset}\`\`\``; // Newline, reset, and closing fence
748
+ // Skip past the closing fence in buffer
749
+ buffer = buffer.slice(closeIndex + 4); // +4 for "\n```"
750
+ state = 'text';
751
+ codeBlockLang = "";
752
+ blockContent = "";
753
+ blockFilePath = "";
754
+ }
755
+ else {
756
+ // Look for opening fence: ``` followed by optional lang and newline
757
+ // Support: ```typescript, ```typescript file.ts, ```{ .typescript }
758
+ const openMatch = buffer.match(/```([^\n]*)\n/);
759
+ if (!openMatch) {
760
+ // No complete opening fence yet
761
+ // Check if buffer might contain partial fence at end
762
+ const partialFence = buffer.match(/```([^\n]*)$/);
763
+ if (partialFence) {
764
+ // Partial fence - output everything before it and keep fence in buffer
765
+ const beforeFence = buffer.slice(0, buffer.length - partialFence[0].length);
766
+ // Apply all text highlighting
767
+ output += highlightAllText(beforeFence);
768
+ buffer = partialFence[0];
769
+ break;
770
+ }
771
+ // No fence at all - output everything with markdown highlighting
772
+ // Keep last 4 chars in case of partial ``` (but try to keep complete lines)
773
+ if (buffer.length > 4) {
774
+ // Find the last newline to avoid splitting mid-line
775
+ const lastNewline = buffer.lastIndexOf('\n', buffer.length - 4);
776
+ let toOutput;
777
+ if (lastNewline > 0 && buffer.length - lastNewline <= 10) {
778
+ // If there's a recent newline, output up to it
779
+ toOutput = buffer.slice(0, lastNewline + 1);
780
+ buffer = buffer.slice(lastNewline + 1);
781
+ }
782
+ else if (buffer.length > 100) {
783
+ // Long buffer with no newline - output all but last 4 chars
784
+ toOutput = buffer.slice(0, -4);
785
+ buffer = buffer.slice(-4);
786
+ }
787
+ else {
788
+ // Short buffer - keep it all for now
789
+ break;
790
+ }
791
+ output += highlightAllText(toOutput);
792
+ }
793
+ break;
794
+ }
795
+ // Found complete opening fence
796
+ const fenceStart = openMatch.index;
797
+ const fenceInfo = openMatch[1] || "";
798
+ const { language, filePath } = parseFenceInfo(fenceInfo);
799
+ // Output text before the fence with markdown highlighting
800
+ const beforeFence = buffer.slice(0, fenceStart);
801
+ output += highlightAllText(beforeFence);
802
+ // Output the opening fence line
803
+ // Show with file path if available
804
+ const detectedLang = language || (filePath ? detectLanguageFromPath(filePath) : '');
805
+ if (filePath) {
806
+ const langDisplay = language || detectedLang || '';
807
+ output += `${COLORS.dim}\`\`\`${COLORS.cyan}${langDisplay}${COLORS.reset} ${COLORS.comment}${filePath}${COLORS.reset}\n`;
808
+ }
809
+ else if (language) {
810
+ output += `${COLORS.dim}\`\`\`${COLORS.cyan}${language}${COLORS.reset}\n`;
811
+ }
812
+ else {
813
+ output += `${COLORS.dim}\`\`\`${COLORS.reset}\n`;
814
+ }
815
+ // Skip past the opening fence in buffer
816
+ buffer = buffer.slice(fenceStart + openMatch[0].length);
817
+ // Determine block type
818
+ if (language === 'diff' || language === 'patch') {
819
+ state = 'diff';
820
+ }
821
+ else {
822
+ state = 'code';
823
+ }
824
+ codeBlockLang = language;
825
+ blockContent = "";
826
+ blockFilePath = filePath || "";
827
+ }
828
+ }
829
+ return output;
830
+ }
831
+ function flush() {
832
+ let output = "";
833
+ if (state === 'code' || state === 'diff') {
834
+ // Unclosed code block - highlight what we have
835
+ const effectiveLang = codeBlockLang || (blockFilePath ? detectLanguageFromPath(blockFilePath) : '');
836
+ if (state === 'diff' || isDiffContent(blockContent)) {
837
+ output += highlightDiffContent(blockContent);
838
+ }
839
+ else if (effectiveLang) {
840
+ try {
841
+ output += highlight_code(blockContent, effectiveLang).html;
842
+ }
843
+ catch {
844
+ output += blockContent;
845
+ }
846
+ }
847
+ else {
848
+ output += blockContent;
849
+ }
850
+ output += COLORS.reset;
851
+ }
852
+ if (buffer) {
853
+ output += highlightAllText(buffer);
854
+ buffer = "";
855
+ }
856
+ return output;
857
+ }
858
+ return { process, flush };
859
+ }
860
+ /**
861
+ * Highlight complete text with code blocks
862
+ * Used for non-streaming contexts or final output
863
+ */
864
+ export function highlightTextWithCodeBlocks(text) {
865
+ // Split by code blocks and highlight each
866
+ // Support language + optional file path: ```typescript path/to/file.ts
867
+ const codeBlockRegex = /```([^\n]*)\n([\s\S]*?)```/g;
868
+ let result = "";
869
+ let lastIndex = 0;
870
+ let match;
871
+ while ((match = codeBlockRegex.exec(text)) !== null) {
872
+ // Add text before code block with all highlighting
873
+ const beforeText = text.slice(lastIndex, match.index);
874
+ result += highlightAllText(beforeText);
875
+ const fenceInfo = match[1] || "";
876
+ const { language, filePath } = parseFenceInfo(fenceInfo);
877
+ const code = match[2] || "";
878
+ // Determine effective language
879
+ const effectiveLang = language || (filePath ? detectLanguageFromPath(filePath) : '');
880
+ // Show fence with file path if available
881
+ if (filePath) {
882
+ const langDisplay = language || effectiveLang || '';
883
+ result += `${COLORS.dim}\`\`\`${COLORS.cyan}${langDisplay}${COLORS.reset} ${COLORS.comment}${filePath}${COLORS.reset}\n`;
884
+ }
885
+ else if (language) {
886
+ result += `${COLORS.dim}\`\`\`${COLORS.cyan}${language}${COLORS.reset}\n`;
887
+ }
888
+ else {
889
+ result += `${COLORS.dim}\`\`\`${COLORS.reset}\n`;
890
+ }
891
+ if (language === 'diff' || language === 'patch' || isDiffContent(code)) {
892
+ // Highlight as diff
893
+ result += highlightDiffContent(code);
894
+ result += `\n${COLORS.reset}\`\`\``;
895
+ }
896
+ else if (effectiveLang) {
897
+ // Highlight with language
898
+ try {
899
+ result += highlight_code(code, effectiveLang).html;
900
+ }
901
+ catch {
902
+ result += code;
903
+ }
904
+ result += `\n${COLORS.reset}\`\`\``;
905
+ }
906
+ else {
907
+ // No language, output as-is
908
+ result += code;
909
+ result += `\n${COLORS.reset}\`\`\``;
910
+ }
911
+ lastIndex = match.index + match[0].length;
912
+ }
913
+ // Add remaining text with all highlighting
914
+ result += highlightAllText(text.slice(lastIndex));
915
+ return result;
916
+ }