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.
- package/LICENSE +21 -0
- package/README.md +449 -0
- package/dist/bundle/index.d.ts +5 -0
- package/dist/bundle/index.js +5 -0
- package/dist/bundle/json.d.ts +90 -0
- package/dist/bundle/json.js +266 -0
- package/dist/bundle/markdown.d.ts +75 -0
- package/dist/bundle/markdown.js +294 -0
- package/dist/bundle/search-list.d.ts +43 -0
- package/dist/bundle/search-list.js +53 -0
- package/dist/bundle/stable-stringify.d.ts +26 -0
- package/dist/bundle/stable-stringify.js +50 -0
- package/dist/cache/contract.d.ts +157 -0
- package/dist/cache/contract.js +0 -0
- package/dist/cache/disk-index.d.ts +82 -0
- package/dist/cache/disk-index.js +220 -0
- package/dist/cache/disk.d.ts +133 -0
- package/dist/cache/disk.js +313 -0
- package/dist/cache/gc.d.ts +78 -0
- package/dist/cache/gc.js +123 -0
- package/dist/cache/get-or-compute.d.ts +36 -0
- package/dist/cache/get-or-compute.js +52 -0
- package/dist/cache/index.d.ts +9 -0
- package/dist/cache/index.js +8 -0
- package/dist/cache/keys.d.ts +76 -0
- package/dist/cache/keys.js +78 -0
- package/dist/cache/memory.d.ts +48 -0
- package/dist/cache/memory.js +110 -0
- package/dist/cache-first.d.ts +127 -0
- package/dist/cache-first.js +227 -0
- package/dist/client/errors.d.ts +33 -0
- package/dist/client/errors.js +49 -0
- package/dist/client/http.d.ts +110 -0
- package/dist/client/http.js +207 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.js +5 -0
- package/dist/client/issues.d.ts +71 -0
- package/dist/client/issues.js +100 -0
- package/dist/client/search.d.ts +58 -0
- package/dist/client/search.js +81 -0
- package/dist/config/credentials.d.ts +247 -0
- package/dist/config/credentials.js +427 -0
- package/dist/config/doctor.d.ts +123 -0
- package/dist/config/doctor.js +260 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.js +6 -0
- package/dist/config/keyring.d.ts +96 -0
- package/dist/config/keyring.js +158 -0
- package/dist/config/login.d.ts +97 -0
- package/dist/config/login.js +189 -0
- package/dist/config/settings.d.ts +94 -0
- package/dist/config/settings.js +140 -0
- package/dist/contract.d.ts +173 -0
- package/dist/contract.js +27 -0
- package/dist/core.d.ts +1 -0
- package/dist/core.js +8 -0
- package/dist/extract/audio-extractor.d.ts +105 -0
- package/dist/extract/audio-extractor.js +156 -0
- package/dist/extract/audio.d.ts +126 -0
- package/dist/extract/audio.js +184 -0
- package/dist/extract/dispatcher.d.ts +132 -0
- package/dist/extract/dispatcher.js +115 -0
- package/dist/extract/download.d.ts +111 -0
- package/dist/extract/download.js +261 -0
- package/dist/extract/duration.d.ts +106 -0
- package/dist/extract/duration.js +148 -0
- package/dist/extract/ffmpeg.d.ts +56 -0
- package/dist/extract/ffmpeg.js +95 -0
- package/dist/extract/gguf.d.ts +137 -0
- package/dist/extract/gguf.js +215 -0
- package/dist/extract/index.d.ts +19 -0
- package/dist/extract/index.js +19 -0
- package/dist/extract/magic.d.ts +80 -0
- package/dist/extract/magic.js +282 -0
- package/dist/extract/ooxml.d.ts +131 -0
- package/dist/extract/ooxml.js +336 -0
- package/dist/extract/pdf.d.ts +147 -0
- package/dist/extract/pdf.js +322 -0
- package/dist/extract/queue.d.ts +167 -0
- package/dist/extract/queue.js +217 -0
- package/dist/extract/subprocess.d.ts +145 -0
- package/dist/extract/subprocess.js +181 -0
- package/dist/extract/tesseract.d.ts +153 -0
- package/dist/extract/tesseract.js +321 -0
- package/dist/extract/video-extractor.d.ts +84 -0
- package/dist/extract/video-extractor.js +89 -0
- package/dist/extract/video.d.ts +198 -0
- package/dist/extract/video.js +418 -0
- package/dist/extract/which.d.ts +63 -0
- package/dist/extract/which.js +72 -0
- package/dist/extract/whisper-extract.d.ts +211 -0
- package/dist/extract/whisper-extract.js +323 -0
- package/dist/extract/whisper.d.ts +50 -0
- package/dist/extract/whisper.js +67 -0
- package/dist/extract/zip.d.ts +50 -0
- package/dist/extract/zip.js +165 -0
- package/dist/extract-issue-attachments.d.ts +82 -0
- package/dist/extract-issue-attachments.js +156 -0
- package/dist/fetch-attachment-text.d.ts +113 -0
- package/dist/fetch-attachment-text.js +155 -0
- package/dist/fetch-issue-bundle.d.ts +81 -0
- package/dist/fetch-issue-bundle.js +93 -0
- package/dist/fetch-issue-search.d.ts +74 -0
- package/dist/fetch-issue-search.js +120 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +67 -0
- package/dist/normalize/collections.d.ts +52 -0
- package/dist/normalize/collections.js +170 -0
- package/dist/normalize/helpers.d.ts +35 -0
- package/dist/normalize/helpers.js +59 -0
- package/dist/normalize/index.d.ts +2 -0
- package/dist/normalize/index.js +2 -0
- package/dist/normalize/issue.d.ts +34 -0
- package/dist/normalize/issue.js +154 -0
- package/dist/surfaces/cli/commands.d.ts +61 -0
- package/dist/surfaces/cli/commands.js +262 -0
- package/dist/surfaces/cli/main.d.ts +32 -0
- package/dist/surfaces/cli/main.js +210 -0
- package/dist/surfaces/cli/prompts.d.ts +66 -0
- package/dist/surfaces/cli/prompts.js +147 -0
- package/dist/surfaces/cli/tty.d.ts +27 -0
- package/dist/surfaces/cli/tty.js +35 -0
- package/dist/surfaces/cli/types.d.ts +39 -0
- package/dist/surfaces/cli/types.js +7 -0
- package/dist/surfaces/mcp/server.d.ts +171 -0
- package/dist/surfaces/mcp/server.js +427 -0
- package/dist/surfaces/tui/app.d.ts +55 -0
- package/dist/surfaces/tui/app.js +180 -0
- package/dist/surfaces/tui/attachment-status.d.ts +79 -0
- package/dist/surfaces/tui/attachment-status.js +113 -0
- package/dist/surfaces/tui/components/breadcrumb.d.ts +7 -0
- package/dist/surfaces/tui/components/breadcrumb.js +31 -0
- package/dist/surfaces/tui/components/gradient-text.d.ts +23 -0
- package/dist/surfaces/tui/components/gradient-text.js +75 -0
- package/dist/surfaces/tui/components/scroll-view.d.ts +25 -0
- package/dist/surfaces/tui/components/scroll-view.js +77 -0
- package/dist/surfaces/tui/components/spinner.d.ts +12 -0
- package/dist/surfaces/tui/components/spinner.js +39 -0
- package/dist/surfaces/tui/components/text-input.d.ts +45 -0
- package/dist/surfaces/tui/components/text-input.js +114 -0
- package/dist/surfaces/tui/format-file-size.d.ts +24 -0
- package/dist/surfaces/tui/format-file-size.js +43 -0
- package/dist/surfaces/tui/glyphs.d.ts +47 -0
- package/dist/surfaces/tui/glyphs.js +84 -0
- package/dist/surfaces/tui/hooks/use-auth-guard.d.ts +39 -0
- package/dist/surfaces/tui/hooks/use-auth-guard.js +135 -0
- package/dist/surfaces/tui/hooks/use-doctor-status.d.ts +64 -0
- package/dist/surfaces/tui/hooks/use-doctor-status.js +123 -0
- package/dist/surfaces/tui/hooks/use-escape-interceptor.d.ts +25 -0
- package/dist/surfaces/tui/hooks/use-escape-interceptor.js +65 -0
- package/dist/surfaces/tui/hooks/use-exit-guard.d.ts +18 -0
- package/dist/surfaces/tui/hooks/use-exit-guard.js +66 -0
- package/dist/surfaces/tui/hooks/use-export-bundle.d.ts +62 -0
- package/dist/surfaces/tui/hooks/use-export-bundle.js +100 -0
- package/dist/surfaces/tui/hooks/use-issue-detail.d.ts +61 -0
- package/dist/surfaces/tui/hooks/use-issue-detail.js +132 -0
- package/dist/surfaces/tui/hooks/use-issue-search.d.ts +71 -0
- package/dist/surfaces/tui/hooks/use-issue-search.js +168 -0
- package/dist/surfaces/tui/hooks/use-list-navigation.d.ts +44 -0
- package/dist/surfaces/tui/hooks/use-list-navigation.js +82 -0
- package/dist/surfaces/tui/hooks/use-media-binaries.d.ts +24 -0
- package/dist/surfaces/tui/hooks/use-media-binaries.js +44 -0
- package/dist/surfaces/tui/hooks/use-my-issues.d.ts +66 -0
- package/dist/surfaces/tui/hooks/use-my-issues.js +151 -0
- package/dist/surfaces/tui/hooks/use-onboarding-callbacks.d.ts +11 -0
- package/dist/surfaces/tui/hooks/use-onboarding-callbacks.js +104 -0
- package/dist/surfaces/tui/hooks/use-terminal-width.d.ts +52 -0
- package/dist/surfaces/tui/hooks/use-terminal-width.js +90 -0
- package/dist/surfaces/tui/index.d.ts +50 -0
- package/dist/surfaces/tui/index.js +158 -0
- package/dist/surfaces/tui/instance.d.ts +37 -0
- package/dist/surfaces/tui/instance.js +36 -0
- package/dist/surfaces/tui/job-registry.d.ts +113 -0
- package/dist/surfaces/tui/job-registry.js +123 -0
- package/dist/surfaces/tui/job-status.d.ts +45 -0
- package/dist/surfaces/tui/job-status.js +81 -0
- package/dist/surfaces/tui/navigation.d.ts +74 -0
- package/dist/surfaces/tui/navigation.js +87 -0
- package/dist/surfaces/tui/palettes.d.ts +38 -0
- package/dist/surfaces/tui/palettes.js +244 -0
- package/dist/surfaces/tui/screen.d.ts +30 -0
- package/dist/surfaces/tui/screen.js +51 -0
- package/dist/surfaces/tui/screens/about.d.ts +2 -0
- package/dist/surfaces/tui/screens/about.js +35 -0
- package/dist/surfaces/tui/screens/appearance.d.ts +2 -0
- package/dist/surfaces/tui/screens/appearance.js +74 -0
- package/dist/surfaces/tui/screens/config.d.ts +2 -0
- package/dist/surfaces/tui/screens/config.js +82 -0
- package/dist/surfaces/tui/screens/doctor.d.ts +2 -0
- package/dist/surfaces/tui/screens/doctor.js +109 -0
- package/dist/surfaces/tui/screens/export.d.ts +2 -0
- package/dist/surfaces/tui/screens/export.js +168 -0
- package/dist/surfaces/tui/screens/home-selection.d.ts +70 -0
- package/dist/surfaces/tui/screens/home-selection.js +80 -0
- package/dist/surfaces/tui/screens/home.d.ts +2 -0
- package/dist/surfaces/tui/screens/home.js +200 -0
- package/dist/surfaces/tui/screens/issue-detail.d.ts +6 -0
- package/dist/surfaces/tui/screens/issue-detail.js +182 -0
- package/dist/surfaces/tui/screens/jobs.d.ts +7 -0
- package/dist/surfaces/tui/screens/jobs.js +89 -0
- package/dist/surfaces/tui/screens/loaded-issue-context.d.ts +49 -0
- package/dist/surfaces/tui/screens/loaded-issue-context.js +57 -0
- package/dist/surfaces/tui/screens/onboarding/api-key.d.ts +2 -0
- package/dist/surfaces/tui/screens/onboarding/api-key.js +69 -0
- package/dist/surfaces/tui/screens/onboarding/login.d.ts +2 -0
- package/dist/surfaces/tui/screens/onboarding/login.js +50 -0
- package/dist/surfaces/tui/screens/onboarding/mode.d.ts +2 -0
- package/dist/surfaces/tui/screens/onboarding/mode.js +42 -0
- package/dist/surfaces/tui/screens/onboarding/onboarding-context.d.ts +221 -0
- package/dist/surfaces/tui/screens/onboarding/onboarding-context.js +131 -0
- package/dist/surfaces/tui/screens/onboarding/success.d.ts +2 -0
- package/dist/surfaces/tui/screens/onboarding/success.js +41 -0
- package/dist/surfaces/tui/screens/onboarding/url.d.ts +24 -0
- package/dist/surfaces/tui/screens/onboarding/url.js +84 -0
- package/dist/surfaces/tui/screens/onboarding/validating.d.ts +1 -0
- package/dist/surfaces/tui/screens/onboarding/validating.js +86 -0
- package/dist/surfaces/tui/screens/welcome.d.ts +6 -0
- package/dist/surfaces/tui/screens/welcome.js +95 -0
- package/dist/surfaces/tui/status-color.d.ts +21 -0
- package/dist/surfaces/tui/status-color.js +23 -0
- package/dist/surfaces/tui/symbols.d.ts +231 -0
- package/dist/surfaces/tui/symbols.js +14 -0
- package/dist/surfaces/tui/terminal-colors.d.ts +29 -0
- package/dist/surfaces/tui/terminal-colors.js +39 -0
- package/dist/surfaces/tui/theme.d.ts +156 -0
- package/dist/surfaces/tui/theme.js +86 -0
- package/dist/surfaces/tui/truncate.d.ts +31 -0
- package/dist/surfaces/tui/truncate.js +81 -0
- 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,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,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,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,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
|
+
}
|