@navios/commander-tui 1.3.0 → 1.4.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 (240) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/{src/__tests__/mocks/scm-mock.ts → dist/base/src/__tests__/mocks/scm-mock.d.ts} +3 -1
  3. package/dist/base/src/__tests__/mocks/scm-mock.d.ts.map +1 -0
  4. package/dist/base/src/__tests__/setup.d.ts +2 -0
  5. package/dist/base/src/__tests__/setup.d.ts.map +1 -0
  6. package/dist/base/src/__tests__/utils/factories.d.ts +67 -0
  7. package/dist/base/src/__tests__/utils/factories.d.ts.map +1 -0
  8. package/dist/base/src/__tests__/utils/render-utils.d.ts +21 -0
  9. package/dist/base/src/__tests__/utils/render-utils.d.ts.map +1 -0
  10. package/dist/base/src/__tests__/utils/test-container.d.ts +20 -0
  11. package/dist/base/src/__tests__/utils/test-container.d.ts.map +1 -0
  12. package/dist/base/src/adapters/interface.d.ts +9 -2
  13. package/dist/base/src/adapters/interface.d.ts.map +1 -1
  14. package/dist/base/src/overrides/missing-adapter.override.d.ts +10 -0
  15. package/dist/base/src/overrides/missing-adapter.override.d.ts.map +1 -1
  16. package/dist/base/src/schemas/logger-options.d.ts +1 -1
  17. package/dist/base/src/services/index.d.ts +1 -0
  18. package/dist/base/src/services/index.d.ts.map +1 -1
  19. package/dist/base/src/services/logger.d.ts.map +1 -1
  20. package/dist/base/src/services/readline_prompt.d.ts +27 -0
  21. package/dist/base/src/services/readline_prompt.d.ts.map +1 -0
  22. package/dist/base/src/services/screen.d.ts +14 -8
  23. package/dist/base/src/services/screen.d.ts.map +1 -1
  24. package/dist/base/src/services/screen_manager.d.ts +62 -12
  25. package/dist/base/src/services/screen_manager.d.ts.map +1 -1
  26. package/dist/base/src/types/events.types.d.ts +40 -0
  27. package/dist/base/src/types/events.types.d.ts.map +1 -0
  28. package/dist/base/src/types/index.d.ts +1 -0
  29. package/dist/base/src/types/index.d.ts.map +1 -1
  30. package/dist/base/src/types/screen.types.d.ts +28 -0
  31. package/dist/base/src/types/screen.types.d.ts.map +1 -1
  32. package/dist/base/src/utils/colors/helpers.d.ts +0 -16
  33. package/dist/base/src/utils/colors/helpers.d.ts.map +1 -1
  34. package/dist/base/src/utils/index.d.ts +2 -0
  35. package/dist/base/src/utils/index.d.ts.map +1 -1
  36. package/dist/base/src/utils/prompt.d.ts +7 -0
  37. package/dist/base/src/utils/prompt.d.ts.map +1 -0
  38. package/dist/base/src/utils/runtime.d.ts +10 -0
  39. package/dist/base/src/utils/runtime.d.ts.map +1 -0
  40. package/dist/base/src/utils/stdout-printer.d.ts +5 -0
  41. package/dist/base/src/utils/stdout-printer.d.ts.map +1 -1
  42. package/dist/base/tsconfig.base.tsbuildinfo +1 -1
  43. package/dist/base/tsconfig.tsbuildinfo +1 -0
  44. package/dist/ink/src/adapters/ink/components/file/file_log.d.ts +28 -0
  45. package/dist/ink/src/adapters/ink/components/file/file_log.d.ts.map +1 -0
  46. package/dist/ink/src/adapters/ink/components/file/index.d.ts +2 -0
  47. package/dist/ink/src/adapters/ink/components/file/index.d.ts.map +1 -0
  48. package/dist/ink/src/adapters/ink/components/filter/filter_bar.d.ts +7 -0
  49. package/dist/ink/src/adapters/ink/components/filter/filter_bar.d.ts.map +1 -0
  50. package/dist/ink/src/adapters/ink/components/filter/index.d.ts +2 -0
  51. package/dist/ink/src/adapters/ink/components/filter/index.d.ts.map +1 -0
  52. package/dist/ink/src/adapters/ink/components/help/help_overlay.d.ts +6 -0
  53. package/dist/ink/src/adapters/ink/components/help/help_overlay.d.ts.map +1 -0
  54. package/dist/ink/src/adapters/ink/components/help/index.d.ts +2 -0
  55. package/dist/ink/src/adapters/ink/components/help/index.d.ts.map +1 -0
  56. package/dist/ink/src/adapters/ink/components/index.d.ts +9 -0
  57. package/dist/ink/src/adapters/ink/components/index.d.ts.map +1 -0
  58. package/dist/ink/src/adapters/ink/components/log/index.d.ts +2 -0
  59. package/dist/ink/src/adapters/ink/components/log/index.d.ts.map +1 -0
  60. package/dist/ink/src/adapters/ink/components/log/log_message.d.ts +15 -0
  61. package/dist/ink/src/adapters/ink/components/log/log_message.d.ts.map +1 -0
  62. package/dist/ink/src/adapters/ink/components/prompt/index.d.ts +2 -0
  63. package/dist/ink/src/adapters/ink/components/prompt/index.d.ts.map +1 -0
  64. package/dist/ink/src/adapters/ink/components/prompt/prompt_renderer.d.ts +6 -0
  65. package/dist/ink/src/adapters/ink/components/prompt/prompt_renderer.d.ts.map +1 -0
  66. package/dist/ink/src/adapters/ink/components/screen/group_renderer.d.ts +14 -0
  67. package/dist/ink/src/adapters/ink/components/screen/group_renderer.d.ts.map +1 -0
  68. package/dist/ink/src/adapters/ink/components/screen/index.d.ts +7 -0
  69. package/dist/ink/src/adapters/ink/components/screen/index.d.ts.map +1 -0
  70. package/dist/ink/src/adapters/ink/components/screen/loading_message.d.ts +6 -0
  71. package/dist/ink/src/adapters/ink/components/screen/loading_message.d.ts.map +1 -0
  72. package/dist/ink/src/adapters/ink/components/screen/message_renderer.d.ts +6 -0
  73. package/dist/ink/src/adapters/ink/components/screen/message_renderer.d.ts.map +1 -0
  74. package/dist/ink/src/adapters/ink/components/screen/progress_message.d.ts +6 -0
  75. package/dist/ink/src/adapters/ink/components/screen/progress_message.d.ts.map +1 -0
  76. package/dist/ink/src/adapters/ink/components/screen/screen_bridge.d.ts +14 -0
  77. package/dist/ink/src/adapters/ink/components/screen/screen_bridge.d.ts.map +1 -0
  78. package/dist/ink/src/adapters/ink/components/screen/table_message.d.ts +6 -0
  79. package/dist/ink/src/adapters/ink/components/screen/table_message.d.ts.map +1 -0
  80. package/dist/ink/src/adapters/ink/components/screen_manager_bridge.d.ts +8 -0
  81. package/dist/ink/src/adapters/ink/components/screen_manager_bridge.d.ts.map +1 -0
  82. package/dist/ink/src/adapters/ink/components/sidebar/index.d.ts +4 -0
  83. package/dist/ink/src/adapters/ink/components/sidebar/index.d.ts.map +1 -0
  84. package/dist/ink/src/adapters/ink/components/sidebar/sidebar.d.ts +11 -0
  85. package/dist/ink/src/adapters/ink/components/sidebar/sidebar.d.ts.map +1 -0
  86. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_item.d.ts +9 -0
  87. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_item.d.ts.map +1 -0
  88. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_separator.d.ts +2 -0
  89. package/dist/ink/src/adapters/ink/components/sidebar/sidebar_separator.d.ts.map +1 -0
  90. package/dist/ink/src/adapters/ink/context/index.d.ts +2 -0
  91. package/dist/ink/src/adapters/ink/context/index.d.ts.map +1 -0
  92. package/dist/ink/src/adapters/ink/context/logger_context.d.ts +33 -0
  93. package/dist/ink/src/adapters/ink/context/logger_context.d.ts.map +1 -0
  94. package/dist/ink/src/adapters/ink/hooks/index.d.ts +2 -0
  95. package/dist/ink/src/adapters/ink/hooks/index.d.ts.map +1 -0
  96. package/dist/ink/src/adapters/ink/hooks/use_theme.d.ts +7 -0
  97. package/dist/ink/src/adapters/ink/hooks/use_theme.d.ts.map +1 -0
  98. package/dist/ink/src/adapters/ink/index.d.ts +18 -0
  99. package/dist/ink/src/adapters/ink/index.d.ts.map +1 -0
  100. package/dist/ink/src/adapters/react-shared/hooks/index.d.ts +4 -0
  101. package/dist/ink/src/adapters/react-shared/hooks/index.d.ts.map +1 -0
  102. package/dist/ink/src/adapters/react-shared/hooks/use_filter_state.d.ts +18 -0
  103. package/dist/ink/src/adapters/react-shared/hooks/use_filter_state.d.ts.map +1 -0
  104. package/dist/ink/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts +26 -0
  105. package/dist/ink/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts.map +1 -0
  106. package/dist/ink/src/adapters/react-shared/hooks/use_manager_subscription.d.ts +7 -0
  107. package/dist/ink/src/adapters/react-shared/hooks/use_manager_subscription.d.ts.map +1 -0
  108. package/dist/ink/src/adapters/react-shared/index.d.ts +2 -0
  109. package/dist/ink/src/adapters/react-shared/index.d.ts.map +1 -0
  110. package/dist/ink/tsconfig.ink.tsbuildinfo +1 -0
  111. package/dist/react/src/adapters/react-shared/hooks/index.d.ts +4 -0
  112. package/dist/react/src/adapters/react-shared/hooks/index.d.ts.map +1 -0
  113. package/dist/react/src/adapters/react-shared/hooks/use_filter_state.d.ts +18 -0
  114. package/dist/react/src/adapters/react-shared/hooks/use_filter_state.d.ts.map +1 -0
  115. package/dist/react/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts +26 -0
  116. package/dist/react/src/adapters/react-shared/hooks/use_keyboard_manager.d.ts.map +1 -0
  117. package/dist/react/src/adapters/react-shared/hooks/use_manager_subscription.d.ts +7 -0
  118. package/dist/react/src/adapters/react-shared/hooks/use_manager_subscription.d.ts.map +1 -0
  119. package/dist/react/src/adapters/react-shared/index.d.ts +2 -0
  120. package/dist/react/src/adapters/react-shared/index.d.ts.map +1 -0
  121. package/dist/react/tsconfig.react.tsbuildinfo +1 -1
  122. package/dist/solid/tsconfig.solid.tsbuildinfo +1 -1
  123. package/lib/index.cjs +2177 -178
  124. package/lib/index.cjs.map +1 -1
  125. package/lib/index.d.cts +942 -78
  126. package/lib/index.d.cts.map +1 -0
  127. package/lib/index.d.mts +902 -38
  128. package/lib/index.d.mts.map +1 -0
  129. package/lib/index.mjs +2098 -135
  130. package/lib/index.mjs.map +1 -1
  131. package/package.json +1 -31
  132. package/src/__tests__/services/logger.spec.ts +32 -0
  133. package/src/__tests__/services/screen.spec.ts +106 -95
  134. package/src/__tests__/utils/factories.ts +2 -0
  135. package/src/adapters/interface.ts +10 -2
  136. package/src/overrides/missing-adapter.override.ts +16 -6
  137. package/src/services/index.ts +1 -0
  138. package/src/services/logger.ts +7 -1
  139. package/src/services/readline_prompt.ts +194 -0
  140. package/src/services/screen.ts +106 -54
  141. package/src/services/screen_manager.ts +282 -74
  142. package/src/types/events.types.ts +84 -0
  143. package/src/types/index.ts +3 -0
  144. package/src/types/screen.types.ts +34 -0
  145. package/src/utils/colors/helpers.ts +0 -25
  146. package/src/utils/index.ts +6 -0
  147. package/src/utils/prompt.ts +18 -0
  148. package/src/utils/runtime.ts +14 -0
  149. package/src/utils/stdout-printer.ts +16 -5
  150. package/tsconfig.base.json +1 -17
  151. package/tsconfig.json +1 -6
  152. package/tsdown.config.mts +13 -70
  153. package/lib/adapters/react/index.cjs +0 -1768
  154. package/lib/adapters/react/index.cjs.map +0 -1
  155. package/lib/adapters/react/index.d.cts +0 -80
  156. package/lib/adapters/react/index.d.mts +0 -80
  157. package/lib/adapters/react/index.mjs +0 -1760
  158. package/lib/adapters/react/index.mjs.map +0 -1
  159. package/lib/adapters/solid/index.cjs +0 -3855
  160. package/lib/adapters/solid/index.cjs.map +0 -1
  161. package/lib/adapters/solid/index.d.cts +0 -74
  162. package/lib/adapters/solid/index.d.mts +0 -74
  163. package/lib/adapters/solid/index.mjs +0 -3847
  164. package/lib/adapters/solid/index.mjs.map +0 -1
  165. package/lib/filter_engine-DXqu9Vaq.cjs +0 -1836
  166. package/lib/filter_engine-DXqu9Vaq.cjs.map +0 -1
  167. package/lib/filter_engine-DmqhEhpA.mjs +0 -1609
  168. package/lib/filter_engine-DmqhEhpA.mjs.map +0 -1
  169. package/lib/interface-CTHQ08aY.d.mts +0 -699
  170. package/lib/interface-DQEIz9Mb.d.cts +0 -699
  171. package/src/__tests__/components/__snapshots__/filter_bar.spec.tsx.snap +0 -2293
  172. package/src/__tests__/components/__snapshots__/loading_message.spec.tsx.snap +0 -1414
  173. package/src/__tests__/components/__snapshots__/log_message.spec.tsx.snap +0 -3245
  174. package/src/__tests__/components/__snapshots__/progress_message.spec.tsx.snap +0 -1783
  175. package/src/__tests__/components/__snapshots__/prompt_renderer.spec.tsx.snap +0 -3203
  176. package/src/__tests__/components/__snapshots__/sidebar.spec.tsx.snap +0 -2857
  177. package/src/__tests__/components/filter_bar.spec.tsx +0 -190
  178. package/src/__tests__/components/loading_message.spec.tsx +0 -110
  179. package/src/__tests__/components/log_message.spec.tsx +0 -166
  180. package/src/__tests__/components/progress_message.spec.tsx +0 -147
  181. package/src/__tests__/components/prompt_renderer.spec.tsx +0 -274
  182. package/src/__tests__/components/sidebar.spec.tsx +0 -322
  183. package/src/__tests__/utils/render-utils.tsx +0 -39
  184. package/src/adapters/react/components/file/file_log.tsx +0 -241
  185. package/src/adapters/react/components/file/index.ts +0 -1
  186. package/src/adapters/react/components/filter/filter_bar.tsx +0 -79
  187. package/src/adapters/react/components/filter/index.ts +0 -1
  188. package/src/adapters/react/components/help/help_overlay.tsx +0 -100
  189. package/src/adapters/react/components/help/index.ts +0 -1
  190. package/src/adapters/react/components/log/index.ts +0 -1
  191. package/src/adapters/react/components/log/log_message.tsx +0 -102
  192. package/src/adapters/react/components/prompt/index.ts +0 -2
  193. package/src/adapters/react/components/prompt/prompt_renderer.tsx +0 -346
  194. package/src/adapters/react/components/screen/group_renderer.tsx +0 -64
  195. package/src/adapters/react/components/screen/index.ts +0 -6
  196. package/src/adapters/react/components/screen/loading_message.tsx +0 -43
  197. package/src/adapters/react/components/screen/message_renderer.tsx +0 -108
  198. package/src/adapters/react/components/screen/progress_message.tsx +0 -60
  199. package/src/adapters/react/components/screen/screen_bridge.tsx +0 -149
  200. package/src/adapters/react/components/screen/table_message.tsx +0 -57
  201. package/src/adapters/react/components/screen_manager_bridge.tsx +0 -245
  202. package/src/adapters/react/components/sidebar/index.ts +0 -3
  203. package/src/adapters/react/components/sidebar/sidebar.tsx +0 -102
  204. package/src/adapters/react/components/sidebar/sidebar_item.tsx +0 -50
  205. package/src/adapters/react/components/sidebar/sidebar_separator.tsx +0 -13
  206. package/src/adapters/react/context/index.ts +0 -1
  207. package/src/adapters/react/context/logger_context.tsx +0 -109
  208. package/src/adapters/react/hooks/index.ts +0 -1
  209. package/src/adapters/react/hooks/use_theme.ts +0 -12
  210. package/src/adapters/react/index.ts +0 -39
  211. package/src/adapters/solid/components/file/file_log.tsx +0 -221
  212. package/src/adapters/solid/components/file/index.ts +0 -1
  213. package/src/adapters/solid/components/filter/filter_bar.tsx +0 -84
  214. package/src/adapters/solid/components/filter/index.ts +0 -1
  215. package/src/adapters/solid/components/help/help_overlay.tsx +0 -106
  216. package/src/adapters/solid/components/help/index.ts +0 -1
  217. package/src/adapters/solid/components/log/index.ts +0 -1
  218. package/src/adapters/solid/components/log/log_message.tsx +0 -92
  219. package/src/adapters/solid/components/prompt/index.ts +0 -2
  220. package/src/adapters/solid/components/prompt/prompt_renderer.tsx +0 -350
  221. package/src/adapters/solid/components/screen/group_renderer.tsx +0 -61
  222. package/src/adapters/solid/components/screen/index.ts +0 -6
  223. package/src/adapters/solid/components/screen/loading_message.tsx +0 -39
  224. package/src/adapters/solid/components/screen/message_renderer.tsx +0 -122
  225. package/src/adapters/solid/components/screen/progress_message.tsx +0 -61
  226. package/src/adapters/solid/components/screen/screen_bridge.tsx +0 -155
  227. package/src/adapters/solid/components/screen/table_message.tsx +0 -58
  228. package/src/adapters/solid/components/screen_manager_bridge.tsx +0 -243
  229. package/src/adapters/solid/components/sidebar/index.ts +0 -3
  230. package/src/adapters/solid/components/sidebar/sidebar.tsx +0 -108
  231. package/src/adapters/solid/components/sidebar/sidebar_item.tsx +0 -55
  232. package/src/adapters/solid/components/sidebar/sidebar_separator.tsx +0 -13
  233. package/src/adapters/solid/context/index.ts +0 -2
  234. package/src/adapters/solid/context/logger_context.tsx +0 -95
  235. package/src/adapters/solid/hooks/index.ts +0 -1
  236. package/src/adapters/solid/hooks/use_theme.ts +0 -12
  237. package/src/adapters/solid/index.tsx +0 -43
  238. package/src/adapters/solid/jsx.d.ts +0 -98
  239. package/tsconfig.react.json +0 -16
  240. package/tsconfig.solid.json +0 -16
package/lib/index.mjs CHANGED
@@ -1,7 +1,561 @@
1
- import { A as SEPARATOR_COLORS, C as getLogLevelColors, D as GROUP_COLORS, E as TABLE_COLORS, F as VARIANT_COLORS, I as ALL_LOG_LEVELS, L as createDefaultFilterState, M as STATUS_INDICATORS, N as DEFAULT_LOG_LEVEL_COLORS, O as PROGRESS_COLORS, P as ERROR_HIGHLIGHT_COLORS, R as hasActiveFilter, S as createTintedColor, T as FILE_COLORS, _ as printMessagesToStdout, a as formatKeyBinding, b as resolveFiletype, c as getThemePreset, d as highContrastTheme, f as lightTheme, g as formatObject, h as captureTrace, i as KeyboardManager, j as SIDEBAR_COLORS, k as HEADER_COLORS, l as mergeThemes, m as Adapter, n as createDefaultBindings, o as createTheme, p as darkTheme, r as handlePrintableInput, s as createThemeFrom, t as FilterEngine, u as resolveTheme, v as COMMON_FILETYPES, w as PROMPT_COLORS, x as createBorderColor, y as getFileName } from "./filter_engine-DmqhEhpA.mjs";
2
- import { createCliRenderer } from "@opentui/core";
3
- import { Factory, Injectable, InjectionToken, Logger, LoggerOutput, inject } from "@navios/core";
1
+ import { Container, Factory, Injectable, InjectionToken, Logger, LoggerOutput, inject } from "@navios/core";
2
+ import { EventEmitter } from "node:events";
3
+ import * as readline from "node:readline";
4
4
 
5
+ //#region src/types/screen.types.ts
6
+ /**
7
+ * Render mode determines how the TUI operates.
8
+ * This is set during bind() and affects prompts, screen printing, and exit behavior.
9
+ */ var RenderMode = /* @__PURE__ */ function(RenderMode$1) {
10
+ /** bind() never called - screens print on completion, prompts return defaults */ RenderMode$1["UNBOUND"] = "unbound";
11
+ /** bind() called with useOpenTUI: false - stdout mode with readline prompts */ RenderMode$1["STDOUT_INTERACTIVE"] = "stdout";
12
+ /** bind() called with useOpenTUI: true but adapter unavailable - fallback to stdout with warning */ RenderMode$1["STDOUT_FALLBACK"] = "fallback";
13
+ /** Full TUI rendering active with adapter */ RenderMode$1["TUI_ACTIVE"] = "tui";
14
+ return RenderMode$1;
15
+ }({});
16
+
17
+ //#endregion
18
+ //#region src/types/filter.types.ts
19
+ /**
20
+ * All log levels in order.
21
+ */ const ALL_LOG_LEVELS = [
22
+ "verbose",
23
+ "debug",
24
+ "log",
25
+ "warn",
26
+ "error",
27
+ "fatal"
28
+ ];
29
+ /**
30
+ * Create a default filter state.
31
+ */ function createDefaultFilterState() {
32
+ return {
33
+ enabledLevels: new Set(ALL_LOG_LEVELS),
34
+ searchQuery: "",
35
+ isVisible: false,
36
+ focusedField: "search"
37
+ };
38
+ }
39
+ /**
40
+ * Check if any filtering is active.
41
+ */ function hasActiveFilter(filter) {
42
+ return filter.searchQuery !== "" || filter.enabledLevels.size < ALL_LOG_LEVELS.length;
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/types/events.types.ts
47
+ /**
48
+ * All manager events that adapters typically subscribe to for re-renders.
49
+ */ const MANAGER_EVENTS = [
50
+ "screen:added",
51
+ "screen:removed",
52
+ "screen:reordered",
53
+ "activeScreen:changed",
54
+ "focus:changed",
55
+ "sidebar:indexChanged",
56
+ "mode:changed"
57
+ ];
58
+ /**
59
+ * All screen events that adapters typically subscribe to for re-renders.
60
+ */ const SCREEN_EVENTS = [
61
+ "message:added",
62
+ "message:updated",
63
+ "messages:cleared",
64
+ "status:changed",
65
+ "visibility:changed",
66
+ "badge:changed",
67
+ "prompt:activated",
68
+ "prompt:updated",
69
+ "prompt:resolved"
70
+ ];
71
+ /**
72
+ * Sidebar-specific events that require re-render.
73
+ */ const SIDEBAR_EVENTS = [
74
+ "screen:added",
75
+ "screen:removed",
76
+ "screen:reordered",
77
+ "sidebar:indexChanged",
78
+ "focus:changed",
79
+ "activeScreen:changed"
80
+ ];
81
+ /**
82
+ * Content area events that affect active screen changes.
83
+ */ const CONTENT_MANAGER_EVENTS = ["activeScreen:changed", "focus:changed"];
84
+
85
+ //#endregion
86
+ //#region src/utils/colors/log-colors.ts
87
+ /**
88
+ * Default color scheme for all log levels.
89
+ * Each level has a prominent border color and a subtle background tint.
90
+ */ const DEFAULT_LOG_LEVEL_COLORS = {
91
+ verbose: {
92
+ border: "#6B7280",
93
+ background: "#6B728015"
94
+ },
95
+ debug: {
96
+ border: "#8B5CF6",
97
+ background: "#8B5CF615"
98
+ },
99
+ log: {
100
+ border: "#3B82F6",
101
+ background: "#3B82F615"
102
+ },
103
+ warn: {
104
+ border: "#F59E0B",
105
+ background: "#F59E0B15"
106
+ },
107
+ error: {
108
+ border: "#EF4444",
109
+ background: "#EF444415"
110
+ },
111
+ fatal: {
112
+ border: "#DC2626",
113
+ background: "#DC262625",
114
+ text: "#FCA5A5"
115
+ }
116
+ };
117
+ /**
118
+ * Colors for semantic variants (override level colors when variant is set).
119
+ */ const VARIANT_COLORS = {
120
+ success: {
121
+ border: "#22C55E",
122
+ background: "#22C55E15"
123
+ },
124
+ trace: {
125
+ border: "#6B7280",
126
+ background: "#6B728015"
127
+ }
128
+ };
129
+ /**
130
+ * Error highlighting colors.
131
+ */ const ERROR_HIGHLIGHT_COLORS = {
132
+ background: "#EF444425",
133
+ border: "#EF4444",
134
+ gutterBackground: "#EF444440"
135
+ };
136
+
137
+ //#endregion
138
+ //#region src/utils/colors/sidebar-colors.ts
139
+ /**
140
+ * Sidebar colors.
141
+ */ const SIDEBAR_COLORS = {
142
+ background: void 0,
143
+ selectedBackground: "#1F293780",
144
+ hoverBackground: "#374151",
145
+ text: "#E5E7EB",
146
+ textDim: "#6B7280",
147
+ border: "#374151",
148
+ badge: "#3B82F6",
149
+ focusBorder: "#3B82F6"
150
+ };
151
+ /**
152
+ * Screen header colors.
153
+ */ const HEADER_COLORS = {
154
+ background: void 0,
155
+ text: "#F9FAFB",
156
+ border: "#374151"
157
+ };
158
+ /**
159
+ * Screen status indicator colors and icons.
160
+ */ const STATUS_INDICATORS = {
161
+ waiting: {
162
+ icon: "○",
163
+ color: "#6B7280"
164
+ },
165
+ pending: {
166
+ icon: "◐",
167
+ color: "#F59E0B"
168
+ },
169
+ success: {
170
+ icon: "✓",
171
+ color: "#22C55E"
172
+ },
173
+ fail: {
174
+ icon: "✗",
175
+ color: "#EF4444"
176
+ }
177
+ };
178
+ /**
179
+ * Separator colors for sidebar sections.
180
+ */ const SEPARATOR_COLORS = {
181
+ line: "#374151",
182
+ text: "#6B7280"
183
+ };
184
+
185
+ //#endregion
186
+ //#region src/utils/colors/progress-colors.ts
187
+ /**
188
+ * Progress bar colors.
189
+ */ const PROGRESS_COLORS = {
190
+ border: "#3B82F6",
191
+ background: "#3B82F615",
192
+ barFilled: "#3B82F6",
193
+ barEmpty: "#374151",
194
+ text: "#E5E7EB",
195
+ textDim: "#9CA3AF",
196
+ complete: "#22C55E",
197
+ completeBackground: "#22C55E15",
198
+ failed: "#EF4444",
199
+ failedBackground: "#EF444415"
200
+ };
201
+ /**
202
+ * Group colors for collapsible log groups.
203
+ */ const GROUP_COLORS = {
204
+ border: "#6B7280",
205
+ background: "#6B728010",
206
+ headerText: "#E5E7EB",
207
+ icon: "#9CA3AF"
208
+ };
209
+
210
+ //#endregion
211
+ //#region src/utils/colors/table-colors.ts
212
+ /**
213
+ * Table colors (uses info/blue scheme).
214
+ */ const TABLE_COLORS = {
215
+ border: "#3B82F6",
216
+ background: "#3B82F615",
217
+ headerText: "#F9FAFB",
218
+ cellText: "#E5E7EB",
219
+ title: "#F9FAFB",
220
+ separator: "#3B82F650"
221
+ };
222
+
223
+ //#endregion
224
+ //#region src/utils/colors/file-colors.ts
225
+ /**
226
+ * File display colors (uses info/blue scheme).
227
+ */ const FILE_COLORS = {
228
+ border: "#3B82F6",
229
+ background: "#3B82F615",
230
+ headerText: "#F9FAFB",
231
+ headerBackground: "#3B82F625"
232
+ };
233
+
234
+ //#endregion
235
+ //#region src/utils/colors/prompt-colors.ts
236
+ /**
237
+ * Prompt colors for interactive prompts.
238
+ */ const PROMPT_COLORS = {
239
+ question: "#F9FAFB",
240
+ optionText: "#E5E7EB",
241
+ optionTextDim: "#9CA3AF",
242
+ optionSelected: "#3B82F6",
243
+ optionSelectedBackground: "#1E3A5F",
244
+ confirmButton: "#22C55E",
245
+ cancelButton: "#EF4444",
246
+ buttonBackground: "#374151",
247
+ buttonSelectedBackground: "#1F2937",
248
+ inputBorder: "#3B82F6",
249
+ inputBackground: "#1F2937",
250
+ inputText: "#F9FAFB",
251
+ inputPlaceholder: "#6B7280",
252
+ inputCursor: "#3B82F6",
253
+ border: "#374151",
254
+ focusBorder: "#3B82F6"
255
+ };
256
+
257
+ //#endregion
258
+ //#region src/utils/colors/helpers.ts
259
+ /**
260
+ * Gets colors for a specific log level.
261
+ *
262
+ * @param level - The log level
263
+ * @param customColors - Optional custom color map
264
+ */ function getLogLevelColors(level, customColors) {
265
+ const defaultColors = DEFAULT_LOG_LEVEL_COLORS[level];
266
+ const custom = customColors?.[level];
267
+ return {
268
+ border: custom?.border ?? defaultColors.border,
269
+ background: custom?.background ?? defaultColors.background,
270
+ text: custom?.text ?? defaultColors.text
271
+ };
272
+ }
273
+
274
+ //#endregion
275
+ //#region src/utils/filetype.ts
276
+ /**
277
+ * Common file extension to filetype mapping for syntax highlighting.
278
+ */ const COMMON_FILETYPES = {
279
+ ts: "typescript",
280
+ tsx: "tsx",
281
+ js: "javascript",
282
+ jsx: "javascript",
283
+ json: "json",
284
+ md: "markdown",
285
+ py: "python",
286
+ rs: "rust",
287
+ go: "go",
288
+ java: "java",
289
+ c: "c",
290
+ cpp: "cpp",
291
+ h: "c",
292
+ hpp: "cpp",
293
+ css: "css",
294
+ html: "html",
295
+ yaml: "yaml",
296
+ yml: "yaml",
297
+ sh: "bash",
298
+ bash: "bash",
299
+ zsh: "bash",
300
+ toml: "toml",
301
+ xml: "xml",
302
+ sql: "sql",
303
+ rb: "ruby",
304
+ php: "php",
305
+ swift: "swift",
306
+ kt: "kotlin",
307
+ scala: "scala",
308
+ hs: "haskell",
309
+ elm: "elm",
310
+ vue: "vue",
311
+ svelte: "svelte"
312
+ };
313
+ /**
314
+ * Resolves filetype from file path for syntax highlighting.
315
+ *
316
+ * @param filePath - Full file path or just filename
317
+ * @returns Filetype string for tree-sitter, or undefined
318
+ */ function resolveFiletype(filePath) {
319
+ const lastDot = filePath.lastIndexOf(".");
320
+ if (lastDot === -1) return void 0;
321
+ return COMMON_FILETYPES[filePath.slice(lastDot + 1).toLowerCase()];
322
+ }
323
+ /**
324
+ * Gets the filename from a full path.
325
+ *
326
+ * @param filePath - Full file path
327
+ * @returns Just the filename
328
+ */ function getFileName(filePath) {
329
+ const lastSlash = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
330
+ return lastSlash === -1 ? filePath : filePath.slice(lastSlash + 1);
331
+ }
332
+
333
+ //#endregion
334
+ //#region src/utils/stdout-printer.ts
335
+ const RESET = "\x1B[0m";
336
+ const BOLD = "\x1B[1m";
337
+ const DIM = "\x1B[2m";
338
+ function hexToAnsi(hex, isForeground = true) {
339
+ const cleanHex = hex.replace("#", "").slice(0, 6);
340
+ if (!/^[0-9A-Fa-f]{6}$/.test(cleanHex)) return "";
341
+ const r = parseInt(cleanHex.slice(0, 2), 16);
342
+ const g = parseInt(cleanHex.slice(2, 4), 16);
343
+ const b = parseInt(cleanHex.slice(4, 6), 16);
344
+ return `\x1b[${isForeground ? 38 : 48};2;${r};${g};${b}m`;
345
+ }
346
+ function getLogLevelAnsiColor(level, variant) {
347
+ return hexToAnsi((variant ? VARIANT_COLORS[variant] : DEFAULT_LOG_LEVEL_COLORS[level]).border, true);
348
+ }
349
+ function formatLevel(level, variant) {
350
+ return `${getLogLevelAnsiColor(level, variant)}${BOLD}[${(variant ?? level).toUpperCase().padEnd(7)}]${RESET}`;
351
+ }
352
+ function formatTimestamp(date$2) {
353
+ return `${DIM}${date$2.toLocaleTimeString()}${RESET}`;
354
+ }
355
+ function printMessage(message, stream) {
356
+ switch (message.type) {
357
+ case "log": {
358
+ const logMessage = message;
359
+ const timestamp = formatTimestamp(message.timestamp);
360
+ const level = formatLevel(logMessage.level, logMessage.variant);
361
+ const label = logMessage.label ? ` ${DIM}[${logMessage.label}]${RESET}` : "";
362
+ stream.write(`${timestamp} ${level}${label} ${logMessage.content}\n`);
363
+ break;
364
+ }
365
+ case "file": {
366
+ const header = `${DIM}─── ${message.filePath} ───${RESET}`;
367
+ stream.write(`${header}\n${message.content}\n`);
368
+ break;
369
+ }
370
+ case "diff": {
371
+ const header = `${DIM}─── ${message.filePath} (diff) ───${RESET}`;
372
+ const coloredDiff = message.diff.split("\n").map((line) => {
373
+ if (line.startsWith("+") && !line.startsWith("+++")) return `\x1b[32m${line}${RESET}`;
374
+ else if (line.startsWith("-") && !line.startsWith("---")) return `\x1b[31m${line}${RESET}`;
375
+ else if (line.startsWith("@@")) return `\x1b[36m${line}${RESET}`;
376
+ return line;
377
+ }).join("\n");
378
+ stream.write(`${header}\n${coloredDiff}\n`);
379
+ break;
380
+ }
381
+ case "fileError": {
382
+ const header = `${DIM}─── ${message.filePath} ───${RESET}`;
383
+ const errorLineSet = new Set(message.errorLines);
384
+ const startLine = message.startLine ?? 1;
385
+ const numberedLines = message.content.split("\n").map((line, index) => {
386
+ const lineNum = startLine + index;
387
+ const numStr = String(lineNum).padStart(4);
388
+ if (errorLineSet.has(lineNum)) return `\x1b[31m${numStr} │ ${line}${RESET}`;
389
+ return `${DIM}${numStr}${RESET} │ ${line}`;
390
+ });
391
+ stream.write(`${header}\n${numberedLines.join("\n")}\n`);
392
+ break;
393
+ }
394
+ case "loading": {
395
+ const loadingMessage = message;
396
+ const status = loadingMessage.status;
397
+ const content = loadingMessage.resolvedContent ?? loadingMessage.content;
398
+ let level = "log";
399
+ let variant;
400
+ if (status === "success") {
401
+ level = "log";
402
+ variant = "success";
403
+ } else if (status === "fail") level = "error";
404
+ const timestamp = formatTimestamp(message.timestamp);
405
+ const levelStr = formatLevel(level, variant);
406
+ const prefix = status === "loading" ? "... " : "";
407
+ stream.write(`${timestamp} ${levelStr} ${prefix}${content}\n`);
408
+ break;
409
+ }
410
+ case "progress": {
411
+ const { label, current, total, status, resolvedContent } = message;
412
+ const percentage = total > 0 ? Math.round(current / total * 100) : 0;
413
+ const barWidth = 20;
414
+ const filledWidth = Math.round(percentage / 100 * barWidth);
415
+ const emptyWidth = barWidth - filledWidth;
416
+ const progressColor = hexToAnsi(PROGRESS_COLORS.barFilled);
417
+ const emptyColor = hexToAnsi(PROGRESS_COLORS.barEmpty);
418
+ const filledBar = "█".repeat(filledWidth);
419
+ const emptyBar = "░".repeat(emptyWidth);
420
+ let statusIcon = "";
421
+ let statusColor = "";
422
+ if (status === "complete") {
423
+ statusIcon = "✓";
424
+ statusColor = hexToAnsi(PROGRESS_COLORS.complete);
425
+ } else if (status === "failed") {
426
+ statusIcon = "✗";
427
+ statusColor = hexToAnsi(PROGRESS_COLORS.failed);
428
+ }
429
+ const displayLabel = resolvedContent ?? label;
430
+ const progressBar = `${progressColor}${filledBar}${RESET}${emptyColor}${emptyBar}${RESET}`;
431
+ const percentStr = `${String(percentage).padStart(3)}%`;
432
+ if (statusIcon) stream.write(`${statusColor}${statusIcon}${RESET} ${displayLabel} [${progressBar}] ${percentStr}\n`);
433
+ else stream.write(` ${displayLabel} [${progressBar}] ${percentStr} (${current}/${total})\n`);
434
+ break;
435
+ }
436
+ case "group": {
437
+ const { label, collapsed, isEnd } = message;
438
+ const groupColor = hexToAnsi(GROUP_COLORS.border);
439
+ const iconColor = hexToAnsi(GROUP_COLORS.icon);
440
+ if (isEnd) stream.write(`${groupColor}└─${RESET} ${DIM}end ${label}${RESET}\n`);
441
+ else {
442
+ const icon = collapsed ? "▶" : "▼";
443
+ stream.write(`${groupColor}┌─${RESET} ${iconColor}${icon}${RESET} ${BOLD}${label}${RESET}\n`);
444
+ }
445
+ break;
446
+ }
447
+ case "table": {
448
+ const { headers, rows, title } = message;
449
+ const tableColor = hexToAnsi(TABLE_COLORS.border);
450
+ const headerColor = hexToAnsi(TABLE_COLORS.headerText);
451
+ const cellColor = hexToAnsi(TABLE_COLORS.cellText);
452
+ const colWidths = headers.map((h, i) => {
453
+ const maxRowWidth = rows.reduce((max, row) => Math.max(max, (row[i] ?? "").length), 0);
454
+ return Math.max(h.length, maxRowWidth);
455
+ });
456
+ const separator = `${tableColor}├${colWidths.map((w) => "─".repeat(w + 2)).join("┼")}┤${RESET}`;
457
+ const topBorder = `${tableColor}┌${colWidths.map((w) => "─".repeat(w + 2)).join("┬")}┐${RESET}`;
458
+ const bottomBorder = `${tableColor}└${colWidths.map((w) => "─".repeat(w + 2)).join("┴")}┘${RESET}`;
459
+ if (title) stream.write(`${BOLD}${title}${RESET}\n`);
460
+ stream.write(`${topBorder}\n`);
461
+ const headerRow = headers.map((h, i) => ` ${h.padEnd(colWidths[i])} `).join(`${tableColor}│${RESET}`);
462
+ stream.write(`${tableColor}│${RESET}${headerColor}${headerRow}${RESET}${tableColor}│${RESET}\n`);
463
+ stream.write(`${separator}\n`);
464
+ for (const row of rows) {
465
+ const rowStr = headers.map((_, i) => ` ${(row[i] ?? "").padEnd(colWidths[i])} `).join(`${tableColor}│${RESET}`);
466
+ stream.write(`${tableColor}│${RESET}${cellColor}${rowStr}${RESET}${tableColor}│${RESET}\n`);
467
+ }
468
+ stream.write(`${bottomBorder}\n`);
469
+ break;
470
+ }
471
+ }
472
+ }
473
+ /**
474
+ * Print a single message to stdout with optional screen name prefix.
475
+ * Used for immediate output in stdout mode (when OpenTUI is not active).
476
+ */ function printSingleMessage(message, screenName, isError = false) {
477
+ const stream = isError ? process.stderr : process.stdout;
478
+ if (screenName) stream.write(`${DIM}[${screenName}]${RESET} `);
479
+ printMessage(message, stream);
480
+ }
481
+ /**
482
+ * Print all messages to stdout (or stderr if isError)
483
+ */ function printMessagesToStdout(messages, screenName, isError = false) {
484
+ const stream = isError ? process.stderr : process.stdout;
485
+ const headerColor = isError ? "\x1B[31m" : "\x1B[32m";
486
+ const status = isError ? "FAILED" : "COMPLETED";
487
+ stream.write(`\n${headerColor}${BOLD}═══ ${screenName} [${status}] ═══${RESET}\n\n`);
488
+ for (const message of messages) printMessage(message, stream);
489
+ stream.write("\n");
490
+ }
491
+
492
+ //#endregion
493
+ //#region src/utils/format.ts
494
+ /**
495
+ * Format an object for display with configurable depth
496
+ */ function formatObject(obj, depth = 2, currentDepth = 0) {
497
+ if (currentDepth >= depth) {
498
+ if (Array.isArray(obj)) return "[Array]";
499
+ if (typeof obj === "object" && obj !== null) return `[${obj.constructor?.name ?? "Object"}]`;
500
+ return String(obj);
501
+ }
502
+ if (obj === null) return "null";
503
+ if (obj === void 0) return "undefined";
504
+ if (typeof obj === "string") return `"${obj}"`;
505
+ if (typeof obj === "number" || typeof obj === "boolean") return String(obj);
506
+ if (typeof obj === "function") return "[Function]";
507
+ if (obj instanceof Date) return obj.toISOString();
508
+ if (obj instanceof Error) return `${obj.name}: ${obj.message}`;
509
+ const indent = " ".repeat(currentDepth);
510
+ const childIndent = " ".repeat(currentDepth + 1);
511
+ if (Array.isArray(obj)) {
512
+ if (obj.length === 0) return "[]";
513
+ return `[\n${childIndent}${obj.map((item) => formatObject(item, depth, currentDepth + 1)).join(`,\n${childIndent}`)}\n${indent}]`;
514
+ }
515
+ if (typeof obj === "object") {
516
+ const entries = Object.entries(obj);
517
+ if (entries.length === 0) return "{}";
518
+ return `{\n${childIndent}${entries.map(([key, value]) => `${key}: ${formatObject(value, depth, currentDepth + 1)}`).join(`,\n${childIndent}`)}\n${indent}}`;
519
+ }
520
+ return String(obj);
521
+ }
522
+ /**
523
+ * Capture a stack trace, filtering out internal frames
524
+ */ function captureTrace(offset = 0) {
525
+ const lines = ((/* @__PURE__ */ new Error()).stack ?? "").split("\n");
526
+ const begin = lines.findIndex((line) => line.includes("captureTrace"));
527
+ return lines.slice(begin !== -1 ? begin + 1 + offset : 4).join("\n");
528
+ }
529
+
530
+ //#endregion
531
+ //#region src/utils/runtime.ts
532
+ /**
533
+ * Detect if running in Bun environment (OpenTUI is not supported in Bun)
534
+ */ function isBunRuntime() {
535
+ return typeof globalThis.Bun !== "undefined";
536
+ }
537
+ /**
538
+ * Dynamic import that bypasses bundler static analysis.
539
+ * Uses Function constructor to prevent bundlers from resolving the import at build time.
540
+ */ function dynamicImport(modulePath) {
541
+ return new Function("modulePath", "return import(modulePath)")(modulePath);
542
+ }
543
+
544
+ //#endregion
545
+ //#region src/utils/prompt.ts
546
+ /**
547
+ * Get the default value for a prompt based on its type.
548
+ * Used for resolving prompts when no interaction is possible.
549
+ */ function getPromptDefaultValue(prompt) {
550
+ switch (prompt.type) {
551
+ case "choice": return prompt.defaultChoice;
552
+ case "confirm": return prompt.defaultValue;
553
+ case "input": return prompt.defaultValue;
554
+ case "multiChoice": return prompt.choices.filter((_, i) => prompt.selectedIndices.has(i)).map((c) => c.value);
555
+ }
556
+ }
557
+
558
+ //#endregion
5
559
  //#region ../../node_modules/zod/v4/core/core.js
6
560
  /** A special constant with type `never` */
7
561
  const NEVER = Object.freeze({ status: "aborted" });
@@ -2628,7 +3182,7 @@ function initializeContext(params) {
2628
3182
  external: params?.external ?? void 0
2629
3183
  };
2630
3184
  }
2631
- function process(schema, ctx, _params = {
3185
+ function process$1(schema, ctx, _params = {
2632
3186
  path: [],
2633
3187
  schemaPath: []
2634
3188
  }) {
@@ -2665,7 +3219,7 @@ function process(schema, ctx, _params = {
2665
3219
  const parent = schema._zod.parent;
2666
3220
  if (parent) {
2667
3221
  if (!result.ref) result.ref = parent;
2668
- process(parent, ctx, params);
3222
+ process$1(parent, ctx, params);
2669
3223
  ctx.seen.get(parent).isParent = true;
2670
3224
  }
2671
3225
  }
@@ -2877,7 +3431,7 @@ const createToJSONSchemaMethod = (schema, processors = {}) => (params) => {
2877
3431
  ...params,
2878
3432
  processors
2879
3433
  });
2880
- process(schema, ctx);
3434
+ process$1(schema, ctx);
2881
3435
  extractDefs(ctx, schema);
2882
3436
  return finalize(ctx, schema);
2883
3437
  };
@@ -2889,7 +3443,7 @@ const createStandardJSONSchemaMethod = (schema, io, processors = {}) => (params)
2889
3443
  io,
2890
3444
  processors
2891
3445
  });
2892
- process(schema, ctx);
3446
+ process$1(schema, ctx);
2893
3447
  extractDefs(ctx, schema);
2894
3448
  return finalize(ctx, schema);
2895
3449
  };
@@ -2976,7 +3530,7 @@ const arrayProcessor = (schema, ctx, _json, params) => {
2976
3530
  if (typeof minimum === "number") json.minItems = minimum;
2977
3531
  if (typeof maximum === "number") json.maxItems = maximum;
2978
3532
  json.type = "array";
2979
- json.items = process(def.element, ctx, {
3533
+ json.items = process$1(def.element, ctx, {
2980
3534
  ...params,
2981
3535
  path: [...params.path, "items"]
2982
3536
  });
@@ -2987,7 +3541,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
2987
3541
  json.type = "object";
2988
3542
  json.properties = {};
2989
3543
  const shape = def.shape;
2990
- for (const key in shape) json.properties[key] = process(shape[key], ctx, {
3544
+ for (const key in shape) json.properties[key] = process$1(shape[key], ctx, {
2991
3545
  ...params,
2992
3546
  path: [
2993
3547
  ...params.path,
@@ -3005,7 +3559,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
3005
3559
  if (def.catchall?._zod.def.type === "never") json.additionalProperties = false;
3006
3560
  else if (!def.catchall) {
3007
3561
  if (ctx.io === "output") json.additionalProperties = false;
3008
- } else if (def.catchall) json.additionalProperties = process(def.catchall, ctx, {
3562
+ } else if (def.catchall) json.additionalProperties = process$1(def.catchall, ctx, {
3009
3563
  ...params,
3010
3564
  path: [...params.path, "additionalProperties"]
3011
3565
  });
@@ -3013,7 +3567,7 @@ const objectProcessor = (schema, ctx, _json, params) => {
3013
3567
  const unionProcessor = (schema, ctx, json, params) => {
3014
3568
  const def = schema._zod.def;
3015
3569
  const isExclusive = def.inclusive === false;
3016
- const options = def.options.map((x, i) => process(x, ctx, {
3570
+ const options = def.options.map((x, i) => process$1(x, ctx, {
3017
3571
  ...params,
3018
3572
  path: [
3019
3573
  ...params.path,
@@ -3026,7 +3580,7 @@ const unionProcessor = (schema, ctx, json, params) => {
3026
3580
  };
3027
3581
  const intersectionProcessor = (schema, ctx, json, params) => {
3028
3582
  const def = schema._zod.def;
3029
- const a = process(def.left, ctx, {
3583
+ const a = process$1(def.left, ctx, {
3030
3584
  ...params,
3031
3585
  path: [
3032
3586
  ...params.path,
@@ -3034,7 +3588,7 @@ const intersectionProcessor = (schema, ctx, json, params) => {
3034
3588
  0
3035
3589
  ]
3036
3590
  });
3037
- const b = process(def.right, ctx, {
3591
+ const b = process$1(def.right, ctx, {
3038
3592
  ...params,
3039
3593
  path: [
3040
3594
  ...params.path,
@@ -3047,7 +3601,7 @@ const intersectionProcessor = (schema, ctx, json, params) => {
3047
3601
  };
3048
3602
  const nullableProcessor = (schema, ctx, json, params) => {
3049
3603
  const def = schema._zod.def;
3050
- const inner = process(def.innerType, ctx, params);
3604
+ const inner = process$1(def.innerType, ctx, params);
3051
3605
  const seen = ctx.seen.get(schema);
3052
3606
  if (ctx.target === "openapi-3.0") {
3053
3607
  seen.ref = def.innerType;
@@ -3056,27 +3610,27 @@ const nullableProcessor = (schema, ctx, json, params) => {
3056
3610
  };
3057
3611
  const nonoptionalProcessor = (schema, ctx, _json, params) => {
3058
3612
  const def = schema._zod.def;
3059
- process(def.innerType, ctx, params);
3613
+ process$1(def.innerType, ctx, params);
3060
3614
  const seen = ctx.seen.get(schema);
3061
3615
  seen.ref = def.innerType;
3062
3616
  };
3063
3617
  const defaultProcessor = (schema, ctx, json, params) => {
3064
3618
  const def = schema._zod.def;
3065
- process(def.innerType, ctx, params);
3619
+ process$1(def.innerType, ctx, params);
3066
3620
  const seen = ctx.seen.get(schema);
3067
3621
  seen.ref = def.innerType;
3068
3622
  json.default = JSON.parse(JSON.stringify(def.defaultValue));
3069
3623
  };
3070
3624
  const prefaultProcessor = (schema, ctx, json, params) => {
3071
3625
  const def = schema._zod.def;
3072
- process(def.innerType, ctx, params);
3626
+ process$1(def.innerType, ctx, params);
3073
3627
  const seen = ctx.seen.get(schema);
3074
3628
  seen.ref = def.innerType;
3075
3629
  if (ctx.io === "input") json._prefault = JSON.parse(JSON.stringify(def.defaultValue));
3076
3630
  };
3077
3631
  const catchProcessor = (schema, ctx, json, params) => {
3078
3632
  const def = schema._zod.def;
3079
- process(def.innerType, ctx, params);
3633
+ process$1(def.innerType, ctx, params);
3080
3634
  const seen = ctx.seen.get(schema);
3081
3635
  seen.ref = def.innerType;
3082
3636
  let catchValue;
@@ -3090,20 +3644,20 @@ const catchProcessor = (schema, ctx, json, params) => {
3090
3644
  const pipeProcessor = (schema, ctx, _json, params) => {
3091
3645
  const def = schema._zod.def;
3092
3646
  const innerType = ctx.io === "input" ? def.in._zod.def.type === "transform" ? def.out : def.in : def.out;
3093
- process(innerType, ctx, params);
3647
+ process$1(innerType, ctx, params);
3094
3648
  const seen = ctx.seen.get(schema);
3095
3649
  seen.ref = innerType;
3096
3650
  };
3097
3651
  const readonlyProcessor = (schema, ctx, json, params) => {
3098
3652
  const def = schema._zod.def;
3099
- process(def.innerType, ctx, params);
3653
+ process$1(def.innerType, ctx, params);
3100
3654
  const seen = ctx.seen.get(schema);
3101
3655
  seen.ref = def.innerType;
3102
3656
  json.readOnly = true;
3103
3657
  };
3104
3658
  const optionalProcessor = (schema, ctx, _json, params) => {
3105
3659
  const def = schema._zod.def;
3106
- process(def.innerType, ctx, params);
3660
+ process$1(def.innerType, ctx, params);
3107
3661
  const seen = ctx.seen.get(schema);
3108
3662
  seen.ref = def.innerType;
3109
3663
  };
@@ -3782,6 +4336,14 @@ const ScreenLogger = InjectionToken.create("ScreenLoggerInstance", LoggerOptions
3782
4336
  //#region src/tokens/prompt.ts
3783
4337
  const Prompt = InjectionToken.create("Prompt", PromptOptionsSchema);
3784
4338
 
4339
+ //#endregion
4340
+ //#region src/tokens/adapter.ts
4341
+ /**
4342
+ * Injection token for the TUI rendering adapter.
4343
+ * Import the specific adapter (e.g., '@navios/commander-tui/adapters/react')
4344
+ * to register an implementation.
4345
+ */ const Adapter = InjectionToken.create("Adapter");
4346
+
3785
4347
  //#endregion
3786
4348
  //#region src/tokens/screen-manager.ts
3787
4349
  /**
@@ -4991,6 +5553,7 @@ function _apply_decs_2203_r$3(targetClass, memberDecs, classDecs, parentClass) {
4991
5553
  return (_apply_decs_2203_r$3 = applyDecs2203RFactory$3())(targetClass, memberDecs, classDecs, parentClass);
4992
5554
  }
4993
5555
  var _dec$3, _initClass$3;
5556
+ const MISSING_ADAPTER_ERROR = "Adapter not registered, add import statement for @navios/tui-adapter-react, @navios/tui-adapter-ink or @navios/tui-adapter-solid to your module";
4994
5557
  let _MissingAdapterOverride;
4995
5558
  _dec$3 = Injectable({
4996
5559
  token: Adapter,
@@ -5000,20 +5563,698 @@ var MissingAdapterOverride = class {
5000
5563
  static {
5001
5564
  ({c: [_MissingAdapterOverride, _initClass$3]} = _apply_decs_2203_r$3(this, [], [_dec$3]));
5002
5565
  }
5566
+ /**
5567
+ * Marker property to identify this as the missing adapter fallback.
5568
+ * Used by ScreenManager.bind() to detect and handle graceful fallback.
5569
+ */ isMissingAdapter = true;
5003
5570
  createRoot() {
5004
- throw new Error("Adapter not registered, add import statement for @navios/commander-tui/adapters/react or @navios/commander-tui/adapters/solid to your module");
5571
+ throw new Error(MISSING_ADAPTER_ERROR);
5005
5572
  }
5006
5573
  renderToRoot() {
5007
- throw new Error("Adapter not registered, add import statement for @navios/commander-tui/adapters/react or @navios/commander-tui/adapters/solid to your module");
5574
+ throw new Error(MISSING_ADAPTER_ERROR);
5008
5575
  }
5009
5576
  static {
5010
5577
  _initClass$3();
5011
5578
  }
5012
5579
  };
5013
5580
 
5581
+ //#endregion
5582
+ //#region src/themes/dark.ts
5583
+ /**
5584
+ * Default dark theme.
5585
+ * Migrated from the scattered color files in utils/colors/.
5586
+ */ const darkTheme = {
5587
+ name: "dark",
5588
+ logLevels: {
5589
+ verbose: {
5590
+ border: "#6B7280",
5591
+ background: "#6B728015"
5592
+ },
5593
+ debug: {
5594
+ border: "#8B5CF6",
5595
+ background: "#8B5CF615"
5596
+ },
5597
+ log: {
5598
+ border: "#3B82F6",
5599
+ background: "#3B82F615"
5600
+ },
5601
+ warn: {
5602
+ border: "#F59E0B",
5603
+ background: "#F59E0B15"
5604
+ },
5605
+ error: {
5606
+ border: "#EF4444",
5607
+ background: "#EF444415"
5608
+ },
5609
+ fatal: {
5610
+ border: "#DC2626",
5611
+ background: "#DC262625",
5612
+ text: "#FCA5A5"
5613
+ }
5614
+ },
5615
+ sidebar: {
5616
+ background: void 0,
5617
+ selectedBackground: "#1F293780",
5618
+ hoverBackground: "#374151",
5619
+ text: "#E5E7EB",
5620
+ textDim: "#6B7280",
5621
+ border: "#374151",
5622
+ badge: "#3B82F6",
5623
+ focusBorder: "#3B82F6"
5624
+ },
5625
+ header: {
5626
+ background: void 0,
5627
+ text: "#F9FAFB",
5628
+ border: "#374151"
5629
+ },
5630
+ statusIndicators: {
5631
+ waiting: {
5632
+ icon: "○",
5633
+ color: "#6B7280"
5634
+ },
5635
+ pending: {
5636
+ icon: "◐",
5637
+ color: "#F59E0B"
5638
+ },
5639
+ success: {
5640
+ icon: "✓",
5641
+ color: "#22C55E"
5642
+ },
5643
+ fail: {
5644
+ icon: "✗",
5645
+ color: "#EF4444"
5646
+ },
5647
+ static: {
5648
+ icon: "●",
5649
+ color: "#3B82F6"
5650
+ }
5651
+ },
5652
+ separator: {
5653
+ line: "#374151",
5654
+ text: "#6B7280"
5655
+ },
5656
+ progress: {
5657
+ border: "#3B82F6",
5658
+ background: "#3B82F615",
5659
+ barFilled: "#3B82F6",
5660
+ barEmpty: "#374151",
5661
+ text: "#E5E7EB",
5662
+ textDim: "#9CA3AF",
5663
+ complete: "#22C55E",
5664
+ completeBackground: "#22C55E15",
5665
+ failed: "#EF4444",
5666
+ failedBackground: "#EF444415"
5667
+ },
5668
+ group: {
5669
+ border: "#6B7280",
5670
+ background: "#6B728010",
5671
+ headerText: "#E5E7EB",
5672
+ icon: "#9CA3AF"
5673
+ },
5674
+ table: {
5675
+ border: "#3B82F6",
5676
+ background: "#3B82F615",
5677
+ headerText: "#F9FAFB",
5678
+ cellText: "#E5E7EB",
5679
+ title: "#F9FAFB",
5680
+ separator: "#3B82F650"
5681
+ },
5682
+ file: {
5683
+ border: "#3B82F6",
5684
+ background: "#3B82F615",
5685
+ headerText: "#F9FAFB",
5686
+ headerBackground: "#3B82F625"
5687
+ },
5688
+ prompt: {
5689
+ question: "#F9FAFB",
5690
+ optionText: "#E5E7EB",
5691
+ optionTextDim: "#9CA3AF",
5692
+ optionSelected: "#3B82F6",
5693
+ optionSelectedBackground: "#1E3A5F",
5694
+ confirmButton: "#22C55E",
5695
+ cancelButton: "#EF4444",
5696
+ buttonBackground: "#374151",
5697
+ buttonSelectedBackground: "#1F2937",
5698
+ inputBorder: "#3B82F6",
5699
+ inputBackground: "#1F2937",
5700
+ inputText: "#F9FAFB",
5701
+ inputPlaceholder: "#6B7280",
5702
+ inputCursor: "#3B82F6",
5703
+ border: "#374151",
5704
+ focusBorder: "#3B82F6"
5705
+ },
5706
+ errorHighlight: {
5707
+ background: "#EF444425",
5708
+ border: "#EF4444",
5709
+ gutterBackground: "#EF444440"
5710
+ },
5711
+ filter: {
5712
+ background: "#1F293780",
5713
+ border: "#3B82F6",
5714
+ text: "#E5E7EB",
5715
+ textDim: "#6B7280",
5716
+ inputBackground: "#1F2937",
5717
+ inputText: "#F9FAFB",
5718
+ inputPlaceholder: "#6B7280",
5719
+ cursor: "#3B82F6",
5720
+ activeLevel: "#3B82F6",
5721
+ inactiveLevel: "#4B5563"
5722
+ },
5723
+ help: {
5724
+ background: "#1F2937",
5725
+ border: "#3B82F6",
5726
+ title: "#F9FAFB",
5727
+ category: "#3B82F6",
5728
+ key: "#F59E0B",
5729
+ description: "#E5E7EB",
5730
+ hint: "#6B7280"
5731
+ },
5732
+ colors: {
5733
+ primary: "#3B82F6",
5734
+ secondary: "#8B5CF6",
5735
+ success: "#22C55E",
5736
+ warning: "#F59E0B",
5737
+ error: "#EF4444",
5738
+ muted: "#6B7280",
5739
+ background: "#111827",
5740
+ foreground: "#F9FAFB"
5741
+ }
5742
+ };
5743
+
5744
+ //#endregion
5745
+ //#region src/themes/light.ts
5746
+ /**
5747
+ * Light theme for terminals with light backgrounds.
5748
+ */ const lightTheme = {
5749
+ name: "light",
5750
+ logLevels: {
5751
+ verbose: {
5752
+ border: "#9CA3AF",
5753
+ background: "#F3F4F6"
5754
+ },
5755
+ debug: {
5756
+ border: "#7C3AED",
5757
+ background: "#EDE9FE"
5758
+ },
5759
+ log: {
5760
+ border: "#2563EB",
5761
+ background: "#DBEAFE"
5762
+ },
5763
+ warn: {
5764
+ border: "#D97706",
5765
+ background: "#FEF3C7"
5766
+ },
5767
+ error: {
5768
+ border: "#DC2626",
5769
+ background: "#FEE2E2"
5770
+ },
5771
+ fatal: {
5772
+ border: "#991B1B",
5773
+ background: "#FECACA",
5774
+ text: "#7F1D1D"
5775
+ }
5776
+ },
5777
+ sidebar: {
5778
+ background: "#F9FAFB",
5779
+ selectedBackground: "#E5E7EB",
5780
+ hoverBackground: "#F3F4F6",
5781
+ text: "#1F2937",
5782
+ textDim: "#6B7280",
5783
+ border: "#D1D5DB",
5784
+ badge: "#2563EB",
5785
+ focusBorder: "#2563EB"
5786
+ },
5787
+ header: {
5788
+ background: "#F9FAFB",
5789
+ text: "#111827",
5790
+ border: "#D1D5DB"
5791
+ },
5792
+ statusIndicators: {
5793
+ waiting: {
5794
+ icon: "○",
5795
+ color: "#9CA3AF"
5796
+ },
5797
+ pending: {
5798
+ icon: "◐",
5799
+ color: "#D97706"
5800
+ },
5801
+ success: {
5802
+ icon: "✓",
5803
+ color: "#16A34A"
5804
+ },
5805
+ fail: {
5806
+ icon: "✗",
5807
+ color: "#DC2626"
5808
+ },
5809
+ static: {
5810
+ icon: "●",
5811
+ color: "#2563EB"
5812
+ }
5813
+ },
5814
+ separator: {
5815
+ line: "#D1D5DB",
5816
+ text: "#6B7280"
5817
+ },
5818
+ progress: {
5819
+ border: "#2563EB",
5820
+ background: "#DBEAFE",
5821
+ barFilled: "#2563EB",
5822
+ barEmpty: "#E5E7EB",
5823
+ text: "#1F2937",
5824
+ textDim: "#6B7280",
5825
+ complete: "#16A34A",
5826
+ completeBackground: "#DCFCE7",
5827
+ failed: "#DC2626",
5828
+ failedBackground: "#FEE2E2"
5829
+ },
5830
+ group: {
5831
+ border: "#9CA3AF",
5832
+ background: "#F3F4F6",
5833
+ headerText: "#1F2937",
5834
+ icon: "#6B7280"
5835
+ },
5836
+ table: {
5837
+ border: "#2563EB",
5838
+ background: "#DBEAFE",
5839
+ headerText: "#111827",
5840
+ cellText: "#1F2937",
5841
+ title: "#111827",
5842
+ separator: "#93C5FD"
5843
+ },
5844
+ file: {
5845
+ border: "#2563EB",
5846
+ background: "#DBEAFE",
5847
+ headerText: "#111827",
5848
+ headerBackground: "#BFDBFE"
5849
+ },
5850
+ prompt: {
5851
+ question: "#111827",
5852
+ optionText: "#1F2937",
5853
+ optionTextDim: "#6B7280",
5854
+ optionSelected: "#2563EB",
5855
+ optionSelectedBackground: "#DBEAFE",
5856
+ confirmButton: "#16A34A",
5857
+ cancelButton: "#DC2626",
5858
+ buttonBackground: "#E5E7EB",
5859
+ buttonSelectedBackground: "#D1D5DB",
5860
+ inputBorder: "#2563EB",
5861
+ inputBackground: "#FFFFFF",
5862
+ inputText: "#111827",
5863
+ inputPlaceholder: "#9CA3AF",
5864
+ inputCursor: "#2563EB",
5865
+ border: "#D1D5DB",
5866
+ focusBorder: "#2563EB"
5867
+ },
5868
+ errorHighlight: {
5869
+ background: "#FEE2E2",
5870
+ border: "#DC2626",
5871
+ gutterBackground: "#FECACA"
5872
+ },
5873
+ filter: {
5874
+ background: "#F3F4F6",
5875
+ border: "#2563EB",
5876
+ text: "#1F2937",
5877
+ textDim: "#6B7280",
5878
+ inputBackground: "#FFFFFF",
5879
+ inputText: "#111827",
5880
+ inputPlaceholder: "#9CA3AF",
5881
+ cursor: "#2563EB",
5882
+ activeLevel: "#2563EB",
5883
+ inactiveLevel: "#D1D5DB"
5884
+ },
5885
+ help: {
5886
+ background: "#FFFFFF",
5887
+ border: "#2563EB",
5888
+ title: "#111827",
5889
+ category: "#2563EB",
5890
+ key: "#D97706",
5891
+ description: "#1F2937",
5892
+ hint: "#6B7280"
5893
+ },
5894
+ colors: {
5895
+ primary: "#2563EB",
5896
+ secondary: "#7C3AED",
5897
+ success: "#16A34A",
5898
+ warning: "#D97706",
5899
+ error: "#DC2626",
5900
+ muted: "#6B7280",
5901
+ background: "#FFFFFF",
5902
+ foreground: "#111827"
5903
+ }
5904
+ };
5905
+
5906
+ //#endregion
5907
+ //#region src/themes/high-contrast.ts
5908
+ /**
5909
+ * High contrast theme for accessibility.
5910
+ * Uses pure black/white with saturated colors for maximum visibility.
5911
+ */ const highContrastTheme = {
5912
+ name: "high-contrast",
5913
+ logLevels: {
5914
+ verbose: {
5915
+ border: "#FFFFFF",
5916
+ background: "#1A1A1A",
5917
+ text: "#FFFFFF"
5918
+ },
5919
+ debug: {
5920
+ border: "#A855F7",
5921
+ background: "#1A1A1A",
5922
+ text: "#E9D5FF"
5923
+ },
5924
+ log: {
5925
+ border: "#3B82F6",
5926
+ background: "#1A1A1A",
5927
+ text: "#BFDBFE"
5928
+ },
5929
+ warn: {
5930
+ border: "#FBBF24",
5931
+ background: "#1A1A1A",
5932
+ text: "#FEF08A"
5933
+ },
5934
+ error: {
5935
+ border: "#EF4444",
5936
+ background: "#1A1A1A",
5937
+ text: "#FECACA"
5938
+ },
5939
+ fatal: {
5940
+ border: "#FF0000",
5941
+ background: "#330000",
5942
+ text: "#FFFFFF"
5943
+ }
5944
+ },
5945
+ sidebar: {
5946
+ background: "#000000",
5947
+ selectedBackground: "#333333",
5948
+ hoverBackground: "#1A1A1A",
5949
+ text: "#FFFFFF",
5950
+ textDim: "#AAAAAA",
5951
+ border: "#FFFFFF",
5952
+ badge: "#FFFF00",
5953
+ focusBorder: "#FFFF00"
5954
+ },
5955
+ header: {
5956
+ background: "#000000",
5957
+ text: "#FFFFFF",
5958
+ border: "#FFFFFF"
5959
+ },
5960
+ statusIndicators: {
5961
+ waiting: {
5962
+ icon: "○",
5963
+ color: "#AAAAAA"
5964
+ },
5965
+ pending: {
5966
+ icon: "◐",
5967
+ color: "#FBBF24"
5968
+ },
5969
+ success: {
5970
+ icon: "✓",
5971
+ color: "#22C55E"
5972
+ },
5973
+ fail: {
5974
+ icon: "✗",
5975
+ color: "#EF4444"
5976
+ },
5977
+ static: {
5978
+ icon: "●",
5979
+ color: "#00FFFF"
5980
+ }
5981
+ },
5982
+ separator: {
5983
+ line: "#FFFFFF",
5984
+ text: "#AAAAAA"
5985
+ },
5986
+ progress: {
5987
+ border: "#3B82F6",
5988
+ background: "#1A1A1A",
5989
+ barFilled: "#3B82F6",
5990
+ barEmpty: "#333333",
5991
+ text: "#FFFFFF",
5992
+ textDim: "#AAAAAA",
5993
+ complete: "#22C55E",
5994
+ completeBackground: "#1A1A1A",
5995
+ failed: "#EF4444",
5996
+ failedBackground: "#1A1A1A"
5997
+ },
5998
+ group: {
5999
+ border: "#FFFFFF",
6000
+ background: "#1A1A1A",
6001
+ headerText: "#FFFFFF",
6002
+ icon: "#AAAAAA"
6003
+ },
6004
+ table: {
6005
+ border: "#FFFFFF",
6006
+ background: "#1A1A1A",
6007
+ headerText: "#FFFFFF",
6008
+ cellText: "#FFFFFF",
6009
+ title: "#FFFFFF",
6010
+ separator: "#666666"
6011
+ },
6012
+ file: {
6013
+ border: "#FFFFFF",
6014
+ background: "#1A1A1A",
6015
+ headerText: "#FFFFFF",
6016
+ headerBackground: "#333333"
6017
+ },
6018
+ prompt: {
6019
+ question: "#FFFFFF",
6020
+ optionText: "#FFFFFF",
6021
+ optionTextDim: "#AAAAAA",
6022
+ optionSelected: "#FFFF00",
6023
+ optionSelectedBackground: "#333333",
6024
+ confirmButton: "#22C55E",
6025
+ cancelButton: "#EF4444",
6026
+ buttonBackground: "#333333",
6027
+ buttonSelectedBackground: "#1A1A1A",
6028
+ inputBorder: "#FFFF00",
6029
+ inputBackground: "#1A1A1A",
6030
+ inputText: "#FFFFFF",
6031
+ inputPlaceholder: "#666666",
6032
+ inputCursor: "#FFFF00",
6033
+ border: "#FFFFFF",
6034
+ focusBorder: "#FFFF00"
6035
+ },
6036
+ errorHighlight: {
6037
+ background: "#330000",
6038
+ border: "#FF0000",
6039
+ gutterBackground: "#660000"
6040
+ },
6041
+ filter: {
6042
+ background: "#1A1A1A",
6043
+ border: "#FFFF00",
6044
+ text: "#FFFFFF",
6045
+ textDim: "#AAAAAA",
6046
+ inputBackground: "#000000",
6047
+ inputText: "#FFFFFF",
6048
+ inputPlaceholder: "#666666",
6049
+ cursor: "#FFFF00",
6050
+ activeLevel: "#FFFF00",
6051
+ inactiveLevel: "#666666"
6052
+ },
6053
+ help: {
6054
+ background: "#000000",
6055
+ border: "#FFFFFF",
6056
+ title: "#FFFFFF",
6057
+ category: "#FFFF00",
6058
+ key: "#00FFFF",
6059
+ description: "#FFFFFF",
6060
+ hint: "#AAAAAA"
6061
+ },
6062
+ colors: {
6063
+ primary: "#3B82F6",
6064
+ secondary: "#A855F7",
6065
+ success: "#22C55E",
6066
+ warning: "#FBBF24",
6067
+ error: "#EF4444",
6068
+ muted: "#AAAAAA",
6069
+ background: "#000000",
6070
+ foreground: "#FFFFFF"
6071
+ }
6072
+ };
6073
+
6074
+ //#endregion
6075
+ //#region src/themes/utils.ts
6076
+ /**
6077
+ * Deep merge two objects, with source taking precedence.
6078
+ */ function deepMerge(target, source) {
6079
+ const result = { ...target };
6080
+ for (const key in source) if (Object.prototype.hasOwnProperty.call(source, key)) {
6081
+ const sourceValue = source[key];
6082
+ const targetValue = target[key];
6083
+ if (sourceValue !== void 0 && typeof sourceValue === "object" && sourceValue !== null && !Array.isArray(sourceValue) && typeof targetValue === "object" && targetValue !== null && !Array.isArray(targetValue)) result[key] = deepMerge(targetValue, sourceValue);
6084
+ else if (sourceValue !== void 0) result[key] = sourceValue;
6085
+ }
6086
+ return result;
6087
+ }
6088
+ /**
6089
+ * Get a theme by preset name.
6090
+ */ function getThemePreset(preset) {
6091
+ switch (preset) {
6092
+ case "dark": return darkTheme;
6093
+ case "light": return lightTheme;
6094
+ case "high-contrast": return highContrastTheme;
6095
+ default: return darkTheme;
6096
+ }
6097
+ }
6098
+ /**
6099
+ * Merge a base theme with partial overrides.
6100
+ */ function mergeThemes(base, overrides) {
6101
+ return deepMerge(base, overrides);
6102
+ }
6103
+ /**
6104
+ * Create a custom theme by extending the dark theme with overrides.
6105
+ */ function createTheme(overrides) {
6106
+ return mergeThemes(darkTheme, overrides);
6107
+ }
6108
+ /**
6109
+ * Create a custom theme by extending a specific base theme.
6110
+ */ function createThemeFrom(base, overrides) {
6111
+ return mergeThemes(typeof base === "string" ? getThemePreset(base) : base, overrides);
6112
+ }
6113
+ /**
6114
+ * Resolve a theme value which can be a Theme object or a preset name.
6115
+ */ function resolveTheme(theme) {
6116
+ return typeof theme === "string" ? getThemePreset(theme) : theme;
6117
+ }
6118
+
6119
+ //#endregion
6120
+ //#region src/services/readline_prompt.ts
6121
+ /**
6122
+ * Readline-based prompt service for stdout mode.
6123
+ * Provides basic interactive prompts when TUI adapter is not available.
6124
+ */ var ReadlinePromptService = class {
6125
+ rl = null;
6126
+ promptQueue = [];
6127
+ isProcessing = false;
6128
+ ensureInterface() {
6129
+ if (!this.rl) this.rl = readline.createInterface({
6130
+ input: process.stdin,
6131
+ output: process.stdout
6132
+ });
6133
+ return this.rl;
6134
+ }
6135
+ /**
6136
+ * Handle a prompt interactively via readline.
6137
+ * Prompts are queued and processed sequentially.
6138
+ */ async handlePrompt(prompt) {
6139
+ return new Promise((resolve) => {
6140
+ this.promptQueue.push({
6141
+ prompt,
6142
+ resolve
6143
+ });
6144
+ this.processQueue();
6145
+ });
6146
+ }
6147
+ async processQueue() {
6148
+ if (this.isProcessing || this.promptQueue.length === 0) return;
6149
+ this.isProcessing = true;
6150
+ while (this.promptQueue.length > 0) {
6151
+ const { prompt, resolve } = this.promptQueue.shift();
6152
+ resolve(await this.processPrompt(prompt));
6153
+ }
6154
+ this.isProcessing = false;
6155
+ }
6156
+ async processPrompt(prompt) {
6157
+ switch (prompt.type) {
6158
+ case "choice": return this.handleChoice(prompt);
6159
+ case "confirm": return this.handleConfirm(prompt);
6160
+ case "input": return this.handleInput(prompt);
6161
+ case "multiChoice": return this.handleMultiChoice(prompt);
6162
+ }
6163
+ }
6164
+ async handleChoice(prompt) {
6165
+ const rl = this.ensureInterface();
6166
+ console.log(`\n${prompt.question}`);
6167
+ prompt.choices.forEach((choice, index) => {
6168
+ const marker = choice.value === prompt.defaultChoice ? "*" : " ";
6169
+ const inputHint = choice.input ? " (allows custom input)" : "";
6170
+ console.log(` ${marker} ${index + 1}. ${choice.label}${inputHint}`);
6171
+ });
6172
+ return new Promise((resolve) => {
6173
+ rl.question("Enter number (or press Enter for default): ", (answer) => {
6174
+ const trimmed = answer.trim();
6175
+ if (!trimmed) {
6176
+ resolve(prompt.defaultChoice);
6177
+ return;
6178
+ }
6179
+ const num = parseInt(trimmed, 10);
6180
+ if (num >= 1 && num <= prompt.choices.length) {
6181
+ const choice = prompt.choices[num - 1];
6182
+ if (choice.input) rl.question(`Enter value for "${choice.label}": `, (inputValue) => {
6183
+ resolve(inputValue.trim() || choice.value);
6184
+ });
6185
+ else resolve(choice.value);
6186
+ } else resolve(prompt.defaultChoice);
6187
+ });
6188
+ });
6189
+ }
6190
+ async handleConfirm(prompt) {
6191
+ const rl = this.ensureInterface();
6192
+ const defaultText = prompt.defaultValue ? "Y/n" : "y/N";
6193
+ return new Promise((resolve) => {
6194
+ rl.question(`${prompt.question} [${defaultText}]: `, (answer) => {
6195
+ const trimmed = answer.trim().toLowerCase();
6196
+ if (!trimmed) {
6197
+ resolve(prompt.defaultValue);
6198
+ return;
6199
+ }
6200
+ resolve(trimmed === "y" || trimmed === "yes");
6201
+ });
6202
+ });
6203
+ }
6204
+ async handleInput(prompt) {
6205
+ const rl = this.ensureInterface();
6206
+ const defaultHint = prompt.defaultValue ? ` (default: ${prompt.defaultValue})` : "";
6207
+ const placeholderHint = prompt.placeholder ? ` [${prompt.placeholder}]` : "";
6208
+ return new Promise((resolve) => {
6209
+ rl.question(`${prompt.question}${placeholderHint}${defaultHint}: `, (answer) => {
6210
+ resolve(answer.trim() || prompt.defaultValue);
6211
+ });
6212
+ });
6213
+ }
6214
+ async handleMultiChoice(prompt) {
6215
+ const rl = this.ensureInterface();
6216
+ console.log(`\n${prompt.question}`);
6217
+ console.log(`(Select ${prompt.minSelect}-${prompt.maxSelect} options, enter comma-separated numbers)`);
6218
+ prompt.choices.forEach((choice, index) => {
6219
+ const selected = prompt.selectedIndices.has(index) ? "[x]" : "[ ]";
6220
+ console.log(` ${selected} ${index + 1}. ${choice.label}`);
6221
+ });
6222
+ return new Promise((resolve) => {
6223
+ rl.question("Enter numbers (e.g., 1,3,5): ", (answer) => {
6224
+ const trimmed = answer.trim();
6225
+ if (!trimmed) {
6226
+ resolve(prompt.choices.filter((_, i) => prompt.selectedIndices.has(i)).map((c) => c.value));
6227
+ return;
6228
+ }
6229
+ const indices = trimmed.split(",").map((s) => parseInt(s.trim(), 10) - 1).filter((n) => n >= 0 && n < prompt.choices.length);
6230
+ if (indices.length < prompt.minSelect) {
6231
+ console.log(`Minimum ${prompt.minSelect} selections required. Using defaults.`);
6232
+ resolve(prompt.choices.filter((_, i) => prompt.selectedIndices.has(i)).map((c) => c.value));
6233
+ return;
6234
+ }
6235
+ if (indices.length > prompt.maxSelect) {
6236
+ console.log(`Maximum ${prompt.maxSelect} selections allowed. Taking first ${prompt.maxSelect}.`);
6237
+ indices.splice(prompt.maxSelect);
6238
+ }
6239
+ resolve(indices.map((i) => prompt.choices[i].value));
6240
+ });
6241
+ });
6242
+ }
6243
+ /**
6244
+ * Cleanup readline interface
6245
+ */ destroy() {
6246
+ if (this.rl) {
6247
+ this.rl.close();
6248
+ this.rl = null;
6249
+ }
6250
+ this.promptQueue = [];
6251
+ this.isProcessing = false;
6252
+ }
6253
+ };
6254
+
5014
6255
  //#endregion
5015
6256
  //#region src/services/screen.ts
5016
- var ScreenInstance = class {
6257
+ var ScreenInstance = class extends EventEmitter {
5017
6258
  id;
5018
6259
  name;
5019
6260
  icon;
@@ -5022,13 +6263,13 @@ var ScreenInstance = class {
5022
6263
  hidden = false;
5023
6264
  messages = [];
5024
6265
  manager = null;
5025
- changeListeners = /* @__PURE__ */ new Set();
5026
6266
  printFn = null;
5027
6267
  hasPrinted = false;
5028
6268
  version = 0;
5029
6269
  promptQueue = [];
5030
6270
  activePrompt = null;
5031
6271
  constructor(id, options) {
6272
+ super();
5032
6273
  this.id = id;
5033
6274
  this.name = options.name;
5034
6275
  this.icon = options.icon;
@@ -5066,7 +6307,7 @@ var ScreenInstance = class {
5066
6307
  }
5067
6308
  setBadgeCount(count) {
5068
6309
  this.badgeCount = count;
5069
- this.notifyChange();
6310
+ this.emit("badge:changed", count);
5070
6311
  return this;
5071
6312
  }
5072
6313
  isHidden() {
@@ -5075,7 +6316,7 @@ var ScreenInstance = class {
5075
6316
  setHidden(hidden) {
5076
6317
  this.hidden = hidden;
5077
6318
  this.manager?.onScreenVisibilityChanged(this);
5078
- this.notifyChange();
6319
+ this.emit("visibility:changed", hidden);
5079
6320
  return this;
5080
6321
  }
5081
6322
  show() {
@@ -5088,15 +6329,22 @@ var ScreenInstance = class {
5088
6329
  return this.status;
5089
6330
  }
5090
6331
  /**
5091
- * Set screen status. When success/fail and TUI is not bound, prints to stdout/stderr
6332
+ * Check if a log level is enabled globally via the ScreenManager.
6333
+ * Returns true if no manager is set or if the level is allowed.
6334
+ */ isLogLevelEnabled(level) {
6335
+ if (!this.manager) return true;
6336
+ return this.manager.isLogLevelEnabled(level);
6337
+ }
6338
+ /**
6339
+ * Set screen status. When success/fail and not in TUI mode, prints to stdout/stderr
5092
6340
  */ setStatus(status) {
5093
6341
  const wasComplete = this.status === "success" || this.status === "fail";
5094
6342
  this.status = status;
5095
6343
  if (!wasComplete && (status === "success" || status === "fail")) {
5096
- if (!this.manager?.isTuiBound()) this.printToConsole();
6344
+ if (!this.manager?.hasTuiRenderer()) this.printToConsole();
5097
6345
  this.manager?.onScreenCompleted(this);
5098
6346
  }
5099
- this.notifyChange();
6347
+ this.emit("status:changed", status);
5100
6348
  return this;
5101
6349
  }
5102
6350
  /**
@@ -5105,9 +6353,12 @@ var ScreenInstance = class {
5105
6353
  return this.status === "success" || this.status === "fail";
5106
6354
  }
5107
6355
  /**
5108
- * Check if this screen has been printed to console
6356
+ * Check if this screen has been printed to console.
6357
+ * Static screens in non-TUI modes are considered printed as they print incrementally.
5109
6358
  */ hasPrintedToConsole() {
5110
- return this.hasPrinted;
6359
+ if (this.hasPrinted) return true;
6360
+ if (this.status === "static" && !this.manager?.hasTuiRenderer()) return true;
6361
+ return false;
5111
6362
  }
5112
6363
  /**
5113
6364
  * Force print to console (called when TUI unbinds)
@@ -5124,19 +6375,25 @@ var ScreenInstance = class {
5124
6375
  */ addMessage(message) {
5125
6376
  this.messages.push(message);
5126
6377
  this.incrementVersion();
5127
- this.notifyChange();
6378
+ if (this.status === "static" && !this.manager?.hasTuiRenderer()) this.printSingleMessageToConsole(message);
6379
+ this.emit("message:added", message.id);
5128
6380
  }
5129
6381
  /**
5130
6382
  * Update a loading message (internal use by Logger)
5131
6383
  */ updateMessage(id, updates) {
5132
6384
  const index = this.messages.findIndex((m) => m.id === id);
5133
6385
  if (index !== -1) {
6386
+ const oldMessage = this.messages[index];
5134
6387
  this.messages[index] = {
5135
6388
  ...this.messages[index],
5136
6389
  ...updates
5137
6390
  };
5138
6391
  this.incrementVersion();
5139
- this.notifyChange();
6392
+ if (this.status === "static" && !this.manager?.hasTuiRenderer()) {
6393
+ const newMessage = this.messages[index];
6394
+ if (newMessage.status !== "loading" && oldMessage.status === "loading") this.printSingleMessageToConsole(newMessage);
6395
+ }
6396
+ this.emit("message:updated", id);
5140
6397
  }
5141
6398
  }
5142
6399
  /**
@@ -5144,12 +6401,17 @@ var ScreenInstance = class {
5144
6401
  */ updateProgressMessage(id, updates) {
5145
6402
  const index = this.messages.findIndex((m) => m.id === id);
5146
6403
  if (index !== -1) {
6404
+ const oldMessage = this.messages[index];
5147
6405
  this.messages[index] = {
5148
6406
  ...this.messages[index],
5149
6407
  ...updates
5150
6408
  };
5151
6409
  this.incrementVersion();
5152
- this.notifyChange();
6410
+ if (this.status === "static" && !this.manager?.hasTuiRenderer()) {
6411
+ const newMessage = this.messages[index];
6412
+ if ((newMessage.status === "complete" || newMessage.status === "failed") && oldMessage.status !== "complete" && oldMessage.status !== "failed") this.printSingleMessageToConsole(newMessage);
6413
+ }
6414
+ this.emit("message:updated", id);
5153
6415
  }
5154
6416
  }
5155
6417
  /**
@@ -5157,7 +6419,7 @@ var ScreenInstance = class {
5157
6419
  */ clear() {
5158
6420
  this.messages = [];
5159
6421
  this.incrementVersion();
5160
- this.notifyChange();
6422
+ this.emit("messages:cleared");
5161
6423
  return this;
5162
6424
  }
5163
6425
  /**
@@ -5165,21 +6427,26 @@ var ScreenInstance = class {
5165
6427
  * Returns a promise that resolves when the user responds
5166
6428
  */ _addPrompt(prompt) {
5167
6429
  return new Promise((resolve) => {
6430
+ const mode = this.manager?.getRenderMode() ?? RenderMode.UNBOUND;
6431
+ if (mode === RenderMode.UNBOUND) {
6432
+ this.resolvePromptWithDefault(prompt, resolve);
6433
+ return;
6434
+ }
6435
+ if (mode === RenderMode.STDOUT_INTERACTIVE || mode === RenderMode.STDOUT_FALLBACK) {
6436
+ this.manager?.handleReadlinePrompt(prompt).then(resolve);
6437
+ return;
6438
+ }
5168
6439
  const pending = {
5169
6440
  data: prompt,
5170
6441
  resolve
5171
6442
  };
5172
- if (!this.manager?.isTuiBound()) {
5173
- this.resolvePromptWithDefault(prompt, resolve);
5174
- return;
5175
- }
5176
6443
  if (prompt.timeout && prompt.timeoutStarted) pending.timeoutId = setTimeout(() => {
5177
6444
  if (this.activePrompt === pending) {
5178
6445
  this.resolvePromptWithDefault(prompt, resolve);
5179
6446
  this.activePrompt = null;
5180
6447
  this.activateNextPrompt();
5181
6448
  this.incrementVersion();
5182
- this.notifyChange();
6449
+ this.emit("prompt:resolved");
5183
6450
  } else {
5184
6451
  const idx = this.promptQueue.indexOf(pending);
5185
6452
  if (idx !== -1) {
@@ -5196,20 +6463,7 @@ var ScreenInstance = class {
5196
6463
  /**
5197
6464
  * Resolve a prompt with its default value
5198
6465
  */ resolvePromptWithDefault(prompt, resolve) {
5199
- switch (prompt.type) {
5200
- case "choice":
5201
- resolve(prompt.defaultChoice);
5202
- break;
5203
- case "confirm":
5204
- resolve(prompt.defaultValue);
5205
- break;
5206
- case "input":
5207
- resolve(prompt.defaultValue);
5208
- break;
5209
- case "multiChoice":
5210
- resolve(prompt.choices.filter((_, i) => prompt.selectedIndices.has(i)).map((c) => c.value));
5211
- break;
5212
- }
6466
+ resolve(getPromptDefaultValue(prompt));
5213
6467
  }
5214
6468
  /**
5215
6469
  * Get the currently active prompt (for rendering)
@@ -5233,7 +6487,7 @@ var ScreenInstance = class {
5233
6487
  const maxIndex = prompt.choices.length - 1;
5234
6488
  prompt.focusedIndex = Math.max(0, Math.min(index, maxIndex));
5235
6489
  } else if (prompt.type === "confirm") prompt.selectedValue = index === 0;
5236
- this.notifyChange();
6490
+ this.emit("prompt:updated");
5237
6491
  }
5238
6492
  /**
5239
6493
  * Navigate prompt selection up
@@ -5260,7 +6514,7 @@ var ScreenInstance = class {
5260
6514
  const prompt = this.activePrompt.data;
5261
6515
  if (prompt.type === "confirm") {
5262
6516
  prompt.selectedValue = true;
5263
- this.notifyChange();
6517
+ this.emit("prompt:updated");
5264
6518
  }
5265
6519
  }
5266
6520
  promptNavigateRight() {
@@ -5268,7 +6522,7 @@ var ScreenInstance = class {
5268
6522
  const prompt = this.activePrompt.data;
5269
6523
  if (prompt.type === "confirm") {
5270
6524
  prompt.selectedValue = false;
5271
- this.notifyChange();
6525
+ this.emit("prompt:updated");
5272
6526
  }
5273
6527
  }
5274
6528
  /**
@@ -5280,7 +6534,7 @@ var ScreenInstance = class {
5280
6534
  const p = prompt;
5281
6535
  if (p.selectedIndices.has(p.focusedIndex)) p.selectedIndices.delete(p.focusedIndex);
5282
6536
  else if (p.selectedIndices.size < p.maxSelect) p.selectedIndices.add(p.focusedIndex);
5283
- this.notifyChange();
6537
+ this.emit("prompt:updated");
5284
6538
  }
5285
6539
  }
5286
6540
  /**
@@ -5292,7 +6546,7 @@ var ScreenInstance = class {
5292
6546
  if (prompt.type === "choice") {
5293
6547
  if (prompt.choices[prompt.selectedIndex]?.input) {
5294
6548
  prompt.inputMode = true;
5295
- this.notifyChange();
6549
+ this.emit("prompt:updated");
5296
6550
  return true;
5297
6551
  }
5298
6552
  } else if (prompt.type === "input") return true;
@@ -5305,7 +6559,7 @@ var ScreenInstance = class {
5305
6559
  const prompt = this.activePrompt.data;
5306
6560
  if (prompt.type === "choice" && prompt.inputMode) {
5307
6561
  prompt.inputMode = false;
5308
- this.notifyChange();
6562
+ this.emit("prompt:updated");
5309
6563
  }
5310
6564
  }
5311
6565
  /**
@@ -5324,10 +6578,10 @@ var ScreenInstance = class {
5324
6578
  const prompt = this.activePrompt.data;
5325
6579
  if (prompt.type === "choice" && prompt.inputMode) {
5326
6580
  prompt.inputValue = value;
5327
- this.notifyChange();
6581
+ this.emit("prompt:updated");
5328
6582
  } else if (prompt.type === "input") {
5329
6583
  prompt.value = value;
5330
- this.notifyChange();
6584
+ this.emit("prompt:updated");
5331
6585
  }
5332
6586
  }
5333
6587
  /**
@@ -5337,10 +6591,10 @@ var ScreenInstance = class {
5337
6591
  const prompt = this.activePrompt.data;
5338
6592
  if (prompt.type === "choice" && prompt.inputMode) {
5339
6593
  prompt.inputValue += char;
5340
- this.notifyChange();
6594
+ this.emit("prompt:updated");
5341
6595
  } else if (prompt.type === "input") {
5342
6596
  prompt.value += char;
5343
- this.notifyChange();
6597
+ this.emit("prompt:updated");
5344
6598
  }
5345
6599
  }
5346
6600
  /**
@@ -5350,10 +6604,10 @@ var ScreenInstance = class {
5350
6604
  const prompt = this.activePrompt.data;
5351
6605
  if (prompt.type === "choice" && prompt.inputMode) {
5352
6606
  prompt.inputValue = prompt.inputValue.slice(0, -1);
5353
- this.notifyChange();
6607
+ this.emit("prompt:updated");
5354
6608
  } else if (prompt.type === "input") {
5355
6609
  prompt.value = prompt.value.slice(0, -1);
5356
- this.notifyChange();
6610
+ this.emit("prompt:updated");
5357
6611
  }
5358
6612
  }
5359
6613
  /**
@@ -5398,7 +6652,7 @@ var ScreenInstance = class {
5398
6652
  this.activePrompt = null;
5399
6653
  this.activateNextPrompt();
5400
6654
  this.incrementVersion();
5401
- this.notifyChange();
6655
+ this.emit("prompt:resolved");
5402
6656
  }
5403
6657
  /**
5404
6658
  * Activate the next prompt in the queue
@@ -5407,17 +6661,13 @@ var ScreenInstance = class {
5407
6661
  this.activePrompt = this.promptQueue.shift();
5408
6662
  this.manager?.onScreenPromptActivated(this);
5409
6663
  this.incrementVersion();
5410
- this.notifyChange();
6664
+ this.emit("prompt:activated");
5411
6665
  }
5412
6666
  }
5413
6667
  /**
5414
- * Register a change listener for re-renders
5415
- */ onChange(listener) {
5416
- this.changeListeners.add(listener);
5417
- return () => this.changeListeners.delete(listener);
5418
- }
5419
- notifyChange() {
5420
- this.changeListeners.forEach((listener) => listener());
6668
+ * Print a single message immediately to stdout (for static screens in stdout mode)
6669
+ */ printSingleMessageToConsole(message) {
6670
+ printSingleMessage(message, this.name, false);
5421
6671
  }
5422
6672
  /**
5423
6673
  * Print all messages to stdout/stderr with ANSI colors
@@ -5710,24 +6960,29 @@ function applyDecs2203RFactory$2() {
5710
6960
  function _apply_decs_2203_r$2(targetClass, memberDecs, classDecs, parentClass) {
5711
6961
  return (_apply_decs_2203_r$2 = applyDecs2203RFactory$2())(targetClass, memberDecs, classDecs, parentClass);
5712
6962
  }
5713
- var _dec$2, _initClass$2;
6963
+ var _dec$2, _initClass$2, _EventEmitter;
5714
6964
  let _ScreenManagerInstance;
5715
6965
  _dec$2 = Injectable({ token: ScreenManager });
5716
- var ScreenManagerInstance = class {
6966
+ var ScreenManagerInstance = class extends (_EventEmitter = EventEmitter) {
5717
6967
  static {
5718
- ({c: [_ScreenManagerInstance, _initClass$2]} = _apply_decs_2203_r$2(this, [], [_dec$2]));
6968
+ ({c: [_ScreenManagerInstance, _initClass$2]} = _apply_decs_2203_r$2(this, [], [_dec$2], _EventEmitter));
6969
+ }
6970
+ constructor() {
6971
+ super();
5719
6972
  }
5720
6973
  screens = /* @__PURE__ */ new Map();
5721
6974
  screenOrder = [];
5722
6975
  activeScreenId = null;
5723
6976
  renderer = null;
5724
6977
  root = null;
5725
- adapter = inject(Adapter);
5726
- isBound = false;
5727
- changeListeners = /* @__PURE__ */ new Set();
6978
+ adapter = null;
6979
+ container = inject(Container);
6980
+ mode = RenderMode.UNBOUND;
6981
+ readlinePromptService = null;
5728
6982
  bindOptions = {};
5729
6983
  autoCloseTimer = null;
5730
6984
  theme;
6985
+ globalLogLevels = null;
5731
6986
  focusArea = "content";
5732
6987
  selectedIndex = 0;
5733
6988
  /**
@@ -5737,11 +6992,11 @@ var ScreenManagerInstance = class {
5737
6992
  const screen = new ScreenInstance(id, options);
5738
6993
  screen._setManager(this);
5739
6994
  screen._setPrintFn(printMessagesToStdout);
5740
- screen.onChange(() => this.notifyChange());
5741
6995
  this.screens.set(id, screen);
5742
6996
  this.screenOrder.push(id);
5743
6997
  if (!this.activeScreenId && !screen.isHidden()) this.activeScreenId = id;
5744
- this.notifyChange();
6998
+ this.checkAutoClose();
6999
+ this.emit("screen:added", id);
5745
7000
  return screen;
5746
7001
  }
5747
7002
  getScreenByName(name) {
@@ -5755,71 +7010,190 @@ var ScreenManagerInstance = class {
5755
7010
  if (!this.screens.has(id)) return;
5756
7011
  this.screens.delete(id);
5757
7012
  this.screenOrder = this.screenOrder.filter((sid) => sid !== id);
5758
- if (this.activeScreenId === id) this.activeScreenId = this.getScreens()[0]?.getId() ?? null;
7013
+ if (this.activeScreenId === id) {
7014
+ this.activeScreenId = this.getScreens()[0]?.getId() ?? null;
7015
+ this.emit("activeScreen:changed", this.activeScreenId);
7016
+ }
5759
7017
  const visibleScreens = this.getScreens();
5760
- if (this.selectedIndex >= visibleScreens.length) this.selectedIndex = Math.max(0, visibleScreens.length - 1);
5761
- this.notifyChange();
7018
+ if (this.selectedIndex >= visibleScreens.length) {
7019
+ const newIndex = Math.max(0, visibleScreens.length - 1);
7020
+ if (newIndex !== this.selectedIndex) {
7021
+ this.selectedIndex = newIndex;
7022
+ this.emit("sidebar:indexChanged", this.selectedIndex);
7023
+ }
7024
+ }
7025
+ this.checkAutoClose();
7026
+ this.emit("screen:removed", id);
5762
7027
  }
5763
7028
  /**
5764
7029
  * Non-blocking bind - starts TUI rendering in background
5765
7030
  */ async bind(options) {
5766
- if (this.isBound) return;
7031
+ if (this.mode !== RenderMode.UNBOUND) return;
5767
7032
  this.bindOptions = options ?? {};
5768
7033
  if (options?.theme) this.theme = typeof options.theme === "string" ? getThemePreset(options.theme) : options.theme;
5769
- this.renderer = await createCliRenderer({
5770
- exitOnCtrlC: options?.exitOnCtrlC ?? true,
5771
- useAlternateScreen: true,
5772
- useMouse: options?.useMouse ?? true
5773
- });
5774
- this.root = await this.adapter.createRoot(this.renderer);
5775
- this.isBound = true;
5776
- this.render();
7034
+ if (!(options?.useOpenTUI ?? !isBunRuntime())) {
7035
+ this.mode = RenderMode.STDOUT_INTERACTIVE;
7036
+ this.readlinePromptService = new ReadlinePromptService();
7037
+ this.emit("mode:changed", this.mode);
7038
+ return;
7039
+ }
7040
+ try {
7041
+ this.adapter = await this.container.get(Adapter);
7042
+ if (this.adapter.isMissingAdapter) throw new Error("No adapter registered");
7043
+ if (this.adapter.handlesOwnRenderer) this.root = await this.adapter.createRoot();
7044
+ else {
7045
+ const { createCliRenderer } = await dynamicImport("@opentui/core");
7046
+ this.renderer = await createCliRenderer({
7047
+ exitOnCtrlC: options?.exitOnCtrlC ?? true,
7048
+ useAlternateScreen: true,
7049
+ useMouse: options?.useMouse ?? true
7050
+ });
7051
+ this.root = await this.adapter.createRoot(this.renderer);
7052
+ }
7053
+ this.mode = RenderMode.TUI_ACTIVE;
7054
+ this.emit("mode:changed", this.mode);
7055
+ this.render();
7056
+ } catch {
7057
+ console.warn("[commander-tui] TUI adapter not available, falling back to stdout mode. To enable TUI, import a TUI adapter: @navios/tui-adapter-react, @navios/tui-adapter-ink, or @navios/tui-adapter-solid");
7058
+ this.mode = RenderMode.STDOUT_FALLBACK;
7059
+ this.readlinePromptService = new ReadlinePromptService();
7060
+ this.adapter = null;
7061
+ this.renderer = null;
7062
+ this.root = null;
7063
+ this.emit("mode:changed", this.mode);
7064
+ }
7065
+ }
7066
+ /**
7067
+ * Get the current render mode
7068
+ */ getRenderMode() {
7069
+ return this.mode;
7070
+ }
7071
+ /**
7072
+ * Check if TUI is interactive (any mode except UNBOUND).
7073
+ * In interactive modes, prompts can be handled via readline or TUI.
7074
+ */ isInteractive() {
7075
+ return this.mode !== RenderMode.UNBOUND;
7076
+ }
7077
+ /**
7078
+ * Check if TUI rendering is active (TUI_ACTIVE mode).
7079
+ * When true, screens are rendered in the TUI and not printed to stdout.
7080
+ */ hasTuiRenderer() {
7081
+ return this.mode === RenderMode.TUI_ACTIVE;
7082
+ }
7083
+ /**
7084
+ * Handle a prompt via readline (for stdout modes)
7085
+ */ handleReadlinePrompt(prompt) {
7086
+ if (!this.readlinePromptService) return Promise.resolve(getPromptDefaultValue(prompt));
7087
+ return this.readlinePromptService.handlePrompt(prompt);
5777
7088
  }
5778
7089
  /**
5779
7090
  * Get the configured theme
5780
7091
  */ getTheme() {
5781
7092
  return this.theme;
5782
7093
  }
7094
+ /**
7095
+ * Setup global configuration for the screen manager.
7096
+ * Can be called before or after bind() to configure theme and log levels.
7097
+ */ setup(options) {
7098
+ if (options.theme) this.theme = typeof options.theme === "string" ? getThemePreset(options.theme) : options.theme;
7099
+ if (options.logLevels) this.globalLogLevels = new Set(options.logLevels);
7100
+ }
7101
+ /**
7102
+ * Check if a log level is enabled globally.
7103
+ * Returns true if no global filter is set, or if the level is in the allowed set.
7104
+ */ isLogLevelEnabled(level) {
7105
+ if (this.globalLogLevels === null) return true;
7106
+ return this.globalLogLevels.has(level);
7107
+ }
7108
+ /**
7109
+ * Get the current global log levels filter.
7110
+ * Returns null if no filter is set (all levels allowed).
7111
+ */ getGlobalLogLevels() {
7112
+ return this.globalLogLevels ? Array.from(this.globalLogLevels) : null;
7113
+ }
5783
7114
  onServiceDestroy() {
5784
7115
  this.unbind();
5785
7116
  }
5786
7117
  /**
5787
7118
  * Stop TUI rendering and cleanup
5788
- * Flushes all completed screens to stdout/stderr
7119
+ * Flushes screens to stdout/stderr based on mode
5789
7120
  */ unbind() {
5790
- if (!this.isBound) return;
7121
+ if (this.mode === RenderMode.UNBOUND) {
7122
+ this.flushRemainingScreens();
7123
+ return;
7124
+ }
7125
+ const previousMode = this.mode;
5791
7126
  if (this.autoCloseTimer) {
5792
7127
  clearTimeout(this.autoCloseTimer);
5793
7128
  this.autoCloseTimer = null;
5794
7129
  }
5795
- this.root?.unmount();
5796
- if (this.renderer && "disableMouse" in this.renderer) this.renderer.disableMouse();
5797
- this.renderer?.destroy();
7130
+ if (previousMode === RenderMode.TUI_ACTIVE) {
7131
+ if (this.root) this.root.unmount();
7132
+ if (this.renderer) {
7133
+ if ("disableMouse" in this.renderer) this.renderer.disableMouse();
7134
+ this.renderer.destroy();
7135
+ }
7136
+ }
7137
+ if (this.readlinePromptService) {
7138
+ this.readlinePromptService.destroy();
7139
+ this.readlinePromptService = null;
7140
+ }
7141
+ this.flushScreensOnExit(previousMode);
7142
+ this.mode = RenderMode.UNBOUND;
5798
7143
  this.renderer = null;
5799
7144
  this.root = null;
5800
- this.isBound = false;
5801
- this.flushCompletedScreens();
7145
+ this.adapter = null;
7146
+ this.emit("mode:changed", this.mode);
7147
+ }
7148
+ /**
7149
+ * Flush screens on exit based on the mode we're exiting from
7150
+ */ flushScreensOnExit(previousMode) {
7151
+ for (const id of this.screenOrder) {
7152
+ const screen = this.screens.get(id);
7153
+ if (!screen || screen.isHidden()) continue;
7154
+ if (previousMode === RenderMode.TUI_ACTIVE) screen._flushToConsole(true);
7155
+ else if (!screen.hasPrintedToConsole()) screen._flushToConsole(true);
7156
+ }
5802
7157
  }
5803
7158
  /**
5804
- * Print all completed screens that haven't been printed yet
5805
- */ flushCompletedScreens() {
7159
+ * Flush any remaining non-hidden screens that haven't been printed.
7160
+ * Called on destroy even in UNBOUND mode to handle forgotten completions.
7161
+ */ flushRemainingScreens() {
5806
7162
  for (const id of this.screenOrder) {
5807
7163
  const screen = this.screens.get(id);
5808
- if (screen && !screen.hasPrintedToConsole()) screen._flushToConsole(true);
7164
+ if (!screen || screen.isHidden()) continue;
7165
+ if (!screen.hasPrintedToConsole()) screen._flushToConsole(true);
5809
7166
  }
5810
7167
  }
5811
7168
  /**
5812
7169
  * Check if TUI is currently bound
7170
+ * @deprecated Use isInteractive() instead
5813
7171
  */ isTuiBound() {
5814
- return this.isBound;
7172
+ return this.isInteractive();
7173
+ }
7174
+ /**
7175
+ * Check if TUI rendering is active (has renderer or self-rendering adapter).
7176
+ * @deprecated Use hasTuiRenderer() instead
7177
+ */ isTuiRendererActive() {
7178
+ return this.hasTuiRenderer();
7179
+ }
7180
+ /**
7181
+ * Check if OpenTUI rendering is active (has renderer).
7182
+ * @deprecated Use hasTuiRenderer() instead
7183
+ */ isOpenTUIActive() {
7184
+ return this.hasTuiRenderer();
5815
7185
  }
5816
7186
  /**
5817
7187
  * Called by Screen when a prompt becomes active
5818
7188
  * Focuses the screen and switches to content area
5819
7189
  */ onScreenPromptActivated(screen) {
5820
- this.setActiveScreen(screen);
5821
- this.focusArea = "content";
5822
- this.notifyChange();
7190
+ const prevActiveId = this.activeScreenId;
7191
+ this.activeScreenId = screen.getId();
7192
+ if (prevActiveId !== this.activeScreenId) this.emit("activeScreen:changed", this.activeScreenId);
7193
+ if (this.focusArea !== "content") {
7194
+ this.focusArea = "content";
7195
+ this.emit("focus:changed", this.focusArea);
7196
+ }
5823
7197
  }
5824
7198
  /**
5825
7199
  * Check if any screen has an active prompt
@@ -5840,10 +7214,18 @@ var ScreenManagerInstance = class {
5840
7214
  if (screen.isHidden() && this.activeScreenId === screen.getId()) {
5841
7215
  this.activeScreenId = this.getScreens()[0]?.getId() ?? null;
5842
7216
  this.selectedIndex = 0;
7217
+ this.emit("activeScreen:changed", this.activeScreenId);
7218
+ this.emit("sidebar:indexChanged", this.selectedIndex);
5843
7219
  }
5844
7220
  const visibleScreens = this.getScreens();
5845
- if (this.selectedIndex >= visibleScreens.length) this.selectedIndex = Math.max(0, visibleScreens.length - 1);
5846
- this.notifyChange();
7221
+ if (this.selectedIndex >= visibleScreens.length) {
7222
+ const newIndex = Math.max(0, visibleScreens.length - 1);
7223
+ if (newIndex !== this.selectedIndex) {
7224
+ this.selectedIndex = newIndex;
7225
+ this.emit("sidebar:indexChanged", this.selectedIndex);
7226
+ }
7227
+ }
7228
+ this.checkAutoClose();
5847
7229
  }
5848
7230
  /**
5849
7231
  * Called by Screen when status becomes success/fail
@@ -5855,9 +7237,16 @@ var ScreenManagerInstance = class {
5855
7237
  this.screenOrder.splice(index, 1);
5856
7238
  this.screenOrder.push(id);
5857
7239
  const visibleScreens = this.getScreens();
5858
- if (this.selectedIndex >= visibleScreens.length) this.selectedIndex = Math.max(0, visibleScreens.length - 1);
7240
+ if (this.selectedIndex >= visibleScreens.length) {
7241
+ const newIndex = Math.max(0, visibleScreens.length - 1);
7242
+ if (newIndex !== this.selectedIndex) {
7243
+ this.selectedIndex = newIndex;
7244
+ this.emit("sidebar:indexChanged", this.selectedIndex);
7245
+ }
7246
+ }
7247
+ this.checkAutoClose();
7248
+ this.emit("screen:reordered");
5859
7249
  }
5860
- this.notifyChange();
5861
7250
  }
5862
7251
  /**
5863
7252
  * Check if all screens are successful (or only static) and start auto-close timer if enabled.
@@ -5865,7 +7254,7 @@ var ScreenManagerInstance = class {
5865
7254
  * If there are only static screens, the timer will trigger after the delay with no new activity.
5866
7255
  */ checkAutoClose() {
5867
7256
  const autoClose = this.bindOptions.autoClose;
5868
- if (!autoClose || !this.isBound) return;
7257
+ if (!autoClose || this.mode === RenderMode.UNBOUND) return;
5869
7258
  if (this.autoCloseTimer) {
5870
7259
  clearTimeout(this.autoCloseTimer);
5871
7260
  this.autoCloseTimer = null;
@@ -5897,8 +7286,9 @@ var ScreenManagerInstance = class {
5897
7286
  /**
5898
7287
  * Set the active screen
5899
7288
  */ setActiveScreen(screen) {
7289
+ const prevActiveId = this.activeScreenId;
5900
7290
  this.activeScreenId = screen.getId();
5901
- this.notifyChange();
7291
+ if (prevActiveId !== this.activeScreenId) this.emit("activeScreen:changed", this.activeScreenId);
5902
7292
  }
5903
7293
  /**
5904
7294
  * Get bind options
@@ -5908,15 +7298,20 @@ var ScreenManagerInstance = class {
5908
7298
  /**
5909
7299
  * Set focus area (sidebar or content)
5910
7300
  */ setFocusArea(area) {
5911
- this.focusArea = area;
5912
- this.notifyChange();
7301
+ if (this.focusArea !== area) {
7302
+ this.focusArea = area;
7303
+ this.emit("focus:changed", area);
7304
+ }
5913
7305
  }
5914
7306
  /**
5915
7307
  * Set selected index in sidebar
5916
7308
  */ setSelectedIndex(index) {
5917
7309
  const visibleScreens = this.getScreens();
5918
- this.selectedIndex = Math.max(0, Math.min(index, visibleScreens.length - 1));
5919
- this.notifyChange();
7310
+ const newIndex = Math.max(0, Math.min(index, visibleScreens.length - 1));
7311
+ if (this.selectedIndex !== newIndex) {
7312
+ this.selectedIndex = newIndex;
7313
+ this.emit("sidebar:indexChanged", newIndex);
7314
+ }
5920
7315
  }
5921
7316
  /**
5922
7317
  * Navigate sidebar up
@@ -5938,20 +7333,10 @@ var ScreenManagerInstance = class {
5938
7333
  * Toggle focus between sidebar and content
5939
7334
  */ toggleFocus() {
5940
7335
  this.focusArea = this.focusArea === "sidebar" ? "content" : "sidebar";
5941
- this.notifyChange();
5942
- }
5943
- /**
5944
- * Register a change listener for re-renders
5945
- */ onChange(listener) {
5946
- this.changeListeners.add(listener);
5947
- return () => this.changeListeners.delete(listener);
5948
- }
5949
- notifyChange() {
5950
- this.checkAutoClose();
5951
- this.changeListeners.forEach((listener) => listener());
7336
+ this.emit("focus:changed", this.focusArea);
5952
7337
  }
5953
7338
  render() {
5954
- if (!this.root) return;
7339
+ if (!this.root || !this.adapter) return;
5955
7340
  this.adapter.renderToRoot(this.root, {
5956
7341
  manager: this,
5957
7342
  theme: this.theme
@@ -6253,7 +7638,10 @@ var ScreenLoggerInstance = class {
6253
7638
  ({c: [_ScreenLoggerInstance, _initClass$1]} = _apply_decs_2203_r$1(this, [], [_dec$1]));
6254
7639
  }
6255
7640
  constructor(options) {
6256
- this.screen = inject(Screen, typeof options.screen === "string" ? { name: options.screen } : options.screen);
7641
+ this.screen = inject(Screen, typeof options.screen === "string" ? {
7642
+ name: options.screen,
7643
+ static: true
7644
+ } : options.screen);
6257
7645
  this.context = options.context;
6258
7646
  this.enabledLevels = new Set(options.enabledLevels);
6259
7647
  }
@@ -6261,7 +7649,8 @@ var ScreenLoggerInstance = class {
6261
7649
  context;
6262
7650
  enabledLevels;
6263
7651
  isLevelEnabled(level) {
6264
- return this.enabledLevels.has(level);
7652
+ if (!this.enabledLevels.has(level)) return false;
7653
+ return this.screen.isLogLevelEnabled(level);
6265
7654
  }
6266
7655
  verbose(msg, label) {
6267
7656
  return this.write("verbose", msg, label);
@@ -6877,5 +8266,579 @@ var PromptInstance = class {
6877
8266
  };
6878
8267
 
6879
8268
  //#endregion
6880
- export { ALL_LOG_LEVELS, Adapter, COMMON_FILETYPES, DEFAULT_LOG_LEVEL_COLORS, ERROR_HIGHLIGHT_COLORS, FILE_COLORS, FilterEngine, GROUP_COLORS, HEADER_COLORS, IsomorphicLogger, _IsomorphicLoggerFactory as IsomorphicLoggerFactory, KeyboardManager, LoggerOptionsSchema, _MissingAdapterOverride as MissingAdapterOverride, PROGRESS_COLORS, PROMPT_COLORS, Prompt, _PromptInstance as PromptInstance, PromptOptionsSchema, SEPARATOR_COLORS, SIDEBAR_COLORS, STATUS_INDICATORS, Screen, _ScreenFactory as ScreenFactory, ScreenInstance, ScreenLogger, _ScreenLoggerInstance as ScreenLoggerInstance, ScreenManager, _ScreenManagerInstance as ScreenManagerInstance, ScreenOptionsSchema, TABLE_COLORS, VARIANT_COLORS, captureTrace, createBorderColor, createDefaultBindings, createDefaultFilterState, createTheme, createThemeFrom, createTintedColor, darkTheme, formatKeyBinding, formatObject, getFileName, getLogLevelColors, getThemePreset, handlePrintableInput, hasActiveFilter, highContrastTheme, lightTheme, mergeThemes, overrideConsoleLogger, printMessagesToStdout, resolveFiletype, resolveTheme };
8269
+ //#region src/keyboard/keyboard_manager.ts
8270
+ /**
8271
+ * Manages keyboard bindings and dispatches key events to handlers.
8272
+ */ var KeyboardManager = class {
8273
+ bindings = [];
8274
+ disabled = /* @__PURE__ */ new Set();
8275
+ constructor(config$1) {
8276
+ if (config$1?.bindings) this.bindings = [...config$1.bindings];
8277
+ if (config$1?.disabled) this.disabled = new Set(config$1.disabled);
8278
+ this.sortBindings();
8279
+ }
8280
+ /**
8281
+ * Add bindings to the manager.
8282
+ */ addBindings(bindings) {
8283
+ this.bindings.push(...bindings);
8284
+ this.sortBindings();
8285
+ }
8286
+ /**
8287
+ * Remove a binding by key name.
8288
+ */ removeBinding(key) {
8289
+ this.bindings = this.bindings.filter((b) => {
8290
+ return !(Array.isArray(b.key) ? b.key : [b.key]).includes(key);
8291
+ });
8292
+ }
8293
+ /**
8294
+ * Disable a key (prevents it from being matched).
8295
+ */ disableKey(key) {
8296
+ this.disabled.add(key);
8297
+ }
8298
+ /**
8299
+ * Enable a previously disabled key.
8300
+ */ enableKey(key) {
8301
+ this.disabled.delete(key);
8302
+ }
8303
+ /**
8304
+ * Handle a key event, dispatching to the appropriate handler.
8305
+ * Returns true if a handler consumed the event.
8306
+ */ handleKey(key, context) {
8307
+ const binding = this.findMatchingBinding(key, context);
8308
+ if (binding) return binding.handler(key, context) !== false;
8309
+ return false;
8310
+ }
8311
+ /**
8312
+ * Get all bindings for display in help overlay.
8313
+ */ getBindingsForHelp() {
8314
+ return this.bindings.filter((b) => b.description);
8315
+ }
8316
+ /**
8317
+ * Get bindings grouped by category.
8318
+ */ getBindingsByCategory() {
8319
+ const grouped = {
8320
+ general: [],
8321
+ navigation: [],
8322
+ screen: [],
8323
+ prompt: [],
8324
+ filter: []
8325
+ };
8326
+ for (const binding of this.bindings) if (binding.description) grouped[binding.category].push(binding);
8327
+ return grouped;
8328
+ }
8329
+ /**
8330
+ * Find a matching binding for the given key and context.
8331
+ */ findMatchingBinding(key, context) {
8332
+ for (const binding of this.bindings) if (this.keyMatches(key, binding) && this.conditionMatches(binding.when, context) && !this.isDisabled(binding)) return binding;
8333
+ return null;
8334
+ }
8335
+ /**
8336
+ * Check if a key event matches a binding's key specification.
8337
+ */ keyMatches(key, binding) {
8338
+ const keys = Array.isArray(binding.key) ? binding.key : [binding.key];
8339
+ if (!(keys.includes(key.name) || key.sequence && keys.includes(key.sequence))) return false;
8340
+ const ctrlMatches = (binding.ctrl ?? false) === (key.ctrl ?? false);
8341
+ const metaMatches = (binding.meta ?? false) === (key.meta ?? false);
8342
+ const shiftMatches = (binding.shift ?? false) === (key.shift ?? false);
8343
+ return ctrlMatches && metaMatches && shiftMatches;
8344
+ }
8345
+ /**
8346
+ * Check if context matches a binding's condition.
8347
+ */ conditionMatches(condition, context) {
8348
+ if (!condition) return true;
8349
+ if (condition.hasPrompt !== void 0 && condition.hasPrompt !== context.hasPrompt) return false;
8350
+ if (condition.inInputMode !== void 0 && condition.inInputMode !== context.inInputMode) return false;
8351
+ if (condition.focusArea !== void 0 && condition.focusArea !== context.focusArea) return false;
8352
+ if (condition.isFilterActive !== void 0 && condition.isFilterActive !== context.isFilterActive) return false;
8353
+ if (condition.isHelpVisible !== void 0 && condition.isHelpVisible !== context.isHelpVisible) return false;
8354
+ if (condition.hasSidebar !== void 0 && condition.hasSidebar !== context.hasSidebar) return false;
8355
+ return true;
8356
+ }
8357
+ /**
8358
+ * Check if a binding is disabled.
8359
+ */ isDisabled(binding) {
8360
+ return (Array.isArray(binding.key) ? binding.key : [binding.key]).some((k) => this.disabled.has(k));
8361
+ }
8362
+ /**
8363
+ * Sort bindings by priority (higher first).
8364
+ */ sortBindings() {
8365
+ this.bindings.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
8366
+ }
8367
+ };
8368
+ /**
8369
+ * Format a key binding for display.
8370
+ */ function formatKeyBinding(binding) {
8371
+ const keys = Array.isArray(binding.key) ? binding.key : [binding.key];
8372
+ const parts = [];
8373
+ if (binding.ctrl) parts.push("Ctrl");
8374
+ if (binding.meta) parts.push("Cmd");
8375
+ if (binding.shift) parts.push("Shift");
8376
+ const keyDisplay = keys.map((k) => {
8377
+ switch (k) {
8378
+ case "up": return "↑";
8379
+ case "down": return "↓";
8380
+ case "left": return "←";
8381
+ case "right": return "→";
8382
+ case "return": return "Enter";
8383
+ case "escape": return "Esc";
8384
+ case "space": return "Space";
8385
+ case "tab": return "Tab";
8386
+ case "\\": return "\\";
8387
+ default: return k;
8388
+ }
8389
+ }).join("/");
8390
+ parts.push(keyDisplay);
8391
+ return parts.join("+");
8392
+ }
8393
+
8394
+ //#endregion
8395
+ //#region src/keyboard/create_bindings.ts
8396
+ /**
8397
+ * Create the default keybindings with access to manager and screens.
8398
+ */ function createDefaultBindings(handlers) {
8399
+ const { manager, getActiveScreen, toggleHelp, toggleFilter, closeFilter } = handlers;
8400
+ const bindings = [];
8401
+ bindings.push({
8402
+ key: "escape",
8403
+ handler: () => {
8404
+ const screen = getActiveScreen();
8405
+ if (screen?.isPromptInInputMode()) {
8406
+ screen.promptExitInputMode();
8407
+ return true;
8408
+ }
8409
+ },
8410
+ description: "Exit input mode",
8411
+ category: "prompt",
8412
+ when: {
8413
+ hasPrompt: true,
8414
+ inInputMode: true
8415
+ },
8416
+ priority: 100
8417
+ });
8418
+ bindings.push({
8419
+ key: "return",
8420
+ handler: () => {
8421
+ const screen = getActiveScreen();
8422
+ if (screen?.isPromptInInputMode()) {
8423
+ screen.promptSubmit();
8424
+ return true;
8425
+ }
8426
+ },
8427
+ description: "Submit input",
8428
+ category: "prompt",
8429
+ when: {
8430
+ hasPrompt: true,
8431
+ inInputMode: true
8432
+ },
8433
+ priority: 100
8434
+ });
8435
+ bindings.push({
8436
+ key: "backspace",
8437
+ handler: () => {
8438
+ const screen = getActiveScreen();
8439
+ if (screen?.isPromptInInputMode()) {
8440
+ screen.promptDeleteLastChar();
8441
+ return true;
8442
+ }
8443
+ },
8444
+ description: "Delete character",
8445
+ category: "prompt",
8446
+ when: {
8447
+ hasPrompt: true,
8448
+ inInputMode: true
8449
+ },
8450
+ priority: 100
8451
+ });
8452
+ bindings.push({
8453
+ key: ["up", "k"],
8454
+ handler: () => {
8455
+ const screen = getActiveScreen();
8456
+ const prompt = screen?.getActivePrompt();
8457
+ if (prompt?.type === "choice" || prompt?.type === "multiChoice") {
8458
+ screen?.promptNavigateUp();
8459
+ return true;
8460
+ }
8461
+ },
8462
+ description: "Navigate up",
8463
+ category: "prompt",
8464
+ when: {
8465
+ hasPrompt: true,
8466
+ inInputMode: false
8467
+ },
8468
+ priority: 90
8469
+ });
8470
+ bindings.push({
8471
+ key: ["down", "j"],
8472
+ handler: () => {
8473
+ const screen = getActiveScreen();
8474
+ const prompt = screen?.getActivePrompt();
8475
+ if (prompt?.type === "choice" || prompt?.type === "multiChoice") {
8476
+ screen?.promptNavigateDown();
8477
+ return true;
8478
+ }
8479
+ },
8480
+ description: "Navigate down",
8481
+ category: "prompt",
8482
+ when: {
8483
+ hasPrompt: true,
8484
+ inInputMode: false
8485
+ },
8486
+ priority: 90
8487
+ });
8488
+ bindings.push({
8489
+ key: ["left", "h"],
8490
+ handler: () => {
8491
+ const screen = getActiveScreen();
8492
+ if ((screen?.getActivePrompt())?.type === "confirm") {
8493
+ screen?.promptNavigateLeft();
8494
+ return true;
8495
+ }
8496
+ },
8497
+ description: "Select confirm",
8498
+ category: "prompt",
8499
+ when: {
8500
+ hasPrompt: true,
8501
+ inInputMode: false
8502
+ },
8503
+ priority: 90
8504
+ });
8505
+ bindings.push({
8506
+ key: ["right", "l"],
8507
+ handler: () => {
8508
+ const screen = getActiveScreen();
8509
+ if ((screen?.getActivePrompt())?.type === "confirm") {
8510
+ screen?.promptNavigateRight();
8511
+ return true;
8512
+ }
8513
+ },
8514
+ description: "Select cancel",
8515
+ category: "prompt",
8516
+ when: {
8517
+ hasPrompt: true,
8518
+ inInputMode: false
8519
+ },
8520
+ priority: 90
8521
+ });
8522
+ bindings.push({
8523
+ key: "space",
8524
+ handler: () => {
8525
+ const screen = getActiveScreen();
8526
+ if ((screen?.getActivePrompt())?.type === "multiChoice") {
8527
+ screen?.promptToggleSelection();
8528
+ return true;
8529
+ }
8530
+ },
8531
+ description: "Toggle selection",
8532
+ category: "prompt",
8533
+ when: {
8534
+ hasPrompt: true,
8535
+ inInputMode: false
8536
+ },
8537
+ priority: 90
8538
+ });
8539
+ bindings.push({
8540
+ key: "return",
8541
+ handler: () => {
8542
+ const screen = getActiveScreen();
8543
+ const prompt = screen?.getActivePrompt();
8544
+ if (!prompt) return false;
8545
+ if (prompt.type === "choice") {
8546
+ if (!screen?.promptEnterInputMode()) screen?.promptSubmit();
8547
+ return true;
8548
+ } else if (prompt.type === "confirm") {
8549
+ screen?.promptSubmit();
8550
+ return true;
8551
+ } else if (prompt.type === "multiChoice") {
8552
+ if (screen?.canSubmitPrompt()) screen.promptSubmit();
8553
+ return true;
8554
+ }
8555
+ },
8556
+ description: "Submit selection",
8557
+ category: "prompt",
8558
+ when: {
8559
+ hasPrompt: true,
8560
+ inInputMode: false
8561
+ },
8562
+ priority: 90
8563
+ });
8564
+ bindings.push({
8565
+ key: "?",
8566
+ handler: () => {
8567
+ toggleHelp();
8568
+ return true;
8569
+ },
8570
+ description: "Toggle help",
8571
+ category: "general",
8572
+ when: {
8573
+ hasPrompt: false,
8574
+ isFilterActive: false
8575
+ },
8576
+ priority: 50
8577
+ });
8578
+ bindings.push({
8579
+ key: "escape",
8580
+ handler: () => {
8581
+ toggleHelp();
8582
+ return true;
8583
+ },
8584
+ description: "Close help",
8585
+ category: "general",
8586
+ when: { isHelpVisible: true },
8587
+ priority: 80
8588
+ });
8589
+ bindings.push({
8590
+ key: "/",
8591
+ handler: () => {
8592
+ toggleFilter();
8593
+ return true;
8594
+ },
8595
+ description: "Toggle filter",
8596
+ category: "filter",
8597
+ when: {
8598
+ hasPrompt: false,
8599
+ isHelpVisible: false
8600
+ },
8601
+ priority: 50
8602
+ });
8603
+ bindings.push({
8604
+ key: "escape",
8605
+ handler: () => {
8606
+ closeFilter();
8607
+ return true;
8608
+ },
8609
+ description: "Close filter",
8610
+ category: "filter",
8611
+ when: { isFilterActive: true },
8612
+ priority: 70
8613
+ });
8614
+ bindings.push({
8615
+ key: "tab",
8616
+ handler: () => {
8617
+ handlers.filterCycleField();
8618
+ return true;
8619
+ },
8620
+ description: "Cycle filter fields",
8621
+ category: "filter",
8622
+ when: { isFilterActive: true },
8623
+ priority: 70
8624
+ });
8625
+ bindings.push({
8626
+ key: "backspace",
8627
+ handler: () => {
8628
+ handlers.filterDeleteChar();
8629
+ return true;
8630
+ },
8631
+ description: "Delete character",
8632
+ category: "filter",
8633
+ when: { isFilterActive: true },
8634
+ priority: 70
8635
+ });
8636
+ for (let i = 1; i <= 7; i++) bindings.push({
8637
+ key: String(i),
8638
+ handler: () => {
8639
+ handlers.filterToggleLevel(i - 1);
8640
+ return true;
8641
+ },
8642
+ description: `Toggle level ${i}`,
8643
+ category: "filter",
8644
+ when: { isFilterActive: true },
8645
+ priority: 70
8646
+ });
8647
+ bindings.push({
8648
+ key: "q",
8649
+ handler: () => {
8650
+ manager.unbind();
8651
+ return true;
8652
+ },
8653
+ description: "Exit",
8654
+ category: "general",
8655
+ when: {
8656
+ hasPrompt: false,
8657
+ isFilterActive: false,
8658
+ isHelpVisible: false
8659
+ },
8660
+ priority: 10
8661
+ });
8662
+ bindings.push({
8663
+ key: "tab",
8664
+ handler: (_, ctx) => {
8665
+ if (ctx.hasSidebar) {
8666
+ manager.toggleFocus();
8667
+ return true;
8668
+ }
8669
+ },
8670
+ description: "Toggle focus",
8671
+ category: "navigation",
8672
+ when: {
8673
+ hasPrompt: false,
8674
+ isFilterActive: false
8675
+ },
8676
+ priority: 20
8677
+ });
8678
+ bindings.push({
8679
+ key: "\\",
8680
+ handler: (_, ctx) => {
8681
+ if (ctx.hasSidebar) {
8682
+ manager.toggleFocus();
8683
+ return true;
8684
+ }
8685
+ },
8686
+ description: "Toggle focus",
8687
+ category: "navigation",
8688
+ when: {
8689
+ hasPrompt: false,
8690
+ isFilterActive: false
8691
+ },
8692
+ priority: 20
8693
+ });
8694
+ bindings.push({
8695
+ key: ["up", "k"],
8696
+ handler: () => {
8697
+ manager.navigateUp();
8698
+ return true;
8699
+ },
8700
+ description: "Navigate up",
8701
+ category: "navigation",
8702
+ when: {
8703
+ focusArea: "sidebar",
8704
+ hasPrompt: false
8705
+ },
8706
+ priority: 30
8707
+ });
8708
+ bindings.push({
8709
+ key: ["down", "j"],
8710
+ handler: () => {
8711
+ manager.navigateDown();
8712
+ return true;
8713
+ },
8714
+ description: "Navigate down",
8715
+ category: "navigation",
8716
+ when: {
8717
+ focusArea: "sidebar",
8718
+ hasPrompt: false
8719
+ },
8720
+ priority: 30
8721
+ });
8722
+ bindings.push({
8723
+ key: "return",
8724
+ handler: () => {
8725
+ manager.selectCurrent();
8726
+ return true;
8727
+ },
8728
+ description: "Select screen",
8729
+ category: "navigation",
8730
+ when: {
8731
+ focusArea: "sidebar",
8732
+ hasPrompt: false
8733
+ },
8734
+ priority: 30
8735
+ });
8736
+ for (let i = 1; i <= 9; i++) bindings.push({
8737
+ key: String(i),
8738
+ handler: () => {
8739
+ const screens = manager.getScreens();
8740
+ if (i <= screens.length) {
8741
+ manager.setActiveScreen(screens[i - 1]);
8742
+ manager.setSelectedIndex(i - 1);
8743
+ return true;
8744
+ }
8745
+ },
8746
+ description: `Jump to screen ${i}`,
8747
+ category: "screen",
8748
+ when: {
8749
+ hasPrompt: false,
8750
+ isFilterActive: false
8751
+ },
8752
+ priority: 15
8753
+ });
8754
+ bindings.push({
8755
+ key: "c",
8756
+ handler: () => {
8757
+ getActiveScreen()?.clear();
8758
+ return true;
8759
+ },
8760
+ description: "Clear screen",
8761
+ category: "screen",
8762
+ when: {
8763
+ focusArea: "content",
8764
+ hasPrompt: false,
8765
+ isFilterActive: false
8766
+ },
8767
+ priority: 15
8768
+ });
8769
+ return bindings;
8770
+ }
8771
+ /**
8772
+ * Handle printable character input for prompts and filter.
8773
+ * This should be called for any key not handled by bindings.
8774
+ */ function handlePrintableInput(key, context, handlers) {
8775
+ if (!key.sequence || key.sequence.length !== 1 || key.ctrl || key.meta) return false;
8776
+ const charCode = key.sequence.charCodeAt(0);
8777
+ if (charCode < 32 || charCode > 126) return false;
8778
+ if (context.isFilterActive) {
8779
+ handlers.filterAppendChar(key.sequence);
8780
+ return true;
8781
+ }
8782
+ if (context.hasPrompt && context.inInputMode) {
8783
+ handlers.getActiveScreen()?.promptAppendInput(key.sequence);
8784
+ return true;
8785
+ }
8786
+ return false;
8787
+ }
8788
+
8789
+ //#endregion
8790
+ //#region src/filter/filter_engine.ts
8791
+ /**
8792
+ * Filter engine for filtering log messages.
8793
+ */ var FilterEngine = class {
8794
+ /**
8795
+ * Apply filter to messages array.
8796
+ */ static filterMessages(messages, filter) {
8797
+ if (filter.searchQuery === "" && filter.enabledLevels.size === ALL_LOG_LEVELS.length) return messages;
8798
+ return messages.filter((msg) => {
8799
+ if (msg.type !== "log") {
8800
+ if (filter.searchQuery) return this.messageMatchesSearch(msg, filter.searchQuery);
8801
+ if (msg.type === "group") return true;
8802
+ return true;
8803
+ }
8804
+ const logMsg = msg;
8805
+ if (!filter.enabledLevels.has(logMsg.level)) return false;
8806
+ if (filter.searchQuery && !this.messageMatchesSearch(logMsg, filter.searchQuery)) return false;
8807
+ return true;
8808
+ });
8809
+ }
8810
+ /**
8811
+ * Check if a message matches the search query.
8812
+ */ static messageMatchesSearch(msg, query) {
8813
+ const lowerQuery = query.toLowerCase();
8814
+ switch (msg.type) {
8815
+ case "log": return msg.content.toLowerCase().includes(lowerQuery) || (msg.label?.toLowerCase().includes(lowerQuery) ?? false);
8816
+ case "file":
8817
+ case "fileError": return msg.filePath.toLowerCase().includes(lowerQuery) || msg.content.toLowerCase().includes(lowerQuery);
8818
+ case "diff": return msg.filePath.toLowerCase().includes(lowerQuery) || msg.diff.toLowerCase().includes(lowerQuery);
8819
+ case "loading": return msg.content.toLowerCase().includes(lowerQuery) || (msg.resolvedContent?.toLowerCase().includes(lowerQuery) ?? false);
8820
+ case "progress": return msg.label.toLowerCase().includes(lowerQuery);
8821
+ case "group": return msg.label.toLowerCase().includes(lowerQuery);
8822
+ case "table": return (msg.title?.toLowerCase().includes(lowerQuery) ?? false) || msg.headers.some((h) => h.toLowerCase().includes(lowerQuery)) || msg.rows.some((row) => row.some((cell) => cell.toLowerCase().includes(lowerQuery)));
8823
+ default: return false;
8824
+ }
8825
+ }
8826
+ /**
8827
+ * Count messages by log level.
8828
+ */ static countByLevel(messages) {
8829
+ const counts = {
8830
+ debug: 0,
8831
+ log: 0,
8832
+ verbose: 0,
8833
+ error: 0,
8834
+ fatal: 0,
8835
+ warn: 0
8836
+ };
8837
+ for (const msg of messages) if (msg.type === "log") counts[msg.level]++;
8838
+ return counts;
8839
+ }
8840
+ };
8841
+
8842
+ //#endregion
8843
+ export { ALL_LOG_LEVELS, Adapter, COMMON_FILETYPES, CONTENT_MANAGER_EVENTS, DEFAULT_LOG_LEVEL_COLORS, ERROR_HIGHLIGHT_COLORS, FILE_COLORS, FilterEngine, GROUP_COLORS, HEADER_COLORS, IsomorphicLogger, _IsomorphicLoggerFactory as IsomorphicLoggerFactory, KeyboardManager, LoggerOptionsSchema, MANAGER_EVENTS, _MissingAdapterOverride as MissingAdapterOverride, PROGRESS_COLORS, PROMPT_COLORS, Prompt, _PromptInstance as PromptInstance, PromptOptionsSchema, ReadlinePromptService, RenderMode, SCREEN_EVENTS, SEPARATOR_COLORS, SIDEBAR_COLORS, SIDEBAR_EVENTS, STATUS_INDICATORS, Screen, _ScreenFactory as ScreenFactory, ScreenInstance, ScreenLogger, _ScreenLoggerInstance as ScreenLoggerInstance, ScreenManager, _ScreenManagerInstance as ScreenManagerInstance, ScreenOptionsSchema, TABLE_COLORS, VARIANT_COLORS, captureTrace, createDefaultBindings, createDefaultFilterState, createTheme, createThemeFrom, darkTheme, dynamicImport, formatKeyBinding, formatObject, getFileName, getLogLevelColors, getPromptDefaultValue, getThemePreset, handlePrintableInput, hasActiveFilter, highContrastTheme, isBunRuntime, lightTheme, mergeThemes, overrideConsoleLogger, printMessagesToStdout, printSingleMessage, resolveFiletype, resolveTheme };
6881
8844
  //# sourceMappingURL=index.mjs.map