redmine-context 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +449 -0
  3. package/dist/bundle/index.d.ts +5 -0
  4. package/dist/bundle/index.js +5 -0
  5. package/dist/bundle/json.d.ts +90 -0
  6. package/dist/bundle/json.js +266 -0
  7. package/dist/bundle/markdown.d.ts +75 -0
  8. package/dist/bundle/markdown.js +294 -0
  9. package/dist/bundle/search-list.d.ts +43 -0
  10. package/dist/bundle/search-list.js +53 -0
  11. package/dist/bundle/stable-stringify.d.ts +26 -0
  12. package/dist/bundle/stable-stringify.js +50 -0
  13. package/dist/cache/contract.d.ts +157 -0
  14. package/dist/cache/contract.js +0 -0
  15. package/dist/cache/disk-index.d.ts +82 -0
  16. package/dist/cache/disk-index.js +220 -0
  17. package/dist/cache/disk.d.ts +133 -0
  18. package/dist/cache/disk.js +313 -0
  19. package/dist/cache/gc.d.ts +78 -0
  20. package/dist/cache/gc.js +123 -0
  21. package/dist/cache/get-or-compute.d.ts +36 -0
  22. package/dist/cache/get-or-compute.js +52 -0
  23. package/dist/cache/index.d.ts +9 -0
  24. package/dist/cache/index.js +8 -0
  25. package/dist/cache/keys.d.ts +76 -0
  26. package/dist/cache/keys.js +78 -0
  27. package/dist/cache/memory.d.ts +48 -0
  28. package/dist/cache/memory.js +110 -0
  29. package/dist/cache-first.d.ts +127 -0
  30. package/dist/cache-first.js +227 -0
  31. package/dist/client/errors.d.ts +33 -0
  32. package/dist/client/errors.js +49 -0
  33. package/dist/client/http.d.ts +110 -0
  34. package/dist/client/http.js +207 -0
  35. package/dist/client/index.d.ts +5 -0
  36. package/dist/client/index.js +5 -0
  37. package/dist/client/issues.d.ts +71 -0
  38. package/dist/client/issues.js +100 -0
  39. package/dist/client/search.d.ts +58 -0
  40. package/dist/client/search.js +81 -0
  41. package/dist/config/credentials.d.ts +247 -0
  42. package/dist/config/credentials.js +427 -0
  43. package/dist/config/doctor.d.ts +123 -0
  44. package/dist/config/doctor.js +260 -0
  45. package/dist/config/index.d.ts +6 -0
  46. package/dist/config/index.js +6 -0
  47. package/dist/config/keyring.d.ts +96 -0
  48. package/dist/config/keyring.js +158 -0
  49. package/dist/config/login.d.ts +97 -0
  50. package/dist/config/login.js +189 -0
  51. package/dist/config/settings.d.ts +94 -0
  52. package/dist/config/settings.js +140 -0
  53. package/dist/contract.d.ts +173 -0
  54. package/dist/contract.js +27 -0
  55. package/dist/core.d.ts +1 -0
  56. package/dist/core.js +8 -0
  57. package/dist/extract/audio-extractor.d.ts +105 -0
  58. package/dist/extract/audio-extractor.js +156 -0
  59. package/dist/extract/audio.d.ts +126 -0
  60. package/dist/extract/audio.js +184 -0
  61. package/dist/extract/dispatcher.d.ts +132 -0
  62. package/dist/extract/dispatcher.js +115 -0
  63. package/dist/extract/download.d.ts +111 -0
  64. package/dist/extract/download.js +261 -0
  65. package/dist/extract/duration.d.ts +106 -0
  66. package/dist/extract/duration.js +148 -0
  67. package/dist/extract/ffmpeg.d.ts +56 -0
  68. package/dist/extract/ffmpeg.js +95 -0
  69. package/dist/extract/gguf.d.ts +137 -0
  70. package/dist/extract/gguf.js +215 -0
  71. package/dist/extract/index.d.ts +19 -0
  72. package/dist/extract/index.js +19 -0
  73. package/dist/extract/magic.d.ts +80 -0
  74. package/dist/extract/magic.js +282 -0
  75. package/dist/extract/ooxml.d.ts +131 -0
  76. package/dist/extract/ooxml.js +336 -0
  77. package/dist/extract/pdf.d.ts +147 -0
  78. package/dist/extract/pdf.js +322 -0
  79. package/dist/extract/queue.d.ts +167 -0
  80. package/dist/extract/queue.js +217 -0
  81. package/dist/extract/subprocess.d.ts +145 -0
  82. package/dist/extract/subprocess.js +181 -0
  83. package/dist/extract/tesseract.d.ts +153 -0
  84. package/dist/extract/tesseract.js +321 -0
  85. package/dist/extract/video-extractor.d.ts +84 -0
  86. package/dist/extract/video-extractor.js +89 -0
  87. package/dist/extract/video.d.ts +198 -0
  88. package/dist/extract/video.js +418 -0
  89. package/dist/extract/which.d.ts +63 -0
  90. package/dist/extract/which.js +72 -0
  91. package/dist/extract/whisper-extract.d.ts +211 -0
  92. package/dist/extract/whisper-extract.js +323 -0
  93. package/dist/extract/whisper.d.ts +50 -0
  94. package/dist/extract/whisper.js +67 -0
  95. package/dist/extract/zip.d.ts +50 -0
  96. package/dist/extract/zip.js +165 -0
  97. package/dist/extract-issue-attachments.d.ts +82 -0
  98. package/dist/extract-issue-attachments.js +156 -0
  99. package/dist/fetch-attachment-text.d.ts +113 -0
  100. package/dist/fetch-attachment-text.js +155 -0
  101. package/dist/fetch-issue-bundle.d.ts +81 -0
  102. package/dist/fetch-issue-bundle.js +93 -0
  103. package/dist/fetch-issue-search.d.ts +74 -0
  104. package/dist/fetch-issue-search.js +120 -0
  105. package/dist/index.d.ts +21 -0
  106. package/dist/index.js +67 -0
  107. package/dist/normalize/collections.d.ts +52 -0
  108. package/dist/normalize/collections.js +170 -0
  109. package/dist/normalize/helpers.d.ts +35 -0
  110. package/dist/normalize/helpers.js +59 -0
  111. package/dist/normalize/index.d.ts +2 -0
  112. package/dist/normalize/index.js +2 -0
  113. package/dist/normalize/issue.d.ts +34 -0
  114. package/dist/normalize/issue.js +154 -0
  115. package/dist/surfaces/cli/commands.d.ts +61 -0
  116. package/dist/surfaces/cli/commands.js +262 -0
  117. package/dist/surfaces/cli/main.d.ts +32 -0
  118. package/dist/surfaces/cli/main.js +210 -0
  119. package/dist/surfaces/cli/prompts.d.ts +66 -0
  120. package/dist/surfaces/cli/prompts.js +147 -0
  121. package/dist/surfaces/cli/tty.d.ts +27 -0
  122. package/dist/surfaces/cli/tty.js +35 -0
  123. package/dist/surfaces/cli/types.d.ts +39 -0
  124. package/dist/surfaces/cli/types.js +7 -0
  125. package/dist/surfaces/mcp/server.d.ts +171 -0
  126. package/dist/surfaces/mcp/server.js +427 -0
  127. package/dist/surfaces/tui/app.d.ts +55 -0
  128. package/dist/surfaces/tui/app.js +180 -0
  129. package/dist/surfaces/tui/attachment-status.d.ts +79 -0
  130. package/dist/surfaces/tui/attachment-status.js +113 -0
  131. package/dist/surfaces/tui/components/breadcrumb.d.ts +7 -0
  132. package/dist/surfaces/tui/components/breadcrumb.js +31 -0
  133. package/dist/surfaces/tui/components/gradient-text.d.ts +23 -0
  134. package/dist/surfaces/tui/components/gradient-text.js +75 -0
  135. package/dist/surfaces/tui/components/scroll-view.d.ts +25 -0
  136. package/dist/surfaces/tui/components/scroll-view.js +77 -0
  137. package/dist/surfaces/tui/components/spinner.d.ts +12 -0
  138. package/dist/surfaces/tui/components/spinner.js +39 -0
  139. package/dist/surfaces/tui/components/text-input.d.ts +45 -0
  140. package/dist/surfaces/tui/components/text-input.js +114 -0
  141. package/dist/surfaces/tui/format-file-size.d.ts +24 -0
  142. package/dist/surfaces/tui/format-file-size.js +43 -0
  143. package/dist/surfaces/tui/glyphs.d.ts +47 -0
  144. package/dist/surfaces/tui/glyphs.js +84 -0
  145. package/dist/surfaces/tui/hooks/use-auth-guard.d.ts +39 -0
  146. package/dist/surfaces/tui/hooks/use-auth-guard.js +135 -0
  147. package/dist/surfaces/tui/hooks/use-doctor-status.d.ts +64 -0
  148. package/dist/surfaces/tui/hooks/use-doctor-status.js +123 -0
  149. package/dist/surfaces/tui/hooks/use-escape-interceptor.d.ts +25 -0
  150. package/dist/surfaces/tui/hooks/use-escape-interceptor.js +65 -0
  151. package/dist/surfaces/tui/hooks/use-exit-guard.d.ts +18 -0
  152. package/dist/surfaces/tui/hooks/use-exit-guard.js +66 -0
  153. package/dist/surfaces/tui/hooks/use-export-bundle.d.ts +62 -0
  154. package/dist/surfaces/tui/hooks/use-export-bundle.js +100 -0
  155. package/dist/surfaces/tui/hooks/use-issue-detail.d.ts +61 -0
  156. package/dist/surfaces/tui/hooks/use-issue-detail.js +132 -0
  157. package/dist/surfaces/tui/hooks/use-issue-search.d.ts +71 -0
  158. package/dist/surfaces/tui/hooks/use-issue-search.js +168 -0
  159. package/dist/surfaces/tui/hooks/use-list-navigation.d.ts +44 -0
  160. package/dist/surfaces/tui/hooks/use-list-navigation.js +82 -0
  161. package/dist/surfaces/tui/hooks/use-media-binaries.d.ts +24 -0
  162. package/dist/surfaces/tui/hooks/use-media-binaries.js +44 -0
  163. package/dist/surfaces/tui/hooks/use-my-issues.d.ts +66 -0
  164. package/dist/surfaces/tui/hooks/use-my-issues.js +151 -0
  165. package/dist/surfaces/tui/hooks/use-onboarding-callbacks.d.ts +11 -0
  166. package/dist/surfaces/tui/hooks/use-onboarding-callbacks.js +104 -0
  167. package/dist/surfaces/tui/hooks/use-terminal-width.d.ts +52 -0
  168. package/dist/surfaces/tui/hooks/use-terminal-width.js +90 -0
  169. package/dist/surfaces/tui/index.d.ts +50 -0
  170. package/dist/surfaces/tui/index.js +158 -0
  171. package/dist/surfaces/tui/instance.d.ts +37 -0
  172. package/dist/surfaces/tui/instance.js +36 -0
  173. package/dist/surfaces/tui/job-registry.d.ts +113 -0
  174. package/dist/surfaces/tui/job-registry.js +123 -0
  175. package/dist/surfaces/tui/job-status.d.ts +45 -0
  176. package/dist/surfaces/tui/job-status.js +81 -0
  177. package/dist/surfaces/tui/navigation.d.ts +74 -0
  178. package/dist/surfaces/tui/navigation.js +87 -0
  179. package/dist/surfaces/tui/palettes.d.ts +38 -0
  180. package/dist/surfaces/tui/palettes.js +244 -0
  181. package/dist/surfaces/tui/screen.d.ts +30 -0
  182. package/dist/surfaces/tui/screen.js +51 -0
  183. package/dist/surfaces/tui/screens/about.d.ts +2 -0
  184. package/dist/surfaces/tui/screens/about.js +35 -0
  185. package/dist/surfaces/tui/screens/appearance.d.ts +2 -0
  186. package/dist/surfaces/tui/screens/appearance.js +74 -0
  187. package/dist/surfaces/tui/screens/config.d.ts +2 -0
  188. package/dist/surfaces/tui/screens/config.js +82 -0
  189. package/dist/surfaces/tui/screens/doctor.d.ts +2 -0
  190. package/dist/surfaces/tui/screens/doctor.js +109 -0
  191. package/dist/surfaces/tui/screens/export.d.ts +2 -0
  192. package/dist/surfaces/tui/screens/export.js +168 -0
  193. package/dist/surfaces/tui/screens/home-selection.d.ts +70 -0
  194. package/dist/surfaces/tui/screens/home-selection.js +80 -0
  195. package/dist/surfaces/tui/screens/home.d.ts +2 -0
  196. package/dist/surfaces/tui/screens/home.js +200 -0
  197. package/dist/surfaces/tui/screens/issue-detail.d.ts +6 -0
  198. package/dist/surfaces/tui/screens/issue-detail.js +182 -0
  199. package/dist/surfaces/tui/screens/jobs.d.ts +7 -0
  200. package/dist/surfaces/tui/screens/jobs.js +89 -0
  201. package/dist/surfaces/tui/screens/loaded-issue-context.d.ts +49 -0
  202. package/dist/surfaces/tui/screens/loaded-issue-context.js +57 -0
  203. package/dist/surfaces/tui/screens/onboarding/api-key.d.ts +2 -0
  204. package/dist/surfaces/tui/screens/onboarding/api-key.js +69 -0
  205. package/dist/surfaces/tui/screens/onboarding/login.d.ts +2 -0
  206. package/dist/surfaces/tui/screens/onboarding/login.js +50 -0
  207. package/dist/surfaces/tui/screens/onboarding/mode.d.ts +2 -0
  208. package/dist/surfaces/tui/screens/onboarding/mode.js +42 -0
  209. package/dist/surfaces/tui/screens/onboarding/onboarding-context.d.ts +221 -0
  210. package/dist/surfaces/tui/screens/onboarding/onboarding-context.js +131 -0
  211. package/dist/surfaces/tui/screens/onboarding/success.d.ts +2 -0
  212. package/dist/surfaces/tui/screens/onboarding/success.js +41 -0
  213. package/dist/surfaces/tui/screens/onboarding/url.d.ts +24 -0
  214. package/dist/surfaces/tui/screens/onboarding/url.js +84 -0
  215. package/dist/surfaces/tui/screens/onboarding/validating.d.ts +1 -0
  216. package/dist/surfaces/tui/screens/onboarding/validating.js +86 -0
  217. package/dist/surfaces/tui/screens/welcome.d.ts +6 -0
  218. package/dist/surfaces/tui/screens/welcome.js +95 -0
  219. package/dist/surfaces/tui/status-color.d.ts +21 -0
  220. package/dist/surfaces/tui/status-color.js +23 -0
  221. package/dist/surfaces/tui/symbols.d.ts +231 -0
  222. package/dist/surfaces/tui/symbols.js +14 -0
  223. package/dist/surfaces/tui/terminal-colors.d.ts +29 -0
  224. package/dist/surfaces/tui/terminal-colors.js +39 -0
  225. package/dist/surfaces/tui/theme.d.ts +156 -0
  226. package/dist/surfaces/tui/theme.js +86 -0
  227. package/dist/surfaces/tui/truncate.d.ts +31 -0
  228. package/dist/surfaces/tui/truncate.js +81 -0
  229. package/package.json +93 -0
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Kits de PALETAS de cores da TUI (#190).
3
+ *
4
+ * Cada paleta é um {@link Theme} COMPLETO em truecolor (hex), curado a partir de
5
+ * esquemas de cor consagrados. Trocar de paleta é escolher um `id` aqui — o
6
+ * `ThemeProvider` (`./theme.tsx`) recebe o `Theme` resolvido. Este arquivo é a
7
+ * ÚNICA fonte de literais hex (junto de `theme.tsx`); as telas nunca declaram cor
8
+ * literal (varredura `no-hardcoded-colors.test.ts`), sempre via `useTheme()`.
9
+ *
10
+ * Os valores hex são bem conhecidos dos respectivos projetos de tema. A
11
+ * degradação para texto puro (NO_COLOR/CI/não-TTY) é decidida ANTES de a TUI
12
+ * subir (`shouldRenderTui`), então aqui só existem terminais com cor.
13
+ */
14
+ /**
15
+ * Lista ORDENADA de paletas (a ordem é a do seletor). A primeira é o default
16
+ * quando não há escolha persistida ({@link DEFAULT_PALETTE_ID}).
17
+ */
18
+ export const PALETTES = [
19
+ // ── Paletas ESCURAS (texto claro sobre fundo escuro) ─────────────────────────
20
+ {
21
+ id: 'catppuccin-mocha',
22
+ label: 'Catppuccin Mocha (escura)',
23
+ theme: {
24
+ primary: '#89b4fa', // blue
25
+ secondary: '#cba6f7', // mauve
26
+ accent: '#f5c2e7', // pink
27
+ muted: '#9399b2', // overlay2
28
+ success: '#a6e3a1', // green
29
+ warning: '#f9e2af', // yellow
30
+ danger: '#f38ba8', // red
31
+ border: '#585b70', // surface2
32
+ background: '#1e1e2e', // base
33
+ text: '#cdd6f4', // text
34
+ gradient: ['#89b4fa', '#cba6f7', '#f5c2e7', '#f38ba8'],
35
+ },
36
+ },
37
+ {
38
+ id: 'dracula',
39
+ label: 'Dracula (escura)',
40
+ theme: {
41
+ primary: '#bd93f9', // purple
42
+ secondary: '#8be9fd', // cyan
43
+ accent: '#ff79c6', // pink
44
+ muted: '#6272a4', // comment
45
+ success: '#50fa7b', // green
46
+ warning: '#f1fa8c', // yellow
47
+ danger: '#ff5555', // red
48
+ border: '#44475a', // current line
49
+ background: '#282a36', // background
50
+ text: '#f8f8f2', // foreground
51
+ gradient: ['#8be9fd', '#bd93f9', '#ff79c6', '#ff5555'],
52
+ },
53
+ },
54
+ {
55
+ id: 'nord',
56
+ label: 'Nord (escura)',
57
+ theme: {
58
+ primary: '#88c0d0', // frost cyan
59
+ secondary: '#81a1c1', // frost blue
60
+ accent: '#b48ead', // aurora purple
61
+ muted: '#7b88a1', // dim
62
+ success: '#a3be8c', // aurora green
63
+ warning: '#ebcb8b', // aurora yellow
64
+ danger: '#bf616a', // aurora red
65
+ border: '#434c5e', // polar night 2
66
+ background: '#2e3440', // polar night 0
67
+ text: '#e5e9f0', // snow storm
68
+ gradient: ['#8fbcbb', '#88c0d0', '#81a1c1', '#5e81ac'],
69
+ },
70
+ },
71
+ {
72
+ id: 'tokyo-night',
73
+ label: 'Tokyo Night (escura)',
74
+ theme: {
75
+ primary: '#7aa2f7', // blue
76
+ secondary: '#7dcfff', // cyan
77
+ accent: '#bb9af7', // purple
78
+ muted: '#737aa2', // comment
79
+ success: '#9ece6a', // green
80
+ warning: '#e0af68', // yellow
81
+ danger: '#f7768e', // red
82
+ border: '#3b4261', // fg gutter
83
+ background: '#1a1b26', // bg
84
+ text: '#c0caf5', // fg
85
+ gradient: ['#7dcfff', '#7aa2f7', '#bb9af7', '#f7768e'],
86
+ },
87
+ },
88
+ {
89
+ id: 'gruvbox-dark',
90
+ label: 'Gruvbox Dark (escura)',
91
+ theme: {
92
+ primary: '#83a598', // blue
93
+ secondary: '#8ec07c', // aqua
94
+ accent: '#d3869b', // purple
95
+ muted: '#a89984', // gray
96
+ success: '#b8bb26', // green
97
+ warning: '#fabd2f', // yellow
98
+ danger: '#fb4934', // red
99
+ border: '#504945', // bg2
100
+ background: '#282828', // bg0
101
+ text: '#ebdbb2', // fg1
102
+ gradient: ['#8ec07c', '#83a598', '#d3869b', '#fb4934'],
103
+ },
104
+ },
105
+ {
106
+ id: 'rose-pine',
107
+ label: 'Rosé Pine (escura)',
108
+ theme: {
109
+ primary: '#c4a7e7', // iris
110
+ secondary: '#9ccfd8', // foam
111
+ accent: '#ebbcba', // rose
112
+ muted: '#908caa', // subtle
113
+ success: '#31748f', // pine
114
+ warning: '#f6c177', // gold
115
+ danger: '#eb6f92', // love
116
+ border: '#403d52', // highlight med
117
+ background: '#191724', // base
118
+ text: '#e0def4', // text
119
+ gradient: ['#9ccfd8', '#c4a7e7', '#ebbcba', '#eb6f92'],
120
+ },
121
+ },
122
+ {
123
+ id: 'tokyo-storm',
124
+ label: 'Tokyo Storm (escura)',
125
+ theme: {
126
+ primary: '#7aa2f7',
127
+ secondary: '#7dcfff',
128
+ accent: '#bb9af7',
129
+ muted: '#7982a9',
130
+ success: '#9ece6a',
131
+ warning: '#e0af68',
132
+ danger: '#f7768e',
133
+ border: '#3b4261',
134
+ background: '#24283b', // storm bg
135
+ text: '#c0caf5',
136
+ gradient: ['#7dcfff', '#7aa2f7', '#bb9af7', '#f7768e'],
137
+ },
138
+ },
139
+ {
140
+ id: 'one-dark',
141
+ label: 'One Dark (escura)',
142
+ theme: {
143
+ primary: '#61afef', // blue
144
+ secondary: '#56b6c2', // cyan
145
+ accent: '#c678dd', // purple
146
+ muted: '#828997', // comment gray
147
+ success: '#98c379', // green
148
+ warning: '#e5c07b', // yellow
149
+ danger: '#e06c75', // red
150
+ border: '#3e4451', // gutter
151
+ background: '#282c34', // bg
152
+ text: '#abb2bf', // fg
153
+ gradient: ['#56b6c2', '#61afef', '#c678dd', '#e06c75'],
154
+ },
155
+ },
156
+ // ── Paletas CLARAS (texto escuro sobre fundo claro) ──────────────────────────
157
+ {
158
+ id: 'catppuccin-latte',
159
+ label: 'Catppuccin Latte (clara)',
160
+ theme: {
161
+ primary: '#1e66f5', // blue
162
+ secondary: '#8839ef', // mauve
163
+ accent: '#ea76cb', // pink
164
+ muted: '#6c6f85', // subtext0
165
+ success: '#40a02b', // green
166
+ warning: '#df8e1d', // yellow
167
+ danger: '#d20f39', // red
168
+ border: '#bcc0cc', // surface1
169
+ background: '#eff1f5', // base
170
+ text: '#4c4f69', // text
171
+ gradient: ['#1e66f5', '#8839ef', '#ea76cb', '#d20f39'],
172
+ },
173
+ },
174
+ {
175
+ id: 'solarized-light',
176
+ label: 'Solarized Light (clara)',
177
+ theme: {
178
+ primary: '#268bd2', // blue
179
+ secondary: '#2aa198', // cyan
180
+ accent: '#d33682', // magenta
181
+ muted: '#93a1a1', // base1
182
+ success: '#859900', // green
183
+ warning: '#b58900', // yellow
184
+ danger: '#dc322f', // red
185
+ border: '#eee8d5', // base2
186
+ background: '#fdf6e3', // base3
187
+ text: '#586e75', // base01
188
+ gradient: ['#2aa198', '#268bd2', '#6c71c4', '#d33682'],
189
+ },
190
+ },
191
+ {
192
+ id: 'github-light',
193
+ label: 'GitHub Light (clara)',
194
+ theme: {
195
+ primary: '#0969da', // accent blue
196
+ secondary: '#1a7f37', // green
197
+ accent: '#8250df', // purple
198
+ muted: '#57606a', // fg muted
199
+ success: '#1a7f37', // green
200
+ warning: '#9a6700', // attention
201
+ danger: '#cf222e', // danger red
202
+ border: '#d0d7de', // border
203
+ background: '#ffffff', // canvas
204
+ text: '#1f2328', // fg default
205
+ gradient: ['#0969da', '#8250df', '#bf3989', '#cf222e'],
206
+ },
207
+ },
208
+ {
209
+ id: 'one-light',
210
+ label: 'One Light (clara)',
211
+ theme: {
212
+ primary: '#4078f2', // blue
213
+ secondary: '#0184bc', // cyan
214
+ accent: '#a626a4', // purple
215
+ muted: '#696c77', // gray
216
+ success: '#50a14f', // green
217
+ warning: '#c18401', // yellow
218
+ danger: '#e45649', // red
219
+ border: '#dcdfe4', // gutter
220
+ background: '#fafafa', // bg
221
+ text: '#383a42', // fg
222
+ gradient: ['#0184bc', '#4078f2', '#a626a4', '#e45649'],
223
+ },
224
+ },
225
+ ];
226
+ /** Id da paleta default (a primeira da lista) — usada sem escolha persistida. */
227
+ export const DEFAULT_PALETTE_ID = PALETTES[0].id;
228
+ /** Índice `id → Palette` para resolução O(1). */
229
+ const BY_ID = new Map(PALETTES.map((p) => [p.id, p]));
230
+ /**
231
+ * Resolve uma paleta por `id`, com fallback para a default se o `id` for
232
+ * desconhecido (ex.: settings.json com uma paleta removida numa versão futura).
233
+ *
234
+ * @param id - Id persistido (ou `undefined`).
235
+ * @returns A paleta correspondente, ou a default.
236
+ */
237
+ export function resolvePalette(id) {
238
+ if (id !== undefined) {
239
+ const found = BY_ID.get(id);
240
+ if (found !== undefined)
241
+ return found;
242
+ }
243
+ return BY_ID.get(DEFAULT_PALETTE_ID);
244
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Registro de telas da TUI (roteador, M2-01; título adicionado no M2-04).
3
+ *
4
+ * Cada tela é um componente Ink sem props — recebe apenas o contexto de
5
+ * navegação via `useNavigation()`. Cada entrada também carrega um `title`
6
+ * legível, consumido pelo breadcrumb fixo (`components/breadcrumb.tsx`)
7
+ * para renderizar o caminho da pilha ("Início › Atalhos"). Adicionar uma
8
+ * tela nova é registrar aqui (`SCREENS`) e estender {@link ScreenName}; o
9
+ * roteador (`app.tsx`) não muda.
10
+ */
11
+ import type { ComponentType } from 'react';
12
+ /** Nomes de tela conhecidos pelo roteador (state machine simples). */
13
+ export type ScreenName = 'welcome' | 'about' | 'appearance' | 'doctor' | 'config' | 'home' | 'issue-detail' | 'export' | 'jobs' | 'onboarding-url' | 'onboarding-mode' | 'onboarding-login' | 'onboarding-validating' | 'onboarding-api-key' | 'onboarding-success';
14
+ /** Tela renderizada ao abrir a TUI (base da pilha de navegação). */
15
+ export declare const INITIAL_SCREEN: ScreenName;
16
+ /** Entrada do registro de telas: componente renderizável + título para o breadcrumb. */
17
+ export interface ScreenEntry {
18
+ /** Componente Ink renderizado para a tela. */
19
+ component: ComponentType;
20
+ /** Título legível — usado pelo breadcrumb fixo (`components/breadcrumb.tsx`). */
21
+ title: string;
22
+ }
23
+ /**
24
+ * Mapa tela -> entrada, consultado pelo roteador a cada troca e pelo
25
+ * breadcrumb. As três telas de onboarding (M2-05.1, issue #27) usam
26
+ * `Onboarding <separador> <passo>` como título — o mesmo separador do
27
+ * breadcrumb entre frames da pilha (`symbols.pointerSmall`) — para que o
28
+ * caminho fique auto-descritivo mesmo isolado (ex.: "Início › Onboarding › URL").
29
+ */
30
+ export declare const SCREENS: Record<ScreenName, ScreenEntry>;
@@ -0,0 +1,51 @@
1
+ import { AboutScreen } from './screens/about.js';
2
+ import { AppearanceScreen } from './screens/appearance.js';
3
+ import { ConfigScreen } from './screens/config.js';
4
+ import { DoctorScreen } from './screens/doctor.js';
5
+ import { ExportScreen } from './screens/export.js';
6
+ import { HomeScreen } from './screens/home.js';
7
+ import { IssueDetailScreen } from './screens/issue-detail.js';
8
+ import { JobsScreen } from './screens/jobs.js';
9
+ import { OnboardingApiKeyScreen } from './screens/onboarding/api-key.js';
10
+ import { OnboardingLoginScreen } from './screens/onboarding/login.js';
11
+ import { OnboardingModeScreen } from './screens/onboarding/mode.js';
12
+ import { OnboardingSuccessScreen } from './screens/onboarding/success.js';
13
+ import { OnboardingUrlScreen } from './screens/onboarding/url.js';
14
+ import { OnboardingValidatingScreen } from './screens/onboarding/validating.js';
15
+ import { WelcomeScreen } from './screens/welcome.js';
16
+ import { symbols } from './symbols.js';
17
+ /** Tela renderizada ao abrir a TUI (base da pilha de navegação). */
18
+ export const INITIAL_SCREEN = 'welcome';
19
+ /**
20
+ * Mapa tela -> entrada, consultado pelo roteador a cada troca e pelo
21
+ * breadcrumb. As três telas de onboarding (M2-05.1, issue #27) usam
22
+ * `Onboarding <separador> <passo>` como título — o mesmo separador do
23
+ * breadcrumb entre frames da pilha (`symbols.pointerSmall`) — para que o
24
+ * caminho fique auto-descritivo mesmo isolado (ex.: "Início › Onboarding › URL").
25
+ */
26
+ export const SCREENS = {
27
+ welcome: { component: WelcomeScreen, title: 'Início' },
28
+ about: { component: AboutScreen, title: 'Atalhos' },
29
+ appearance: { component: AppearanceScreen, title: 'Aparência' },
30
+ doctor: { component: DoctorScreen, title: 'Doctor' },
31
+ config: { component: ConfigScreen, title: 'Configuração' },
32
+ home: { component: HomeScreen, title: 'Minhas issues' },
33
+ 'issue-detail': { component: IssueDetailScreen, title: 'Detalhe da issue' },
34
+ export: { component: ExportScreen, title: 'Exportar' },
35
+ jobs: { component: JobsScreen, title: 'Jobs' },
36
+ 'onboarding-url': { component: OnboardingUrlScreen, title: `Onboarding ${symbols.pointerSmall} URL` },
37
+ 'onboarding-mode': { component: OnboardingModeScreen, title: `Onboarding ${symbols.pointerSmall} Modo` },
38
+ 'onboarding-login': { component: OnboardingLoginScreen, title: `Onboarding ${symbols.pointerSmall} Login` },
39
+ 'onboarding-validating': {
40
+ component: OnboardingValidatingScreen,
41
+ title: `Onboarding ${symbols.pointerSmall} Validando`,
42
+ },
43
+ 'onboarding-api-key': {
44
+ component: OnboardingApiKeyScreen,
45
+ title: `Onboarding ${symbols.pointerSmall} api_key`,
46
+ },
47
+ 'onboarding-success': {
48
+ component: OnboardingSuccessScreen,
49
+ title: `Onboarding ${symbols.pointerSmall} Sucesso`,
50
+ },
51
+ };
@@ -0,0 +1,2 @@
1
+ /** Tela de atalhos: `b` (ou `Esc`, atalho global) volta para a tela anterior (ver `app.tsx`). */
2
+ export declare function AboutScreen(): import("react").JSX.Element;
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Tela de atalhos da TUI — placeholder do scaffold M2-01.
4
+ *
5
+ * Existe também para provar o roteador: `?` na tela de boas-vindas navega até
6
+ * aqui, `b` volta — a troca de componente é o que o teste de render valida.
7
+ * `b` chama `pop()` (M2-04): mesmo efeito do atalho global `Esc`
8
+ * (`../app.tsx`), mantido aqui como atalho adicional específico desta tela.
9
+ * Cores vêm do tema central (M2-02, `useTheme()`) — nenhum literal de cor
10
+ * aqui, ver `theme.ts` para o guideline de uso de cada token.
11
+ */
12
+ import { Box, Text, useInput } from 'ink';
13
+ import { useNavigation } from '../navigation.js';
14
+ import { useTheme } from '../theme.js';
15
+ /** Lista de atalhos conhecidos pela TUI (crescerá conforme novas telas chegam). */
16
+ const SHORTCUTS = [
17
+ { key: '?', description: 'abre esta tela' },
18
+ { key: 'd', description: 'abre o doctor (diagnóstico: Node, instância, credencial, conectividade)' },
19
+ { key: 'c', description: 'abre a configuração (instância + logout)' },
20
+ { key: 'a', description: 'abre a aparência (escolher a paleta de cores)' },
21
+ { key: 't', description: 'abre o painel de jobs da sessão (na home/detalhe)' },
22
+ { key: 'b / Esc', description: 'volta para a tela anterior' },
23
+ { key: 'q', description: 'sai da TUI' },
24
+ ];
25
+ /** Tela de atalhos: `b` (ou `Esc`, atalho global) volta para a tela anterior (ver `app.tsx`). */
26
+ export function AboutScreen() {
27
+ const { pop } = useNavigation();
28
+ const theme = useTheme();
29
+ useInput((input) => {
30
+ if (input === 'b') {
31
+ pop();
32
+ }
33
+ });
34
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsx(Text, { color: theme.primary, children: "Atalhos" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: SHORTCUTS.map((shortcut) => (_jsxs(Text, { children: [_jsx(Text, { color: theme.accent, children: shortcut.key }), ' ', shortcut.description] }, shortcut.key))) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.muted, children: ["Pressione", ' ', _jsx(Text, { color: theme.accent, children: "b" }), ' ', "para voltar."] }) })] }));
35
+ }
@@ -0,0 +1,2 @@
1
+ /** Tela seletora de paleta com preview ao vivo, salvar (Enter) e cancelar (Esc). */
2
+ export declare function AppearanceScreen(): import("react").JSX.Element;
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Tela de APARÊNCIA — seletor de paleta de cores da TUI (#190).
4
+ *
5
+ * Lista as paletas (`../palettes.ts`) com PREVIEW AO VIVO: navegar com ↑/↓
6
+ * aplica a paleta na hora (via `useThemeController().preview`, sem persistir),
7
+ * `Enter` confirma e PERSISTE (`select`), `Esc` cancela e REVERTE para a paleta
8
+ * original (via `useEscapeInterceptor`, que intercepta o Esc global antes do
9
+ * `pop()`). Cada linha mostra swatches (blocos coloridos) dos tokens daquela
10
+ * paleta — as cores vêm dos dados da paleta (variáveis), então nenhuma cor
11
+ * literal aparece aqui (varredura anti-hardcode).
12
+ */
13
+ import { useCallback, useRef, useState } from 'react';
14
+ import { Box, Text, useInput } from 'ink';
15
+ import { GradientText } from '../components/gradient-text.js';
16
+ import { useEscapeInterceptor } from '../hooks/use-escape-interceptor.js';
17
+ import { useNavigation } from '../navigation.js';
18
+ import { PALETTES } from '../palettes.js';
19
+ import { symbols } from '../symbols.js';
20
+ import { useTheme, useThemeController } from '../theme.js';
21
+ /** Índice da paleta com um dado id (0 se não achar). */
22
+ function indexOfPalette(id) {
23
+ const i = PALETTES.findIndex((p) => p.id === id);
24
+ return i >= 0 ? i : 0;
25
+ }
26
+ /** Tela seletora de paleta com preview ao vivo, salvar (Enter) e cancelar (Esc). */
27
+ export function AppearanceScreen() {
28
+ const { pop } = useNavigation();
29
+ const theme = useTheme();
30
+ const controller = useThemeController();
31
+ const [index, setIndex] = useState(() => indexOfPalette(controller.paletteId));
32
+ // Paleta ORIGINAL ao abrir a tela — restaurada no cancelamento (Esc).
33
+ const originalRef = useRef(controller.paletteId);
34
+ // Refs estáveis (padrão do repo: identidade nova des/re-subscreve o useInput e
35
+ // perde teclas rápidas).
36
+ const controllerRef = useRef(controller);
37
+ controllerRef.current = controller;
38
+ const popRef = useRef(pop);
39
+ popRef.current = pop;
40
+ const indexRef = useRef(index);
41
+ indexRef.current = index;
42
+ const move = useCallback((delta) => {
43
+ const next = (indexRef.current + delta + PALETTES.length) % PALETTES.length;
44
+ setIndex(next);
45
+ controllerRef.current.preview(PALETTES[next].id);
46
+ }, []);
47
+ // Esc cancela: reverte para a paleta original e volta.
48
+ useEscapeInterceptor(true, () => {
49
+ controllerRef.current.preview(originalRef.current);
50
+ popRef.current();
51
+ });
52
+ const handleInput = useCallback((input, key) => {
53
+ if (key.upArrow || input === 'k') {
54
+ move(-1);
55
+ return;
56
+ }
57
+ if (key.downArrow || input === 'j') {
58
+ move(1);
59
+ return;
60
+ }
61
+ if (key.return) {
62
+ void controllerRef.current.select(PALETTES[indexRef.current].id);
63
+ popRef.current();
64
+ }
65
+ }, [move]);
66
+ useInput(handleInput);
67
+ const gradient = theme.gradient ?? [theme.primary];
68
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsx(GradientText, { colors: gradient, children: `Aparência ${symbols.pointerSmall} paleta de cores` }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: PALETTES.map((palette, i) => {
69
+ const selected = i === index;
70
+ const t = palette.theme;
71
+ const swatches = [t.primary, t.secondary ?? t.primary, t.accent, t.success, t.warning, t.danger];
72
+ return (_jsxs(Box, { children: [_jsx(Box, { width: 30, children: _jsxs(Text, { color: selected ? theme.primary : theme.muted, children: [selected ? symbols.pointer : ' ', " ", palette.label] }) }), swatches.map((color, si) => (_jsx(Text, { backgroundColor: color, children: ' ' }, si))), palette.id === originalRef.current ? (_jsxs(Text, { color: theme.muted, children: [" ", symbols.tick, " atual"] })) : null] }, palette.id));
73
+ }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.muted, children: [symbols.arrowUp, "/", symbols.arrowDown, " pr\u00E9-visualiza ", symbols.pointerSmall, ' ', _jsx(Text, { color: theme.accent, children: "Enter" }), ' ', "salva ", symbols.pointerSmall, ' ', _jsx(Text, { color: theme.accent, children: "Esc" }), ' ', "cancela"] }) })] }));
74
+ }
@@ -0,0 +1,2 @@
1
+ /** Tela config: instância + credencial em uso, `l` faz logout, `b` volta. */
2
+ export declare function ConfigScreen(): import("react").JSX.Element;
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Tela config da TUI (M2-12, #35): mostra a instância configurada e a fonte
4
+ * de credencial em uso (reaproveita `use-doctor-status.js`, sem duplicar a
5
+ * leitura da cascata) e permite logout — `l` remove a credencial da cascata
6
+ * INTEIRA (keychain + arquivo, via `core.createCredentialCascade().delete()`);
7
+ * a variável de ambiente é somente-leitura e NÃO é apagada por aqui — se
8
+ * ainda resolver a credencial depois do logout, um aviso é mostrado (nunca a
9
+ * api_key em si, só a fonte, via `describeCredentialSource`).
10
+ *
11
+ * Depois do logout, a tela aguarda uma tecla qualquer para voltar ao início
12
+ * com `resetTo('welcome')` — como `config` só é alcançada a partir da
13
+ * `welcome` (hint da tela inicial), isso equivale a resetar a pilha de
14
+ * navegação para a base.
15
+ */
16
+ import { useState } from 'react';
17
+ import { Box, Text, useInput } from 'ink';
18
+ import { createCredentialCascade, describeCredentialSource } from '../../../index.js';
19
+ import { useDoctorStatus } from '../hooks/use-doctor-status.js';
20
+ import { useInstance } from '../instance.js';
21
+ import { useNavigation } from '../navigation.js';
22
+ import { symbols } from '../symbols.js';
23
+ import { useTheme } from '../theme.js';
24
+ /** Rótulo legível da origem da instância (#187). */
25
+ function originLabel(origin) {
26
+ if (origin === 'env')
27
+ return 'via REDMINE_URL';
28
+ if (origin === 'config')
29
+ return 'salva neste dispositivo';
30
+ return '';
31
+ }
32
+ /** Tela config: instância + credencial em uso, `l` faz logout, `b` volta. */
33
+ export function ConfigScreen() {
34
+ const { pop, resetTo } = useNavigation();
35
+ const theme = useTheme();
36
+ const status = useDoctorStatus();
37
+ const instance = useInstance();
38
+ const [logoutState, setLogoutState] = useState('idle');
39
+ const [envStillPresent, setEnvStillPresent] = useState(false);
40
+ const [errorMessage, setErrorMessage] = useState(undefined);
41
+ const startLogout = (instanceUrl) => {
42
+ setLogoutState('working');
43
+ void (async () => {
44
+ try {
45
+ await createCredentialCascade({ env: process.env }).delete(instanceUrl);
46
+ // Também remove a URL persistida (#187) para não reconfigurar sozinha no
47
+ // próximo boot. Isolado em try próprio: a parte CRÍTICA (a credencial) já
48
+ // foi removida acima, então uma falha ao limpar o settings.json NÃO deve
49
+ // marcar o logout como erro total — degrada silenciosamente.
50
+ try {
51
+ await instance.clearPersisted();
52
+ }
53
+ catch {
54
+ // Best-effort: a credencial já foi removida; settings.json fica para a próxima.
55
+ }
56
+ // Env é somente-leitura: se ainda resolver a credencial, avisa (sem expor a key).
57
+ const remaining = await describeCredentialSource(instanceUrl, { env: process.env });
58
+ setEnvStillPresent(remaining === 'env');
59
+ setLogoutState('done');
60
+ }
61
+ catch (cause) {
62
+ setErrorMessage(cause instanceof Error ? cause.message : String(cause));
63
+ setLogoutState('error');
64
+ }
65
+ })();
66
+ };
67
+ useInput((input) => {
68
+ if (logoutState === 'done' || logoutState === 'error') {
69
+ // Qualquer tecla confirma e volta ao início — pilha zerada (resetTo).
70
+ resetTo('welcome');
71
+ return;
72
+ }
73
+ if (input === 'b') {
74
+ pop();
75
+ return;
76
+ }
77
+ if (input === 'l' && logoutState === 'idle' && status.instanceUrl !== undefined) {
78
+ startLogout(status.instanceUrl);
79
+ }
80
+ });
81
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsx(Text, { color: theme.primary, children: "Configura\u00E7\u00E3o" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: "Inst\u00E2ncia: " }), status.instanceUrl ?? 'não configurada (defina REDMINE_URL ou faça login)', status.instanceUrl !== undefined && instance.origin !== 'none' ? (_jsxs(Text, { color: theme.muted, children: [" (", originLabel(instance.origin), ")"] })) : null] }), _jsxs(Text, { children: [_jsx(Text, { color: theme.muted, children: "Credencial: " }), status.credentialMethod] })] }), logoutState === 'working' ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: theme.muted, children: "Removendo credencial..." }) })) : null, logoutState === 'done' ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: theme.success, children: [symbols.tick, " Credencial removida do keychain e do arquivo local."] }), envStillPresent ? (_jsxs(Text, { color: theme.warning, children: [symbols.warning, " REDMINE_API_KEY ainda definida no ambiente \u2014 a credencial pode continuar ativa por essa vari\u00E1vel. Remova-a manualmente para desativar por completo."] })) : null, _jsx(Text, { color: theme.muted, children: "Pressione qualquer tecla para voltar ao in\u00EDcio." })] })) : null, logoutState === 'error' ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { color: theme.danger, children: [symbols.cross, " Falha ao remover a credencial: ", errorMessage] }), _jsx(Text, { color: theme.muted, children: "Pressione qualquer tecla para voltar ao in\u00EDcio." })] })) : null, logoutState === 'idle' ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.muted, children: ["Pressione", ' ', _jsx(Text, { color: theme.accent, children: "l" }), ' ', "para fazer logout (remove a credencial salva),", ' ', _jsx(Text, { color: theme.accent, children: "b" }), ' ', "para voltar."] }) })) : null] }));
82
+ }
@@ -0,0 +1,2 @@
1
+ /** Tela doctor: `b` (ou `Esc`, atalho global) volta para a tela anterior (ver `app.tsx`). */
2
+ export declare function DoctorScreen(): import("react").JSX.Element;
@@ -0,0 +1,109 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Tela doctor da TUI (M2-12, #35): painel de diagnóstico — versão do Node, da
4
+ * ferramenta, instância configurada, método de credencial em uso (keychain /
5
+ * arquivo / env, sem NUNCA expor a api_key) e status de conectividade (GET
6
+ * leve à instância, com timeout curto). Toda a lógica assíncrona vive em
7
+ * `../hooks/use-doctor-status.js` (testável isoladamente, com deps
8
+ * injetáveis); esta tela só formata o "painel de status": uma linha por
9
+ * item, `symbols.tick`/`symbols.cross` coloridos por `theme.success`/
10
+ * `theme.danger`, rótulos em `theme.muted`.
11
+ *
12
+ * M2-16 (#39): `value` de cada `StatusRow` é truncado (`../truncate.js`) ao
13
+ * espaço restante do terminal — a instância (`REDMINE_URL`) é a candidata
14
+ * mais provável a estourar a largura, e a linha é um `<Box>` de 3 `<Text>`
15
+ * IRMÃS (ícone/rótulo/valor): sem truncar, um valor comprido sobrepõe as
16
+ * demais (o Ink não reflui `<Text>` irmãs; ver o JSDoc de `../truncate.ts`).
17
+ */
18
+ import { Box, Text, useInput } from 'ink';
19
+ import { useDoctorStatus, } from '../hooks/use-doctor-status.js';
20
+ import { useMediaBinaries } from '../hooks/use-media-binaries.js';
21
+ import { useTerminalWidth } from '../hooks/use-terminal-width.js';
22
+ import { useNavigation } from '../navigation.js';
23
+ import { symbols } from '../symbols.js';
24
+ import { useTheme } from '../theme.js';
25
+ import { truncate } from '../truncate.js';
26
+ /** Largura mínima garantida ao valor de um `StatusRow`, mesmo em terminais muito estreitos. */
27
+ const MIN_VALUE_WIDTH = 8;
28
+ /** `paddingX={1}` dos dois lados do `Box` raiz da tela. */
29
+ const SCREEN_PADDING_X = 2;
30
+ /** Largura da coluna de ícone (`<Box width={2}>`, ver `StatusRow` abaixo). */
31
+ const ICON_COLUMN_WIDTH = 2;
32
+ /** Rótulo legível de cada fonte de credencial (nunca a api_key em si). */
33
+ const CREDENTIAL_LABELS = {
34
+ keyring: 'keychain do SO',
35
+ file: 'arquivo local (credentials.json)',
36
+ env: 'variável de ambiente (REDMINE_API_KEY)',
37
+ none: 'nenhuma credencial encontrada',
38
+ checking: 'verificando...',
39
+ };
40
+ /** Uma linha do painel: símbolo de status opcional + rótulo em muted + valor truncado ao espaço disponível. */
41
+ function StatusRow({ label, value, tone }) {
42
+ const theme = useTheme();
43
+ const terminalWidth = useTerminalWidth();
44
+ // "label: " ocupa `label.length + 2` (": ") colunas antes do valor.
45
+ const overhead = ICON_COLUMN_WIDTH + label.length + 2 + SCREEN_PADDING_X;
46
+ const valueBudget = Math.max(terminalWidth - overhead, MIN_VALUE_WIDTH);
47
+ return (_jsxs(Box, { children: [_jsx(Box, { width: ICON_COLUMN_WIDTH, children: tone === 'ok' ? (_jsx(Text, { color: theme.success, children: symbols.tick })) : tone === 'error' ? (_jsx(Text, { color: theme.danger, children: symbols.cross })) : null }), _jsxs(Text, { color: theme.muted, children: [label, ": "] }), _jsx(Text, { children: truncate(value, valueBudget) })] }));
48
+ }
49
+ /** Formata o valor + tom da linha de instância. */
50
+ function instanceRow(status) {
51
+ if (status.instanceUrl === undefined) {
52
+ return { value: 'não configurada (defina REDMINE_URL)', tone: 'error' };
53
+ }
54
+ return { value: status.instanceUrl, tone: 'ok' };
55
+ }
56
+ /** Formata o valor + tom da linha de credencial. */
57
+ function credentialRow(status) {
58
+ const value = CREDENTIAL_LABELS[status.credentialMethod];
59
+ if (status.credentialMethod === 'checking') {
60
+ return { value, tone: 'neutral' };
61
+ }
62
+ return { value, tone: status.credentialMethod === 'none' ? 'error' : 'ok' };
63
+ }
64
+ /** Formata o valor + tom da linha de conectividade a partir do status. */
65
+ function connectivityRow(connectivity, detail) {
66
+ if (connectivity === 'skipped') {
67
+ return { value: 'não verificada (nenhuma instância configurada)', tone: 'neutral' };
68
+ }
69
+ if (connectivity === 'checking') {
70
+ return { value: 'verificando...', tone: 'neutral' };
71
+ }
72
+ if (connectivity === 'ok') {
73
+ return { value: 'conectado', tone: 'ok' };
74
+ }
75
+ return { value: `falha${detail !== undefined ? ` (${detail})` : ''}`, tone: 'error' };
76
+ }
77
+ /** Formata o valor + tom da linha de um binário de mídia (M3-11, #53). */
78
+ function mediaBinaryRow(binary) {
79
+ if (!binary.found) {
80
+ return { value: `ausente — instale com: ${binary.installHint}`, tone: 'error' };
81
+ }
82
+ const version = binary.version !== undefined ? `v${binary.version}` : 'instalado';
83
+ const location = binary.path !== undefined ? ` (${binary.path})` : '';
84
+ return { value: `${version}${location}`, tone: 'ok' };
85
+ }
86
+ /** Seção "Binários de mídia": consome o mesmo diagnóstico do core que a CLI (#53). */
87
+ function MediaBinariesSection() {
88
+ const theme = useTheme();
89
+ const { loading, binaries } = useMediaBinaries();
90
+ return (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: theme.muted, children: "Bin\u00E1rios de m\u00EDdia" }), loading ? (_jsx(StatusRow, { label: "tesseract", value: "verificando...", tone: "neutral" })) : (binaries.map((binary) => {
91
+ const row = mediaBinaryRow(binary);
92
+ return _jsx(StatusRow, { label: binary.name, value: row.value, tone: row.tone }, binary.name);
93
+ }))] }));
94
+ }
95
+ /** Tela doctor: `b` (ou `Esc`, atalho global) volta para a tela anterior (ver `app.tsx`). */
96
+ export function DoctorScreen() {
97
+ const { pop } = useNavigation();
98
+ const theme = useTheme();
99
+ const status = useDoctorStatus();
100
+ useInput((input) => {
101
+ if (input === 'b') {
102
+ pop();
103
+ }
104
+ });
105
+ const instance = instanceRow(status);
106
+ const credential = credentialRow(status);
107
+ const connectivity = connectivityRow(status.connectivity, status.connectivityDetail);
108
+ return (_jsxs(Box, { flexGrow: 1, flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsx(Text, { color: theme.primary, children: "Doctor" }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusRow, { label: "Node", value: status.nodeVersion, tone: "neutral" }), _jsx(StatusRow, { label: "Ferramenta", value: `${status.toolName} v${status.toolVersion}`, tone: "neutral" }), _jsx(StatusRow, { label: "Inst\u00E2ncia", value: instance.value, tone: instance.tone }), _jsx(StatusRow, { label: "Credencial", value: credential.value, tone: credential.tone }), _jsx(StatusRow, { label: "Conectividade", value: connectivity.value, tone: connectivity.tone })] }), _jsx(MediaBinariesSection, {}), _jsx(Box, { flexGrow: 1 }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: theme.muted, children: ["Pressione", ' ', _jsx(Text, { color: theme.accent, children: "b" }), ' ', "para voltar."] }) })] }));
109
+ }
@@ -0,0 +1,2 @@
1
+ /** Tela de exportação: escolhe formato + destino, grava via o core, mostra progresso/sucesso/erro. */
2
+ export declare function ExportScreen(): import("react").JSX.Element;