@golba98/codexa 1.0.1 → 1.0.2
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/README.md +0 -0
- package/package.json +3 -2
- package/scripts/audit-codexa-capabilities.mjs +0 -0
- package/scripts/gen-build-info.mjs +33 -0
- package/scripts/smoke-terminal-bench.mjs +0 -0
- package/src/app.tsx +103 -2
- package/src/appRenderStability.test.ts +0 -0
- package/src/commands/handler.test.ts +12 -0
- package/src/commands/handler.ts +5 -0
- package/src/config/buildInfo.ts +3 -0
- package/src/config/launchArgs.test.ts +31 -0
- package/src/config/launchArgs.ts +10 -0
- package/src/config/layeredConfig.test.ts +0 -0
- package/src/config/layeredConfig.ts +0 -0
- package/src/config/persistence.test.ts +6 -2
- package/src/config/persistence.ts +41 -0
- package/src/config/runtimeConfig.test.ts +0 -0
- package/src/config/runtimeConfig.ts +4 -0
- package/src/config/settings.test.ts +0 -0
- package/src/config/settings.ts +7 -6
- package/src/config/toml-serialize.ts +0 -0
- package/src/config/trustStore.test.ts +0 -0
- package/src/config/trustStore.ts +0 -0
- package/src/config/updateCheckCache.ts +45 -0
- package/src/core/attachments.test.ts +0 -0
- package/src/core/attachments.ts +0 -0
- package/src/core/auth/codexAuth.test.ts +0 -0
- package/src/core/auth/codexAuth.ts +0 -0
- package/src/core/cleanupFastFail.test.ts +0 -0
- package/src/core/cleanupFastFail.ts +0 -0
- package/src/core/clipboard.ts +0 -0
- package/src/core/codex.ts +0 -0
- package/src/core/codexExecArgs.test.ts +0 -0
- package/src/core/codexExecArgs.ts +0 -0
- package/src/core/codexLaunch.test.ts +0 -0
- package/src/core/codexLaunch.ts +0 -0
- package/src/core/codexPrompt.test.ts +0 -0
- package/src/core/codexPrompt.ts +0 -0
- package/src/core/executables/claudeExecutable.ts +0 -0
- package/src/core/executables/codexExecutable.test.ts +0 -0
- package/src/core/executables/codexExecutable.ts +0 -0
- package/src/core/executables/executableResolver.test.ts +0 -0
- package/src/core/executables/executableResolver.ts +0 -0
- package/src/core/executables/geminiExecutable.test.ts +0 -0
- package/src/core/executables/geminiExecutable.ts +0 -0
- package/src/core/executables/pathSanityScan.test.ts +0 -0
- package/src/core/githubDiagnostics.test.ts +0 -0
- package/src/core/githubDiagnostics.ts +0 -0
- package/src/core/hollowResponseFormat.test.ts +0 -0
- package/src/core/hollowResponseFormat.ts +0 -0
- package/src/core/inputDebug.ts +0 -0
- package/src/core/launchContext.test.ts +0 -0
- package/src/core/launchContext.ts +0 -0
- package/src/core/models/codexCapabilities.test.ts +0 -0
- package/src/core/models/codexCapabilities.ts +0 -0
- package/src/core/models/codexModelCapabilities.test.ts +0 -0
- package/src/core/models/codexModelCapabilities.ts +0 -0
- package/src/core/models/modelSpecs.test.ts +0 -0
- package/src/core/models/modelSpecs.ts +0 -0
- package/src/core/perf/profiler.ts +0 -0
- package/src/core/perf/renderDebug.test.ts +0 -0
- package/src/core/perf/renderDebug.ts +0 -0
- package/src/core/planStorage.test.ts +0 -0
- package/src/core/planStorage.ts +0 -0
- package/src/core/process/CommandRunner.test.ts +0 -0
- package/src/core/process/CommandRunner.ts +0 -0
- package/src/core/process/processValidation.ts +0 -0
- package/src/core/projectInstructions.test.ts +0 -0
- package/src/core/projectInstructions.ts +0 -0
- package/src/core/providerLauncher/launcher.test.ts +0 -0
- package/src/core/providerLauncher/launcher.ts +0 -0
- package/src/core/providerLauncher/registry.test.ts +0 -0
- package/src/core/providerLauncher/registry.ts +0 -0
- package/src/core/providerLauncher/types.ts +0 -0
- package/src/core/providerLauncher/workspaceConfig.test.ts +0 -0
- package/src/core/providerLauncher/workspaceConfig.ts +0 -0
- package/src/core/providerRuntime/anthropic.test.ts +0 -0
- package/src/core/providerRuntime/anthropic.ts +0 -0
- package/src/core/providerRuntime/capabilityProfile.test.ts +0 -0
- package/src/core/providerRuntime/capabilityProfile.ts +0 -0
- package/src/core/providerRuntime/claudeCodeDiscovery.ts +0 -0
- package/src/core/providerRuntime/contextMetadata.test.ts +0 -0
- package/src/core/providerRuntime/contextMetadata.ts +0 -0
- package/src/core/providerRuntime/gemini.test.ts +0 -0
- package/src/core/providerRuntime/gemini.ts +0 -0
- package/src/core/providerRuntime/lmstudio.test.ts +0 -0
- package/src/core/providerRuntime/lmstudio.ts +0 -0
- package/src/core/providerRuntime/local.test.ts +0 -0
- package/src/core/providerRuntime/local.ts +0 -0
- package/src/core/providerRuntime/models.ts +0 -0
- package/src/core/providerRuntime/reasoning.ts +0 -0
- package/src/core/providerRuntime/registry.test.ts +0 -0
- package/src/core/providerRuntime/registry.ts +0 -0
- package/src/core/providerRuntime/types.ts +0 -0
- package/src/core/providers/codexJsonStream.test.ts +0 -0
- package/src/core/providers/codexJsonStream.ts +0 -0
- package/src/core/providers/codexSubprocess.test.ts +0 -0
- package/src/core/providers/codexSubprocess.ts +0 -0
- package/src/core/providers/codexTranscript.test.ts +0 -0
- package/src/core/providers/codexTranscript.ts +0 -0
- package/src/core/providers/openaiNative.ts +0 -0
- package/src/core/providers/registry.ts +0 -0
- package/src/core/providers/types.ts +0 -0
- package/src/core/terminal/startupClear.test.ts +55 -0
- package/src/core/terminal/startupClear.ts +20 -0
- package/src/core/terminal/terminalCapabilities.test.ts +0 -0
- package/src/core/terminal/terminalCapabilities.ts +0 -0
- package/src/core/terminal/terminalControl.test.ts +0 -0
- package/src/core/terminal/terminalControl.ts +0 -0
- package/src/core/terminal/terminalSanitize.test.ts +0 -0
- package/src/core/terminal/terminalSanitize.ts +0 -0
- package/src/core/terminal/terminalSelection.test.ts +0 -0
- package/src/core/terminal/terminalSelection.ts +0 -0
- package/src/core/terminal/terminalTitle.test.ts +0 -0
- package/src/core/terminal/terminalTitle.ts +0 -0
- package/src/core/updateCheck.test.ts +194 -0
- package/src/core/updateCheck.ts +172 -0
- package/src/core/workspaceActivity.test.ts +0 -0
- package/src/core/workspaceActivity.ts +0 -0
- package/src/core/workspaceGuard.test.ts +0 -0
- package/src/core/workspaceGuard.ts +0 -0
- package/src/core/workspaceRoot.test.ts +0 -0
- package/src/core/workspaceRoot.ts +0 -0
- package/src/exec.test.ts +0 -0
- package/src/exec.ts +0 -0
- package/src/headless/execArgs.test.ts +0 -0
- package/src/headless/execArgs.ts +1 -0
- package/src/headless/execRunner.test.ts +8 -6
- package/src/headless/execRunner.ts +0 -0
- package/src/index.test.tsx +5 -3
- package/src/index.tsx +13 -9
- package/src/session/appSession.test.ts +0 -0
- package/src/session/appSession.ts +0 -0
- package/src/session/chatLifecycle.test.ts +0 -0
- package/src/session/chatLifecycle.ts +0 -0
- package/src/session/liveRenderScheduler.test.ts +0 -0
- package/src/session/liveRenderScheduler.ts +0 -0
- package/src/session/planFlow.test.ts +0 -0
- package/src/session/planFlow.ts +0 -0
- package/src/session/planTranscript.test.ts +0 -0
- package/src/session/planTranscript.ts +0 -0
- package/src/session/promptRunSchedule.test.ts +0 -0
- package/src/session/promptRunSchedule.ts +0 -0
- package/src/session/types.ts +0 -0
- package/src/test/runtimeTestUtils.ts +0 -0
- package/src/types/react-dom.d.ts +0 -0
- package/src/ui/ActionRequiredBlock.tsx +0 -0
- package/src/ui/ActivityBars.tsx +0 -0
- package/src/ui/ActivityIndicator.test.tsx +0 -0
- package/src/ui/ActivityIndicator.tsx +0 -0
- package/src/ui/AgentBlock.test.ts +0 -0
- package/src/ui/AgentBlock.tsx +0 -0
- package/src/ui/AnimatedStatusText.test.ts +0 -0
- package/src/ui/AnimatedStatusText.tsx +0 -0
- package/src/ui/AppShell.test.tsx +60 -23
- package/src/ui/AppShell.tsx +28 -5
- package/src/ui/AttachmentImportPanel.test.tsx +0 -0
- package/src/ui/AttachmentImportPanel.tsx +0 -0
- package/src/ui/AuthPanel.tsx +0 -0
- package/src/ui/BackendPicker.tsx +0 -0
- package/src/ui/BottomComposer.test.ts +0 -0
- package/src/ui/BottomComposer.tsx +0 -0
- package/src/ui/CodexLogo.tsx +0 -0
- package/src/ui/DashCard.tsx +0 -0
- package/src/ui/Markdown.test.ts +0 -0
- package/src/ui/Markdown.tsx +0 -0
- package/src/ui/ModePicker.tsx +0 -0
- package/src/ui/ModelPicker.tsx +0 -0
- package/src/ui/ModelPickerProviderScope.test.tsx +0 -0
- package/src/ui/ModelPickerScreen.test.tsx +0 -0
- package/src/ui/ModelPickerScreen.tsx +0 -0
- package/src/ui/ModelPickerState.test.tsx +0 -0
- package/src/ui/ModelReasoningPicker.test.tsx +0 -0
- package/src/ui/ModelReasoningPicker.tsx +0 -0
- package/src/ui/Panel.tsx +0 -0
- package/src/ui/PermissionsPanel.tsx +0 -0
- package/src/ui/PlanActionPicker.tsx +0 -0
- package/src/ui/PlanReviewPanel.test.tsx +0 -0
- package/src/ui/PlanReviewPanel.tsx +0 -0
- package/src/ui/PromptCardBorder.test.tsx +0 -0
- package/src/ui/ProviderPicker.test.tsx +0 -0
- package/src/ui/ProviderPicker.tsx +0 -0
- package/src/ui/ProviderShortcut.test.tsx +0 -0
- package/src/ui/ReasoningPicker.tsx +0 -0
- package/src/ui/RunFooter.tsx +0 -0
- package/src/ui/SelectionPanel.tsx +0 -0
- package/src/ui/SettingsPanel.test.tsx +0 -0
- package/src/ui/SettingsPanel.tsx +0 -0
- package/src/ui/Spinner.tsx +0 -0
- package/src/ui/StaticIntroItem.tsx +0 -0
- package/src/ui/StaticTranscriptItem.tsx +0 -0
- package/src/ui/TextEntryPanel.tsx +0 -0
- package/src/ui/ThemePicker.tsx +0 -0
- package/src/ui/ThinkingBlock.tsx +0 -0
- package/src/ui/Timeline.test.ts +0 -0
- package/src/ui/Timeline.tsx +0 -0
- package/src/ui/TimelineNavigation.test.tsx +0 -0
- package/src/ui/TopHeader.test.tsx +53 -38
- package/src/ui/TopHeader.tsx +51 -15
- package/src/ui/TurnGroup.test.tsx +0 -0
- package/src/ui/TurnGroup.tsx +0 -0
- package/src/ui/busyStatusAnimation.test.ts +0 -0
- package/src/ui/busyStatusAnimation.ts +0 -0
- package/src/ui/commandNormalize.test.ts +0 -0
- package/src/ui/commandNormalize.ts +0 -0
- package/src/ui/diffRenderer.test.ts +0 -0
- package/src/ui/diffRenderer.ts +0 -0
- package/src/ui/focus.ts +0 -0
- package/src/ui/focusFlow.test.tsx +0 -0
- package/src/ui/inputBuffer.test.ts +0 -0
- package/src/ui/inputBuffer.ts +0 -0
- package/src/ui/layout.test.ts +3 -2
- package/src/ui/layout.ts +0 -0
- package/src/ui/modeDisplay.test.ts +0 -0
- package/src/ui/modeDisplay.ts +0 -0
- package/src/ui/outputPipeline.ts +0 -0
- package/src/ui/progressEntries.ts +0 -0
- package/src/ui/runActivityView.test.ts +0 -0
- package/src/ui/runActivityView.ts +0 -0
- package/src/ui/runLifecycleView.test.tsx +0 -0
- package/src/ui/slashCommands.ts +0 -0
- package/src/ui/statusRenderIsolation.test.tsx +0 -0
- package/src/ui/terminalAnswerFormat.test.ts +0 -0
- package/src/ui/terminalAnswerFormat.ts +0 -0
- package/src/ui/textLayout.test.ts +0 -0
- package/src/ui/textLayout.ts +0 -0
- package/src/ui/theme.tsx +0 -0
- package/src/ui/themeFlow.test.ts +0 -0
- package/src/ui/themeFlow.ts +0 -0
- package/src/ui/timelineMeasure.ts +0 -0
- package/src/ui/timelineMeasureCache.test.ts +0 -0
- package/src/ui/useThrottledValue.ts +0 -0
package/src/index.test.tsx
CHANGED
|
@@ -365,8 +365,9 @@ test("resize repaint does not erase terminal scrollback buffer", async () => {
|
|
|
365
365
|
const harness = createSupportedHarness();
|
|
366
366
|
startApp(harness.deps);
|
|
367
367
|
|
|
368
|
-
// Startup clears
|
|
369
|
-
|
|
368
|
+
// Startup intentionally clears scrollback (\x1b[3J) so the app opens into a
|
|
369
|
+
// clean screen. Verify it IS written exactly once during startup.
|
|
370
|
+
assert.match(harness.stdout.writes, /\x1b\[3J/, "startup must erase scrollback for clean open");
|
|
370
371
|
|
|
371
372
|
// Capture offset so we can inspect only post-startup writes.
|
|
372
373
|
const startupEnd = harness.stdout.writes.length;
|
|
@@ -407,7 +408,8 @@ test("startup writes safe fallback title before repaint and workspace title befo
|
|
|
407
408
|
const harness = createSupportedHarness();
|
|
408
409
|
startApp(harness.deps);
|
|
409
410
|
|
|
410
|
-
|
|
411
|
+
// Startup now writes a full transcript clear: viewport + scrollback + cursor home.
|
|
412
|
+
const repaintIndex = harness.stdout.writes.indexOf("\x1b[2J\x1b[3J\x1b[H");
|
|
411
413
|
const firstTitleIndex = harness.stdout.writes.indexOf("\x1b]0;");
|
|
412
414
|
const postRepaintTitleIndex = harness.stdout.writes.indexOf("\x1b]0;", repaintIndex + 1);
|
|
413
415
|
const bracketedPasteIndex = harness.stdout.writes.indexOf("\x1b[?2004h");
|
package/src/index.tsx
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
traceTerminalClear,
|
|
20
20
|
writeTerminalControl,
|
|
21
21
|
} from "./core/terminal/terminalControl.js";
|
|
22
|
+
import { performStartupClear } from "./core/terminal/startupClear.js";
|
|
22
23
|
|
|
23
24
|
type RenderHandle = Pick<Instance, "clear" | "cleanup" | "waitUntilExit">;
|
|
24
25
|
const KITTY_KEYBOARD_OPTIONS: RenderOptions["kittyKeyboard"] = {
|
|
@@ -174,15 +175,18 @@ export function startApp({
|
|
|
174
175
|
durationMs: 3500,
|
|
175
176
|
});
|
|
176
177
|
|
|
177
|
-
// Clear the screen and move cursor
|
|
178
|
-
//
|
|
179
|
-
// the
|
|
180
|
-
//
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
// Clear the screen (viewport + scrollback) and move cursor home before Ink
|
|
179
|
+
// renders the first frame. This removes any previous terminal content so
|
|
180
|
+
// the app opens into a clean screen. We stay in the normal screen buffer
|
|
181
|
+
// (no \x1b[?1049h) to preserve mouse text selection after exit.
|
|
182
|
+
// Skipped when --no-clear or CODEXA_NO_CLEAR=1 is set.
|
|
183
|
+
// NOTE: Mouse reporting is NOT enabled here — managed solely by app.tsx.
|
|
184
|
+
traceTerminalClear("src/index.tsx:startup", { mode: "transcript" });
|
|
185
|
+
performStartupClear({
|
|
186
|
+
write: (c) => writeStdout(c, "src/index.tsx:startup"),
|
|
187
|
+
noClear: launchArgs.noClear,
|
|
188
|
+
env,
|
|
189
|
+
});
|
|
186
190
|
const startupWorkspaceRoot = resolveWorkspaceRoot();
|
|
187
191
|
const startupSettings = loadSettings();
|
|
188
192
|
const startupTitle =
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/session/planFlow.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/session/types.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/src/types/react-dom.d.ts
CHANGED
|
File without changes
|
|
File without changes
|
package/src/ui/ActivityBars.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/AgentBlock.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/AppShell.test.tsx
CHANGED
|
@@ -4,8 +4,9 @@ import React from "react";
|
|
|
4
4
|
import { PassThrough } from "node:stream";
|
|
5
5
|
import { render, Text } from "ink";
|
|
6
6
|
import type { Screen, TimelineEvent, UIState } from "../session/types.js";
|
|
7
|
-
import { buildRuntimeSummary } from "../config/runtimeConfig.js";
|
|
8
|
-
import { HEADER_CONFIG_DEFAULTS, type HeaderConfig } from "../config/settings.js";
|
|
7
|
+
import { buildRuntimeSummary } from "../config/runtimeConfig.js";
|
|
8
|
+
import { HEADER_CONFIG_DEFAULTS, type HeaderConfig } from "../config/settings.js";
|
|
9
|
+
import type { UpdateCheckResult } from "../core/updateCheck.js";
|
|
9
10
|
import { TEST_RUNTIME } from "../test/runtimeTestUtils.js";
|
|
10
11
|
import { BottomComposer, measureBottomComposerRows } from "./BottomComposer.js";
|
|
11
12
|
import { AppShell, calculateColdStartSpacerRows, calculateHeaderToContentGapRows, calculateNativeSpacerRows } from "./AppShell.js";
|
|
@@ -77,6 +78,13 @@ const EVENTS: TimelineEvent[] = [
|
|
|
77
78
|
},
|
|
78
79
|
];
|
|
79
80
|
|
|
81
|
+
const STARTUP_HEADER_CONFIG: HeaderConfig = {
|
|
82
|
+
...HEADER_CONFIG_DEFAULTS,
|
|
83
|
+
showModel: false,
|
|
84
|
+
showReasoning: false,
|
|
85
|
+
showContext: true,
|
|
86
|
+
};
|
|
87
|
+
|
|
80
88
|
function stripAnsi(value: string): string {
|
|
81
89
|
return value.replace(/\u001B\[[0-?]*[ -/]*[@-~]/g, "");
|
|
82
90
|
}
|
|
@@ -89,15 +97,16 @@ function sleep(ms = 50): Promise<void> {
|
|
|
89
97
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
90
98
|
}
|
|
91
99
|
|
|
92
|
-
function renderShell(
|
|
93
|
-
layoutCols: number,
|
|
94
|
-
layoutRows: number,
|
|
95
|
-
uiState: UIState,
|
|
96
|
-
screen: "main" | "theme-picker" | "model-picker" = "main",
|
|
97
|
-
panel: React.ReactNode = null,
|
|
98
|
-
mainPanel: React.ReactNode = null,
|
|
99
|
-
mainPanelMode: "viewport" | "full-output" = "viewport",
|
|
100
|
-
|
|
100
|
+
function renderShell(
|
|
101
|
+
layoutCols: number,
|
|
102
|
+
layoutRows: number,
|
|
103
|
+
uiState: UIState,
|
|
104
|
+
screen: "main" | "theme-picker" | "model-picker" = "main",
|
|
105
|
+
panel: React.ReactNode = null,
|
|
106
|
+
mainPanel: React.ReactNode = null,
|
|
107
|
+
mainPanelMode: "viewport" | "full-output" = "viewport",
|
|
108
|
+
updateCheckResult: UpdateCheckResult | null = null,
|
|
109
|
+
): Promise<string> {
|
|
101
110
|
const stdin = new TestInput();
|
|
102
111
|
const stdout = new TestOutput();
|
|
103
112
|
stdout.columns = layoutCols;
|
|
@@ -163,9 +172,11 @@ function renderShell(
|
|
|
163
172
|
onQuit={() => {}}
|
|
164
173
|
/>
|
|
165
174
|
}
|
|
166
|
-
composerRows={composerRows}
|
|
167
|
-
|
|
168
|
-
|
|
175
|
+
composerRows={composerRows}
|
|
176
|
+
headerConfig={STARTUP_HEADER_CONFIG}
|
|
177
|
+
updateCheckResult={updateCheckResult}
|
|
178
|
+
/>
|
|
179
|
+
</ThemeProvider>,
|
|
169
180
|
{
|
|
170
181
|
stdin: stdin as unknown as NodeJS.ReadStream,
|
|
171
182
|
stdout: stdout as unknown as NodeJS.WriteStream,
|
|
@@ -181,7 +192,28 @@ function renderShell(
|
|
|
181
192
|
await sleep(20);
|
|
182
193
|
return stripAnsi(output);
|
|
183
194
|
});
|
|
184
|
-
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
test("renders npm update notice when a newer Codexa version is available", async () => {
|
|
198
|
+
const output = await renderShell(
|
|
199
|
+
120,
|
|
200
|
+
40,
|
|
201
|
+
{ kind: "IDLE" },
|
|
202
|
+
"main",
|
|
203
|
+
null,
|
|
204
|
+
null,
|
|
205
|
+
"viewport",
|
|
206
|
+
{
|
|
207
|
+
status: "update-available",
|
|
208
|
+
currentVersion: "1.0.1",
|
|
209
|
+
latestVersion: "1.0.2",
|
|
210
|
+
checkedAt: Date.now(),
|
|
211
|
+
},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
assert.match(stripAnsi(output), /Update available: Codexa 1\.0\.2 is available\. You are using 1\.0\.1\./);
|
|
215
|
+
assert.match(stripAnsi(output), /Run: npm install -g @golba98\/codexa@latest/);
|
|
216
|
+
});
|
|
185
217
|
|
|
186
218
|
function renderStartupShell(
|
|
187
219
|
layoutCols: number,
|
|
@@ -256,6 +288,7 @@ function renderStartupShell(
|
|
|
256
288
|
/>
|
|
257
289
|
}
|
|
258
290
|
composerRows={composerRows}
|
|
291
|
+
headerConfig={STARTUP_HEADER_CONFIG}
|
|
259
292
|
/>
|
|
260
293
|
</ThemeProvider>,
|
|
261
294
|
{
|
|
@@ -283,13 +316,17 @@ test("startup uses the large logo only when the viewport height can contain it",
|
|
|
283
316
|
assert.match(output, /\n╭[─]+╮\n│ ❯/);
|
|
284
317
|
});
|
|
285
318
|
|
|
286
|
-
test("startup uses
|
|
319
|
+
test("startup uses stacked ASCII header at normal shorter terminal width", async () => {
|
|
287
320
|
const output = await renderStartupShell(100, 24);
|
|
288
321
|
|
|
322
|
+
assert.match(output, /██████/);
|
|
289
323
|
assert.match(output, /Codexa v/);
|
|
290
324
|
assert.match(output, /C:\\Development\\1-JavaScript\\13-Custom CLI/);
|
|
325
|
+
assert.match(output, /Provider: Codexa Core/);
|
|
326
|
+
assert.match(output, /Context: Unknown/);
|
|
327
|
+
assert.doesNotMatch(output, /Model: gpt-5\.4/);
|
|
328
|
+
assert.doesNotMatch(output, /Reasoning:/);
|
|
291
329
|
assert.match(output, /\n╭[─]+╮\n│ ❯/);
|
|
292
|
-
assert.doesNotMatch(output, /██████/);
|
|
293
330
|
});
|
|
294
331
|
|
|
295
332
|
test("startup micro mode keeps the live header and composer visible", async () => {
|
|
@@ -551,22 +588,22 @@ test("cold-start header gap adapts to terminal height", () => {
|
|
|
551
588
|
layoutMode: "micro",
|
|
552
589
|
availableRows: 9,
|
|
553
590
|
}), 1);
|
|
554
|
-
// full 30-row medium: measureTopHeaderRows=
|
|
591
|
+
// full 30-row medium: measureTopHeaderRows=7 (1+6+0), headerToContentGap=1, shellHeight=29
|
|
555
592
|
assert.equal(calculateColdStartSpacerRows({
|
|
556
593
|
shellRows: 29,
|
|
557
594
|
headerRows: 8,
|
|
558
595
|
composerRows: 7,
|
|
559
596
|
layoutMode: "full",
|
|
560
597
|
availableRows: 11,
|
|
561
|
-
}),
|
|
562
|
-
// full 40-row tall: measureTopHeaderRows=
|
|
598
|
+
}), 1);
|
|
599
|
+
// full 40-row tall: measureTopHeaderRows=7 (1+6+0), headerToContentGap=1, shellHeight=39
|
|
563
600
|
assert.equal(calculateColdStartSpacerRows({
|
|
564
601
|
shellRows: 39,
|
|
565
602
|
headerRows: 9,
|
|
566
603
|
composerRows: 7,
|
|
567
604
|
layoutMode: "full",
|
|
568
605
|
availableRows: 20,
|
|
569
|
-
}),
|
|
606
|
+
}), 1);
|
|
570
607
|
});
|
|
571
608
|
|
|
572
609
|
test("cold-start header gap is capped by available rows", () => {
|
|
@@ -576,7 +613,7 @@ test("cold-start header gap is capped by available rows", () => {
|
|
|
576
613
|
composerRows: 7,
|
|
577
614
|
layoutMode: "full",
|
|
578
615
|
availableRows: 2,
|
|
579
|
-
}),
|
|
616
|
+
}), 1);
|
|
580
617
|
});
|
|
581
618
|
|
|
582
619
|
test("header-to-content gap is reserved outside the hero", () => {
|
|
@@ -1156,7 +1193,7 @@ test("project instructions render with breathing room below the live header", as
|
|
|
1156
1193
|
const projectRow = rows.findIndex((row) => row.includes("Project instructions"));
|
|
1157
1194
|
|
|
1158
1195
|
assert.ok(lastLogoRow >= 0, "logo should render");
|
|
1159
|
-
assert.ok(projectRow > lastLogoRow +
|
|
1196
|
+
assert.ok(projectRow > lastLogoRow + 1, "project instructions should not touch the logo block");
|
|
1160
1197
|
assertHeaderBefore(raw, "Project instructions");
|
|
1161
1198
|
assert.equal(countLogoInOutput(raw), 1, "project instruction notice must not add a transcript banner");
|
|
1162
1199
|
});
|
package/src/ui/AppShell.tsx
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import React, { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
2
2
|
import { Box, Text, useStdin } from "ink";
|
|
3
|
+
import { useTheme } from "./theme.js";
|
|
4
|
+
import type { UpdateCheckResult } from "../core/updateCheck.js";
|
|
3
5
|
import type { RuntimeSummary } from "../config/runtimeConfig.js";
|
|
4
6
|
import type { CodexAuthState } from "../core/auth/codexAuth.js";
|
|
5
7
|
import { HEADER_CONFIG_DEFAULTS, type HeaderConfig } from "../config/settings.js";
|
|
@@ -25,9 +27,9 @@ import { buildNativeTranscriptParts, type NativeTranscriptRowItem, type Timeline
|
|
|
25
27
|
import type { TerminalSelectionProfile } from "../core/terminal/terminalSelection.js";
|
|
26
28
|
import { MemoizedTopHeader, measureTopHeaderRows } from "./TopHeader.js";
|
|
27
29
|
|
|
28
|
-
const COMPACT_HEADER_TO_COMPOSER_GAP_ROWS =
|
|
29
|
-
const MEDIUM_HEADER_TO_COMPOSER_GAP_ROWS =
|
|
30
|
-
const TALL_HEADER_TO_COMPOSER_GAP_ROWS =
|
|
30
|
+
const COMPACT_HEADER_TO_COMPOSER_GAP_ROWS = 1;
|
|
31
|
+
const MEDIUM_HEADER_TO_COMPOSER_GAP_ROWS = 1;
|
|
32
|
+
const TALL_HEADER_TO_COMPOSER_GAP_ROWS = 1;
|
|
31
33
|
|
|
32
34
|
// ─── Types & constants ────────────────────────────────────────────────────────
|
|
33
35
|
|
|
@@ -57,6 +59,7 @@ export interface AppShellProps {
|
|
|
57
59
|
selectionProfile?: TerminalSelectionProfile;
|
|
58
60
|
clearCount?: number;
|
|
59
61
|
headerConfig?: HeaderConfig;
|
|
62
|
+
updateCheckResult?: UpdateCheckResult | null;
|
|
60
63
|
}
|
|
61
64
|
|
|
62
65
|
// ─── Helpers & subcomponents ─────────────────────────────────────────────────
|
|
@@ -161,7 +164,9 @@ function AppShellInner({
|
|
|
161
164
|
selectionProfile,
|
|
162
165
|
clearCount = 0,
|
|
163
166
|
headerConfig = HEADER_CONFIG_DEFAULTS,
|
|
167
|
+
updateCheckResult = null,
|
|
164
168
|
}: AppShellProps) {
|
|
169
|
+
const theme = useTheme();
|
|
165
170
|
renderDebug.useRenderDebug("AppShell", {
|
|
166
171
|
cols: layout.cols,
|
|
167
172
|
rows: layout.rows,
|
|
@@ -188,7 +193,7 @@ function AppShellInner({
|
|
|
188
193
|
|
|
189
194
|
const shellWidth = getShellWidth(layout.cols);
|
|
190
195
|
const shellHeight = getShellHeight(layout.rows);
|
|
191
|
-
const headerRows = measureTopHeaderRows(layout);
|
|
196
|
+
const headerRows = measureTopHeaderRows(layout, headerConfig);
|
|
192
197
|
const headerToContentGapRows = calculateHeaderToContentGapRows(layout);
|
|
193
198
|
const showComposer = screen === "main";
|
|
194
199
|
const showMainPanel = screen === "main" && mainPanel !== undefined && mainPanel !== null;
|
|
@@ -500,6 +505,17 @@ function AppShellInner({
|
|
|
500
505
|
? React.cloneElement(composer as React.ReactElement<{ selectionProfile?: TerminalSelectionProfile }>, { selectionProfile })
|
|
501
506
|
: composer;
|
|
502
507
|
|
|
508
|
+
const updateNotice = updateCheckResult?.status === "update-available" ? (
|
|
509
|
+
<Box paddingX={1} flexDirection="column">
|
|
510
|
+
<Text color={theme.WARNING}>
|
|
511
|
+
{`Update available: Codexa ${updateCheckResult.latestVersion ?? "unknown"} is available. You are using ${updateCheckResult.currentVersion}.`}
|
|
512
|
+
</Text>
|
|
513
|
+
<Text color={theme.WARNING}>
|
|
514
|
+
{"Run: npm install -g @golba98/codexa@latest"}
|
|
515
|
+
</Text>
|
|
516
|
+
</Box>
|
|
517
|
+
) : null;
|
|
518
|
+
|
|
503
519
|
if (showMainPanelFullOutput) {
|
|
504
520
|
return (
|
|
505
521
|
<Box flexDirection="column" width="100%">
|
|
@@ -512,6 +528,8 @@ function AppShellInner({
|
|
|
512
528
|
headerConfig={headerConfig}
|
|
513
529
|
/>
|
|
514
530
|
|
|
531
|
+
{updateNotice}
|
|
532
|
+
|
|
515
533
|
{headerToContentGapRows > 0 && (
|
|
516
534
|
<Box height={headerToContentGapRows} />
|
|
517
535
|
)}
|
|
@@ -542,6 +560,8 @@ function AppShellInner({
|
|
|
542
560
|
headerConfig={headerConfig}
|
|
543
561
|
/>
|
|
544
562
|
|
|
563
|
+
{updateNotice}
|
|
564
|
+
|
|
545
565
|
{headerToContentGapRows > 0 && (
|
|
546
566
|
<Box height={headerToContentGapRows} />
|
|
547
567
|
)}
|
|
@@ -596,6 +616,8 @@ function AppShellInner({
|
|
|
596
616
|
headerConfig={headerConfig}
|
|
597
617
|
/>
|
|
598
618
|
|
|
619
|
+
{updateNotice}
|
|
620
|
+
|
|
599
621
|
{headerToContentGapRows > 0 && (
|
|
600
622
|
<Box height={headerToContentGapRows} />
|
|
601
623
|
)}
|
|
@@ -692,7 +714,8 @@ export const AppShell = memo(AppShellInner, (prev, next) => {
|
|
|
692
714
|
prev.verboseMode === next.verboseMode &&
|
|
693
715
|
prev.mouseCapture === next.mouseCapture &&
|
|
694
716
|
prev.onMouseActivity === next.onMouseActivity &&
|
|
695
|
-
prev.clearCount
|
|
717
|
+
prev.clearCount === next.clearCount &&
|
|
718
|
+
prev.updateCheckResult === next.updateCheckResult &&
|
|
696
719
|
panelPropsEqual
|
|
697
720
|
);
|
|
698
721
|
});
|
|
File without changes
|
|
File without changes
|
package/src/ui/AuthPanel.tsx
CHANGED
|
File without changes
|
package/src/ui/BackendPicker.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/CodexLogo.tsx
CHANGED
|
File without changes
|
package/src/ui/DashCard.tsx
CHANGED
|
File without changes
|
package/src/ui/Markdown.test.ts
CHANGED
|
File without changes
|
package/src/ui/Markdown.tsx
CHANGED
|
File without changes
|
package/src/ui/ModePicker.tsx
CHANGED
|
File without changes
|
package/src/ui/ModelPicker.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/Panel.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/RunFooter.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/SettingsPanel.tsx
CHANGED
|
File without changes
|
package/src/ui/Spinner.tsx
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/src/ui/ThemePicker.tsx
CHANGED
|
File without changes
|
package/src/ui/ThinkingBlock.tsx
CHANGED
|
File without changes
|
package/src/ui/Timeline.test.ts
CHANGED
|
File without changes
|
package/src/ui/Timeline.tsx
CHANGED
|
File without changes
|
|
File without changes
|