@golba98/codexa 1.0.3 → 1.0.5
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 +17 -18
- package/bin/codexa.js +62 -144
- package/package.json +4 -3
- package/src/app.tsx +642 -303
- package/src/commands/handler.ts +7 -18
- package/src/config/buildInfo.ts +2 -2
- package/src/config/layeredConfig.ts +1 -1
- package/src/config/runtimeConfig.ts +1 -1
- package/src/config/settings.ts +1 -1
- package/src/config/trustStore.ts +1 -1
- package/src/core/README.md +52 -0
- package/src/core/agent/loop.ts +282 -0
- package/src/core/agent/protocol.ts +211 -0
- package/src/core/agent/tools.ts +414 -0
- package/src/core/{codexExecArgs.ts → codex/codexExecArgs.ts} +2 -2
- package/src/core/{codexLaunch.ts → codex/codexLaunch.ts} +3 -3
- package/src/core/{codexPrompt.ts → codex/codexPrompt.ts} +3 -3
- package/src/core/debug/modelStateDebug.ts +34 -0
- package/src/core/executables/antigravityExecutable.ts +48 -0
- package/src/core/executables/executableResolver.ts +5 -1
- package/src/core/models/codexModelCapabilities.ts +57 -4
- package/src/core/models/codexModelsCacheSeed.ts +153 -0
- package/src/core/models/providerModelCache.ts +106 -0
- package/src/core/perf/renderDebug.ts +10 -6
- package/src/core/process/CommandRunner.ts +12 -1
- package/src/core/providerLauncher/registry.ts +64 -18
- package/src/core/providerLauncher/types.ts +12 -9
- package/src/core/providerLauncher/workspaceConfig.ts +41 -26
- package/src/core/providerRuntime/anthropic.ts +10 -6
- package/src/core/providerRuntime/antigravity.ts +461 -0
- package/src/core/providerRuntime/claudeCodeDiscovery.ts +724 -446
- package/src/core/providerRuntime/claudeCodeDiscoveryDebug.ts +55 -0
- package/src/core/providerRuntime/contextMetadata.ts +12 -24
- package/src/core/providerRuntime/local.ts +129 -51
- package/src/core/providerRuntime/mistralVibe.ts +663 -0
- package/src/core/providerRuntime/models.ts +40 -15
- package/src/core/providerRuntime/reasoning.ts +9 -6
- package/src/core/providerRuntime/registry.ts +76 -4
- package/src/core/providerRuntime/types.ts +20 -14
- package/src/core/providers/codexSubprocess.ts +2 -2
- package/src/core/providers/types.ts +1 -1
- package/src/core/{attachments.ts → shared/attachments.ts} +27 -4
- package/src/core/{cleanupFastFail.ts → shared/cleanupFastFail.ts} +1 -1
- package/src/core/{hollowResponseFormat.ts → shared/hollowResponseFormat.ts} +1 -1
- package/src/core/terminal/clearFrameBoundary.ts +814 -0
- package/src/core/terminal/frameLock.ts +109 -0
- package/src/core/terminal/inkRenderReset.ts +123 -0
- package/src/core/terminal/terminalControl.ts +22 -0
- package/src/core/terminal/terminalTitle.ts +16 -102
- package/src/core/{channel.ts → version/channel.ts} +1 -1
- package/src/core/{updateCheck.ts → version/updateCheck.ts} +10 -5
- package/src/core/{launchContext.ts → workspace/launchContext.ts} +9 -16
- package/src/core/{planStorage.ts → workspace/planStorage.ts} +2 -2
- package/src/core/{workspaceGuard.ts → workspace/workspaceGuard.ts} +97 -13
- package/src/headless/execRunner.ts +2 -2
- package/src/index.tsx +66 -98
- package/src/session/appSession.ts +10 -7
- package/src/session/chatLifecycle.ts +1 -1
- package/src/session/liveRenderScheduler.ts +1 -1
- package/src/session/types.ts +1 -1
- package/src/test/runtimeTestUtils.ts +90 -0
- package/src/ui/{ActivityBars.tsx → chrome/ActivityBars.tsx} +1 -1
- package/src/ui/{ActivityIndicator.tsx → chrome/ActivityIndicator.tsx} +3 -3
- package/src/ui/{AnimatedStatusText.tsx → chrome/AnimatedStatusText.tsx} +3 -3
- package/src/ui/chrome/AppShell.tsx +672 -0
- package/src/ui/{BottomComposer.tsx → chrome/BottomComposer.tsx} +159 -158
- package/src/ui/{DashCard.tsx → chrome/DashCard.tsx} +2 -2
- package/src/ui/{RunFooter.tsx → chrome/RunFooter.tsx} +3 -3
- package/src/ui/chrome/RuntimeStatusBar.tsx +108 -0
- package/src/ui/{Spinner.tsx → chrome/Spinner.tsx} +1 -1
- package/src/ui/{TopHeader.tsx → chrome/TopHeader.tsx} +54 -38
- package/src/ui/{UpdateAvailableCard.tsx → chrome/UpdateAvailableCard.tsx} +5 -5
- package/src/ui/{commandNormalize.ts → input/commandNormalize.ts} +1 -1
- package/src/ui/{focus.ts → input/focus.ts} +1 -1
- package/src/ui/{inputBuffer.ts → input/inputBuffer.ts} +3 -3
- package/src/ui/layout.ts +298 -24
- package/src/ui/{AttachmentImportPanel.tsx → panels/AttachmentImportPanel.tsx} +3 -3
- package/src/ui/{AuthPanel.tsx → panels/AuthPanel.tsx} +5 -5
- package/src/ui/{BackendPicker.tsx → panels/BackendPicker.tsx} +2 -2
- package/src/ui/{ModePicker.tsx → panels/ModePicker.tsx} +2 -2
- package/src/ui/{ModelPicker.tsx → panels/ModelPicker.tsx} +2 -2
- package/src/ui/{ModelPickerScreen.tsx → panels/ModelPickerScreen.tsx} +224 -42
- package/src/ui/{ModelReasoningPicker.tsx → panels/ModelReasoningPicker.tsx} +5 -5
- package/src/ui/{Panel.tsx → panels/Panel.tsx} +1 -1
- package/src/ui/{PermissionsPanel.tsx → panels/PermissionsPanel.tsx} +3 -3
- package/src/ui/{PlanActionPicker.tsx → panels/PlanActionPicker.tsx} +2 -2
- package/src/ui/{PlanReviewPanel.tsx → panels/PlanReviewPanel.tsx} +5 -5
- package/src/ui/panels/ProviderPicker.tsx +737 -0
- package/src/ui/{ReasoningPicker.tsx → panels/ReasoningPicker.tsx} +3 -3
- package/src/ui/{SelectionPanel.tsx → panels/SelectionPanel.tsx} +5 -1
- package/src/ui/{SettingsPanel.tsx → panels/SettingsPanel.tsx} +4 -4
- package/src/ui/{TextEntryPanel.tsx → panels/TextEntryPanel.tsx} +4 -4
- package/src/ui/{ThemePicker.tsx → panels/ThemePicker.tsx} +2 -2
- package/src/ui/{UpdatePromptPanel.tsx → panels/UpdatePromptPanel.tsx} +17 -23
- package/src/ui/{Markdown.tsx → render/Markdown.tsx} +2 -2
- package/src/ui/{diffRenderer.ts → render/diffRenderer.ts} +1 -1
- package/src/ui/{logoVariants.ts → render/logoVariants.ts} +4 -8
- package/src/ui/{modeDisplay.ts → render/modeDisplay.ts} +2 -2
- package/src/ui/{outputPipeline.ts → render/outputPipeline.ts} +2 -2
- package/src/ui/{runtimeDisplay.ts → render/runtimeDisplay.ts} +23 -10
- package/src/ui/{textLayout.ts → render/textLayout.ts} +15 -4
- package/src/ui/{ActionRequiredBlock.tsx → timeline/ActionRequiredBlock.tsx} +3 -3
- package/src/ui/{AgentBlock.tsx → timeline/AgentBlock.tsx} +10 -10
- package/src/ui/{StaticIntroItem.tsx → timeline/StaticIntroItem.tsx} +2 -2
- package/src/ui/{ThinkingBlock.tsx → timeline/ThinkingBlock.tsx} +4 -4
- package/src/ui/{Timeline.tsx → timeline/Timeline.tsx} +1620 -1471
- package/src/ui/timeline/TranscriptShell.tsx +322 -0
- package/src/ui/{TurnGroup.tsx → timeline/TurnGroup.tsx} +15 -15
- package/src/ui/timeline/layoutListWindow.ts +145 -0
- package/src/ui/{progressEntries.ts → timeline/progressEntries.ts} +3 -3
- package/src/ui/{runActivityView.ts → timeline/runActivityView.ts} +1 -1
- package/src/ui/{timelineMeasure.ts → timeline/timelineMeasure.ts} +206 -134
- package/src/core/codex.ts +0 -124
- package/src/ui/AppShell.tsx +0 -706
- package/src/ui/ProviderPicker.tsx +0 -321
- package/src/ui/StaticTranscriptItem.tsx +0 -56
- /package/src/core/{inputDebug.ts → debug/inputDebug.ts} +0 -0
- /package/src/core/{clipboard.ts → shared/clipboard.ts} +0 -0
- /package/src/core/{githubDiagnostics.ts → shared/githubDiagnostics.ts} +0 -0
- /package/src/core/{projectInstructions.ts → workspace/projectInstructions.ts} +0 -0
- /package/src/core/{workspaceActivity.ts → workspace/workspaceActivity.ts} +0 -0
- /package/src/core/{workspaceRoot.ts → workspace/workspaceRoot.ts} +0 -0
- /package/src/ui/{busyStatusAnimation.ts → chrome/busyStatusAnimation.ts} +0 -0
- /package/src/ui/{slashCommands.ts → input/slashCommands.ts} +0 -0
- /package/src/ui/{terminalAnswerFormat.ts → render/terminalAnswerFormat.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { useTheme } from "
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
5
5
|
|
|
6
6
|
export interface PendingImportFile {
|
|
7
7
|
srcPath: string;
|
|
@@ -65,7 +65,7 @@ export function AttachmentImportPanel({
|
|
|
65
65
|
|
|
66
66
|
<Box
|
|
67
67
|
borderStyle="round"
|
|
68
|
-
borderColor={theme.
|
|
68
|
+
borderColor={theme.border}
|
|
69
69
|
paddingX={2}
|
|
70
70
|
paddingY={1}
|
|
71
71
|
marginTop={1}
|
|
@@ -90,7 +90,7 @@ export function AttachmentImportPanel({
|
|
|
90
90
|
)}
|
|
91
91
|
|
|
92
92
|
<Box marginTop={1}>
|
|
93
|
-
<Text color={theme.textDim}>
|
|
93
|
+
<Text color={theme.textDim}>Esc to close · Enter to confirm</Text>
|
|
94
94
|
</Box>
|
|
95
95
|
</Box>
|
|
96
96
|
</Box>
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
|
-
import { AUTH_PREFERENCES, formatAuthPreferenceLabel } from "
|
|
4
|
-
import type { CodexAuthProbeResult } from "
|
|
5
|
-
import { getAuthStateLabel } from "
|
|
6
|
-
import type { BackendProvider } from "
|
|
7
|
-
import { useTheme } from "
|
|
3
|
+
import { AUTH_PREFERENCES, formatAuthPreferenceLabel } from "../../config/settings.js";
|
|
4
|
+
import type { CodexAuthProbeResult } from "../../core/auth/codexAuth.js";
|
|
5
|
+
import { getAuthStateLabel } from "../../core/auth/codexAuth.js";
|
|
6
|
+
import type { BackendProvider } from "../../core/providers/types.js";
|
|
7
|
+
import { useTheme } from "../theme.js";
|
|
8
8
|
|
|
9
9
|
interface AuthPanelProps {
|
|
10
10
|
focusId: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { AVAILABLE_BACKENDS } from "
|
|
3
|
-
import { FOCUS_IDS } from "
|
|
2
|
+
import { AVAILABLE_BACKENDS } from "../../config/settings.js";
|
|
3
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
4
4
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
5
5
|
|
|
6
6
|
interface BackendPickerProps {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AVAILABLE_MODES } from "
|
|
2
|
-
import { FOCUS_IDS } from "
|
|
1
|
+
import { AVAILABLE_MODES } from "../../config/settings.js";
|
|
2
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
3
3
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
4
4
|
|
|
5
5
|
interface ModePickerProps {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type CodexModelCapability } from "
|
|
2
|
-
import { FOCUS_IDS } from "
|
|
1
|
+
import { type CodexModelCapability } from "../../core/models/codexModelCapabilities.js";
|
|
2
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
3
3
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
4
4
|
|
|
5
5
|
interface ModelPickerProps {
|
|
@@ -4,20 +4,38 @@ import {
|
|
|
4
4
|
type CodexModelCapability,
|
|
5
5
|
type ReasoningEffortCapability,
|
|
6
6
|
normalizeReasoningForModelCapabilities,
|
|
7
|
-
} from "
|
|
8
|
-
import { formatReasoningLabel } from "
|
|
9
|
-
import { traceInputDebug } from "
|
|
10
|
-
import { FOCUS_IDS } from "
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
} from "../../core/models/codexModelCapabilities.js";
|
|
8
|
+
import { formatReasoningLabel } from "../../config/settings.js";
|
|
9
|
+
import { traceInputDebug } from "../../core/debug/inputDebug.js";
|
|
10
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
11
|
+
import {
|
|
12
|
+
clampVisualText,
|
|
13
|
+
getShellWidth,
|
|
14
|
+
getAvailableRowsForPanel,
|
|
15
|
+
useAppLayoutBudget,
|
|
16
|
+
usePanelAvailableRows,
|
|
17
|
+
type Layout,
|
|
18
|
+
useActivePanelLayout,
|
|
19
|
+
type ActivePanelLayout,
|
|
20
|
+
type PanelLayout,
|
|
21
|
+
usePanelLayout,
|
|
22
|
+
} from "../layout.js";
|
|
23
|
+
import { calculateListWindow } from "../timeline/layoutListWindow.js";
|
|
24
|
+
import { useTheme } from "../theme.js";
|
|
25
|
+
import type { GeminiModelSelection } from "../../core/providerRuntime/types.js";
|
|
14
26
|
|
|
15
27
|
// ─── Types & helpers ─────────────────────────────────────────────────────────
|
|
16
28
|
|
|
17
29
|
type ModelPickerCloseReason = "escape" | "empty-selection";
|
|
30
|
+
type ModelRenderMode = "full" | "compact" | "windowed";
|
|
18
31
|
|
|
19
32
|
interface ModelPickerScreenProps {
|
|
20
|
-
layout: Layout
|
|
33
|
+
layout: Layout & {
|
|
34
|
+
contentWidth?: number;
|
|
35
|
+
};
|
|
36
|
+
availableRows?: number;
|
|
37
|
+
activePanelLayout?: ActivePanelLayout;
|
|
38
|
+
panelLayout?: PanelLayout;
|
|
21
39
|
models: readonly CodexModelCapability[];
|
|
22
40
|
currentModel: string;
|
|
23
41
|
currentReasoning: string;
|
|
@@ -50,10 +68,25 @@ function getReasoningLevels(model: CodexModelCapability | undefined): readonly R
|
|
|
50
68
|
|
|
51
69
|
function getModelSourceMarker(models: readonly CodexModelCapability[], activeProviderLabel: string): string | null {
|
|
52
70
|
if (activeProviderLabel !== "Claude" || models.length === 0) return null;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
71
|
+
const raw = models[0]?.raw as { source?: string; discoveryKind?: string } | null | undefined;
|
|
72
|
+
const source = raw?.source;
|
|
73
|
+
const sourceLabel = source === "claude-code-package"
|
|
74
|
+
? "installed package metadata"
|
|
75
|
+
: source === "claude-code-command"
|
|
76
|
+
? "Claude Code command"
|
|
77
|
+
: source === "claude-code-cache"
|
|
78
|
+
? "Claude Code cache"
|
|
79
|
+
: source === "claude-code-config" || source === "settings" || source === "config"
|
|
80
|
+
? "Claude settings"
|
|
81
|
+
: "Claude Code";
|
|
82
|
+
if (source === "claude-code-package" || source === "claude-code-command" || source === "claude-code-cache" || source === "claude-code-config" || source === "claude-code" || source === "discovered") {
|
|
83
|
+
return raw?.discoveryKind === "aliases"
|
|
84
|
+
? `Claude Code aliases resolved from ${sourceLabel}`
|
|
85
|
+
: `Claude Code models discovered from ${sourceLabel}`;
|
|
86
|
+
}
|
|
87
|
+
if (source === "settings" || source === "config") return "Claude Code models discovered from Claude settings";
|
|
88
|
+
if (source === "fallback") return "Claude Code discovery failed; using fallback aliases";
|
|
89
|
+
return null;
|
|
57
90
|
}
|
|
58
91
|
|
|
59
92
|
function normalizeDraftReasoning(
|
|
@@ -109,6 +142,9 @@ function describeInputKey(
|
|
|
109
142
|
|
|
110
143
|
export function ModelPickerScreen({
|
|
111
144
|
layout,
|
|
145
|
+
availableRows: propAvailableRows,
|
|
146
|
+
activePanelLayout,
|
|
147
|
+
panelLayout,
|
|
112
148
|
models: baseModels,
|
|
113
149
|
currentModel,
|
|
114
150
|
currentReasoning,
|
|
@@ -279,13 +315,40 @@ export function ModelPickerScreen({
|
|
|
279
315
|
{ isActive: isFocused },
|
|
280
316
|
);
|
|
281
317
|
|
|
318
|
+
const contextLayout = useActivePanelLayout();
|
|
319
|
+
const activeLayout = (activePanelLayout ?? contextLayout) as ActivePanelLayout | undefined;
|
|
320
|
+
|
|
282
321
|
const shellWidth = getShellWidth(layout.cols);
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
const
|
|
322
|
+
const hookPanelLayout = usePanelLayout();
|
|
323
|
+
const hookAvailableRows = usePanelAvailableRows();
|
|
324
|
+
const resolvedPanelLayout = useMemo<PanelLayout>(() => {
|
|
325
|
+
if (panelLayout) return panelLayout;
|
|
326
|
+
if (hookPanelLayout) return hookPanelLayout;
|
|
327
|
+
|
|
328
|
+
const mode = layout.mode;
|
|
329
|
+
const resolvedRows = activeLayout
|
|
330
|
+
? activeLayout.availableRows
|
|
331
|
+
: getAvailableRowsForPanel(layout, propAvailableRows ?? hookAvailableRows);
|
|
332
|
+
const resolvedCols = activeLayout
|
|
333
|
+
? activeLayout.availableCols
|
|
334
|
+
: Math.max(20, shellWidth - 4);
|
|
335
|
+
|
|
336
|
+
return {
|
|
337
|
+
mode: (mode === "compact" || mode === "micro" as any) ? "compact" : mode === "expanded" || mode === "max" as any || mode === "wide" as any ? "expanded" : "regular",
|
|
338
|
+
availableRows: resolvedRows,
|
|
339
|
+
availableCols: resolvedCols,
|
|
340
|
+
};
|
|
341
|
+
}, [panelLayout, hookPanelLayout, layout, activeLayout, propAvailableRows, shellWidth, hookAvailableRows]);
|
|
342
|
+
|
|
343
|
+
const panelWidth = activeLayout
|
|
344
|
+
? activeLayout.width
|
|
345
|
+
: Math.max(38, Math.min((layout as any).contentWidth ?? shellWidth, shellWidth - 2));
|
|
346
|
+
|
|
347
|
+
const availableRows = resolvedPanelLayout.availableRows;
|
|
348
|
+
const innerWidth = resolvedPanelLayout.availableCols;
|
|
349
|
+
const help = resolvedPanelLayout.mode === "compact"
|
|
286
350
|
? "↑↓ · ←→ · Enter · Esc"
|
|
287
351
|
: "↑↓ model · ←→ reasoning · Enter select · Esc cancel";
|
|
288
|
-
const title = clampVisualText(`Select model ${help}`, innerWidth);
|
|
289
352
|
const aOrAn = /^[aeiou]/i.test(activeProviderLabel) ? "an" : "a";
|
|
290
353
|
const routeText = routeTextOverride ?? `Choose ${aOrAn} ${activeProviderLabel} model to use inside Codexa.`;
|
|
291
354
|
const reasoningText = reasoningUnavailable
|
|
@@ -293,6 +356,92 @@ export function ModelPickerScreen({
|
|
|
293
356
|
: `Reasoning: ${formatReasoningLabel(draftReasoning)}`;
|
|
294
357
|
const sourceMarker = getModelSourceMarker(models, activeProviderLabel);
|
|
295
358
|
|
|
359
|
+
const appLayoutBudget = useAppLayoutBudget();
|
|
360
|
+
|
|
361
|
+
const activeModelIndex = models.findIndex((m) => m.model === currentModel || m.id === currentModel);
|
|
362
|
+
const hasSourceMarker = !!sourceMarker;
|
|
363
|
+
|
|
364
|
+
// ─── Layout & Windowing ───────────────────────────────────────────────────
|
|
365
|
+
|
|
366
|
+
const windowResult = useMemo(() => {
|
|
367
|
+
const allowFull = appLayoutBudget?.showPanelColumnHeaders ?? true;
|
|
368
|
+
|
|
369
|
+
// Try fitting with full metadata
|
|
370
|
+
const fullChrome = 5 + (hasSourceMarker ? 1 : 0);
|
|
371
|
+
if (allowFull && models.length + fullChrome <= availableRows) {
|
|
372
|
+
return {
|
|
373
|
+
...calculateListWindow({ itemCount: models.length, selectedIndex: draftSelectedModel, availableRows, chromeRows: fullChrome, showIndicators: false }),
|
|
374
|
+
mode: "full" as const,
|
|
375
|
+
showRouteText: true,
|
|
376
|
+
showReasoningText: true,
|
|
377
|
+
showSourceMarker: hasSourceMarker,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Try fitting without source marker
|
|
382
|
+
if (allowFull && models.length + 5 <= availableRows) {
|
|
383
|
+
return {
|
|
384
|
+
...calculateListWindow({ itemCount: models.length, selectedIndex: draftSelectedModel, availableRows, chromeRows: 5, showIndicators: false }),
|
|
385
|
+
mode: "full" as const,
|
|
386
|
+
showRouteText: true,
|
|
387
|
+
showReasoningText: true,
|
|
388
|
+
showSourceMarker: false,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Try compact with reasoning
|
|
393
|
+
if (models.length + 4 <= availableRows) {
|
|
394
|
+
return {
|
|
395
|
+
...calculateListWindow({ itemCount: models.length, selectedIndex: draftSelectedModel, availableRows, chromeRows: 4, showIndicators: false }),
|
|
396
|
+
mode: "compact" as const,
|
|
397
|
+
showRouteText: false,
|
|
398
|
+
showReasoningText: true,
|
|
399
|
+
showSourceMarker: false,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Try minimal compact
|
|
404
|
+
if (models.length + 3 <= availableRows) {
|
|
405
|
+
return {
|
|
406
|
+
...calculateListWindow({ itemCount: models.length, selectedIndex: draftSelectedModel, availableRows, chromeRows: 3, showIndicators: false }),
|
|
407
|
+
mode: "compact" as const,
|
|
408
|
+
showRouteText: false,
|
|
409
|
+
showReasoningText: false,
|
|
410
|
+
showSourceMarker: false,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Windowed mode
|
|
415
|
+
const window = calculateListWindow({
|
|
416
|
+
itemCount: models.length,
|
|
417
|
+
selectedIndex: draftSelectedModel,
|
|
418
|
+
availableRows,
|
|
419
|
+
chromeRows: 3, // Title (1) + Border (2)
|
|
420
|
+
showIndicators: true,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
...window,
|
|
425
|
+
mode: "windowed" as const,
|
|
426
|
+
showRouteText: false,
|
|
427
|
+
showReasoningText: false,
|
|
428
|
+
showSourceMarker: false,
|
|
429
|
+
};
|
|
430
|
+
}, [models.length, draftSelectedModel, availableRows, hasSourceMarker, appLayoutBudget?.showPanelColumnHeaders]);
|
|
431
|
+
|
|
432
|
+
const visibleModels = useMemo(() => {
|
|
433
|
+
return models.slice(windowResult.start, windowResult.end);
|
|
434
|
+
}, [models, windowResult.start, windowResult.end]);
|
|
435
|
+
|
|
436
|
+
const activeModel = models[activeModelIndex];
|
|
437
|
+
const showCurrentLine = windowResult.mode === "windowed" && activeModelIndex >= 0 && (activeModelIndex < windowResult.start || activeModelIndex >= windowResult.end);
|
|
438
|
+
const title = clampVisualText(
|
|
439
|
+
windowResult.mode === "windowed"
|
|
440
|
+
? `Select model · Showing ${windowResult.start + 1}-${windowResult.end} of ${models.length}`
|
|
441
|
+
: `Select model ${help}`,
|
|
442
|
+
innerWidth,
|
|
443
|
+
);
|
|
444
|
+
|
|
296
445
|
return (
|
|
297
446
|
<Box flexDirection="column" width={panelWidth}>
|
|
298
447
|
<Box
|
|
@@ -306,17 +455,21 @@ export function ModelPickerScreen({
|
|
|
306
455
|
<Box width="100%" overflow="hidden">
|
|
307
456
|
<Text color={theme.accent} bold>{title}</Text>
|
|
308
457
|
</Box>
|
|
309
|
-
|
|
310
|
-
<
|
|
311
|
-
{
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
458
|
+
{windowResult.showRouteText && (
|
|
459
|
+
<Box width="100%" overflow="hidden">
|
|
460
|
+
<Text color={theme.textMuted}>
|
|
461
|
+
{clampVisualText(routeText, innerWidth)}
|
|
462
|
+
</Text>
|
|
463
|
+
</Box>
|
|
464
|
+
)}
|
|
465
|
+
{windowResult.showReasoningText && (
|
|
466
|
+
<Box width="100%" overflow="hidden">
|
|
467
|
+
<Text color={reasoningUnavailable ? theme.textDim : theme.textMuted}>
|
|
468
|
+
{clampVisualText(reasoningText, innerWidth)}
|
|
469
|
+
</Text>
|
|
470
|
+
</Box>
|
|
471
|
+
)}
|
|
472
|
+
{windowResult.showSourceMarker && sourceMarker && (
|
|
320
473
|
<Box width="100%" overflow="hidden">
|
|
321
474
|
<Text color={theme.textDim}>
|
|
322
475
|
{clampVisualText(sourceMarker, innerWidth)}
|
|
@@ -324,25 +477,54 @@ export function ModelPickerScreen({
|
|
|
324
477
|
</Box>
|
|
325
478
|
)}
|
|
326
479
|
|
|
327
|
-
|
|
480
|
+
{showCurrentLine && activeModel && (
|
|
481
|
+
<Box height={1} overflow="hidden">
|
|
482
|
+
<Text color={theme.textMuted} wrap="truncate">Current: <Text color={theme.text} bold>{getModelName(activeModel)}</Text></Text>
|
|
483
|
+
</Box>
|
|
484
|
+
)}
|
|
485
|
+
|
|
486
|
+
{windowResult.showAbove && (
|
|
487
|
+
<Box height={1} overflow="hidden">
|
|
488
|
+
<Text color={theme.accent}>↑ {windowResult.start} more</Text>
|
|
489
|
+
</Box>
|
|
490
|
+
)}
|
|
491
|
+
|
|
492
|
+
<Box
|
|
493
|
+
flexDirection="column"
|
|
494
|
+
marginTop={0}
|
|
495
|
+
width="100%"
|
|
496
|
+
height={models.length > 0 ? visibleModels.length : undefined}
|
|
497
|
+
overflow={models.length > 0 ? "hidden" : undefined}
|
|
498
|
+
>
|
|
328
499
|
{models.length === 0 ? (
|
|
329
500
|
<Text color={theme.textMuted}>
|
|
330
|
-
{isLoading
|
|
501
|
+
{isLoading
|
|
502
|
+
? `Discovering models from ${activeProviderLabel === "OpenAI" ? "the Codex runtime" : activeProviderLabel}...`
|
|
503
|
+
: (emptyMessage ?? "No models available.")}
|
|
331
504
|
</Text>
|
|
332
505
|
) : (
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
506
|
+
visibleModels.map((model, index) => {
|
|
507
|
+
const actualIndex = windowResult.start + index;
|
|
508
|
+
return (
|
|
509
|
+
<ModelPickerRow
|
|
510
|
+
key={model.id}
|
|
511
|
+
model={model}
|
|
512
|
+
width={innerWidth}
|
|
513
|
+
currentModel={currentModel}
|
|
514
|
+
currentGeminiSelection={currentGeminiSelection}
|
|
515
|
+
isHighlighted={actualIndex === draftSelectedModel}
|
|
516
|
+
selectedReasoning={actualIndex === draftSelectedModel ? draftReasoning : normalizeDraftReasoning(model, currentReasoning)}
|
|
517
|
+
/>
|
|
518
|
+
);
|
|
519
|
+
})
|
|
344
520
|
)}
|
|
345
521
|
</Box>
|
|
522
|
+
|
|
523
|
+
{windowResult.showBelow && (
|
|
524
|
+
<Box height={1} overflow="hidden">
|
|
525
|
+
<Text color={theme.accent}>↓ {windowResult.hiddenBelow} more</Text>
|
|
526
|
+
</Box>
|
|
527
|
+
)}
|
|
346
528
|
</Box>
|
|
347
529
|
</Box>
|
|
348
530
|
);
|
|
@@ -392,7 +574,7 @@ function ModelPickerRow({
|
|
|
392
574
|
<Text color={isHighlighted ? theme.accent : theme.textDim}>{isHighlighted ? ">" : " "}</Text>
|
|
393
575
|
</Box>
|
|
394
576
|
<Box width={nameWidth} flexShrink={0} overflow="hidden">
|
|
395
|
-
<Text color={isHighlighted ? theme.text : theme.textMuted} bold={isHighlighted}>
|
|
577
|
+
<Text color={isHighlighted ? theme.text : theme.textMuted} bold={isHighlighted} wrap="truncate">
|
|
396
578
|
{name}
|
|
397
579
|
</Text>
|
|
398
580
|
</Box>
|
|
@@ -405,7 +587,7 @@ function ModelPickerRow({
|
|
|
405
587
|
<Text> </Text>
|
|
406
588
|
</Box>
|
|
407
589
|
<Box width={pillWidth} flexShrink={0} overflow="hidden">
|
|
408
|
-
<Text color={theme.accent} bold>
|
|
590
|
+
<Text color={theme.accent} bold wrap="truncate">
|
|
409
591
|
{pillText}
|
|
410
592
|
</Text>
|
|
411
593
|
</Box>
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
type CodexModelCapability,
|
|
5
5
|
type ReasoningEffortCapability,
|
|
6
6
|
normalizeReasoningForModelCapabilities,
|
|
7
|
-
} from "
|
|
8
|
-
import { formatReasoningLabel } from "
|
|
9
|
-
import { traceInputDebug } from "
|
|
10
|
-
import { FOCUS_IDS } from "
|
|
11
|
-
import { useTheme } from "
|
|
7
|
+
} from "../../core/models/codexModelCapabilities.js";
|
|
8
|
+
import { formatReasoningLabel } from "../../config/settings.js";
|
|
9
|
+
import { traceInputDebug } from "../../core/debug/inputDebug.js";
|
|
10
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
11
|
+
import { useTheme } from "../theme.js";
|
|
12
12
|
|
|
13
13
|
// ─── Types & helpers ─────────────────────────────────────────────────────────
|
|
14
14
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { ResolvedRuntimeConfig, RuntimeConfig } from "
|
|
1
|
+
import type { ResolvedRuntimeConfig, RuntimeConfig } from "../../config/runtimeConfig.js";
|
|
2
2
|
import {
|
|
3
3
|
formatApprovalPolicyLabel,
|
|
4
4
|
formatNetworkAccessLabel,
|
|
5
5
|
formatSandboxModeLabel,
|
|
6
|
-
} from "
|
|
7
|
-
import { FOCUS_IDS } from "
|
|
6
|
+
} from "../../config/runtimeConfig.js";
|
|
7
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
8
8
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
9
9
|
|
|
10
10
|
export type PermissionsPanelAction =
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput, useStdin } from "ink";
|
|
3
|
-
import { FOCUS_IDS } from "
|
|
4
|
-
import { useTheme } from "
|
|
3
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
5
5
|
|
|
6
6
|
export type PlanActionValue = "implement" | "revise" | "cancel";
|
|
7
7
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { normalizePlanReviewMarkdown } from "
|
|
4
|
-
import { getUsableShellWidth } from "
|
|
5
|
-
import { parseMarkdown } from "
|
|
6
|
-
import { getTextWidth } from "
|
|
7
|
-
import { useTheme } from "
|
|
3
|
+
import { normalizePlanReviewMarkdown } from "../../core/workspace/planStorage.js";
|
|
4
|
+
import { getUsableShellWidth } from "../layout.js";
|
|
5
|
+
import { parseMarkdown } from "../render/Markdown.js";
|
|
6
|
+
import { getTextWidth } from "../render/textLayout.js";
|
|
7
|
+
import { useTheme } from "../theme.js";
|
|
8
8
|
|
|
9
9
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
10
10
|
|