@navios/commander-tui 1.0.0

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 (348) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +275 -0
  3. package/coverage/__tests__/utils/factories.ts.html +1147 -0
  4. package/coverage/__tests__/utils/index.html +131 -0
  5. package/coverage/__tests__/utils/render-utils.tsx.html +202 -0
  6. package/coverage/base.css +224 -0
  7. package/coverage/block-navigation.js +87 -0
  8. package/coverage/clover.xml +959 -0
  9. package/coverage/components/filter/filter_bar.tsx.html +322 -0
  10. package/coverage/components/filter/index.html +116 -0
  11. package/coverage/components/log/index.html +131 -0
  12. package/coverage/components/log/index.ts.html +88 -0
  13. package/coverage/components/log/log_message.tsx.html +391 -0
  14. package/coverage/components/prompt/index.html +116 -0
  15. package/coverage/components/prompt/prompt_renderer.tsx.html +1123 -0
  16. package/coverage/components/screen/index.html +131 -0
  17. package/coverage/components/screen/loading_message.tsx.html +217 -0
  18. package/coverage/components/screen/progress_message.tsx.html +265 -0
  19. package/coverage/components/sidebar/index.html +146 -0
  20. package/coverage/components/sidebar/sidebar.tsx.html +391 -0
  21. package/coverage/components/sidebar/sidebar_item.tsx.html +235 -0
  22. package/coverage/components/sidebar/sidebar_separator.tsx.html +124 -0
  23. package/coverage/context/index.html +131 -0
  24. package/coverage/context/index.ts.html +88 -0
  25. package/coverage/context/logger_context.tsx.html +412 -0
  26. package/coverage/coverage-final.json +55 -0
  27. package/coverage/favicon.png +0 -0
  28. package/coverage/filter/filter_engine.ts.html +424 -0
  29. package/coverage/filter/index.html +116 -0
  30. package/coverage/hooks/index.html +131 -0
  31. package/coverage/hooks/index.ts.html +88 -0
  32. package/coverage/hooks/use_theme.ts.html +121 -0
  33. package/coverage/index.html +356 -0
  34. package/coverage/keyboard/index.html +116 -0
  35. package/coverage/keyboard/keyboard_manager.ts.html +784 -0
  36. package/coverage/prettify.css +1 -0
  37. package/coverage/prettify.js +2 -0
  38. package/coverage/schemas/index.html +161 -0
  39. package/coverage/schemas/index.ts.html +94 -0
  40. package/coverage/schemas/logger-options.ts.html +124 -0
  41. package/coverage/schemas/prompt-options.ts.html +112 -0
  42. package/coverage/schemas/screen-options.ts.html +127 -0
  43. package/coverage/services/index.html +146 -0
  44. package/coverage/services/logger.ts.html +1192 -0
  45. package/coverage/services/prompt.ts.html +568 -0
  46. package/coverage/services/screen.ts.html +1804 -0
  47. package/coverage/sort-arrow-sprite.png +0 -0
  48. package/coverage/sorter.js +210 -0
  49. package/coverage/themes/dark.ts.html +604 -0
  50. package/coverage/themes/high-contrast.ts.html +619 -0
  51. package/coverage/themes/index.html +176 -0
  52. package/coverage/themes/index.ts.html +97 -0
  53. package/coverage/themes/light.ts.html +601 -0
  54. package/coverage/themes/utils.ts.html +334 -0
  55. package/coverage/tokens/index.html +161 -0
  56. package/coverage/tokens/index.ts.html +94 -0
  57. package/coverage/tokens/logger.ts.html +115 -0
  58. package/coverage/tokens/prompt.ts.html +115 -0
  59. package/coverage/tokens/screen.ts.html +115 -0
  60. package/coverage/types/file.types.ts.html +265 -0
  61. package/coverage/types/filter.types.ts.html +238 -0
  62. package/coverage/types/index.html +236 -0
  63. package/coverage/types/index.ts.html +151 -0
  64. package/coverage/types/keyboard.types.ts.html +364 -0
  65. package/coverage/types/log.types.ts.html +268 -0
  66. package/coverage/types/message.types.ts.html +445 -0
  67. package/coverage/types/prompt.types.ts.html +403 -0
  68. package/coverage/types/screen.types.ts.html +451 -0
  69. package/coverage/types/theme.types.ts.html +841 -0
  70. package/coverage/utils/colors/file-colors.ts.html +112 -0
  71. package/coverage/utils/colors/helpers.ts.html +235 -0
  72. package/coverage/utils/colors/index.html +221 -0
  73. package/coverage/utils/colors/index.ts.html +145 -0
  74. package/coverage/utils/colors/log-colors.ts.html +253 -0
  75. package/coverage/utils/colors/progress-colors.ts.html +160 -0
  76. package/coverage/utils/colors/prompt-colors.ts.html +175 -0
  77. package/coverage/utils/colors/sidebar-colors.ts.html +241 -0
  78. package/coverage/utils/colors/table-colors.ts.html +118 -0
  79. package/coverage/utils/filetype.ts.html +277 -0
  80. package/coverage/utils/format.ts.html +241 -0
  81. package/coverage/utils/index.html +161 -0
  82. package/coverage/utils/index.ts.html +118 -0
  83. package/coverage/utils/stdout-printer.ts.html +523 -0
  84. package/dist/src/components/file/file_log.d.ts +35 -0
  85. package/dist/src/components/file/file_log.d.ts.map +1 -0
  86. package/dist/src/components/file/index.d.ts +2 -0
  87. package/dist/src/components/file/index.d.ts.map +1 -0
  88. package/dist/src/components/filter/filter_bar.d.ts +10 -0
  89. package/dist/src/components/filter/filter_bar.d.ts.map +1 -0
  90. package/dist/src/components/filter/index.d.ts +2 -0
  91. package/dist/src/components/filter/index.d.ts.map +1 -0
  92. package/dist/src/components/help/help_overlay.d.ts +10 -0
  93. package/dist/src/components/help/help_overlay.d.ts.map +1 -0
  94. package/dist/src/components/help/index.d.ts +2 -0
  95. package/dist/src/components/help/index.d.ts.map +1 -0
  96. package/dist/src/components/index.d.ts +27 -0
  97. package/dist/src/components/index.d.ts.map +1 -0
  98. package/dist/src/components/log/debug_log.d.ts +3 -0
  99. package/dist/src/components/log/debug_log.d.ts.map +1 -0
  100. package/dist/src/components/log/error_log.d.ts +3 -0
  101. package/dist/src/components/log/error_log.d.ts.map +1 -0
  102. package/dist/src/components/log/fatal_log.d.ts +3 -0
  103. package/dist/src/components/log/fatal_log.d.ts.map +1 -0
  104. package/dist/src/components/log/index.d.ts +9 -0
  105. package/dist/src/components/log/index.d.ts.map +1 -0
  106. package/dist/src/components/log/info_log.d.ts +3 -0
  107. package/dist/src/components/log/info_log.d.ts.map +1 -0
  108. package/dist/src/components/log/log_message.d.ts +33 -0
  109. package/dist/src/components/log/log_message.d.ts.map +1 -0
  110. package/dist/src/components/log/success_log.d.ts +3 -0
  111. package/dist/src/components/log/success_log.d.ts.map +1 -0
  112. package/dist/src/components/log/trace_log.d.ts +3 -0
  113. package/dist/src/components/log/trace_log.d.ts.map +1 -0
  114. package/dist/src/components/log/warning_log.d.ts +3 -0
  115. package/dist/src/components/log/warning_log.d.ts.map +1 -0
  116. package/dist/src/components/prompt/index.d.ts +3 -0
  117. package/dist/src/components/prompt/index.d.ts.map +1 -0
  118. package/dist/src/components/prompt/prompt_renderer.d.ts +6 -0
  119. package/dist/src/components/prompt/prompt_renderer.d.ts.map +1 -0
  120. package/dist/src/components/screen/group_renderer.d.ts +19 -0
  121. package/dist/src/components/screen/group_renderer.d.ts.map +1 -0
  122. package/dist/src/components/screen/index.d.ts +13 -0
  123. package/dist/src/components/screen/index.d.ts.map +1 -0
  124. package/dist/src/components/screen/loading_message.d.ts +6 -0
  125. package/dist/src/components/screen/loading_message.d.ts.map +1 -0
  126. package/dist/src/components/screen/message_renderer.d.ts +8 -0
  127. package/dist/src/components/screen/message_renderer.d.ts.map +1 -0
  128. package/dist/src/components/screen/progress_message.d.ts +8 -0
  129. package/dist/src/components/screen/progress_message.d.ts.map +1 -0
  130. package/dist/src/components/screen/screen_bridge.d.ts +20 -0
  131. package/dist/src/components/screen/screen_bridge.d.ts.map +1 -0
  132. package/dist/src/components/screen/table_message.d.ts +6 -0
  133. package/dist/src/components/screen/table_message.d.ts.map +1 -0
  134. package/dist/src/components/screen_manager_bridge.d.ts +11 -0
  135. package/dist/src/components/screen_manager_bridge.d.ts.map +1 -0
  136. package/dist/src/components/sidebar/index.d.ts +6 -0
  137. package/dist/src/components/sidebar/index.d.ts.map +1 -0
  138. package/dist/src/components/sidebar/sidebar.d.ts +18 -0
  139. package/dist/src/components/sidebar/sidebar.d.ts.map +1 -0
  140. package/dist/src/components/sidebar/sidebar_item.d.ts +14 -0
  141. package/dist/src/components/sidebar/sidebar_item.d.ts.map +1 -0
  142. package/dist/src/components/sidebar/sidebar_separator.d.ts +2 -0
  143. package/dist/src/components/sidebar/sidebar_separator.d.ts.map +1 -0
  144. package/dist/src/context/logger_context.d.ts +60 -0
  145. package/dist/src/context/logger_context.d.ts.map +1 -0
  146. package/dist/src/filter/filter_engine.d.ts +20 -0
  147. package/dist/src/filter/filter_engine.d.ts.map +1 -0
  148. package/dist/src/filter/index.d.ts +4 -0
  149. package/dist/src/filter/index.d.ts.map +1 -0
  150. package/dist/src/hooks/index.d.ts +2 -0
  151. package/dist/src/hooks/index.d.ts.map +1 -0
  152. package/dist/src/hooks/use_theme.d.ts +7 -0
  153. package/dist/src/hooks/use_theme.d.ts.map +1 -0
  154. package/dist/src/index.d.ts +88 -0
  155. package/dist/src/index.d.ts.map +1 -0
  156. package/dist/src/keyboard/create_bindings.d.ts +31 -0
  157. package/dist/src/keyboard/create_bindings.d.ts.map +1 -0
  158. package/dist/src/keyboard/index.d.ts +12 -0
  159. package/dist/src/keyboard/index.d.ts.map +1 -0
  160. package/dist/src/keyboard/keyboard_manager.d.ts +69 -0
  161. package/dist/src/keyboard/keyboard_manager.d.ts.map +1 -0
  162. package/dist/src/services/index.d.ts +5 -0
  163. package/dist/src/services/index.d.ts.map +1 -0
  164. package/dist/src/services/logger.d.ts +61 -0
  165. package/dist/src/services/logger.d.ts.map +1 -0
  166. package/dist/src/services/prompt.d.ts +37 -0
  167. package/dist/src/services/prompt.d.ts.map +1 -0
  168. package/dist/src/services/screen.d.ts +165 -0
  169. package/dist/src/services/screen.d.ts.map +1 -0
  170. package/dist/src/services/screen_manager.d.ts +124 -0
  171. package/dist/src/services/screen_manager.d.ts.map +1 -0
  172. package/dist/src/themes/dark.d.ts +7 -0
  173. package/dist/src/themes/dark.d.ts.map +1 -0
  174. package/dist/src/themes/high-contrast.d.ts +7 -0
  175. package/dist/src/themes/high-contrast.d.ts.map +1 -0
  176. package/dist/src/themes/index.d.ts +18 -0
  177. package/dist/src/themes/index.d.ts.map +1 -0
  178. package/dist/src/themes/light.d.ts +6 -0
  179. package/dist/src/themes/light.d.ts.map +1 -0
  180. package/dist/src/themes/utils.d.ts +22 -0
  181. package/dist/src/themes/utils.d.ts.map +1 -0
  182. package/dist/src/types/file.types.d.ts +40 -0
  183. package/dist/src/types/file.types.d.ts.map +1 -0
  184. package/dist/src/types/filter.types.d.ts +31 -0
  185. package/dist/src/types/filter.types.d.ts.map +1 -0
  186. package/dist/src/types/index.d.ts +81 -0
  187. package/dist/src/types/index.d.ts.map +1 -0
  188. package/dist/src/types/keyboard.types.d.ts +83 -0
  189. package/dist/src/types/keyboard.types.d.ts.map +1 -0
  190. package/dist/src/types/log.types.d.ts +32 -0
  191. package/dist/src/types/log.types.d.ts.map +1 -0
  192. package/dist/src/types/message.types.d.ts +91 -0
  193. package/dist/src/types/message.types.d.ts.map +1 -0
  194. package/dist/src/types/prompt.types.d.ts +89 -0
  195. package/dist/src/types/prompt.types.d.ts.map +1 -0
  196. package/dist/src/types/screen.types.d.ts +85 -0
  197. package/dist/src/types/screen.types.d.ts.map +1 -0
  198. package/dist/src/types/theme.types.d.ts +216 -0
  199. package/dist/src/types/theme.types.d.ts.map +1 -0
  200. package/dist/src/utils/colors/file-colors.d.ts +10 -0
  201. package/dist/src/utils/colors/file-colors.d.ts.map +1 -0
  202. package/dist/src/utils/colors/helpers.d.ts +29 -0
  203. package/dist/src/utils/colors/helpers.d.ts.map +1 -0
  204. package/dist/src/utils/colors/index.d.ts +13 -0
  205. package/dist/src/utils/colors/index.d.ts.map +1 -0
  206. package/dist/src/utils/colors/log-colors.d.ts +15 -0
  207. package/dist/src/utils/colors/log-colors.d.ts.map +1 -0
  208. package/dist/src/utils/colors/progress-colors.d.ts +25 -0
  209. package/dist/src/utils/colors/progress-colors.d.ts.map +1 -0
  210. package/dist/src/utils/colors/prompt-colors.d.ts +22 -0
  211. package/dist/src/utils/colors/prompt-colors.d.ts.map +1 -0
  212. package/dist/src/utils/colors/sidebar-colors.d.ts +50 -0
  213. package/dist/src/utils/colors/sidebar-colors.d.ts.map +1 -0
  214. package/dist/src/utils/colors/table-colors.d.ts +12 -0
  215. package/dist/src/utils/colors/table-colors.d.ts.map +1 -0
  216. package/dist/src/utils/filetype.d.ts +19 -0
  217. package/dist/src/utils/filetype.d.ts.map +1 -0
  218. package/dist/src/utils/format.d.ts +9 -0
  219. package/dist/src/utils/format.d.ts.map +1 -0
  220. package/dist/src/utils/index.d.ts +20 -0
  221. package/dist/src/utils/index.d.ts.map +1 -0
  222. package/dist/src/utils/stdout-printer.d.ts +10 -0
  223. package/dist/src/utils/stdout-printer.d.ts.map +1 -0
  224. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  225. package/dist/tsconfig.tsbuildinfo +1 -0
  226. package/dist/tsdown.config.d.mts +5 -0
  227. package/dist/tsdown.config.d.mts.map +1 -0
  228. package/dist/vitest.config.d.mts +3 -0
  229. package/dist/vitest.config.d.mts.map +1 -0
  230. package/lib/index.cjs +6349 -0
  231. package/lib/index.cjs.map +1 -0
  232. package/lib/index.d.cts +1720 -0
  233. package/lib/index.d.cts.map +1 -0
  234. package/lib/index.d.mts +1720 -0
  235. package/lib/index.d.mts.map +1 -0
  236. package/lib/index.mjs +6264 -0
  237. package/lib/index.mjs.map +1 -0
  238. package/lib/screen_manager_bridge-BpDgVu3e.cjs +3357 -0
  239. package/lib/screen_manager_bridge-BpDgVu3e.cjs.map +1 -0
  240. package/lib/screen_manager_bridge-CkV7637i.cjs +3 -0
  241. package/lib/screen_manager_bridge-DN2J6_k1.mjs +3 -0
  242. package/lib/screen_manager_bridge-Dfg4QUrl.mjs +3034 -0
  243. package/lib/screen_manager_bridge-Dfg4QUrl.mjs.map +1 -0
  244. package/package.json +43 -0
  245. package/project.json +60 -0
  246. package/src/__tests__/components/__snapshots__/filter_bar.spec.tsx.snap +2245 -0
  247. package/src/__tests__/components/__snapshots__/loading_message.spec.tsx.snap +1382 -0
  248. package/src/__tests__/components/__snapshots__/log_message.spec.tsx.snap +3169 -0
  249. package/src/__tests__/components/__snapshots__/progress_message.spec.tsx.snap +1743 -0
  250. package/src/__tests__/components/__snapshots__/prompt_renderer.spec.tsx.snap +3135 -0
  251. package/src/__tests__/components/__snapshots__/sidebar.spec.tsx.snap +2617 -0
  252. package/src/__tests__/components/filter_bar.spec.tsx +190 -0
  253. package/src/__tests__/components/loading_message.spec.tsx +110 -0
  254. package/src/__tests__/components/log_message.spec.tsx +166 -0
  255. package/src/__tests__/components/progress_message.spec.tsx +147 -0
  256. package/src/__tests__/components/prompt_renderer.spec.tsx +274 -0
  257. package/src/__tests__/components/sidebar.spec.tsx +305 -0
  258. package/src/__tests__/filter/filter_engine.spec.ts +325 -0
  259. package/src/__tests__/keyboard/keyboard_manager.spec.ts +557 -0
  260. package/src/__tests__/mocks/scm-mock.ts +5 -0
  261. package/src/__tests__/services/logger.spec.ts +630 -0
  262. package/src/__tests__/services/prompt.spec.ts +411 -0
  263. package/src/__tests__/services/screen.spec.ts +721 -0
  264. package/src/__tests__/setup.ts +43 -0
  265. package/src/__tests__/utils/factories.ts +354 -0
  266. package/src/__tests__/utils/filetype.spec.ts +195 -0
  267. package/src/__tests__/utils/format.spec.ts +178 -0
  268. package/src/__tests__/utils/render-utils.tsx +39 -0
  269. package/src/__tests__/utils/test-container.ts +48 -0
  270. package/src/components/file/file_log.tsx +241 -0
  271. package/src/components/file/index.ts +1 -0
  272. package/src/components/filter/filter_bar.tsx +79 -0
  273. package/src/components/filter/index.ts +1 -0
  274. package/src/components/help/help_overlay.tsx +100 -0
  275. package/src/components/help/index.ts +1 -0
  276. package/src/components/index.ts +15 -0
  277. package/src/components/log/index.ts +1 -0
  278. package/src/components/log/log_message.tsx +102 -0
  279. package/src/components/prompt/index.ts +2 -0
  280. package/src/components/prompt/prompt_renderer.tsx +346 -0
  281. package/src/components/screen/group_renderer.tsx +64 -0
  282. package/src/components/screen/index.ts +6 -0
  283. package/src/components/screen/loading_message.tsx +44 -0
  284. package/src/components/screen/message_renderer.tsx +108 -0
  285. package/src/components/screen/progress_message.tsx +60 -0
  286. package/src/components/screen/screen_bridge.tsx +149 -0
  287. package/src/components/screen/table_message.tsx +57 -0
  288. package/src/components/screen_manager_bridge.tsx +245 -0
  289. package/src/components/sidebar/index.ts +3 -0
  290. package/src/components/sidebar/sidebar.tsx +102 -0
  291. package/src/components/sidebar/sidebar_item.tsx +50 -0
  292. package/src/components/sidebar/sidebar_separator.tsx +13 -0
  293. package/src/context/index.ts +1 -0
  294. package/src/context/logger_context.tsx +109 -0
  295. package/src/factories/index.ts +1 -0
  296. package/src/factories/screen.factory.ts +22 -0
  297. package/src/filter/filter_engine.ts +113 -0
  298. package/src/filter/index.ts +1 -0
  299. package/src/hooks/index.ts +1 -0
  300. package/src/hooks/use_theme.ts +12 -0
  301. package/src/index.ts +64 -0
  302. package/src/keyboard/create_bindings.ts +457 -0
  303. package/src/keyboard/index.ts +2 -0
  304. package/src/keyboard/keyboard_manager.ts +233 -0
  305. package/src/overrides/console.logger.override.ts +61 -0
  306. package/src/overrides/index.ts +1 -0
  307. package/src/schemas/index.ts +3 -0
  308. package/src/schemas/logger-options.ts +13 -0
  309. package/src/schemas/prompt-options.ts +9 -0
  310. package/src/schemas/screen-options.ts +14 -0
  311. package/src/services/index.ts +4 -0
  312. package/src/services/logger.ts +369 -0
  313. package/src/services/prompt.ts +169 -0
  314. package/src/services/screen.ts +590 -0
  315. package/src/services/screen_manager.tsx +390 -0
  316. package/src/themes/dark.ts +173 -0
  317. package/src/themes/high-contrast.ts +178 -0
  318. package/src/themes/index.ts +4 -0
  319. package/src/themes/light.ts +172 -0
  320. package/src/themes/utils.ts +83 -0
  321. package/src/tokens/index.ts +3 -0
  322. package/src/tokens/logger.ts +10 -0
  323. package/src/tokens/prompt.ts +10 -0
  324. package/src/tokens/screen.ts +10 -0
  325. package/src/types/file.types.ts +60 -0
  326. package/src/types/filter.types.ts +51 -0
  327. package/src/types/index.ts +22 -0
  328. package/src/types/keyboard.types.ts +93 -0
  329. package/src/types/log.types.ts +61 -0
  330. package/src/types/message.types.ts +120 -0
  331. package/src/types/prompt.types.ts +106 -0
  332. package/src/types/screen.types.ts +124 -0
  333. package/src/types/theme.types.ts +252 -0
  334. package/src/utils/colors/file-colors.ts +9 -0
  335. package/src/utils/colors/helpers.ts +50 -0
  336. package/src/utils/colors/index.ts +20 -0
  337. package/src/utils/colors/log-colors.ts +56 -0
  338. package/src/utils/colors/progress-colors.ts +25 -0
  339. package/src/utils/colors/prompt-colors.ts +30 -0
  340. package/src/utils/colors/sidebar-colors.ts +52 -0
  341. package/src/utils/colors/table-colors.ts +11 -0
  342. package/src/utils/filetype.ts +64 -0
  343. package/src/utils/format.ts +52 -0
  344. package/src/utils/index.ts +11 -0
  345. package/src/utils/stdout-printer.ts +255 -0
  346. package/tsconfig.json +14 -0
  347. package/tsdown.config.mts +34 -0
  348. package/vitest.config.mts +10 -0
@@ -0,0 +1,15 @@
1
+ // Log components
2
+ export * from './log/index.ts'
3
+
4
+ // File components
5
+ export * from './file/index.ts'
6
+
7
+ // Prompt components
8
+ export * from './prompt/index.ts'
9
+
10
+ // Screen components
11
+ export * from './screen/index.ts'
12
+ export * from './sidebar/index.ts'
13
+
14
+ // Main bridge
15
+ export * from './screen_manager_bridge.tsx'
@@ -0,0 +1 @@
1
+ export * from './log_message.tsx'
@@ -0,0 +1,102 @@
1
+ import { TextAttributes } from '@opentui/core'
2
+
3
+ import { useTheme } from '../../hooks/index.ts'
4
+ import { VARIANT_COLORS } from '../../utils/index.ts'
5
+
6
+ import type { LogMessageProps } from '../../types/index.ts'
7
+
8
+ /**
9
+ * LogMessage - A chat-like styled log message with level-based coloring.
10
+ *
11
+ * Features:
12
+ * - Left border with prominent color based on log level
13
+ * - Subtle tinted background matching the log level
14
+ * - Optional timestamp and label display
15
+ * - Supports both simple text and complex React children
16
+ * - Optional variant for semantic styling (e.g., 'success', 'trace')
17
+ *
18
+ * @example
19
+ * <LogMessage level="error">
20
+ * Connection failed: timeout after 30s
21
+ * </LogMessage>
22
+ *
23
+ * @example
24
+ * <LogMessage level="log" timestamp={new Date()} label="API">
25
+ * Request completed successfully
26
+ * </LogMessage>
27
+ *
28
+ * @example
29
+ * <LogMessage level="log" variant="success">
30
+ * Operation completed successfully
31
+ * </LogMessage>
32
+ */
33
+ export function LogMessage({
34
+ level,
35
+ variant,
36
+ children,
37
+ timestamp,
38
+ label,
39
+ trace,
40
+ borderColor: customBorderColor,
41
+ backgroundColor: customBackgroundColor,
42
+ borderStyle = 'thin',
43
+ padding = 1,
44
+ margin = 0,
45
+ }: LogMessageProps) {
46
+ const theme = useTheme()
47
+
48
+ // Get colors: variant colors take precedence over level colors
49
+ const levelColors = variant ? VARIANT_COLORS[variant] : theme.logLevels[level]
50
+
51
+ // Resolve final colors (custom overrides level colors)
52
+ const borderColor = customBorderColor ?? levelColors.border
53
+ const backgroundColor = customBackgroundColor ?? levelColors.background
54
+
55
+ // Text color: use level-specific text color if defined, otherwise use foreground
56
+ const textColor = levelColors.text ?? theme.colors.foreground
57
+
58
+ // Determine border sides based on style
59
+ const borderSides: ('left' | 'top' | 'bottom')[] =
60
+ borderStyle === 'thin' ? ['left'] : ['left', 'top', 'bottom']
61
+
62
+ // Format timestamp if provided
63
+ const formattedTimestamp = timestamp
64
+ ? timestamp instanceof Date
65
+ ? timestamp.toLocaleTimeString()
66
+ : timestamp
67
+ : null
68
+
69
+ return (
70
+ <box
71
+ flexDirection="column"
72
+ border={borderSides}
73
+ borderColor={borderColor}
74
+ backgroundColor={backgroundColor}
75
+ paddingLeft={padding}
76
+ paddingRight={padding}
77
+ marginBottom={margin}
78
+ >
79
+ {/* Header row with timestamp and label */}
80
+ {(formattedTimestamp || label) && (
81
+ <box flexDirection="row" gap={1}>
82
+ {formattedTimestamp && <text fg={theme.colors.muted}>{formattedTimestamp}</text>}
83
+ {label && (
84
+ <text fg={levelColors.border} attributes={TextAttributes.BOLD}>
85
+ [{label}]
86
+ </text>
87
+ )}
88
+ </box>
89
+ )}
90
+
91
+ {/* Message content */}
92
+ <text fg={textColor}>{children}</text>
93
+
94
+ {/* Stack trace (for trace level) */}
95
+ {trace && (
96
+ <box marginTop={1}>
97
+ <text fg={theme.colors.muted}>{trace}</text>
98
+ </box>
99
+ )}
100
+ </box>
101
+ )
102
+ }
@@ -0,0 +1,2 @@
1
+ export { PromptRenderer } from './prompt_renderer.tsx'
2
+ export type { PromptRendererProps } from './prompt_renderer.tsx'
@@ -0,0 +1,346 @@
1
+ import { TextAttributes } from '@opentui/core'
2
+
3
+ import { useTheme } from '../../hooks/index.ts'
4
+
5
+ import type {
6
+ PromptData,
7
+ ChoicePromptData,
8
+ ConfirmPromptData,
9
+ InputPromptData,
10
+ MultiChoicePromptData,
11
+ PromptTheme,
12
+ } from '../../types/index.ts'
13
+
14
+ export interface PromptRendererProps {
15
+ prompt: PromptData
16
+ }
17
+
18
+ export function PromptRenderer({ prompt }: PromptRendererProps) {
19
+ const theme = useTheme()
20
+ // Calculate timeout remaining if applicable
21
+ const timeoutRemaining = getTimeoutRemaining(prompt)
22
+
23
+ switch (prompt.type) {
24
+ case 'choice':
25
+ return (
26
+ <ChoicePromptRenderer
27
+ prompt={prompt}
28
+ timeoutRemaining={timeoutRemaining}
29
+ colors={theme.prompt}
30
+ />
31
+ )
32
+ case 'confirm':
33
+ return (
34
+ <ConfirmPromptRenderer
35
+ prompt={prompt}
36
+ timeoutRemaining={timeoutRemaining}
37
+ colors={theme.prompt}
38
+ />
39
+ )
40
+ case 'input':
41
+ return (
42
+ <InputPromptRenderer
43
+ prompt={prompt}
44
+ timeoutRemaining={timeoutRemaining}
45
+ colors={theme.prompt}
46
+ />
47
+ )
48
+ case 'multiChoice':
49
+ return (
50
+ <MultiChoicePromptRenderer
51
+ prompt={prompt}
52
+ timeoutRemaining={timeoutRemaining}
53
+ colors={theme.prompt}
54
+ />
55
+ )
56
+ default:
57
+ return null
58
+ }
59
+ }
60
+
61
+ function getTimeoutRemaining(prompt: PromptData): number | null {
62
+ if (!prompt.timeout || !prompt.timeoutStarted) return null
63
+ const elapsed = Date.now() - prompt.timeoutStarted
64
+ const remaining = Math.max(0, prompt.timeout - elapsed)
65
+ return Math.ceil(remaining / 1000)
66
+ }
67
+
68
+ function TimeoutIndicator({ seconds, colors }: { seconds: number | null; colors: PromptTheme }) {
69
+ if (seconds === null) return null
70
+ return (
71
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
72
+ {' '}
73
+ (auto-select in {seconds}s)
74
+ </text>
75
+ )
76
+ }
77
+
78
+ interface ChoicePromptRendererProps {
79
+ prompt: ChoicePromptData
80
+ timeoutRemaining: number | null
81
+ colors: PromptTheme
82
+ }
83
+
84
+ function ChoicePromptRenderer({ prompt, timeoutRemaining, colors }: ChoicePromptRendererProps) {
85
+ return (
86
+ <box
87
+ flexDirection="column"
88
+ borderColor={colors.focusBorder}
89
+ border={['left']}
90
+ paddingLeft={1}
91
+ paddingRight={1}
92
+ gap={1}
93
+ >
94
+ {/* Question */}
95
+ <box flexDirection="row">
96
+ <text fg={colors.question} attributes={TextAttributes.BOLD}>
97
+ ? {prompt.question}
98
+ </text>
99
+ <TimeoutIndicator seconds={timeoutRemaining} colors={colors} />
100
+ </box>
101
+
102
+ {/* Choices */}
103
+ <box flexDirection="column">
104
+ {prompt.choices.map((choice, index) => {
105
+ const isSelected = index === prompt.selectedIndex
106
+ const showInput = isSelected && choice.input && prompt.inputMode
107
+
108
+ return (
109
+ <box key={choice.value} flexDirection="row">
110
+ {/* Selection indicator */}
111
+ <text fg={isSelected ? colors.optionSelected : 'transparent'}>{'>'} </text>
112
+
113
+ {/* Choice label */}
114
+ <text
115
+ fg={isSelected ? colors.optionText : colors.optionTextDim}
116
+ attributes={isSelected ? TextAttributes.BOLD : undefined}
117
+ >
118
+ {choice.label}
119
+ </text>
120
+
121
+ {/* Input field (if applicable) */}
122
+ {showInput && (
123
+ <box flexDirection="row" marginLeft={1}>
124
+ <text fg={colors.inputText}>: </text>
125
+ <text fg={colors.inputText}>{prompt.inputValue}</text>
126
+ <text fg={colors.inputCursor} attributes={TextAttributes.BLINK}>
127
+ _
128
+ </text>
129
+ </box>
130
+ )}
131
+
132
+ {/* Show hint for input option when selected but not in input mode */}
133
+ {isSelected && choice.input && !prompt.inputMode && (
134
+ <text fg={colors.optionTextDim}> (press Enter to type)</text>
135
+ )}
136
+ </box>
137
+ )
138
+ })}
139
+ </box>
140
+
141
+ {/* Instructions */}
142
+ {prompt.inputMode ? (
143
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
144
+ Type your answer, Enter to submit, Esc to cancel
145
+ </text>
146
+ ) : (
147
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
148
+ ↑/↓ to navigate, Enter to select
149
+ </text>
150
+ )}
151
+ </box>
152
+ )
153
+ }
154
+
155
+ interface ConfirmPromptRendererProps {
156
+ prompt: ConfirmPromptData
157
+ timeoutRemaining: number | null
158
+ colors: PromptTheme
159
+ }
160
+
161
+ function ConfirmPromptRenderer({ prompt, timeoutRemaining, colors }: ConfirmPromptRendererProps) {
162
+ const confirmSelected = prompt.selectedValue === true
163
+ const cancelSelected = prompt.selectedValue === false
164
+
165
+ return (
166
+ <box
167
+ flexDirection="column"
168
+ borderColor={colors.focusBorder}
169
+ border={['left']}
170
+ paddingLeft={1}
171
+ paddingRight={1}
172
+ gap={1}
173
+ >
174
+ {/* Question */}
175
+ <box flexDirection="row">
176
+ <text fg={colors.question} attributes={TextAttributes.BOLD}>
177
+ ? {prompt.question}
178
+ </text>
179
+ <TimeoutIndicator seconds={timeoutRemaining} colors={colors} />
180
+ </box>
181
+
182
+ {/* Buttons */}
183
+ <box flexDirection="row" gap={2}>
184
+ {/* Confirm button */}
185
+ <box
186
+ backgroundColor={confirmSelected ? colors.buttonSelectedBackground : undefined}
187
+ paddingLeft={1}
188
+ paddingRight={1}
189
+ >
190
+ <text
191
+ fg={confirmSelected ? colors.confirmButton : colors.optionTextDim}
192
+ attributes={confirmSelected ? TextAttributes.BOLD : undefined}
193
+ >
194
+ {confirmSelected ? '>' : ' '} {prompt.confirmText}
195
+ </text>
196
+ </box>
197
+
198
+ {/* Cancel button */}
199
+ <box
200
+ backgroundColor={cancelSelected ? colors.buttonSelectedBackground : undefined}
201
+ paddingLeft={1}
202
+ paddingRight={1}
203
+ >
204
+ <text
205
+ fg={cancelSelected ? colors.cancelButton : colors.optionTextDim}
206
+ attributes={cancelSelected ? TextAttributes.BOLD : undefined}
207
+ >
208
+ {cancelSelected ? '>' : ' '} {prompt.cancelText}
209
+ </text>
210
+ </box>
211
+ </box>
212
+
213
+ {/* Instructions */}
214
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
215
+ ←/→ to select, Enter to confirm
216
+ </text>
217
+ </box>
218
+ )
219
+ }
220
+
221
+ interface InputPromptRendererProps {
222
+ prompt: InputPromptData
223
+ timeoutRemaining: number | null
224
+ colors: PromptTheme
225
+ }
226
+
227
+ function InputPromptRenderer({ prompt, timeoutRemaining, colors }: InputPromptRendererProps) {
228
+ const hasValue = prompt.value.length > 0
229
+
230
+ return (
231
+ <box
232
+ flexDirection="column"
233
+ borderColor={colors.focusBorder}
234
+ border={['left']}
235
+ paddingLeft={1}
236
+ paddingRight={1}
237
+ gap={1}
238
+ >
239
+ {/* Question */}
240
+ <box flexDirection="row">
241
+ <text fg={colors.question} attributes={TextAttributes.BOLD}>
242
+ ? {prompt.question}
243
+ </text>
244
+ <TimeoutIndicator seconds={timeoutRemaining} colors={colors} />
245
+ </box>
246
+
247
+ {/* Input field */}
248
+ <box flexDirection="row" borderColor={colors.inputBorder} border={['left']} paddingLeft={1}>
249
+ <text fg={hasValue ? colors.inputText : colors.inputPlaceholder}>
250
+ {hasValue ? prompt.value : prompt.placeholder}
251
+ </text>
252
+ <text fg={colors.inputCursor} attributes={TextAttributes.BLINK}>
253
+ _
254
+ </text>
255
+ </box>
256
+
257
+ {/* Instructions */}
258
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
259
+ Type your answer, Enter to submit
260
+ </text>
261
+ </box>
262
+ )
263
+ }
264
+
265
+ interface MultiChoicePromptRendererProps {
266
+ prompt: MultiChoicePromptData
267
+ timeoutRemaining: number | null
268
+ colors: PromptTheme
269
+ }
270
+
271
+ function MultiChoicePromptRenderer({
272
+ prompt,
273
+ timeoutRemaining,
274
+ colors,
275
+ }: MultiChoicePromptRendererProps) {
276
+ const selectedCount = prompt.selectedIndices.size
277
+ const canSubmit = selectedCount >= prompt.minSelect
278
+
279
+ return (
280
+ <box
281
+ flexDirection="column"
282
+ borderColor={colors.focusBorder}
283
+ border={['left']}
284
+ paddingLeft={1}
285
+ paddingRight={1}
286
+ gap={1}
287
+ >
288
+ {/* Question */}
289
+ <box flexDirection="row">
290
+ <text fg={colors.question} attributes={TextAttributes.BOLD}>
291
+ ? {prompt.question}
292
+ </text>
293
+ <text fg={colors.optionTextDim}>
294
+ {' '}
295
+ ({selectedCount}/{prompt.maxSelect} selected)
296
+ </text>
297
+ <TimeoutIndicator seconds={timeoutRemaining} colors={colors} />
298
+ </box>
299
+
300
+ {/* Choices */}
301
+ <box flexDirection="column">
302
+ {prompt.choices.map((choice, index) => {
303
+ const isFocused = index === prompt.focusedIndex
304
+ const isChecked = prompt.selectedIndices.has(index)
305
+
306
+ return (
307
+ <box key={choice.value} flexDirection="row">
308
+ {/* Focus indicator */}
309
+ <text fg={isFocused ? colors.optionSelected : 'transparent'}>{'>'} </text>
310
+
311
+ {/* Checkbox */}
312
+ <text fg={isChecked ? colors.optionSelected : colors.optionTextDim}>
313
+ {isChecked ? '[✓]' : '[ ]'}{' '}
314
+ </text>
315
+
316
+ {/* Choice label */}
317
+ <text
318
+ fg={isFocused ? colors.optionText : colors.optionTextDim}
319
+ attributes={isFocused ? TextAttributes.BOLD : undefined}
320
+ >
321
+ {choice.label}
322
+ </text>
323
+ </box>
324
+ )
325
+ })}
326
+ </box>
327
+
328
+ {/* Instructions */}
329
+ <box flexDirection="column">
330
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
331
+ ↑/↓ to navigate, Space to toggle
332
+ </text>
333
+ {canSubmit ? (
334
+ <text fg={colors.optionTextDim} attributes={TextAttributes.DIM}>
335
+ Enter to confirm
336
+ </text>
337
+ ) : (
338
+ <text fg={colors.cancelButton} attributes={TextAttributes.DIM}>
339
+ Select at least {prompt.minSelect} option
340
+ {prompt.minSelect > 1 ? 's' : ''}
341
+ </text>
342
+ )}
343
+ </box>
344
+ </box>
345
+ )
346
+ }
@@ -0,0 +1,64 @@
1
+ import { TextAttributes } from '@opentui/core'
2
+
3
+ import { useTheme } from '../../hooks/index.ts'
4
+
5
+ import type { MessageData, GroupMessageData } from '../../types/index.ts'
6
+
7
+ import { MessageRenderer } from './message_renderer.tsx'
8
+
9
+ export interface GroupRendererProps {
10
+ label: string
11
+ messages: MessageData[]
12
+ }
13
+
14
+ export function GroupRenderer({ label, messages }: GroupRendererProps) {
15
+ const theme = useTheme()
16
+
17
+ return (
18
+ <box
19
+ flexDirection="column"
20
+ border={['left']}
21
+ borderColor={theme.group.border}
22
+ backgroundColor={theme.group.background}
23
+ paddingLeft={1}
24
+ >
25
+ {/* Group header */}
26
+ <box flexDirection="row" marginBottom={1}>
27
+ <text fg={theme.group.icon}>▼ </text>
28
+ <text fg={theme.group.headerText} attributes={TextAttributes.BOLD}>
29
+ {label}
30
+ </text>
31
+ </box>
32
+
33
+ {/* Group content */}
34
+ <box flexDirection="column" gap={1}>
35
+ {messages.map((msg) => (
36
+ <MessageRenderer key={msg.id} message={msg} />
37
+ ))}
38
+ </box>
39
+ </box>
40
+ )
41
+ }
42
+
43
+ export interface GroupMessageRendererProps {
44
+ message: GroupMessageData
45
+ }
46
+
47
+ /**
48
+ * Fallback renderer for group markers (when not processed at higher level)
49
+ */
50
+ export function GroupMessageRenderer({ message }: GroupMessageRendererProps) {
51
+ const theme = useTheme()
52
+
53
+ if (message.isEnd) {
54
+ return null
55
+ }
56
+
57
+ return (
58
+ <box flexDirection="row" borderColor={theme.group.border} border={['left']} paddingLeft={1}>
59
+ <text fg={theme.group.headerText} attributes={TextAttributes.BOLD}>
60
+ ▼ {message.label}
61
+ </text>
62
+ </box>
63
+ )
64
+ }
@@ -0,0 +1,6 @@
1
+ export * from './screen_bridge.tsx'
2
+ export * from './message_renderer.tsx'
3
+ export * from './loading_message.tsx'
4
+ export * from './progress_message.tsx'
5
+ export * from './group_renderer.tsx'
6
+ export * from './table_message.tsx'
@@ -0,0 +1,44 @@
1
+ import { useState, useEffect, useRef } from 'react'
2
+
3
+ import { LogMessage } from '../log/index.ts'
4
+
5
+ import type { LoadingMessageData, LogMessageVariant } from '../../types/index.ts'
6
+
7
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
8
+
9
+ export interface LoadingMessageProps {
10
+ message: LoadingMessageData
11
+ }
12
+
13
+ export function LoadingMessage({ message }: LoadingMessageProps) {
14
+ const [frameIndex, setFrameIndex] = useState(0)
15
+ const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
16
+
17
+ useEffect(() => {
18
+ if (message.status === 'loading') {
19
+ intervalRef.current = setInterval(() => {
20
+ setFrameIndex((prev) => (prev + 1) % SPINNER_FRAMES.length)
21
+ }, 80)
22
+ }
23
+
24
+ return () => {
25
+ if (intervalRef.current) {
26
+ clearInterval(intervalRef.current)
27
+ }
28
+ }
29
+ }, [message.status])
30
+
31
+ // Map loading status to log level and variant for display
32
+ const level = message.status === 'fail' ? 'error' : 'log'
33
+ const variant: LogMessageVariant | undefined = message.status === 'success' ? 'success' : undefined
34
+
35
+ const displayContent = message.resolvedContent ?? message.content
36
+ const spinner = message.status === 'loading' ? SPINNER_FRAMES[frameIndex] + ' ' : ''
37
+
38
+ return (
39
+ <LogMessage level={level} variant={variant} timestamp={message.timestamp}>
40
+ {spinner}
41
+ {displayContent}
42
+ </LogMessage>
43
+ )
44
+ }
@@ -0,0 +1,108 @@
1
+ import { useTheme } from '../../hooks/index.ts'
2
+ import { FileLog } from '../file/index.ts'
3
+ import { LogMessage } from '../log/index.ts'
4
+
5
+ import type {
6
+ MessageData,
7
+ LoadingMessageData,
8
+ ProgressMessageData,
9
+ GroupMessageData,
10
+ TableMessageData,
11
+ } from '../../types/index.ts'
12
+
13
+ import { GroupMessageRenderer } from './group_renderer.tsx'
14
+ import { LoadingMessage } from './loading_message.tsx'
15
+ import { ProgressMessage } from './progress_message.tsx'
16
+ import { TableMessage } from './table_message.tsx'
17
+
18
+ export interface MessageRendererProps {
19
+ message: MessageData
20
+ }
21
+
22
+ export function MessageRenderer({ message }: MessageRendererProps) {
23
+ const theme = useTheme()
24
+
25
+ switch (message.type) {
26
+ case 'log':
27
+ return (
28
+ <LogMessage
29
+ level={message.level}
30
+ timestamp={message.timestamp}
31
+ variant={message.variant}
32
+ label={message.label}
33
+ trace={message.trace}
34
+ >
35
+ {message.content}
36
+ </LogMessage>
37
+ )
38
+
39
+ case 'file':
40
+ return (
41
+ <box
42
+ flexDirection="column"
43
+ border={['left']}
44
+ borderColor={theme.file.border}
45
+ backgroundColor={theme.file.background}
46
+ >
47
+ <FileLog
48
+ mode="full"
49
+ filePath={message.filePath}
50
+ content={message.content}
51
+ headerBackgroundColor={theme.file.headerBackground}
52
+ />
53
+ </box>
54
+ )
55
+
56
+ case 'diff':
57
+ return (
58
+ <box
59
+ flexDirection="column"
60
+ border={['left']}
61
+ borderColor={theme.file.border}
62
+ backgroundColor={theme.file.background}
63
+ >
64
+ <FileLog
65
+ mode="diff"
66
+ filePath={message.filePath}
67
+ diff={message.diff}
68
+ view={message.view}
69
+ headerBackgroundColor={theme.file.headerBackground}
70
+ />
71
+ </box>
72
+ )
73
+
74
+ case 'fileError':
75
+ return (
76
+ <box
77
+ flexDirection="column"
78
+ border={['left']}
79
+ borderColor={theme.file.border}
80
+ backgroundColor={theme.file.background}
81
+ >
82
+ <FileLog
83
+ mode="partial"
84
+ filePath={message.filePath}
85
+ content={message.content}
86
+ startLine={message.startLine}
87
+ errorLines={message.errorLines}
88
+ headerBackgroundColor={theme.file.headerBackground}
89
+ />
90
+ </box>
91
+ )
92
+
93
+ case 'loading':
94
+ return <LoadingMessage message={message as LoadingMessageData} />
95
+
96
+ case 'progress':
97
+ return <ProgressMessage message={message as ProgressMessageData} />
98
+
99
+ case 'group':
100
+ return <GroupMessageRenderer message={message as GroupMessageData} />
101
+
102
+ case 'table':
103
+ return <TableMessage message={message as TableMessageData} />
104
+
105
+ default:
106
+ return null
107
+ }
108
+ }