@golba98/codexa 1.0.2 → 1.0.3

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 (150) hide show
  1. package/README.md +391 -94
  2. package/package.json +12 -7
  3. package/src/app.tsx +149 -117
  4. package/src/commands/handler.ts +4 -4
  5. package/src/config/buildInfo.ts +2 -2
  6. package/src/config/persistence.ts +10 -0
  7. package/src/config/settings.ts +7 -15
  8. package/src/config/updateCheckCache.ts +19 -1
  9. package/src/core/channel.ts +23 -0
  10. package/src/core/executables/codexExecutable.ts +1 -0
  11. package/src/core/executables/executableResolver.ts +61 -43
  12. package/src/core/launchContext.ts +33 -33
  13. package/src/core/process/processValidation.ts +9 -5
  14. package/src/core/providerLauncher/launcher.ts +59 -42
  15. package/src/core/updateCheck.ts +111 -95
  16. package/src/session/types.ts +2 -1
  17. package/src/ui/ActionRequiredBlock.tsx +5 -5
  18. package/src/ui/ActivityBars.tsx +3 -3
  19. package/src/ui/ActivityIndicator.tsx +6 -6
  20. package/src/ui/AgentBlock.tsx +6 -6
  21. package/src/ui/AnimatedStatusText.tsx +1 -1
  22. package/src/ui/AppShell.tsx +9 -24
  23. package/src/ui/AttachmentImportPanel.tsx +8 -8
  24. package/src/ui/AuthPanel.tsx +20 -20
  25. package/src/ui/BottomComposer.tsx +117 -78
  26. package/src/ui/DashCard.tsx +3 -3
  27. package/src/ui/Markdown.tsx +17 -17
  28. package/src/ui/ModelPickerScreen.tsx +10 -10
  29. package/src/ui/ModelReasoningPicker.tsx +14 -14
  30. package/src/ui/Panel.tsx +3 -3
  31. package/src/ui/PlanActionPicker.tsx +6 -6
  32. package/src/ui/PlanReviewPanel.tsx +8 -8
  33. package/src/ui/ProviderPicker.tsx +18 -18
  34. package/src/ui/RunFooter.tsx +3 -3
  35. package/src/ui/SelectionPanel.tsx +4 -4
  36. package/src/ui/SettingsPanel.tsx +8 -8
  37. package/src/ui/Spinner.tsx +1 -1
  38. package/src/ui/TextEntryPanel.tsx +10 -10
  39. package/src/ui/ThinkingBlock.tsx +8 -8
  40. package/src/ui/Timeline.tsx +21 -17
  41. package/src/ui/TopHeader.tsx +421 -293
  42. package/src/ui/TurnGroup.tsx +31 -31
  43. package/src/ui/UpdateAvailableCard.tsx +41 -0
  44. package/src/ui/UpdatePromptPanel.tsx +203 -0
  45. package/src/ui/focus.ts +3 -0
  46. package/src/ui/layout.ts +1 -1
  47. package/src/ui/logoVariants.ts +107 -0
  48. package/src/ui/modeDisplay.ts +12 -12
  49. package/src/ui/runtimeDisplay.ts +100 -0
  50. package/src/ui/theme.tsx +274 -395
  51. package/src/ui/timelineMeasure.ts +29 -19
  52. package/scripts/audit-codexa-capabilities.mjs +0 -466
  53. package/scripts/gen-build-info.mjs +0 -33
  54. package/scripts/smoke-terminal-bench.mjs +0 -35
  55. package/src/appRenderStability.test.ts +0 -131
  56. package/src/commands/handler.test.ts +0 -655
  57. package/src/config/launchArgs.test.ts +0 -189
  58. package/src/config/layeredConfig.test.ts +0 -143
  59. package/src/config/persistence.test.ts +0 -114
  60. package/src/config/runtimeConfig.test.ts +0 -218
  61. package/src/config/settings.test.ts +0 -155
  62. package/src/config/trustStore.test.ts +0 -29
  63. package/src/core/attachments.test.ts +0 -155
  64. package/src/core/auth/codexAuth.test.ts +0 -68
  65. package/src/core/cleanupFastFail.test.ts +0 -76
  66. package/src/core/codexExecArgs.test.ts +0 -195
  67. package/src/core/codexLaunch.test.ts +0 -205
  68. package/src/core/codexPrompt.test.ts +0 -252
  69. package/src/core/executables/codexExecutable.test.ts +0 -212
  70. package/src/core/executables/executableResolver.test.ts +0 -129
  71. package/src/core/executables/geminiExecutable.test.ts +0 -116
  72. package/src/core/executables/pathSanityScan.test.ts +0 -47
  73. package/src/core/githubDiagnostics.test.ts +0 -92
  74. package/src/core/hollowResponseFormat.test.ts +0 -58
  75. package/src/core/launchContext.test.ts +0 -157
  76. package/src/core/models/codexCapabilities.test.ts +0 -45
  77. package/src/core/models/codexModelCapabilities.test.ts +0 -246
  78. package/src/core/models/modelSpecs.test.ts +0 -283
  79. package/src/core/perf/renderDebug.test.ts +0 -230
  80. package/src/core/planStorage.test.ts +0 -143
  81. package/src/core/process/CommandRunner.test.ts +0 -105
  82. package/src/core/projectInstructions.test.ts +0 -50
  83. package/src/core/providerLauncher/launcher.test.ts +0 -238
  84. package/src/core/providerLauncher/registry.test.ts +0 -324
  85. package/src/core/providerLauncher/workspaceConfig.test.ts +0 -638
  86. package/src/core/providerRuntime/anthropic.test.ts +0 -1120
  87. package/src/core/providerRuntime/capabilityProfile.test.ts +0 -311
  88. package/src/core/providerRuntime/contextMetadata.test.ts +0 -468
  89. package/src/core/providerRuntime/gemini.test.ts +0 -437
  90. package/src/core/providerRuntime/lmstudio.test.ts +0 -168
  91. package/src/core/providerRuntime/local.test.ts +0 -787
  92. package/src/core/providerRuntime/registry.test.ts +0 -233
  93. package/src/core/providers/codexJsonStream.test.ts +0 -148
  94. package/src/core/providers/codexSubprocess.test.ts +0 -68
  95. package/src/core/providers/codexTranscript.test.ts +0 -284
  96. package/src/core/terminal/startupClear.test.ts +0 -55
  97. package/src/core/terminal/terminalCapabilities.test.ts +0 -93
  98. package/src/core/terminal/terminalControl.test.ts +0 -75
  99. package/src/core/terminal/terminalSanitize.test.ts +0 -22
  100. package/src/core/terminal/terminalSelection.test.ts +0 -42
  101. package/src/core/terminal/terminalTitle.test.ts +0 -328
  102. package/src/core/updateCheck.test.ts +0 -194
  103. package/src/core/workspaceActivity.test.ts +0 -163
  104. package/src/core/workspaceGuard.test.ts +0 -151
  105. package/src/core/workspaceRoot.test.ts +0 -23
  106. package/src/exec.test.ts +0 -13
  107. package/src/headless/execArgs.test.ts +0 -147
  108. package/src/headless/execRunner.test.ts +0 -436
  109. package/src/index.test.tsx +0 -620
  110. package/src/session/appSession.test.ts +0 -897
  111. package/src/session/chatLifecycle.test.ts +0 -64
  112. package/src/session/liveRenderScheduler.test.ts +0 -201
  113. package/src/session/planFlow.test.ts +0 -103
  114. package/src/session/planTranscript.test.ts +0 -65
  115. package/src/session/promptRunSchedule.test.ts +0 -36
  116. package/src/ui/ActivityIndicator.test.tsx +0 -58
  117. package/src/ui/AgentBlock.test.ts +0 -6
  118. package/src/ui/AnimatedStatusText.test.ts +0 -16
  119. package/src/ui/AppShell.test.tsx +0 -1776
  120. package/src/ui/AttachmentImportPanel.test.tsx +0 -204
  121. package/src/ui/BottomComposer.test.ts +0 -674
  122. package/src/ui/CodexLogo.tsx +0 -55
  123. package/src/ui/Markdown.test.ts +0 -157
  124. package/src/ui/ModelPickerProviderScope.test.tsx +0 -411
  125. package/src/ui/ModelPickerScreen.test.tsx +0 -99
  126. package/src/ui/ModelPickerState.test.tsx +0 -151
  127. package/src/ui/ModelReasoningPicker.test.tsx +0 -447
  128. package/src/ui/PlanReviewPanel.test.tsx +0 -267
  129. package/src/ui/PromptCardBorder.test.tsx +0 -161
  130. package/src/ui/ProviderPicker.test.tsx +0 -289
  131. package/src/ui/ProviderShortcut.test.tsx +0 -143
  132. package/src/ui/SettingsPanel.test.tsx +0 -233
  133. package/src/ui/Timeline.test.ts +0 -2067
  134. package/src/ui/TimelineNavigation.test.tsx +0 -201
  135. package/src/ui/TopHeader.test.tsx +0 -254
  136. package/src/ui/TurnGroup.test.tsx +0 -365
  137. package/src/ui/busyStatusAnimation.test.ts +0 -30
  138. package/src/ui/commandNormalize.test.ts +0 -142
  139. package/src/ui/diffRenderer.test.ts +0 -102
  140. package/src/ui/focusFlow.test.tsx +0 -1098
  141. package/src/ui/inputBuffer.test.ts +0 -151
  142. package/src/ui/layout.test.ts +0 -146
  143. package/src/ui/modeDisplay.test.ts +0 -42
  144. package/src/ui/runActivityView.test.ts +0 -89
  145. package/src/ui/runLifecycleView.test.tsx +0 -237
  146. package/src/ui/statusRenderIsolation.test.tsx +0 -654
  147. package/src/ui/terminalAnswerFormat.test.ts +0 -19
  148. package/src/ui/textLayout.test.ts +0 -18
  149. package/src/ui/themeFlow.test.ts +0 -53
  150. package/src/ui/timelineMeasureCache.test.ts +0 -986
package/src/ui/Panel.tsx CHANGED
@@ -13,8 +13,8 @@ interface PanelProps {
13
13
 
14
14
  export function Panel({ cols, title, rightTitle, borderColor, titleColor, children }: PanelProps) {
15
15
  const theme = useTheme();
16
- const cBorder = borderColor || theme.BORDER_ACTIVE;
17
- const cTitle = titleColor || theme.TEXT;
16
+ const cBorder = borderColor || theme.borderFocused;
17
+ const cTitle = titleColor || theme.text;
18
18
 
19
19
  const leftLabel = ` ${title} `;
20
20
  const rightLabel = rightTitle ? ` ${rightTitle} ` : "";
@@ -32,7 +32,7 @@ export function Panel({ cols, title, rightTitle, borderColor, titleColor, childr
32
32
  {"╭─"}
33
33
  <Text color={cTitle}>{leftLabel}</Text>
34
34
  {"─".repeat(dashCount)}
35
- {rightTitle && <Text color={theme.DIM}>{rightLabel}</Text>}
35
+ {rightTitle && <Text color={theme.textDim}>{rightLabel}</Text>}
36
36
  {"╮"}
37
37
  </Text>
38
38
  <Box
@@ -85,10 +85,10 @@ export function PlanActionPicker({
85
85
  const selected = index === selectedIndex;
86
86
  return (
87
87
  <Text key={row.value}>
88
- <Text color={selected ? theme.ACCENT : theme.DIM}>
88
+ <Text color={selected ? theme.accent : theme.textDim}>
89
89
  {selected ? "› " : vertical ? " " : ""}
90
90
  </Text>
91
- <Text color={selected ? theme.TEXT : theme.MUTED}>
91
+ <Text color={selected ? theme.text : theme.textMuted}>
92
92
  {`[${row.key}] ${row.label}`}
93
93
  </Text>
94
94
  </Text>
@@ -98,7 +98,7 @@ export function PlanActionPicker({
98
98
  if (vertical) {
99
99
  return (
100
100
  <Box flexDirection="column">
101
- <Text color={isFocused ? theme.TEXT : theme.MUTED} bold={isFocused}>Plan ready</Text>
101
+ <Text color={isFocused ? theme.text : theme.textMuted} bold={isFocused}>Plan ready</Text>
102
102
  {ACTION_ROWS.map(renderAction)}
103
103
  </Box>
104
104
  );
@@ -106,12 +106,12 @@ export function PlanActionPicker({
106
106
 
107
107
  return (
108
108
  <Text>
109
- <Text color={isFocused ? theme.TEXT : theme.MUTED} bold={isFocused}>Plan ready</Text>
110
- <Text color={theme.DIM}>{" "}</Text>
109
+ <Text color={isFocused ? theme.text : theme.textMuted} bold={isFocused}>Plan ready</Text>
110
+ <Text color={theme.textDim}>{" "}</Text>
111
111
  {ACTION_ROWS.map((row, index) => (
112
112
  <React.Fragment key={row.value}>
113
113
  {renderAction(row, index)}
114
- {index < ACTION_ROWS.length - 1 && <Text color={theme.DIM}>{" "}</Text>}
114
+ {index < ACTION_ROWS.length - 1 && <Text color={theme.textDim}>{" "}</Text>}
115
115
  </React.Fragment>
116
116
  ))}
117
117
  </Text>
@@ -192,21 +192,21 @@ export function PlanReviewPanel({
192
192
  return (
193
193
  <Box width="100%" flexDirection="column" paddingX={2}>
194
194
  <Text wrap="truncate">
195
- <Text color={theme.BORDER_SUBTLE}>{"╭─ "}</Text>
196
- <Text color={theme.TEXT} bold>{topBorder.title}</Text>
197
- <Text color={theme.BORDER_SUBTLE}>{topBorder.fill}</Text>
198
- <Text color={theme.BORDER_SUBTLE}>{"╮"}</Text>
195
+ <Text color={theme.border}>{"╭─ "}</Text>
196
+ <Text color={theme.text} bold>{topBorder.title}</Text>
197
+ <Text color={theme.border}>{topBorder.fill}</Text>
198
+ <Text color={theme.border}>{"╮"}</Text>
199
199
  </Text>
200
200
  {displayRows.map((row, index) => (
201
201
  <Text key={index} wrap="truncate">
202
- <Text color={theme.BORDER_SUBTLE}>{"│ "}</Text>
203
- <Text color={row.tone === "muted" ? theme.MUTED : theme.TEXT} bold={row.bold}>
202
+ <Text color={theme.border}>{"│ "}</Text>
203
+ <Text color={row.tone === "muted" ? theme.textMuted : theme.text} bold={row.bold}>
204
204
  {padVisual(row.text, contentWidth)}
205
205
  </Text>
206
- <Text color={theme.BORDER_SUBTLE}>{" │"}</Text>
206
+ <Text color={theme.border}>{" │"}</Text>
207
207
  </Text>
208
208
  ))}
209
- <Text wrap="truncate" color={theme.BORDER_SUBTLE}>{`╰${"─".repeat(Math.max(1, panelCols - 2))}╯`}</Text>
209
+ <Text wrap="truncate" color={theme.border}>{`╰${"─".repeat(Math.max(1, panelCols - 2))}╯`}</Text>
210
210
  </Box>
211
211
  );
212
212
  }
@@ -150,14 +150,14 @@ export function ProviderPicker({ layout, providers, onAction, onCancel, initialP
150
150
  const inCodexaAvailable = selectedProvider.routeMode === "in-codexa";
151
151
  const isConfigured = inCodexaAvailable && !selectedProvider.routeUnavailableReason;
152
152
  const inCodexaStatusText = !inCodexaAvailable ? "Unavailable" : isConfigured ? "Available" : "Needs configuration";
153
- const inCodexaStatusColor = !inCodexaAvailable ? theme.ERROR : isConfigured ? theme.SUCCESS : theme.WARNING;
153
+ const inCodexaStatusColor = !inCodexaAvailable ? theme.error : isConfigured ? theme.success : theme.warning;
154
154
 
155
155
  return (
156
156
  <Box flexDirection="column">
157
157
  <Box marginBottom={1} flexDirection="column" paddingX={2}>
158
- <Text color={theme.DIM}>Status: <Text color={theme.TEXT}>{selectedProvider.routeUnavailableReason ?? "Ready"}</Text></Text>
159
- <Text color={theme.DIM}>Backend: <Text color={theme.TEXT}>{selectedProvider.backendType}</Text></Text>
160
- <Text color={theme.DIM}>Use in Codexa: <Text color={inCodexaStatusColor}>{inCodexaStatusText}</Text></Text>
158
+ <Text color={theme.textDim}>Status: <Text color={theme.text}>{selectedProvider.routeUnavailableReason ?? "Ready"}</Text></Text>
159
+ <Text color={theme.textDim}>Backend: <Text color={theme.text}>{selectedProvider.backendType}</Text></Text>
160
+ <Text color={theme.textDim}>Use in Codexa: <Text color={inCodexaStatusColor}>{inCodexaStatusText}</Text></Text>
161
161
  </Box>
162
162
  {actions.map((action, index) => (
163
163
  <ActionRow
@@ -186,21 +186,21 @@ export function ProviderPicker({ layout, providers, onAction, onCancel, initialP
186
186
  <Box flexDirection="column" width={panelWidth}>
187
187
  <Box
188
188
  borderStyle="round"
189
- borderColor={theme.PROMPT}
189
+ borderColor={theme.prompt}
190
190
  paddingX={1}
191
191
  paddingY={0}
192
192
  width={panelWidth}
193
193
  flexDirection="column"
194
194
  >
195
195
  <Box width="100%" overflow="hidden">
196
- <Text color={theme.ACCENT} bold>
196
+ <Text color={theme.accent} bold>
197
197
  {clampVisualText(`${title} ${helpText}`, innerWidth)}
198
198
  </Text>
199
199
  </Box>
200
200
 
201
201
  {mode === "providers" && (
202
202
  <Box width="100%" overflow="hidden">
203
- <Text color={theme.DIM}>
203
+ <Text color={theme.textDim}>
204
204
  {" "}
205
205
  {clampVisualText("Provider", providerNameWidth)}
206
206
  {" "}
@@ -251,10 +251,10 @@ function ProviderRow({
251
251
  }) {
252
252
  const theme = useTheme();
253
253
  const statusColor = provider.isActiveRoute
254
- ? theme.SUCCESS
254
+ ? theme.success
255
255
  : provider.enabled && !provider.routeUnavailableReason
256
- ? theme.SUCCESS
257
- : theme.WARNING;
256
+ ? theme.success
257
+ : theme.warning;
258
258
  const marker = isHighlighted ? ">" : " ";
259
259
  const defaultMark = provider.isActiveRoute ? "@" : provider.isDefault ? "*" : " ";
260
260
  const statusText = provider.isActiveRoute ? "Active" : provider.statusLabel;
@@ -262,28 +262,28 @@ function ProviderRow({
262
262
  return (
263
263
  <Box width="100%" overflow="hidden">
264
264
  <Box width={2} flexShrink={0}>
265
- <Text color={isHighlighted ? theme.ACCENT : theme.DIM}>{marker}{defaultMark}</Text>
265
+ <Text color={isHighlighted ? theme.accent : theme.textDim}>{marker}{defaultMark}</Text>
266
266
  </Box>
267
267
  <Box width={widths.providerNameWidth} flexShrink={0} overflow="hidden">
268
- <Text color={isHighlighted ? theme.TEXT : theme.MUTED} bold={isHighlighted}>
268
+ <Text color={isHighlighted ? theme.text : theme.textMuted} bold={isHighlighted}>
269
269
  {clampVisualText(provider.displayName, widths.providerNameWidth)}
270
270
  </Text>
271
271
  </Box>
272
272
  <Text> </Text>
273
273
  <Box width={widths.modelWidth} flexShrink={0} overflow="hidden">
274
- <Text color={theme.MUTED}>{clampVisualText(provider.currentModel, widths.modelWidth)}</Text>
274
+ <Text color={theme.textMuted}>{clampVisualText(provider.currentModel, widths.modelWidth)}</Text>
275
275
  </Box>
276
276
  <Text> </Text>
277
277
  <Box width={widths.contextWidth} flexShrink={0} overflow="hidden">
278
- <Text color={theme.MUTED}>{clampVisualText(provider.contextLengthLabel ?? "Unknown", widths.contextWidth)}</Text>
278
+ <Text color={theme.textMuted}>{clampVisualText(provider.contextLengthLabel ?? "Unknown", widths.contextWidth)}</Text>
279
279
  </Box>
280
280
  <Text> </Text>
281
281
  <Box width={widths.toolsWidth} flexShrink={0} overflow="hidden">
282
- <Text color={theme.MUTED}>{clampVisualText(capabilityFlag(provider.capabilityProfile?.supportsToolCalls), widths.toolsWidth)}</Text>
282
+ <Text color={theme.textMuted}>{clampVisualText(capabilityFlag(provider.capabilityProfile?.supportsToolCalls), widths.toolsWidth)}</Text>
283
283
  </Box>
284
284
  <Text> </Text>
285
285
  <Box width={widths.streamWidth} flexShrink={0} overflow="hidden">
286
- <Text color={theme.MUTED}>{clampVisualText(capabilityFlag(provider.capabilityProfile?.supportsStreaming), widths.streamWidth)}</Text>
286
+ <Text color={theme.textMuted}>{clampVisualText(capabilityFlag(provider.capabilityProfile?.supportsStreaming), widths.streamWidth)}</Text>
287
287
  </Box>
288
288
  <Text> </Text>
289
289
  <Box width={widths.statusWidth} flexShrink={0} overflow="hidden">
@@ -309,10 +309,10 @@ function ActionRow({
309
309
  return (
310
310
  <Box width="100%" overflow="hidden">
311
311
  <Box width={2} flexShrink={0}>
312
- <Text color={isHighlighted ? theme.ACCENT : theme.DIM}>{isHighlighted ? ">" : " "}</Text>
312
+ <Text color={isHighlighted ? theme.accent : theme.textDim}>{isHighlighted ? ">" : " "}</Text>
313
313
  </Box>
314
314
  <Box width={Math.max(10, width - 2)} flexShrink={0} overflow="hidden">
315
- <Text color={disabledReason ? theme.DIM : isHighlighted ? theme.TEXT : theme.MUTED} bold={isHighlighted && !disabledReason}>
315
+ <Text color={disabledReason ? theme.textDim : isHighlighted ? theme.text : theme.textMuted} bold={isHighlighted && !disabledReason}>
316
316
  {clampVisualText(text, Math.max(10, width - 2))}
317
317
  </Text>
318
318
  </Box>
@@ -43,14 +43,14 @@ function RunFooter({ uiState, showBusyLoader = true }: RunFooterProps) {
43
43
 
44
44
  return (
45
45
  <Box flexDirection="column" paddingBottom={1} width="100%">
46
- <Box borderStyle="single" borderTop={true} borderBottom={false} borderLeft={false} borderRight={false} borderColor={theme.BORDER_SUBTLE} marginBottom={1} />
46
+ <Box borderStyle="single" borderTop={true} borderBottom={false} borderLeft={false} borderRight={false} borderColor={theme.border} marginBottom={1} />
47
47
  <Box paddingX={1} width="100%" justifyContent="space-between" overflow="hidden">
48
48
  <Box flexShrink={1} flexGrow={1} overflow="hidden">
49
- <Text color={theme.INFO}>{"✧ "}</Text>
49
+ <Text color={theme.info}>{"✧ "}</Text>
50
50
  <AnimatedStatusText baseText={getRunFooterStatus(uiState)} isActive={isActive} />
51
51
  </Box>
52
52
  <Box flexShrink={0}>
53
- <Text color={theme.DIM}>Esc cancel Ctrl+C quit</Text>
53
+ <Text color={theme.textDim}>Esc cancel Ctrl+C quit</Text>
54
54
  </Box>
55
55
  </Box>
56
56
  </Box>
@@ -36,19 +36,19 @@ export function SelectionPanel({
36
36
  {/* Block 1: title + instructions */}
37
37
  <Box
38
38
  borderStyle="round"
39
- borderColor={theme.BORDER_SUBTLE}
39
+ borderColor={theme.border}
40
40
  paddingX={2}
41
41
  paddingY={1}
42
42
  width="100%"
43
43
  >
44
- <Text color={theme.ACCENT} bold>{title} </Text>
45
- <Text color={theme.MUTED}>{subtitle}</Text>
44
+ <Text color={theme.accent} bold>{title} </Text>
45
+ <Text color={theme.textMuted}>{subtitle}</Text>
46
46
  </Box>
47
47
 
48
48
  {/* Block 2: selection list */}
49
49
  <Box
50
50
  borderStyle="round"
51
- borderColor={theme.BORDER_ACTIVE}
51
+ borderColor={theme.borderFocused}
52
52
  paddingX={2}
53
53
  paddingY={1}
54
54
  marginTop={1}
@@ -91,26 +91,26 @@ export function SettingsPanel<TKey extends string>({
91
91
  <Box flexDirection="column" width="100%" marginTop={1}>
92
92
  <Box
93
93
  borderStyle="round"
94
- borderColor={theme.BORDER_SUBTLE}
94
+ borderColor={theme.border}
95
95
  paddingX={2}
96
96
  paddingY={1}
97
97
  width="100%"
98
98
  flexDirection="column"
99
99
  >
100
100
  <Box>
101
- <Text color={theme.ACCENT} bold>{title} </Text>
102
- <Text color={theme.MUTED}>{subtitle.split("\n")[0]}</Text>
101
+ <Text color={theme.accent} bold>{title} </Text>
102
+ <Text color={theme.textMuted}>{subtitle.split("\n")[0]}</Text>
103
103
  </Box>
104
104
  {activeSetting?.description && (
105
105
  <Box marginTop={1}>
106
- <Text color={theme.DIM}>{activeSetting.description}</Text>
106
+ <Text color={theme.textDim}>{activeSetting.description}</Text>
107
107
  </Box>
108
108
  )}
109
109
  </Box>
110
110
 
111
111
  <Box
112
112
  borderStyle="round"
113
- borderColor={theme.BORDER_ACTIVE}
113
+ borderColor={theme.borderFocused}
114
114
  paddingX={2}
115
115
  paddingY={1}
116
116
  marginTop={1}
@@ -124,10 +124,10 @@ export function SettingsPanel<TKey extends string>({
124
124
  return (
125
125
  <Box key={setting.key} flexDirection="row" width="100%">
126
126
  <Box width={3}>
127
- <Text color={isSelectedRow ? theme.ACCENT : theme.DIM}>{isSelectedRow ? "▸ " : " "}</Text>
127
+ <Text color={isSelectedRow ? theme.accent : theme.textDim}>{isSelectedRow ? "▸ " : " "}</Text>
128
128
  </Box>
129
129
  <Box width={20}>
130
- <Text color={isSelectedRow ? theme.TEXT : theme.MUTED} bold={isSelectedRow}>
130
+ <Text color={isSelectedRow ? theme.text : theme.textMuted} bold={isSelectedRow}>
131
131
  {setting.label}
132
132
  </Text>
133
133
  </Box>
@@ -138,7 +138,7 @@ export function SettingsPanel<TKey extends string>({
138
138
  return (
139
139
  <Text
140
140
  key={option.value}
141
- color={isActiveOption ? (isSelectedRow ? theme.ACCENT : theme.TEXT) : theme.DIM}
141
+ color={isActiveOption ? (isSelectedRow ? theme.accent : theme.text) : theme.textDim}
142
142
  bold={isActiveOption}
143
143
  >
144
144
  {optionIndex > 0 ? " " : ""}
@@ -7,7 +7,7 @@ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "
7
7
  export function Spinner({ color }: { color?: string }) {
8
8
  const theme = useTheme();
9
9
  const [frame, setFrame] = useState(0);
10
- const activeColor = color ?? theme.DIM;
10
+ const activeColor = color ?? theme.textDim;
11
11
 
12
12
  useEffect(() => {
13
13
  const timer = setInterval(() => {
@@ -97,18 +97,18 @@ export function TextEntryPanel({
97
97
  <Box flexDirection="column" width="100%" marginTop={1}>
98
98
  <Box
99
99
  borderStyle="round"
100
- borderColor={theme.BORDER_SUBTLE}
100
+ borderColor={theme.border}
101
101
  paddingX={2}
102
102
  paddingY={1}
103
103
  width="100%"
104
104
  >
105
- <Text color={theme.ACCENT} bold>{title} </Text>
106
- <Text color={theme.MUTED}>{subtitle}</Text>
105
+ <Text color={theme.accent} bold>{title} </Text>
106
+ <Text color={theme.textMuted}>{subtitle}</Text>
107
107
  </Box>
108
108
 
109
109
  <Box
110
110
  borderStyle="round"
111
- borderColor={theme.BORDER_ACTIVE}
111
+ borderColor={theme.borderFocused}
112
112
  paddingX={2}
113
113
  paddingY={1}
114
114
  marginTop={1}
@@ -116,18 +116,18 @@ export function TextEntryPanel({
116
116
  flexDirection="column"
117
117
  >
118
118
  <Box>
119
- <Text color={theme.TEXT}>{inputLabel}: </Text>
120
- <Text color={display.isPlaceholder ? theme.DIM : theme.TEXT}>{display.before}</Text>
119
+ <Text color={theme.text}>{inputLabel}: </Text>
120
+ <Text color={display.isPlaceholder ? theme.textDim : theme.text}>{display.before}</Text>
121
121
  <Text
122
- backgroundColor={theme.TEXT}
123
- color={theme.PANEL}
122
+ backgroundColor={theme.text}
123
+ color={theme.surface}
124
124
  >
125
125
  {display.current}
126
126
  </Text>
127
- <Text color={display.isPlaceholder ? theme.DIM : theme.TEXT}>{display.after}</Text>
127
+ <Text color={display.isPlaceholder ? theme.textDim : theme.text}>{display.after}</Text>
128
128
  </Box>
129
129
  <Box marginTop={1}>
130
- <Text color={theme.DIM}>{footerHint}</Text>
130
+ <Text color={theme.textDim}>{footerHint}</Text>
131
131
  </Box>
132
132
  </Box>
133
133
  </Box>
@@ -53,21 +53,21 @@ export function ThinkingBlock({ cols, run }: ThinkingBlockProps) {
53
53
  cols={cols}
54
54
  title="Processing"
55
55
  rightBadge={rightBadge}
56
- borderColor={run.status === "running" ? theme.BORDER_ACTIVE : theme.BORDER_SUBTLE}
56
+ borderColor={run.status === "running" ? theme.borderFocused : theme.border}
57
57
  >
58
58
  {blocks.length === 0 ? (
59
- <Text color={theme.DIM}>No processing updates</Text>
59
+ <Text color={theme.textDim}>No processing updates</Text>
60
60
  ) : (
61
61
  <Box flexDirection="column" width="100%">
62
62
  {currentText && run.status === "running" && (
63
63
  <Box width="100%">
64
- <Text color={theme.INFO} bold>Current: </Text>
65
- <Text color={theme.TEXT}>{currentText}</Text>
64
+ <Text color={theme.info} bold>Current: </Text>
65
+ <Text color={theme.text}>{currentText}</Text>
66
66
  </Box>
67
67
  )}
68
68
  {hiddenCount > 0 && (
69
69
  <Box marginTop={currentText && run.status === "running" ? 1 : 0}>
70
- <Text color={theme.DIM}>{`... ${hiddenCount} earlier update${hiddenCount === 1 ? "" : "s"}`}</Text>
70
+ <Text color={theme.textDim}>{`... ${hiddenCount} earlier update${hiddenCount === 1 ? "" : "s"}`}</Text>
71
71
  </Box>
72
72
  )}
73
73
  {blocks.map((block, blockIndex) => {
@@ -79,16 +79,16 @@ export function ThinkingBlock({ cols, run }: ThinkingBlockProps) {
79
79
  width="100%"
80
80
  marginTop={blockIndex === 0 && hiddenCount === 0 && !(currentText && run.status === "running") ? 0 : 1}
81
81
  >
82
- <Text color={isLive ? theme.ACCENT : theme.INFO} bold={isLive}>
82
+ <Text color={isLive ? theme.accent : theme.info} bold={isLive}>
83
83
  {`${getBlockMarker(isLive)} ${isLive ? "Live" : block.label}`}
84
84
  </Text>
85
85
  {formatProgressBlockBodyLines(block.text, contentWidth).map((line, lineIndex) => (
86
- <Text key={`${block.key}-${lineIndex}`} color={theme.MUTED}>
86
+ <Text key={`${block.key}-${lineIndex}`} color={theme.textMuted}>
87
87
  {line ? `${isLive ? " | " : " "}${line}` : " "}
88
88
  </Text>
89
89
  ))}
90
90
  {isLive && (
91
- <Text color={theme.ACCENT}> | ▌</Text>
91
+ <Text color={theme.accent}> | ▌</Text>
92
92
  )}
93
93
  </Box>
94
94
  );
@@ -11,7 +11,8 @@ import {
11
11
  type UIState,
12
12
  type UserPromptEvent,
13
13
  } from "../session/types.js";
14
- import { APP_VERSION } from "../config/settings.js";
14
+ import { APP_VERSION } from "../config/settings.js";
15
+ import { formatCodexaVersionLabel } from "../core/channel.js";
15
16
  import type { CodexAuthState } from "../core/auth/codexAuth.js";
16
17
  import { getAuthStateLabel } from "../core/auth/codexAuth.js";
17
18
  import * as renderDebug from "../core/perf/renderDebug.js";
@@ -854,8 +855,8 @@ export function buildIntroRenderItem(params: {
854
855
  key: "codexa-intro",
855
856
  type: "intro",
856
857
  padded: true,
857
- intro: {
858
- version: APP_VERSION,
858
+ intro: {
859
+ version: formatCodexaVersionLabel(APP_VERSION),
859
860
  layoutMode: params.layout.mode,
860
861
  startupHeaderMode: params.startupHeaderMode,
861
862
  authLabel: formatAuthLabel(params.authState),
@@ -868,18 +869,21 @@ export function buildIntroRenderItem(params: {
868
869
 
869
870
  function getToneColor(theme: ReturnType<typeof useTheme>, tone: TimelineTone | undefined): string | undefined {
870
871
  switch (tone) {
871
- case "text": return theme.TEXT;
872
- case "dim": return theme.DIM;
873
- case "muted": return theme.MUTED;
874
- case "accent": return theme.ACCENT;
875
- case "info": return theme.INFO;
876
- case "error": return theme.ERROR;
877
- case "warning": return theme.WARNING;
878
- case "success": return theme.SUCCESS;
879
- case "borderSubtle": return theme.BORDER_SUBTLE;
880
- case "borderActive": return theme.BORDER_ACTIVE;
881
- case "panel": return theme.PANEL;
882
- case "star": return theme.STAR;
872
+ case "text": return theme.text;
873
+ case "dim": return theme.textDim;
874
+ case "muted": return theme.textMuted;
875
+ case "accent": return theme.accent;
876
+ case "info": return theme.info;
877
+ case "error": return theme.error;
878
+ case "warning": return theme.warning;
879
+ case "success": return theme.success;
880
+ case "borderSubtle": return theme.border;
881
+ case "borderActive": return theme.borderFocused;
882
+ case "panel": return theme.surface;
883
+ case "star": return theme.warning;
884
+ case "logoPrimary": return theme.logoPrimary;
885
+ case "logoSecondary": return theme.logoSecondary;
886
+ case "logoShadow": return theme.logoShadow;
883
887
  default: return undefined;
884
888
  }
885
889
  }
@@ -959,8 +963,8 @@ const JumpToBottomBar = memo(function JumpToBottomBar({
959
963
  const hint = mouseCapture ? "wheel↓/End to bottom" : "PgDn/End to bottom";
960
964
  return (
961
965
  <Box width="100%" paddingX={1}>
962
- <Text color={theme.INFO}>{label}</Text>
963
- <Text color={theme.DIM}>{` · ${hint}`}</Text>
966
+ <Text color={theme.info}>{label}</Text>
967
+ <Text color={theme.textDim}>{` · ${hint}`}</Text>
964
968
  </Box>
965
969
  );
966
970
  });