@ebowwa/coder 0.2.1 → 0.7.64

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 (401) hide show
  1. package/README.md +31 -32
  2. package/dist/core/__tests__/permissions.test.d.ts +12 -0
  3. package/dist/core/__tests__/permissions.test.d.ts.map +1 -0
  4. package/dist/core/__tests__/permissions.test.js +851 -0
  5. package/dist/core/agent-loop/__tests__/compaction.test.d.ts +5 -0
  6. package/dist/core/agent-loop/__tests__/compaction.test.d.ts.map +1 -0
  7. package/dist/core/agent-loop/__tests__/compaction.test.js +209 -0
  8. package/dist/core/agent-loop/__tests__/formatters.test.d.ts +5 -0
  9. package/dist/core/agent-loop/__tests__/formatters.test.d.ts.map +1 -0
  10. package/dist/core/agent-loop/__tests__/formatters.test.js +195 -0
  11. package/dist/core/agent-loop/__tests__/index.test.d.ts +5 -0
  12. package/dist/core/agent-loop/__tests__/index.test.d.ts.map +1 -0
  13. package/dist/core/agent-loop/__tests__/index.test.js +121 -0
  14. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts +5 -0
  15. package/dist/core/agent-loop/__tests__/loop-state.test.d.ts.map +1 -0
  16. package/dist/core/agent-loop/__tests__/loop-state.test.js +340 -0
  17. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts +5 -0
  18. package/dist/core/agent-loop/__tests__/message-builder.test.d.ts.map +1 -0
  19. package/dist/core/agent-loop/__tests__/message-builder.test.js +178 -0
  20. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts +5 -0
  21. package/dist/core/agent-loop/__tests__/tool-executor.test.d.ts.map +1 -0
  22. package/dist/core/agent-loop/__tests__/tool-executor.test.js +331 -0
  23. package/dist/core/agent-loop/compaction.d.ts +39 -0
  24. package/dist/core/agent-loop/compaction.d.ts.map +1 -0
  25. package/dist/core/agent-loop/compaction.js +51 -0
  26. package/dist/core/agent-loop/formatters.d.ts +21 -0
  27. package/dist/core/agent-loop/formatters.d.ts.map +1 -0
  28. package/dist/core/agent-loop/formatters.js +42 -0
  29. package/dist/core/agent-loop/index.d.ts +25 -0
  30. package/dist/core/agent-loop/index.d.ts.map +1 -0
  31. package/dist/core/agent-loop/index.js +83 -0
  32. package/dist/core/agent-loop/loop-state.d.ts +74 -0
  33. package/dist/core/agent-loop/loop-state.d.ts.map +1 -0
  34. package/dist/core/agent-loop/loop-state.js +147 -0
  35. package/dist/core/agent-loop/message-builder.d.ts +13 -0
  36. package/dist/core/agent-loop/message-builder.d.ts.map +1 -0
  37. package/dist/core/agent-loop/message-builder.js +49 -0
  38. package/dist/core/agent-loop/tool-executor.d.ts +23 -0
  39. package/dist/core/agent-loop/tool-executor.d.ts.map +1 -0
  40. package/dist/core/agent-loop/tool-executor.js +152 -0
  41. package/dist/core/agent-loop/turn-executor.d.ts +57 -0
  42. package/dist/core/agent-loop/turn-executor.d.ts.map +1 -0
  43. package/dist/core/agent-loop/turn-executor.js +124 -0
  44. package/dist/core/agent-loop/types.d.ts +141 -0
  45. package/dist/core/agent-loop/types.d.ts.map +1 -0
  46. package/dist/core/agent-loop/types.js +4 -0
  47. package/dist/core/agent-loop.d.ts +17 -0
  48. package/dist/core/agent-loop.d.ts.map +1 -0
  49. package/dist/core/agent-loop.js +16 -0
  50. package/dist/core/api-client-impl.d.ts +62 -0
  51. package/dist/core/api-client-impl.d.ts.map +1 -0
  52. package/dist/core/api-client-impl.js +479 -0
  53. package/dist/core/api-client.d.ts +6 -0
  54. package/dist/core/api-client.d.ts.map +1 -0
  55. package/dist/core/api-client.js +5 -0
  56. package/dist/core/checkpoints.d.ts +128 -0
  57. package/dist/core/checkpoints.d.ts.map +1 -0
  58. package/dist/core/checkpoints.js +438 -0
  59. package/dist/core/claude-md.d.ts +71 -0
  60. package/dist/core/claude-md.d.ts.map +1 -0
  61. package/dist/core/claude-md.js +198 -0
  62. package/dist/core/cognitive-security/hooks.d.ts +138 -0
  63. package/dist/core/cognitive-security/hooks.d.ts.map +1 -0
  64. package/dist/core/cognitive-security/hooks.js +389 -0
  65. package/dist/core/cognitive-security/index.d.ts +751 -0
  66. package/dist/core/cognitive-security/index.d.ts.map +1 -0
  67. package/dist/core/cognitive-security/index.js +1123 -0
  68. package/dist/core/cognitive-security/middleware.d.ts +136 -0
  69. package/dist/core/cognitive-security/middleware.d.ts.map +1 -0
  70. package/dist/core/cognitive-security/middleware.js +376 -0
  71. package/dist/core/config-loader.d.ts +127 -0
  72. package/dist/core/config-loader.d.ts.map +1 -0
  73. package/dist/core/config-loader.js +219 -0
  74. package/dist/core/context-compaction.d.ts +87 -0
  75. package/dist/core/context-compaction.d.ts.map +1 -0
  76. package/dist/core/context-compaction.js +428 -0
  77. package/dist/core/git-status.d.ts +25 -0
  78. package/dist/core/git-status.d.ts.map +1 -0
  79. package/dist/core/git-status.js +204 -0
  80. package/dist/core/image.d.ts +69 -0
  81. package/dist/core/image.d.ts.map +1 -0
  82. package/dist/core/image.js +290 -0
  83. package/dist/core/image.test.d.ts +2 -0
  84. package/dist/core/image.test.d.ts.map +1 -0
  85. package/dist/core/image.test.js +149 -0
  86. package/dist/core/models.d.ts +123 -0
  87. package/dist/core/models.d.ts.map +1 -0
  88. package/dist/core/models.js +325 -0
  89. package/dist/core/permissions.d.ts +81 -0
  90. package/dist/core/permissions.d.ts.map +1 -0
  91. package/dist/core/permissions.js +327 -0
  92. package/dist/core/retry.d.ts +25 -0
  93. package/dist/core/retry.d.ts.map +1 -0
  94. package/dist/core/retry.js +121 -0
  95. package/dist/core/session-store.d.ts +9 -0
  96. package/dist/core/session-store.d.ts.map +1 -0
  97. package/dist/core/session-store.js +10 -0
  98. package/dist/core/sessions/export.d.ts +47 -0
  99. package/dist/core/sessions/export.d.ts.map +1 -0
  100. package/dist/core/sessions/export.js +256 -0
  101. package/dist/core/sessions/index.d.ts +132 -0
  102. package/dist/core/sessions/index.d.ts.map +1 -0
  103. package/dist/core/sessions/index.js +442 -0
  104. package/dist/core/sessions/metadata.d.ts +77 -0
  105. package/dist/core/sessions/metadata.d.ts.map +1 -0
  106. package/dist/core/sessions/metadata.js +233 -0
  107. package/dist/core/sessions/persistence.d.ts +72 -0
  108. package/dist/core/sessions/persistence.d.ts.map +1 -0
  109. package/dist/core/sessions/persistence.js +201 -0
  110. package/dist/core/sessions/types.d.ts +110 -0
  111. package/dist/core/sessions/types.d.ts.map +1 -0
  112. package/dist/core/sessions/types.js +4 -0
  113. package/dist/core/stream-highlighter.d.ts +18 -0
  114. package/dist/core/stream-highlighter.d.ts.map +1 -0
  115. package/dist/core/stream-highlighter.js +916 -0
  116. package/dist/core/system-reminders.d.ts +89 -0
  117. package/dist/core/system-reminders.d.ts.map +1 -0
  118. package/dist/core/system-reminders.js +285 -0
  119. package/dist/ecosystem/hooks/__tests__/index.test.d.ts +5 -0
  120. package/dist/ecosystem/hooks/__tests__/index.test.d.ts.map +1 -0
  121. package/dist/ecosystem/hooks/__tests__/index.test.js +458 -0
  122. package/dist/ecosystem/hooks/index.d.ts +59 -0
  123. package/dist/ecosystem/hooks/index.d.ts.map +1 -0
  124. package/dist/ecosystem/hooks/index.js +294 -0
  125. package/dist/ecosystem/hooks/prompt-evaluator.d.ts +32 -0
  126. package/dist/ecosystem/hooks/prompt-evaluator.d.ts.map +1 -0
  127. package/dist/ecosystem/hooks/prompt-evaluator.js +229 -0
  128. package/dist/ecosystem/skills/index.d.ts +55 -0
  129. package/dist/ecosystem/skills/index.d.ts.map +1 -0
  130. package/dist/ecosystem/skills/index.js +258 -0
  131. package/dist/ecosystem/tools/__tests__/index.test.d.ts +7 -0
  132. package/dist/ecosystem/tools/__tests__/index.test.d.ts.map +1 -0
  133. package/dist/ecosystem/tools/__tests__/index.test.js +856 -0
  134. package/dist/ecosystem/tools/index.d.ts +24 -0
  135. package/dist/ecosystem/tools/index.d.ts.map +1 -0
  136. package/dist/ecosystem/tools/index.js +1709 -0
  137. package/dist/index.d.ts +24 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +32 -2
  140. package/dist/interfaces/mcp/client.d.ts +40 -0
  141. package/dist/interfaces/mcp/client.d.ts.map +1 -0
  142. package/dist/interfaces/mcp/client.js +309 -0
  143. package/dist/interfaces/ui/index.d.ts +36 -0
  144. package/dist/interfaces/ui/index.d.ts.map +1 -0
  145. package/dist/interfaces/ui/index.js +61 -0
  146. package/dist/interfaces/ui/spinner.d.ts +140 -0
  147. package/dist/interfaces/ui/spinner.d.ts.map +1 -0
  148. package/dist/interfaces/ui/spinner.js +342 -0
  149. package/dist/interfaces/ui/terminal/cli/index.d.ts +12 -0
  150. package/dist/interfaces/ui/terminal/cli/index.d.ts.map +1 -0
  151. package/dist/interfaces/ui/terminal/cli/index.js +167 -0
  152. package/dist/interfaces/ui/terminal/shared/args.d.ts +39 -0
  153. package/dist/interfaces/ui/terminal/shared/args.d.ts.map +1 -0
  154. package/dist/interfaces/ui/terminal/shared/args.js +176 -0
  155. package/dist/interfaces/ui/terminal/shared/index.d.ts +11 -0
  156. package/dist/interfaces/ui/terminal/shared/index.d.ts.map +1 -0
  157. package/dist/interfaces/ui/terminal/shared/index.js +16 -0
  158. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts +124 -0
  159. package/dist/interfaces/ui/terminal/shared/loading-state.d.ts.map +1 -0
  160. package/dist/interfaces/ui/terminal/shared/loading-state.js +246 -0
  161. package/dist/interfaces/ui/terminal/shared/query.d.ts +22 -0
  162. package/dist/interfaces/ui/terminal/shared/query.d.ts.map +1 -0
  163. package/dist/interfaces/ui/terminal/shared/query.js +100 -0
  164. package/dist/interfaces/ui/terminal/shared/setup.d.ts +33 -0
  165. package/dist/interfaces/ui/terminal/shared/setup.d.ts.map +1 -0
  166. package/dist/interfaces/ui/terminal/shared/setup.js +226 -0
  167. package/dist/interfaces/ui/terminal/shared/status-line.d.ts +117 -0
  168. package/dist/interfaces/ui/terminal/shared/status-line.d.ts.map +1 -0
  169. package/dist/interfaces/ui/terminal/shared/status-line.js +267 -0
  170. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts +38 -0
  171. package/dist/interfaces/ui/terminal/shared/system-prompt.d.ts.map +1 -0
  172. package/dist/interfaces/ui/terminal/shared/system-prompt.js +102 -0
  173. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts +39 -0
  174. package/dist/interfaces/ui/terminal/tui/HelpPanel.d.ts.map +1 -0
  175. package/dist/interfaces/ui/terminal/tui/HelpPanel.js +215 -0
  176. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts +91 -0
  177. package/dist/interfaces/ui/terminal/tui/InputContext.d.ts.map +1 -0
  178. package/dist/interfaces/ui/terminal/tui/InputContext.js +154 -0
  179. package/dist/interfaces/ui/terminal/tui/InputField.d.ts +18 -0
  180. package/dist/interfaces/ui/terminal/tui/InputField.d.ts.map +1 -0
  181. package/dist/interfaces/ui/terminal/tui/InputField.js +41 -0
  182. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts +16 -0
  183. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.d.ts.map +1 -0
  184. package/dist/interfaces/ui/terminal/tui/InteractiveTUI.js +451 -0
  185. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts +10 -0
  186. package/dist/interfaces/ui/terminal/tui/MessageArea.d.ts.map +1 -0
  187. package/dist/interfaces/ui/terminal/tui/MessageArea.js +91 -0
  188. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts +48 -0
  189. package/dist/interfaces/ui/terminal/tui/MessageStore.d.ts.map +1 -0
  190. package/dist/interfaces/ui/terminal/tui/MessageStore.js +151 -0
  191. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts +9 -0
  192. package/dist/interfaces/ui/terminal/tui/StatusBar.d.ts.map +1 -0
  193. package/dist/interfaces/ui/terminal/tui/StatusBar.js +36 -0
  194. package/dist/interfaces/ui/terminal/tui/commands.d.ts +21 -0
  195. package/dist/interfaces/ui/terminal/tui/commands.d.ts.map +1 -0
  196. package/dist/interfaces/ui/terminal/tui/commands.js +359 -0
  197. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts +115 -0
  198. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.d.ts.map +1 -0
  199. package/dist/interfaces/ui/terminal/tui/components/InteractiveElements.js +306 -0
  200. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts +92 -0
  201. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.d.ts.map +1 -0
  202. package/dist/interfaces/ui/terminal/tui/components/MultilineInput.js +399 -0
  203. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts +59 -0
  204. package/dist/interfaces/ui/terminal/tui/components/PaneManager.d.ts.map +1 -0
  205. package/dist/interfaces/ui/terminal/tui/components/PaneManager.js +139 -0
  206. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts +68 -0
  207. package/dist/interfaces/ui/terminal/tui/components/Sidebar.d.ts.map +1 -0
  208. package/dist/interfaces/ui/terminal/tui/components/Sidebar.js +340 -0
  209. package/dist/interfaces/ui/terminal/tui/components/index.d.ts +23 -0
  210. package/dist/interfaces/ui/terminal/tui/components/index.d.ts.map +1 -0
  211. package/dist/interfaces/ui/terminal/tui/components/index.js +51 -0
  212. package/dist/interfaces/ui/terminal/tui/console.d.ts +20 -0
  213. package/dist/interfaces/ui/terminal/tui/console.d.ts.map +1 -0
  214. package/dist/interfaces/ui/terminal/tui/console.js +46 -0
  215. package/dist/interfaces/ui/terminal/tui/index.d.ts +20 -0
  216. package/dist/interfaces/ui/terminal/tui/index.d.ts.map +1 -0
  217. package/dist/interfaces/ui/terminal/tui/index.js +28 -0
  218. package/dist/interfaces/ui/terminal/tui/run.d.ts +13 -0
  219. package/dist/interfaces/ui/terminal/tui/run.d.ts.map +1 -0
  220. package/dist/interfaces/ui/terminal/tui/run.js +31 -0
  221. package/dist/interfaces/ui/terminal/tui/spinner.d.ts +44 -0
  222. package/dist/interfaces/ui/terminal/tui/spinner.d.ts.map +1 -0
  223. package/dist/interfaces/ui/terminal/tui/spinner.js +59 -0
  224. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts +39 -0
  225. package/dist/interfaces/ui/terminal/tui/tui-app.d.ts.map +1 -0
  226. package/dist/interfaces/ui/terminal/tui/tui-app.js +198 -0
  227. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts +167 -0
  228. package/dist/interfaces/ui/terminal/tui/tui-footer.d.ts.map +1 -0
  229. package/dist/interfaces/ui/terminal/tui/tui-footer.js +330 -0
  230. package/dist/interfaces/ui/terminal/tui/types.d.ts +165 -0
  231. package/dist/interfaces/ui/terminal/tui/types.d.ts.map +1 -0
  232. package/dist/interfaces/ui/terminal/tui/types.js +5 -0
  233. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts +23 -0
  234. package/dist/interfaces/ui/terminal/tui/useInputHandler.d.ts.map +1 -0
  235. package/dist/interfaces/ui/terminal/tui/useInputHandler.js +72 -0
  236. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts +90 -0
  237. package/dist/interfaces/ui/terminal/tui/useNativeInput.d.ts.map +1 -0
  238. package/dist/interfaces/ui/terminal/tui/useNativeInput.js +188 -0
  239. package/dist/native/index.d.ts +480 -0
  240. package/dist/native/index.d.ts.map +1 -0
  241. package/dist/native/index.js +1625 -0
  242. package/dist/teammates/index.d.ts +161 -0
  243. package/dist/teammates/index.d.ts.map +1 -0
  244. package/dist/teammates/index.js +827 -0
  245. package/dist/types/index.d.ts +482 -0
  246. package/dist/types/index.d.ts.map +1 -0
  247. package/dist/types/index.js +52 -0
  248. package/native/README.md +5 -5
  249. package/native/index.darwin-arm64.node +0 -0
  250. package/native/index.node +0 -0
  251. package/native/package.json +4 -4
  252. package/package.json +33 -16
  253. package/packages/src/core/__tests__/permissions.test.ts +1091 -0
  254. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +280 -0
  255. package/packages/src/core/agent-loop/__tests__/formatters.test.ts +234 -0
  256. package/packages/src/core/agent-loop/__tests__/index.test.ts +162 -0
  257. package/packages/src/core/agent-loop/__tests__/loop-state.test.ts +413 -0
  258. package/packages/src/core/agent-loop/__tests__/message-builder.test.ts +229 -0
  259. package/packages/src/core/agent-loop/__tests__/tool-executor.test.ts +457 -0
  260. package/packages/src/core/agent-loop/compaction.ts +88 -0
  261. package/packages/src/core/agent-loop/formatters.ts +50 -0
  262. package/packages/src/core/agent-loop/index.ts +135 -0
  263. package/packages/src/core/agent-loop/loop-state.ts +187 -0
  264. package/packages/src/core/agent-loop/message-builder.ts +62 -0
  265. package/packages/src/core/agent-loop/tool-executor.ts +211 -0
  266. package/packages/src/core/agent-loop/turn-executor.ts +222 -0
  267. package/packages/src/core/agent-loop/types.ts +148 -0
  268. package/packages/src/core/agent-loop.ts +18 -0
  269. package/packages/src/core/api-client-impl.ts +619 -0
  270. package/packages/src/core/api-client.ts +6 -0
  271. package/packages/src/core/checkpoints.ts +606 -0
  272. package/packages/src/core/claude-md.ts +272 -0
  273. package/packages/src/core/cognitive-security/hooks.ts +590 -0
  274. package/packages/src/core/cognitive-security/index.ts +2041 -0
  275. package/packages/src/core/cognitive-security/middleware.ts +536 -0
  276. package/packages/src/core/config-loader.ts +324 -0
  277. package/packages/src/core/context-compaction.ts +578 -0
  278. package/packages/src/core/git-status.ts +262 -0
  279. package/packages/src/core/image.test.ts +180 -0
  280. package/packages/src/core/image.ts +350 -0
  281. package/packages/src/core/lmdb.db +0 -0
  282. package/packages/src/core/lmdb.db-lock +0 -0
  283. package/packages/src/core/models.ts +430 -0
  284. package/packages/src/core/normalizers/todo +4 -0
  285. package/packages/src/core/permissions.ts +431 -0
  286. package/packages/src/core/retry.ts +170 -0
  287. package/packages/src/core/session-store.ts +36 -0
  288. package/packages/src/core/sessions/export.ts +329 -0
  289. package/packages/src/core/sessions/index.ts +587 -0
  290. package/packages/src/core/sessions/metadata.ts +309 -0
  291. package/packages/src/core/sessions/persistence.ts +244 -0
  292. package/packages/src/core/sessions/types.ts +169 -0
  293. package/packages/src/core/stream-highlighter.ts +1123 -0
  294. package/packages/src/core/system-reminders.ts +402 -0
  295. package/packages/src/core/todo +8 -0
  296. package/packages/src/ecosystem/hooks/__tests__/index.test.ts +561 -0
  297. package/packages/src/ecosystem/hooks/index.ts +341 -0
  298. package/packages/src/ecosystem/hooks/prompt-evaluator.ts +300 -0
  299. package/packages/src/ecosystem/skills/index.ts +295 -0
  300. package/packages/src/ecosystem/tools/__tests__/index.test.ts +1335 -0
  301. package/packages/src/ecosystem/tools/index.ts +1877 -0
  302. package/packages/src/index.ts +120 -0
  303. package/packages/src/interfaces/mcp/client.ts +389 -0
  304. package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
  305. package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
  306. package/packages/src/interfaces/ui/index.ts +161 -0
  307. package/packages/src/interfaces/ui/lmdb.db +0 -0
  308. package/packages/src/interfaces/ui/lmdb.db-lock +0 -0
  309. package/packages/src/interfaces/ui/spinner.ts +451 -0
  310. package/packages/src/interfaces/ui/terminal/cli/index.ts +228 -0
  311. package/packages/src/interfaces/ui/terminal/lmdb.db +0 -0
  312. package/packages/src/interfaces/ui/terminal/lmdb.db-lock +0 -0
  313. package/packages/src/interfaces/ui/terminal/shared/args.ts +222 -0
  314. package/packages/src/interfaces/ui/terminal/shared/index.ts +71 -0
  315. package/packages/src/interfaces/ui/terminal/shared/loading-state.ts +322 -0
  316. package/packages/src/interfaces/ui/terminal/shared/query.ts +146 -0
  317. package/packages/src/interfaces/ui/terminal/shared/setup.ts +295 -0
  318. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +358 -0
  319. package/packages/src/interfaces/ui/terminal/shared/system-prompt.ts +146 -0
  320. package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +262 -0
  321. package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +232 -0
  322. package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +62 -0
  323. package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +537 -0
  324. package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +107 -0
  325. package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +240 -0
  326. package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +54 -0
  327. package/packages/src/interfaces/ui/terminal/tui/commands.ts +438 -0
  328. package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +584 -0
  329. package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +614 -0
  330. package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +333 -0
  331. package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +604 -0
  332. package/packages/src/interfaces/ui/terminal/tui/components/index.ts +118 -0
  333. package/packages/src/interfaces/ui/terminal/tui/console.ts +49 -0
  334. package/packages/src/interfaces/ui/terminal/tui/index.ts +90 -0
  335. package/packages/src/interfaces/ui/terminal/tui/run.tsx +42 -0
  336. package/packages/src/interfaces/ui/terminal/tui/spinner.ts +69 -0
  337. package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +390 -0
  338. package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +422 -0
  339. package/packages/src/interfaces/ui/terminal/tui/types.ts +186 -0
  340. package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +104 -0
  341. package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +239 -0
  342. package/packages/src/lmdb.db +0 -0
  343. package/packages/src/lmdb.db-lock +0 -0
  344. package/packages/src/native/index.ts +2345 -0
  345. package/packages/src/teammates/index.ts +982 -0
  346. package/packages/src/types/index.ts +722 -0
  347. package/dist/cli.js +0 -148
  348. package/dist/index-0pkak453.js +0 -136
  349. package/dist/index-0qd0x8b4.js +0 -110
  350. package/dist/index-0x3kprq6.js +0 -240
  351. package/dist/index-1eawy937.js +0 -308
  352. package/dist/index-24m2aygy.js +0 -240
  353. package/dist/index-29xcjnne.js +0 -280
  354. package/dist/index-2avyytn5.js +0 -349
  355. package/dist/index-4ms367ey.js +0 -136
  356. package/dist/index-4w2t3b0m.js +0 -240
  357. package/dist/index-4xfgd8nz.js +0 -261
  358. package/dist/index-5acjp9gc.js +0 -157
  359. package/dist/index-5s15hr56.js +0 -136
  360. package/dist/index-6e4wf341.js +0 -349
  361. package/dist/index-6fvnkedw.js +0 -240
  362. package/dist/index-6rqpmd4g.js +0 -128
  363. package/dist/index-77ckwnbm.js +0 -280
  364. package/dist/index-9knxy49k.js +0 -128
  365. package/dist/index-9zrnw4zx.js +0 -128
  366. package/dist/index-bk21w99v.js +0 -280
  367. package/dist/index-c41n76fv.js +0 -240
  368. package/dist/index-cb4ppjdt.js +0 -255
  369. package/dist/index-cfb2edt6.js +0 -240
  370. package/dist/index-cmfa38hh.js +0 -308
  371. package/dist/index-datjz8q1.js +0 -257
  372. package/dist/index-eadf4wvn.js +0 -240
  373. package/dist/index-em5k0m3z.js +0 -345
  374. package/dist/index-gh8r333a.js +0 -110
  375. package/dist/index-gkx6k2tr.js +0 -261
  376. package/dist/index-h5cabfks.js +0 -155
  377. package/dist/index-hcrpwyy3.js +0 -261
  378. package/dist/index-hk7fwwa8.js +0 -257
  379. package/dist/index-jb8cw7f8.js +0 -136
  380. package/dist/index-kbyw4th1.js +0 -347
  381. package/dist/index-kgj5gqnm.js +0 -345
  382. package/dist/index-mdf6xp1z.js +0 -255
  383. package/dist/index-mrhv8kvc.js +0 -280
  384. package/dist/index-mt4743dd.js +0 -161
  385. package/dist/index-qnwsg97q.js +0 -240
  386. package/dist/index-qwdy6x44.js +0 -261
  387. package/dist/index-rmj77261.js +0 -157
  388. package/dist/index-sbbw1a61.js +0 -349
  389. package/dist/index-svy5bcpn.js +0 -345
  390. package/dist/index-tvmy7tm9.js +0 -261
  391. package/dist/index-tzz4vzkj.js +0 -312
  392. package/dist/index-vz80zmhe.js +0 -110
  393. package/dist/index-wed2fk67.js +0 -240
  394. package/dist/index-wksgzz8e.js +0 -280
  395. package/dist/index-wn2m4wma.js +0 -240
  396. package/dist/index-xha05vjc.js +0 -257
  397. package/dist/index-yc6eh8p8.js +0 -136
  398. package/dist/index-ycjxx9ft.js +0 -240
  399. package/dist/index-z0gzd0fc.js +0 -110
  400. package/dist/index-z8cwtf8j.js +0 -240
  401. package/dist/index-zy5mtt00.js +0 -128
@@ -0,0 +1,537 @@
1
+ /**
2
+ * Main Interactive TUI Component
3
+ * Orchestrates all sub-components and manages state and agent loop
4
+ *
5
+ * Uses:
6
+ * - MessageStore: Centralized message state management
7
+ * - InputContext: Centralized keyboard input handling
8
+ */
9
+
10
+ import React, { useState, useEffect, useCallback, useRef, useMemo } from "react";
11
+ import { Box, Text, useApp, useStdout } from "ink";
12
+ import type { ExtendedThinkingConfig } from "../../../../types/index.js";
13
+ import { agentLoop } from "../../../../core/agent-loop.js";
14
+ import { getGitStatus } from "../../../../core/git-status.js";
15
+ import { createStreamHighlighter } from "../../../../core/stream-highlighter.js";
16
+ import { calculateContextInfo } from "../shared/status-line.js";
17
+ import { spinnerFrames } from "./spinner.js";
18
+ import { MessageArea } from "./MessageArea.js";
19
+ import { InputField, setGlobalInput } from "./InputField.js";
20
+ import { handleCommand } from "./commands.js";
21
+ import { useNativeInput, KeyEvents } from "./useNativeInput.js";
22
+ import { InputProvider } from "./InputContext.js";
23
+ import { MessageStoreProvider, useMessageStore } from "./MessageStore.js";
24
+ import type { InteractiveTUIProps, MessageSubType } from "./types.js";
25
+
26
+ /**
27
+ * Estimate token count from text
28
+ * Uses ~4 characters per token as rough approximation
29
+ */
30
+ function estimateTokens(text: string): number {
31
+ if (!text) return 0;
32
+ return Math.ceil(text.length / 4);
33
+ }
34
+
35
+ /**
36
+ * Estimate total tokens from messages
37
+ */
38
+ function estimateMessagesTokens(messages: import("../../../../types/index.js").Message[]): number {
39
+ let total = 0;
40
+ for (const msg of messages) {
41
+ if (typeof msg.content === "string") {
42
+ total += estimateTokens(msg.content);
43
+ } else if (Array.isArray(msg.content)) {
44
+ for (const block of msg.content) {
45
+ if (block.type === "text") {
46
+ total += estimateTokens(block.text);
47
+ } else if (block.type === "tool_use") {
48
+ total += estimateTokens(JSON.stringify(block.input));
49
+ } else if (block.type === "tool_result") {
50
+ if (typeof block.content === "string") {
51
+ total += estimateTokens(block.content);
52
+ }
53
+ }
54
+ }
55
+ }
56
+ }
57
+ return total;
58
+ }
59
+
60
+ /**
61
+ * Inner component that uses MessageStore
62
+ */
63
+ function InteractiveTUIInner({
64
+ apiKey,
65
+ model: initialModel,
66
+ permissionMode,
67
+ maxTokens,
68
+ systemPrompt: initialSystemPrompt,
69
+ tools,
70
+ hookManager,
71
+ sessionStore,
72
+ sessionId,
73
+ setSessionId,
74
+ workingDirectory,
75
+ onExit,
76
+ }: InteractiveTUIProps) {
77
+ // Message store
78
+ const {
79
+ messages,
80
+ apiMessages,
81
+ addMessage,
82
+ addApiMessages,
83
+ addSystem,
84
+ tokenCount,
85
+ setTokenCount,
86
+ } = useMessageStore();
87
+
88
+ // UI state - use refs for immediate input display updates
89
+ const inputRef = useRef("");
90
+ const cursorRef = useRef(0);
91
+ const [isLoading, setIsLoading] = useState(false);
92
+
93
+ // Update input and sync to global state for InputField
94
+ // NOTE: Use inputRef.current and cursorRef.current directly in callbacks
95
+ // to avoid stale closure values. Don't use inputValue/cursorPos variables.
96
+ const setInputValue = useCallback((value: string) => {
97
+ inputRef.current = value;
98
+ setGlobalInput(value, cursorRef.current);
99
+ }, []);
100
+
101
+ const setCursorPos = useCallback((pos: number | ((prev: number) => number)) => {
102
+ const newPos = typeof pos === "function" ? pos(cursorRef.current) : pos;
103
+ cursorRef.current = newPos;
104
+ setGlobalInput(inputRef.current, newPos);
105
+ }, []);
106
+
107
+ const [totalCost, setTotalCost] = useState(0);
108
+ const [spinnerFrame, setSpinnerFrame] = useState("⠋");
109
+ const [model, setModel] = useState(initialModel);
110
+ const [systemPrompt] = useState(initialSystemPrompt);
111
+ const [streamingText, setStreamingText] = useState("");
112
+ const [scrollOffset, setScrollOffset] = useState(0);
113
+ const [sessionSelectMode, setSessionSelectMode] = useState(false);
114
+ const [selectableSessions, setSelectableSessions] = useState<Array<{ id: string; messageCount: number; metadata?: Record<string, unknown> }>>([]);
115
+ const [helpMode, setHelpMode] = useState(false);
116
+ const [helpSection, setHelpSection] = useState(0);
117
+
118
+ // Input history
119
+ const [inputHistory, setInputHistory] = useState<string[]>([]);
120
+ const [historyIndex, setHistoryIndex] = useState(-1);
121
+ const [savedInput, setSavedInput] = useState("");
122
+
123
+ const { exit } = useApp();
124
+ const { stdout } = useStdout();
125
+ const frameRef = useRef(0);
126
+ const isProcessingRef = useRef(false);
127
+ const highlighterRef = useRef(createStreamHighlighter());
128
+
129
+ // Calculate terminal layout
130
+ const terminalHeight = stdout.rows || 24;
131
+ const inputHeight = 3;
132
+ const statusHeight = 3;
133
+ const messageHeight = terminalHeight - inputHeight - statusHeight;
134
+
135
+ // Calculate context warning
136
+ const contextInfo = calculateContextInfo(tokenCount, model);
137
+ const contextWarning = contextInfo.isCritical
138
+ ? "Context critical! Use /compact or start new conversation"
139
+ : contextInfo.isLow
140
+ ? `Context low: ${contextInfo.percentRemaining.toFixed(0)}% remaining`
141
+ : null;
142
+
143
+ // Auto-scroll to bottom when new messages arrive
144
+ useEffect(() => {
145
+ setScrollOffset(0);
146
+ }, [messages.length]);
147
+
148
+ // Spinner animation
149
+ useEffect(() => {
150
+ if (!isLoading) return;
151
+
152
+ const interval = setInterval(() => {
153
+ frameRef.current = (frameRef.current + 1) % spinnerFrames.length;
154
+ const frame = spinnerFrames[frameRef.current];
155
+ if (frame) setSpinnerFrame(frame);
156
+ }, 80);
157
+
158
+ return () => clearInterval(interval);
159
+ }, [isLoading]);
160
+
161
+ // Process a message
162
+ const processMessage = useCallback(async (input: string, messageAlreadyAdded = false) => {
163
+ if (isProcessingRef.current) return;
164
+ isProcessingRef.current = true;
165
+
166
+ // Add user message to UI if not already added
167
+ if (!messageAlreadyAdded) {
168
+ addMessage({ role: "user", content: input });
169
+ }
170
+
171
+ setIsLoading(true);
172
+ setStreamingText("");
173
+ highlighterRef.current = createStreamHighlighter();
174
+
175
+ try {
176
+ // Execute UserPromptSubmit hook
177
+ const hookResult = await hookManager.execute("UserPromptSubmit", {
178
+ prompt: input,
179
+ session_id: sessionId,
180
+ });
181
+
182
+ if (hookResult.decision === "deny" || hookResult.decision === "block") {
183
+ addSystem(`Input blocked: ${hookResult.reason || "Security policy"}`);
184
+ return;
185
+ }
186
+
187
+ const processedInput = (hookResult.modified_input?.prompt as string) ?? input;
188
+
189
+ // Build messages for API
190
+ const newUserMsg = {
191
+ role: "user" as const,
192
+ content: [{ type: "text" as const, text: processedInput }],
193
+ };
194
+ const messagesForApi = [...apiMessages, newUserMsg];
195
+
196
+ // Get git status
197
+ const gitStatus = await getGitStatus(workingDirectory);
198
+
199
+ // Run agent loop
200
+ const result = await agentLoop(messagesForApi, {
201
+ apiKey,
202
+ model,
203
+ maxTokens,
204
+ systemPrompt,
205
+ tools,
206
+ permissionMode,
207
+ workingDirectory,
208
+ gitStatus,
209
+ extendedThinking: undefined,
210
+ hookManager,
211
+ sessionId,
212
+ onText: (text) => {
213
+ setStreamingText((prev) => prev + text);
214
+ },
215
+ onThinking: () => {
216
+ // Could show thinking in UI
217
+ },
218
+ onToolUse: (toolUse) => {
219
+ addSystem(`[Using: ${toolUse.name}]`, "tool_call", toolUse.name);
220
+ },
221
+ onToolResult: (toolResult) => {
222
+ if (toolResult.result.is_error) {
223
+ addSystem(`[Tool ${toolResult.id}: Error]`, "tool_result", undefined, true);
224
+ }
225
+ },
226
+ onMetrics: async (metrics) => {
227
+ const apiTokens = metrics.usage.input_tokens + metrics.usage.output_tokens;
228
+ if (apiTokens > 0) {
229
+ setTokenCount(apiTokens);
230
+ }
231
+ await sessionStore.saveMetrics(metrics);
232
+ },
233
+ });
234
+
235
+ // Update API messages (MessageStore will convert to UI messages)
236
+ // Note: result.messages already includes newUserMsg, so we don't add it again
237
+ // Only add the NEW messages from the result (skip ones we already have)
238
+ addApiMessages(result.messages.slice(apiMessages.length));
239
+ setTotalCost((prev) => prev + result.totalCost);
240
+
241
+ // Estimate tokens from final messages
242
+ const estimatedTokens = estimateMessagesTokens(result.messages);
243
+ setTokenCount(estimatedTokens);
244
+
245
+ // Save to session
246
+ const lastUserMsg = result.messages[result.messages.length - 2];
247
+ const lastAssistantMsg = result.messages[result.messages.length - 1];
248
+ if (lastUserMsg) await sessionStore.saveMessage(lastUserMsg);
249
+ if (lastAssistantMsg) await sessionStore.saveMessage(lastAssistantMsg);
250
+
251
+ } catch (error) {
252
+ const errorMessage = error instanceof Error ? error.message : String(error);
253
+ addSystem(`Error: ${errorMessage}`, "error");
254
+ } finally {
255
+ setIsLoading(false);
256
+ isProcessingRef.current = false;
257
+ setStreamingText("");
258
+ }
259
+ }, [apiMessages, apiKey, model, maxTokens, systemPrompt, tools, permissionMode, workingDirectory, hookManager, sessionId, sessionStore, addMessage, addSystem, addApiMessages, setTokenCount]);
260
+
261
+ // Handle commands
262
+ const handleCommandWrapper = useCallback(async (cmd: string) => {
263
+ // Import command context dynamically to avoid circular deps
264
+ const { setMessages: setExternalMessages, processedCountRef } = {
265
+ setMessages: () => {}, // MessageStore handles this now
266
+ processedCountRef: { current: apiMessages.length },
267
+ };
268
+
269
+ await handleCommand(cmd, {
270
+ sessionId,
271
+ setSessionId,
272
+ model,
273
+ setModel,
274
+ apiMessages,
275
+ setApiMessages: (msgs) => addApiMessages(msgs.slice(apiMessages.length)),
276
+ setMessages: setExternalMessages,
277
+ processedCountRef,
278
+ totalCost,
279
+ setTotalCost,
280
+ totalTokens: tokenCount,
281
+ setTotalTokens: setTokenCount,
282
+ permissionMode,
283
+ tools,
284
+ workingDirectory,
285
+ sessionStore,
286
+ addSystemMessage: (content: string, subType?: MessageSubType, toolName?: string, isError?: boolean) => {
287
+ addSystem(content, subType, toolName, isError);
288
+ },
289
+ messagesLength: messages.length,
290
+ onExit,
291
+ exit,
292
+ sessionSelectMode,
293
+ setSessionSelectMode,
294
+ setSelectableSessions,
295
+ helpMode,
296
+ setHelpMode,
297
+ helpSection,
298
+ setHelpSection,
299
+ });
300
+ }, [sessionId, setSessionId, model, apiMessages, addApiMessages, totalCost, tokenCount, setTokenCount, permissionMode, tools, workingDirectory, sessionStore, addSystem, messages.length, onExit, exit, sessionSelectMode, helpMode, helpSection]);
301
+
302
+ // Handle input with native terminal input
303
+ useNativeInput({
304
+ isActive: true,
305
+ onKey: (event) => {
306
+ // Scroll handling
307
+ if (KeyEvents.isPageUp(event)) {
308
+ setScrollOffset((prev) => prev + 5);
309
+ return;
310
+ }
311
+
312
+ if (KeyEvents.isPageDown(event)) {
313
+ setScrollOffset((prev) => Math.max(0, prev - 5));
314
+ return;
315
+ }
316
+
317
+ if (KeyEvents.isShiftUp(event)) {
318
+ setScrollOffset((prev) => prev + 1);
319
+ return;
320
+ }
321
+
322
+ if (KeyEvents.isShiftDown(event)) {
323
+ setScrollOffset((prev) => Math.max(0, prev - 1));
324
+ return;
325
+ }
326
+
327
+ // Ctrl+C to exit
328
+ if (KeyEvents.isCtrlC(event)) {
329
+ onExit();
330
+ exit();
331
+ return;
332
+ }
333
+
334
+ if (isLoading) return;
335
+
336
+ // Help mode navigation
337
+ if (helpMode) {
338
+ const HELP_SECTIONS_COUNT = 5;
339
+
340
+ if (event.code === "escape" || event.code === "q") {
341
+ setHelpMode(false);
342
+ return;
343
+ }
344
+
345
+ if (event.code === "tab" || KeyEvents.isRight(event)) {
346
+ setHelpSection((prev) => (prev + 1) % HELP_SECTIONS_COUNT);
347
+ return;
348
+ }
349
+
350
+ if (KeyEvents.isLeft(event)) {
351
+ setHelpSection((prev) => (prev - 1 + HELP_SECTIONS_COUNT) % HELP_SECTIONS_COUNT);
352
+ return;
353
+ }
354
+
355
+ return;
356
+ }
357
+
358
+ // Session selection mode
359
+ if (sessionSelectMode) {
360
+ const num = parseInt(event.code, 10);
361
+ if (!isNaN(num) && num >= 1 && num <= selectableSessions.length) {
362
+ const selectedSession = selectableSessions[num - 1];
363
+ if (selectedSession) {
364
+ setSessionSelectMode(false);
365
+ setSelectableSessions([]);
366
+ handleCommandWrapper(`/resume ${selectedSession.id}`);
367
+ }
368
+ } else if (KeyEvents.isEnter(event) || (event.code && isNaN(num))) {
369
+ setSessionSelectMode(false);
370
+ setSelectableSessions([]);
371
+ addSystem("Session selection cancelled.");
372
+ }
373
+ return;
374
+ }
375
+
376
+ // Submit on Enter
377
+ if (KeyEvents.isEnter(event)) {
378
+ // Prevent duplicate submissions while processing
379
+ if (isProcessingRef.current) return;
380
+
381
+ const currentInput = inputRef.current;
382
+ if (currentInput.trim()) {
383
+ // Capture value BEFORE clearing
384
+ const valueToSubmit = currentInput;
385
+
386
+ // Clear input IMMEDIATELY to prevent duplicate submissions
387
+ // This must happen before any async operations
388
+ inputRef.current = "";
389
+ setGlobalInput("", 0);
390
+
391
+ // Add user message to UI
392
+ addMessage({ role: "user", content: valueToSubmit });
393
+
394
+ // Clear cursor and history state
395
+ setCursorPos(0);
396
+ setHistoryIndex(-1);
397
+ setSavedInput("");
398
+
399
+ // Update history
400
+ if (!valueToSubmit.startsWith("/") && valueToSubmit !== inputHistory[0]) {
401
+ setInputHistory((prev) => [valueToSubmit, ...prev].slice(0, 100));
402
+ }
403
+
404
+ // Process after UI updates
405
+ setTimeout(() => {
406
+ if (valueToSubmit.startsWith("/")) {
407
+ handleCommandWrapper(valueToSubmit);
408
+ } else {
409
+ processMessage(valueToSubmit, true); // true = message already added
410
+ }
411
+ }, 50);
412
+ }
413
+ return;
414
+ }
415
+
416
+ // History navigation
417
+ if (KeyEvents.isUp(event)) {
418
+ if (inputHistory.length > 0) {
419
+ if (historyIndex === -1) {
420
+ setSavedInput(inputRef.current);
421
+ }
422
+ const newIndex = Math.min(historyIndex + 1, inputHistory.length - 1);
423
+ setHistoryIndex(newIndex);
424
+ setInputValue(inputHistory[newIndex] ?? "");
425
+ setCursorPos((inputHistory[newIndex] ?? "").length);
426
+ }
427
+ return;
428
+ }
429
+
430
+ if (KeyEvents.isDown(event)) {
431
+ if (historyIndex > 0) {
432
+ const newIndex = historyIndex - 1;
433
+ setHistoryIndex(newIndex);
434
+ setInputValue(inputHistory[newIndex] ?? "");
435
+ setCursorPos((inputHistory[newIndex] ?? "").length);
436
+ } else if (historyIndex === 0) {
437
+ setHistoryIndex(-1);
438
+ setInputValue(savedInput);
439
+ setCursorPos(savedInput.length);
440
+ }
441
+ return;
442
+ }
443
+
444
+ // Text editing
445
+ if (KeyEvents.isBackspace(event)) {
446
+ const currentInput = inputRef.current;
447
+ const currentCursor = cursorRef.current;
448
+ if (currentCursor > 0) {
449
+ const newVal = currentInput.slice(0, currentCursor - 1) + currentInput.slice(currentCursor);
450
+ setInputValue(newVal);
451
+ setCursorPos((p) => p - 1);
452
+ }
453
+ return;
454
+ }
455
+
456
+ if (KeyEvents.isDelete(event)) {
457
+ const currentInput = inputRef.current;
458
+ const currentCursor = cursorRef.current;
459
+ if (currentCursor < currentInput.length) {
460
+ const newVal = currentInput.slice(0, currentCursor) + currentInput.slice(currentCursor + 1);
461
+ setInputValue(newVal);
462
+ }
463
+ return;
464
+ }
465
+
466
+ if (KeyEvents.isLeft(event)) {
467
+ setCursorPos((p) => Math.max(0, p - 1));
468
+ return;
469
+ }
470
+
471
+ if (KeyEvents.isRight(event)) {
472
+ setCursorPos((p) => Math.min(inputRef.current.length, p + 1));
473
+ return;
474
+ }
475
+
476
+ if (KeyEvents.isHome(event) || KeyEvents.isCtrlA(event)) {
477
+ setCursorPos(0);
478
+ return;
479
+ }
480
+
481
+ if (KeyEvents.isEnd(event) || KeyEvents.isCtrlE(event)) {
482
+ setCursorPos(inputRef.current.length);
483
+ return;
484
+ }
485
+
486
+ // Regular character
487
+ if (KeyEvents.isPrintable(event)) {
488
+ if (historyIndex !== -1) {
489
+ setHistoryIndex(-1);
490
+ setSavedInput("");
491
+ }
492
+ const currentInput = inputRef.current;
493
+ const currentCursor = cursorRef.current;
494
+ setInputValue(currentInput.slice(0, currentCursor) + event.code + currentInput.slice(currentCursor));
495
+ setCursorPos((p) => p + 1);
496
+ }
497
+ },
498
+ });
499
+
500
+ return (
501
+ <InputProvider initialBlocked={isLoading}>
502
+ <Box flexDirection="column" width="100%">
503
+ <MessageArea
504
+ messages={messages}
505
+ isLoading={isLoading}
506
+ spinnerFrame={spinnerFrame}
507
+ height={messageHeight}
508
+ scrollOffset={scrollOffset}
509
+ contextWarning={contextWarning}
510
+ streamingText={streamingText}
511
+ />
512
+
513
+ <Text dimColor>
514
+ {isLoading ? spinnerFrame : ""} Context: {tokenCount} tokens | {permissionMode}
515
+ </Text>
516
+
517
+ <InputField
518
+ placeholder="Type your message... (/help for commands)"
519
+ isActive={!isLoading}
520
+ />
521
+ </Box>
522
+ </InputProvider>
523
+ );
524
+ }
525
+
526
+ /**
527
+ * Main Interactive TUI Component with providers
528
+ */
529
+ function InteractiveTUI(props: InteractiveTUIProps) {
530
+ return (
531
+ <MessageStoreProvider initialMessages={props.initialMessages}>
532
+ <InteractiveTUIInner {...props} />
533
+ </MessageStoreProvider>
534
+ );
535
+ }
536
+
537
+ export default InteractiveTUI;
@@ -0,0 +1,107 @@
1
+ /** @jsx React.createElement */
2
+ /** @jsxFrag React.Fragment */
3
+ /**
4
+ * Message Area Component - Simple plain text display
5
+ */
6
+
7
+ import React from "react";
8
+ import { Text } from "ink";
9
+ import type { MessageAreaProps, UIMessage, MessageSubType } from "./types.js";
10
+ import { VERSION } from "../shared/status-line.js";
11
+
12
+ function getMessageColor(role: UIMessage["role"], subType?: MessageSubType, isError?: boolean): string {
13
+ if (role === "system") {
14
+ if (isError || subType === "error") return "red";
15
+ if (subType === "tool_call") return "blue";
16
+ if (subType === "tool_result") return "green";
17
+ if (subType === "hook") return "yellow";
18
+ if (subType === "thinking") return "gray";
19
+ if (subType === "info") return "cyan";
20
+ return "yellow";
21
+ }
22
+ switch (role) {
23
+ case "user": return "cyan";
24
+ case "assistant": return "magenta";
25
+ default: return "white";
26
+ }
27
+ }
28
+
29
+ function getMessageLabel(message: UIMessage): string {
30
+ const { role, subType, toolName, isError } = message;
31
+
32
+ if (role === "system" && subType) {
33
+ switch (subType) {
34
+ case "tool_call": return toolName ? `[${toolName}]` : "[Tool]";
35
+ case "tool_result": return isError ? "[Error]" : "[Result]";
36
+ case "hook": return "[Hook]";
37
+ case "error": return "[Error]";
38
+ case "thinking": return "[Thinking]";
39
+ case "info": return "[Info]";
40
+ }
41
+ }
42
+
43
+ switch (role) {
44
+ case "user": return "You:";
45
+ case "system": return "[System]";
46
+ case "assistant": return "Claude:";
47
+ default: return "";
48
+ }
49
+ }
50
+
51
+ export function MessageArea({
52
+ messages,
53
+ isLoading,
54
+ spinnerFrame,
55
+ height,
56
+ scrollOffset = 0,
57
+ contextWarning,
58
+ streamingText,
59
+ }: MessageAreaProps) {
60
+ const totalMessages = messages.length;
61
+ const maxVisibleMessages = 50;
62
+ const endIdx = totalMessages - scrollOffset;
63
+ const startIdx = Math.max(0, endIdx - maxVisibleMessages);
64
+ const visibleMessages = messages.slice(startIdx, endIdx);
65
+
66
+ const isEmpty = visibleMessages.length === 0 && !isLoading && !streamingText;
67
+
68
+ return (
69
+ <>
70
+ {contextWarning && (
71
+ <Text color="yellow" bold>Warning: {contextWarning}{"\n"}</Text>
72
+ )}
73
+
74
+ {isEmpty && (
75
+ <Text dimColor>Welcome to Coder v{VERSION}. Type your message or /help for commands.{"\n"}</Text>
76
+ )}
77
+
78
+ {visibleMessages.map((msg) => {
79
+ const displayContent = msg.content.length > 2000
80
+ ? msg.content.slice(0, 2000) + "..."
81
+ : msg.content;
82
+ const color = getMessageColor(msg.role, msg.subType, msg.isError);
83
+ const label = getMessageLabel(msg);
84
+
85
+ return (
86
+ <Text key={msg.id}>
87
+ <Text bold color={color}>{label} </Text>
88
+ <Text dimColor={msg.role === "system"}>{displayContent}{"\n"}</Text>
89
+ </Text>
90
+ );
91
+ })}
92
+
93
+ {streamingText && (
94
+ <Text>
95
+ <Text bold color="magenta">Claude: </Text>
96
+ <Text dimColor>{streamingText.length > 500 ? "..." + streamingText.slice(-500) : streamingText}{"\n"}</Text>
97
+ </Text>
98
+ )}
99
+
100
+ {isLoading && !streamingText && (
101
+ <Text color="cyan">{spinnerFrame} Processing...{"\n"}</Text>
102
+ )}
103
+ </>
104
+ );
105
+ }
106
+
107
+ export default MessageArea;