@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,721 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ import { ScreenInstance } from '../../services/screen.ts'
4
+ import {
5
+ createChoicePrompt,
6
+ createConfirmPrompt,
7
+ createInputPrompt,
8
+ createLogMessage,
9
+ createMultiChoicePrompt,
10
+ } from '../utils/factories.ts'
11
+
12
+ import type { ScreenManager } from '../../services/screen_manager.tsx'
13
+
14
+ describe('ScreenInstance', () => {
15
+ let screen: ScreenInstance
16
+
17
+ beforeEach(() => {
18
+ screen = new ScreenInstance('test-id', { name: 'Test Screen' })
19
+ })
20
+
21
+ describe('construction and getters', () => {
22
+ it('should set id from constructor', () => {
23
+ expect(screen.getId()).toBe('test-id')
24
+ })
25
+
26
+ it('should set name from options', () => {
27
+ expect(screen.getName()).toBe('Test Screen')
28
+ })
29
+
30
+ it('should set icon from options', () => {
31
+ const screenWithIcon = new ScreenInstance('id', { name: 'Test', icon: '📦' })
32
+ expect(screenWithIcon.getIcon()).toBe('📦')
33
+ })
34
+
35
+ it('should return undefined icon when not set', () => {
36
+ expect(screen.getIcon()).toBeUndefined()
37
+ })
38
+
39
+ it('should set badgeCount from options', () => {
40
+ const screenWithBadge = new ScreenInstance('id', { name: 'Test', badgeCount: 5 })
41
+ expect(screenWithBadge.getBadgeCount()).toBe(5)
42
+ })
43
+
44
+ it('should default badgeCount to 0', () => {
45
+ expect(screen.getBadgeCount()).toBe(0)
46
+ })
47
+
48
+ it('should default hidden to false', () => {
49
+ expect(screen.isHidden()).toBe(false)
50
+ })
51
+
52
+ it('should set hidden from options', () => {
53
+ const hiddenScreen = new ScreenInstance('id', { name: 'Test', hidden: true })
54
+ expect(hiddenScreen.isHidden()).toBe(true)
55
+ })
56
+
57
+ it('should default status to waiting', () => {
58
+ expect(screen.getStatus()).toBe('waiting')
59
+ })
60
+ })
61
+
62
+ describe('setBadgeCount', () => {
63
+ it('should update badge count', () => {
64
+ screen.setBadgeCount(10)
65
+ expect(screen.getBadgeCount()).toBe(10)
66
+ })
67
+
68
+ it('should be chainable', () => {
69
+ const result = screen.setBadgeCount(5)
70
+ expect(result).toBe(screen)
71
+ })
72
+
73
+ it('should notify change listeners', () => {
74
+ const listener = vi.fn()
75
+ screen.onChange(listener)
76
+
77
+ screen.setBadgeCount(3)
78
+
79
+ expect(listener).toHaveBeenCalled()
80
+ })
81
+ })
82
+
83
+ describe('setHidden / show / hide', () => {
84
+ it('should toggle hidden state with setHidden', () => {
85
+ screen.setHidden(true)
86
+ expect(screen.isHidden()).toBe(true)
87
+
88
+ screen.setHidden(false)
89
+ expect(screen.isHidden()).toBe(false)
90
+ })
91
+
92
+ it('should show screen', () => {
93
+ screen.setHidden(true)
94
+ screen.show()
95
+ expect(screen.isHidden()).toBe(false)
96
+ })
97
+
98
+ it('should hide screen', () => {
99
+ screen.hide()
100
+ expect(screen.isHidden()).toBe(true)
101
+ })
102
+
103
+ it('should be chainable', () => {
104
+ expect(screen.setHidden(true)).toBe(screen)
105
+ expect(screen.show()).toBe(screen)
106
+ expect(screen.hide()).toBe(screen)
107
+ })
108
+
109
+ it('should notify change listeners', () => {
110
+ const listener = vi.fn()
111
+ screen.onChange(listener)
112
+
113
+ screen.setHidden(true)
114
+
115
+ expect(listener).toHaveBeenCalled()
116
+ })
117
+ })
118
+
119
+ describe('setStatus', () => {
120
+ it('should update status', () => {
121
+ screen.setStatus('pending')
122
+ expect(screen.getStatus()).toBe('pending')
123
+
124
+ screen.setStatus('success')
125
+ expect(screen.getStatus()).toBe('success')
126
+ })
127
+
128
+ it('should be chainable', () => {
129
+ const result = screen.setStatus('fail')
130
+ expect(result).toBe(screen)
131
+ })
132
+
133
+ it('should notify change listeners', () => {
134
+ const listener = vi.fn()
135
+ screen.onChange(listener)
136
+
137
+ screen.setStatus('success')
138
+
139
+ expect(listener).toHaveBeenCalled()
140
+ })
141
+
142
+ it('should call manager.onScreenCompleted when transitioning to success', () => {
143
+ const mockManager = {
144
+ onScreenCompleted: vi.fn(),
145
+ onScreenVisibilityChanged: vi.fn(),
146
+ onScreenPromptActivated: vi.fn(),
147
+ isTuiBound: vi.fn(() => true),
148
+ } as unknown as ScreenManager
149
+
150
+ screen._setManager(mockManager)
151
+ screen.setStatus('success')
152
+
153
+ expect(mockManager.onScreenCompleted).toHaveBeenCalledWith(screen)
154
+ })
155
+
156
+ it('should call manager.onScreenCompleted when transitioning to fail', () => {
157
+ const mockManager = {
158
+ onScreenCompleted: vi.fn(),
159
+ onScreenVisibilityChanged: vi.fn(),
160
+ onScreenPromptActivated: vi.fn(),
161
+ isTuiBound: vi.fn(() => true),
162
+ } as unknown as ScreenManager
163
+
164
+ screen._setManager(mockManager)
165
+ screen.setStatus('fail')
166
+
167
+ expect(mockManager.onScreenCompleted).toHaveBeenCalledWith(screen)
168
+ })
169
+
170
+ it('should not call onScreenCompleted when already complete', () => {
171
+ const mockManager = {
172
+ onScreenCompleted: vi.fn(),
173
+ onScreenVisibilityChanged: vi.fn(),
174
+ onScreenPromptActivated: vi.fn(),
175
+ isTuiBound: vi.fn(() => true),
176
+ } as unknown as ScreenManager
177
+
178
+ screen._setManager(mockManager)
179
+ screen.setStatus('success')
180
+ screen.setStatus('fail') // Already complete
181
+
182
+ expect(mockManager.onScreenCompleted).toHaveBeenCalledTimes(1)
183
+ })
184
+ })
185
+
186
+ describe('isComplete', () => {
187
+ it('should return false for waiting status', () => {
188
+ expect(screen.isComplete()).toBe(false)
189
+ })
190
+
191
+ it('should return false for pending status', () => {
192
+ screen.setStatus('pending')
193
+ expect(screen.isComplete()).toBe(false)
194
+ })
195
+
196
+ it('should return true for success status', () => {
197
+ screen.setStatus('success')
198
+ expect(screen.isComplete()).toBe(true)
199
+ })
200
+
201
+ it('should return true for fail status', () => {
202
+ screen.setStatus('fail')
203
+ expect(screen.isComplete()).toBe(true)
204
+ })
205
+ })
206
+
207
+ describe('message management', () => {
208
+ it('should add message to array', () => {
209
+ const message = createLogMessage()
210
+ screen.addMessage(message)
211
+
212
+ expect(screen.getMessages()).toHaveLength(1)
213
+ expect(screen.getMessages()[0]).toEqual(message)
214
+ })
215
+
216
+ it('should return copy of messages array', () => {
217
+ const message = createLogMessage()
218
+ screen.addMessage(message)
219
+
220
+ const messages1 = screen.getMessages()
221
+ const messages2 = screen.getMessages()
222
+
223
+ expect(messages1).not.toBe(messages2)
224
+ expect(messages1).toEqual(messages2)
225
+ })
226
+
227
+ it('should notify change listeners when adding message', () => {
228
+ const listener = vi.fn()
229
+ screen.onChange(listener)
230
+
231
+ screen.addMessage(createLogMessage())
232
+
233
+ expect(listener).toHaveBeenCalled()
234
+ })
235
+
236
+ it('should update message by id', () => {
237
+ const message = createLogMessage({ id: 'msg-1', content: 'Original' })
238
+ screen.addMessage(message)
239
+
240
+ screen.updateMessage('msg-1', { content: 'Updated' } as any)
241
+
242
+ const messages = screen.getMessages()
243
+ expect((messages[0] as any).content).toBe('Updated')
244
+ })
245
+
246
+ it('should not update if id not found', () => {
247
+ const message = createLogMessage({ id: 'msg-1', content: 'Original' })
248
+ screen.addMessage(message)
249
+
250
+ screen.updateMessage('nonexistent', { content: 'Updated' } as any)
251
+
252
+ const messages = screen.getMessages()
253
+ expect((messages[0] as any).content).toBe('Original')
254
+ })
255
+
256
+ it('should update progress message by id', () => {
257
+ const message = {
258
+ id: 'progress-1',
259
+ type: 'progress' as const,
260
+ timestamp: new Date(),
261
+ label: 'Processing',
262
+ current: 0,
263
+ total: 100,
264
+ status: 'active' as const,
265
+ }
266
+ screen.addMessage(message)
267
+
268
+ screen.updateProgressMessage('progress-1', { current: 50 })
269
+
270
+ const messages = screen.getMessages()
271
+ expect((messages[0] as any).current).toBe(50)
272
+ })
273
+
274
+ it('should clear all messages', () => {
275
+ screen.addMessage(createLogMessage())
276
+ screen.addMessage(createLogMessage())
277
+ screen.addMessage(createLogMessage())
278
+
279
+ expect(screen.getMessages()).toHaveLength(3)
280
+
281
+ screen.clear()
282
+
283
+ expect(screen.getMessages()).toHaveLength(0)
284
+ })
285
+
286
+ it('should be chainable (clear)', () => {
287
+ const result = screen.clear()
288
+ expect(result).toBe(screen)
289
+ })
290
+ })
291
+
292
+ describe('prompt queue system', () => {
293
+ let mockManager: ScreenManager
294
+
295
+ beforeEach(() => {
296
+ mockManager = {
297
+ isTuiBound: vi.fn(() => true),
298
+ onScreenPromptActivated: vi.fn(),
299
+ } as unknown as ScreenManager
300
+ })
301
+
302
+ it('should return Promise from _addPrompt', () => {
303
+ screen._setManager(mockManager)
304
+ const prompt = createChoicePrompt()
305
+ const result = screen._addPrompt(prompt)
306
+
307
+ expect(result).toBeInstanceOf(Promise)
308
+ })
309
+
310
+ it('should return active prompt after adding', () => {
311
+ screen._setManager(mockManager)
312
+ const prompt = createChoicePrompt()
313
+ screen._addPrompt(prompt)
314
+
315
+ expect(screen.getActivePrompt()).toEqual(prompt)
316
+ })
317
+
318
+ it('should return true for hasActivePrompt when prompt exists', () => {
319
+ screen._setManager(mockManager)
320
+ const prompt = createChoicePrompt()
321
+ screen._addPrompt(prompt)
322
+
323
+ expect(screen.hasActivePrompt()).toBe(true)
324
+ })
325
+
326
+ it('should return false for hasActivePrompt when no prompt', () => {
327
+ expect(screen.hasActivePrompt()).toBe(false)
328
+ })
329
+
330
+ it('should queue multiple prompts', () => {
331
+ screen._setManager(mockManager)
332
+ const prompt1 = createChoicePrompt({ question: 'First?' })
333
+ const prompt2 = createChoicePrompt({ question: 'Second?' })
334
+
335
+ screen._addPrompt(prompt1)
336
+ screen._addPrompt(prompt2)
337
+
338
+ // First prompt should be active
339
+ expect(screen.getActivePrompt()?.question).toBe('First?')
340
+ })
341
+
342
+ it('should resolve with default immediately in non-interactive mode', async () => {
343
+ // No manager bound = non-interactive mode
344
+ const prompt = createChoicePrompt({ defaultChoice: 'default-value' })
345
+
346
+ const result = await screen._addPrompt(prompt)
347
+
348
+ expect(result).toBe('default-value')
349
+ })
350
+ })
351
+
352
+ describe('prompt navigation', () => {
353
+ describe('choice prompts', () => {
354
+ beforeEach(() => {
355
+ const prompt = createChoicePrompt({
356
+ choices: [
357
+ { label: 'A', value: 'a' },
358
+ { label: 'B', value: 'b' },
359
+ { label: 'C', value: 'c' },
360
+ ],
361
+ selectedIndex: 0,
362
+ })
363
+ // Need to mock manager to prevent immediate resolution
364
+ const mockManager = {
365
+ isTuiBound: vi.fn(() => true),
366
+ onScreenPromptActivated: vi.fn(),
367
+ } as unknown as ScreenManager
368
+ screen._setManager(mockManager)
369
+ screen._addPrompt(prompt)
370
+ })
371
+
372
+ it('should update selection with updatePromptSelection', () => {
373
+ screen.updatePromptSelection(2)
374
+ expect(screen.getActivePrompt()?.selectedIndex).toBe(2)
375
+ })
376
+
377
+ it('should clamp selection to valid range (min)', () => {
378
+ screen.updatePromptSelection(-5)
379
+ expect(screen.getActivePrompt()?.selectedIndex).toBe(0)
380
+ })
381
+
382
+ it('should clamp selection to valid range (max)', () => {
383
+ screen.updatePromptSelection(100)
384
+ expect(screen.getActivePrompt()?.selectedIndex).toBe(2)
385
+ })
386
+
387
+ it('should navigate up', () => {
388
+ screen.updatePromptSelection(2)
389
+ screen.promptNavigateUp()
390
+ expect(screen.getActivePrompt()?.selectedIndex).toBe(1)
391
+ })
392
+
393
+ it('should navigate down', () => {
394
+ screen.promptNavigateDown()
395
+ expect(screen.getActivePrompt()?.selectedIndex).toBe(1)
396
+ })
397
+ })
398
+
399
+ describe('confirm prompts', () => {
400
+ beforeEach(() => {
401
+ const prompt = createConfirmPrompt({ selectedValue: true })
402
+ const mockManager = {
403
+ isTuiBound: vi.fn(() => true),
404
+ onScreenPromptActivated: vi.fn(),
405
+ } as unknown as ScreenManager
406
+ screen._setManager(mockManager)
407
+ screen._addPrompt(prompt)
408
+ })
409
+
410
+ it('should navigate left (select true)', () => {
411
+ const prompt = screen.getActivePrompt() as any
412
+ prompt.selectedValue = false
413
+
414
+ screen.promptNavigateLeft()
415
+
416
+ expect(screen.getActivePrompt()?.selectedValue).toBe(true)
417
+ })
418
+
419
+ it('should navigate right (select false)', () => {
420
+ screen.promptNavigateRight()
421
+ expect(screen.getActivePrompt()?.selectedValue).toBe(false)
422
+ })
423
+ })
424
+
425
+ describe('multiChoice prompts', () => {
426
+ beforeEach(() => {
427
+ const prompt = createMultiChoicePrompt({
428
+ choices: [
429
+ { label: 'A', value: 'a' },
430
+ { label: 'B', value: 'b' },
431
+ { label: 'C', value: 'c' },
432
+ ],
433
+ selectedIndices: new Set(),
434
+ focusedIndex: 0,
435
+ maxSelect: 3,
436
+ })
437
+ const mockManager = {
438
+ isTuiBound: vi.fn(() => true),
439
+ onScreenPromptActivated: vi.fn(),
440
+ } as unknown as ScreenManager
441
+ screen._setManager(mockManager)
442
+ screen._addPrompt(prompt)
443
+ })
444
+
445
+ it('should toggle selection', () => {
446
+ screen.promptToggleSelection()
447
+ expect((screen.getActivePrompt() as any).selectedIndices.has(0)).toBe(true)
448
+
449
+ screen.promptToggleSelection()
450
+ expect((screen.getActivePrompt() as any).selectedIndices.has(0)).toBe(false)
451
+ })
452
+
453
+ it('should respect maxSelect limit', () => {
454
+ const prompt = screen.getActivePrompt() as any
455
+ prompt.maxSelect = 1
456
+ prompt.selectedIndices.add(0)
457
+
458
+ screen.updatePromptSelection(1)
459
+ screen.promptToggleSelection() // Should not add because maxSelect is 1
460
+
461
+ expect(prompt.selectedIndices.size).toBe(1)
462
+ })
463
+ })
464
+ })
465
+
466
+ describe('prompt input mode', () => {
467
+ it('should enter input mode for choice with input option', () => {
468
+ const prompt = createChoicePrompt({
469
+ choices: [{ label: 'Other', value: 'other', input: true }],
470
+ selectedIndex: 0,
471
+ })
472
+ const mockManager = {
473
+ isTuiBound: vi.fn(() => true),
474
+ onScreenPromptActivated: vi.fn(),
475
+ } as unknown as ScreenManager
476
+ screen._setManager(mockManager)
477
+ screen._addPrompt(prompt)
478
+
479
+ const result = screen.promptEnterInputMode()
480
+
481
+ expect(result).toBe(true)
482
+ expect(screen.isPromptInInputMode()).toBe(true)
483
+ })
484
+
485
+ it('should not enter input mode for choice without input option', () => {
486
+ const prompt = createChoicePrompt({
487
+ choices: [{ label: 'Regular', value: 'regular' }],
488
+ selectedIndex: 0,
489
+ })
490
+ const mockManager = {
491
+ isTuiBound: vi.fn(() => true),
492
+ onScreenPromptActivated: vi.fn(),
493
+ } as unknown as ScreenManager
494
+ screen._setManager(mockManager)
495
+ screen._addPrompt(prompt)
496
+
497
+ const result = screen.promptEnterInputMode()
498
+
499
+ expect(result).toBe(false)
500
+ })
501
+
502
+ it('should always be in input mode for input prompts', () => {
503
+ const prompt = createInputPrompt()
504
+ const mockManager = {
505
+ isTuiBound: vi.fn(() => true),
506
+ onScreenPromptActivated: vi.fn(),
507
+ } as unknown as ScreenManager
508
+ screen._setManager(mockManager)
509
+ screen._addPrompt(prompt)
510
+
511
+ expect(screen.isPromptInInputMode()).toBe(true)
512
+ })
513
+
514
+ it('should exit input mode for choice prompts', () => {
515
+ const prompt = createChoicePrompt({
516
+ choices: [{ label: 'Other', value: 'other', input: true }],
517
+ selectedIndex: 0,
518
+ inputMode: true,
519
+ })
520
+ const mockManager = {
521
+ isTuiBound: vi.fn(() => true),
522
+ onScreenPromptActivated: vi.fn(),
523
+ } as unknown as ScreenManager
524
+ screen._setManager(mockManager)
525
+ screen._addPrompt(prompt)
526
+
527
+ screen.promptExitInputMode()
528
+
529
+ expect((screen.getActivePrompt() as any).inputMode).toBe(false)
530
+ })
531
+
532
+ it('should update input value', () => {
533
+ const prompt = createInputPrompt({ value: '' })
534
+ const mockManager = {
535
+ isTuiBound: vi.fn(() => true),
536
+ onScreenPromptActivated: vi.fn(),
537
+ } as unknown as ScreenManager
538
+ screen._setManager(mockManager)
539
+ screen._addPrompt(prompt)
540
+
541
+ screen.promptUpdateInput('hello')
542
+
543
+ expect((screen.getActivePrompt() as any).value).toBe('hello')
544
+ })
545
+
546
+ it('should append to input value', () => {
547
+ const prompt = createInputPrompt({ value: 'hel' })
548
+ const mockManager = {
549
+ isTuiBound: vi.fn(() => true),
550
+ onScreenPromptActivated: vi.fn(),
551
+ } as unknown as ScreenManager
552
+ screen._setManager(mockManager)
553
+ screen._addPrompt(prompt)
554
+
555
+ screen.promptAppendInput('lo')
556
+
557
+ expect((screen.getActivePrompt() as any).value).toBe('hello')
558
+ })
559
+
560
+ it('should delete last character from input', () => {
561
+ const prompt = createInputPrompt({ value: 'hello' })
562
+ const mockManager = {
563
+ isTuiBound: vi.fn(() => true),
564
+ onScreenPromptActivated: vi.fn(),
565
+ } as unknown as ScreenManager
566
+ screen._setManager(mockManager)
567
+ screen._addPrompt(prompt)
568
+
569
+ screen.promptDeleteLastChar()
570
+
571
+ expect((screen.getActivePrompt() as any).value).toBe('hell')
572
+ })
573
+ })
574
+
575
+ describe('promptSubmit', () => {
576
+ let mockManager: ScreenManager
577
+
578
+ beforeEach(() => {
579
+ mockManager = {
580
+ isTuiBound: vi.fn(() => true),
581
+ onScreenPromptActivated: vi.fn(),
582
+ } as unknown as ScreenManager
583
+ screen._setManager(mockManager)
584
+ })
585
+
586
+ it('should resolve choice prompt with selected value', async () => {
587
+ const prompt = createChoicePrompt({
588
+ choices: [
589
+ { label: 'A', value: 'a' },
590
+ { label: 'B', value: 'b' },
591
+ ],
592
+ selectedIndex: 1,
593
+ })
594
+
595
+ const resultPromise = screen._addPrompt(prompt)
596
+ screen.promptSubmit()
597
+
598
+ const result = await resultPromise
599
+ expect(result).toBe('b')
600
+ })
601
+
602
+ it('should resolve choice prompt with input value when in input mode', async () => {
603
+ const prompt = createChoicePrompt({
604
+ choices: [{ label: 'Other', value: 'other', input: true }],
605
+ selectedIndex: 0,
606
+ inputMode: true,
607
+ inputValue: 'custom input',
608
+ })
609
+
610
+ const resultPromise = screen._addPrompt(prompt)
611
+ screen.promptSubmit()
612
+
613
+ const result = await resultPromise
614
+ expect(result).toBe('custom input')
615
+ })
616
+
617
+ it('should resolve confirm prompt with boolean', async () => {
618
+ const prompt = createConfirmPrompt({ selectedValue: false })
619
+
620
+ const resultPromise = screen._addPrompt(prompt)
621
+ screen.promptSubmit()
622
+
623
+ const result = await resultPromise
624
+ expect(result).toBe(false)
625
+ })
626
+
627
+ it('should resolve input prompt with text value', async () => {
628
+ const prompt = createInputPrompt({ value: 'entered text' })
629
+
630
+ const resultPromise = screen._addPrompt(prompt)
631
+ screen.promptSubmit()
632
+
633
+ const result = await resultPromise
634
+ expect(result).toBe('entered text')
635
+ })
636
+
637
+ it('should resolve multiChoice with selected values array', async () => {
638
+ const prompt = createMultiChoicePrompt({
639
+ choices: [
640
+ { label: 'A', value: 'a' },
641
+ { label: 'B', value: 'b' },
642
+ { label: 'C', value: 'c' },
643
+ ],
644
+ selectedIndices: new Set([0, 2]),
645
+ })
646
+
647
+ const resultPromise = screen._addPrompt(prompt)
648
+ screen.promptSubmit()
649
+
650
+ const result = await resultPromise
651
+ expect(result).toEqual(['a', 'c'])
652
+ })
653
+
654
+ it('should respect minSelect constraint (canSubmitPrompt)', () => {
655
+ const prompt = createMultiChoicePrompt({
656
+ choices: [
657
+ { label: 'A', value: 'a' },
658
+ { label: 'B', value: 'b' },
659
+ ],
660
+ selectedIndices: new Set(),
661
+ minSelect: 1,
662
+ })
663
+
664
+ screen._addPrompt(prompt)
665
+
666
+ expect(screen.canSubmitPrompt()).toBe(false)
667
+
668
+ screen.promptToggleSelection() // Select first item
669
+
670
+ expect(screen.canSubmitPrompt()).toBe(true)
671
+ })
672
+
673
+ it('should activate next prompt after submit', async () => {
674
+ const prompt1 = createChoicePrompt({ question: 'First?' })
675
+ const prompt2 = createChoicePrompt({ question: 'Second?' })
676
+
677
+ screen._addPrompt(prompt1)
678
+ screen._addPrompt(prompt2)
679
+
680
+ expect(screen.getActivePrompt()?.question).toBe('First?')
681
+
682
+ screen.promptSubmit()
683
+
684
+ expect(screen.getActivePrompt()?.question).toBe('Second?')
685
+ })
686
+ })
687
+
688
+ describe('change listeners', () => {
689
+ it('should register listener with onChange', () => {
690
+ const listener = vi.fn()
691
+ screen.onChange(listener)
692
+
693
+ screen.addMessage(createLogMessage())
694
+
695
+ expect(listener).toHaveBeenCalled()
696
+ })
697
+
698
+ it('should return unsubscribe function', () => {
699
+ const listener = vi.fn()
700
+ const unsubscribe = screen.onChange(listener)
701
+
702
+ unsubscribe()
703
+ screen.addMessage(createLogMessage())
704
+
705
+ expect(listener).not.toHaveBeenCalled()
706
+ })
707
+
708
+ it('should notify all listeners', () => {
709
+ const listener1 = vi.fn()
710
+ const listener2 = vi.fn()
711
+
712
+ screen.onChange(listener1)
713
+ screen.onChange(listener2)
714
+
715
+ screen.addMessage(createLogMessage())
716
+
717
+ expect(listener1).toHaveBeenCalled()
718
+ expect(listener2).toHaveBeenCalled()
719
+ })
720
+ })
721
+ })