@golba98/codexa 1.0.4 → 1.0.6
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 +6 -10
- package/package.json +1 -1
- package/src/app.tsx +188 -121
- package/src/commands/handler.ts +11 -20
- package/src/config/appVersion.ts +65 -0
- package/src/config/buildInfo.ts +2 -2
- package/src/config/settings.ts +5 -1
- package/src/config/updateCheckCache.ts +18 -8
- package/src/core/models/codexModelCapabilities.ts +57 -4
- package/src/core/models/codexModelsCacheSeed.ts +153 -0
- package/src/core/models/providerModelCache.ts +90 -0
- package/src/core/process/CommandRunner.ts +12 -1
- package/src/core/providerLauncher/registry.ts +37 -7
- package/src/core/providerLauncher/types.ts +2 -1
- package/src/core/providerRuntime/anthropic.ts +3 -5
- package/src/core/providerRuntime/antigravity.ts +257 -90
- package/src/core/providerRuntime/claudeCodeDiscovery.ts +724 -692
- package/src/core/providerRuntime/mistralVibe.ts +663 -0
- package/src/core/providerRuntime/models.ts +18 -4
- package/src/core/providerRuntime/reasoning.ts +9 -6
- package/src/core/providerRuntime/registry.ts +93 -44
- package/src/core/providerRuntime/types.ts +1 -0
- package/src/core/version/packageManager.ts +119 -0
- package/src/core/version/updateCheck.ts +15 -9
- package/src/index.tsx +23 -9
- 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/{AppShell.tsx → chrome/AppShell.tsx} +11 -11
- package/src/ui/{BottomComposer.tsx → chrome/BottomComposer.tsx} +15 -15
- package/src/ui/{DashCard.tsx → chrome/DashCard.tsx} +2 -2
- package/src/ui/{RunFooter.tsx → chrome/RunFooter.tsx} +3 -3
- package/src/ui/{RuntimeStatusBar.tsx → chrome/RuntimeStatusBar.tsx} +3 -3
- package/src/ui/{Spinner.tsx → chrome/Spinner.tsx} +1 -1
- package/src/ui/{TopHeader.tsx → chrome/TopHeader.tsx} +15 -13
- package/src/ui/{UpdateAvailableCard.tsx → chrome/UpdateAvailableCard.tsx} +6 -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/{slashCommands.ts → input/slashCommands.ts} +1 -0
- package/src/ui/{AttachmentImportPanel.tsx → panels/AttachmentImportPanel.tsx} +1 -1
- 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} +11 -9
- 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/{ProviderPicker.tsx → panels/ProviderPicker.tsx} +9 -7
- package/src/ui/{ReasoningPicker.tsx → panels/ReasoningPicker.tsx} +3 -3
- package/src/ui/{SelectionPanel.tsx → panels/SelectionPanel.tsx} +1 -1
- package/src/ui/{SettingsPanel.tsx → panels/SettingsPanel.tsx} +3 -3
- package/src/ui/{TextEntryPanel.tsx → panels/TextEntryPanel.tsx} +3 -3
- package/src/ui/{ThemePicker.tsx → panels/ThemePicker.tsx} +2 -2
- package/src/ui/{UpdatePromptPanel.tsx → panels/UpdatePromptPanel.tsx} +54 -44
- package/src/ui/{Markdown.tsx → render/Markdown.tsx} +2 -2
- package/src/ui/{diffRenderer.ts → render/diffRenderer.ts} +1 -1
- 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} +9 -8
- 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} +8 -8
- package/src/ui/{TranscriptShell.tsx → timeline/TranscriptShell.tsx} +6 -6
- package/src/ui/{TurnGroup.tsx → timeline/TurnGroup.tsx} +15 -15
- 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} +14 -14
- /package/src/ui/{busyStatusAnimation.ts → chrome/busyStatusAnimation.ts} +0 -0
- /package/src/ui/{logoVariants.ts → render/logoVariants.ts} +0 -0
- /package/src/ui/{terminalAnswerFormat.ts → render/terminalAnswerFormat.ts} +0 -0
- /package/src/ui/{textLayout.ts → render/textLayout.ts} +0 -0
- /package/src/ui/{layoutListWindow.ts → timeline/layoutListWindow.ts} +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import React, { memo } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { HEADER_CONFIG_DEFAULTS, type HeaderConfig } from "
|
|
4
|
-
import { formatCodexaBrandLabel } from "
|
|
5
|
-
import { formatVersionLabel } from "
|
|
6
|
-
import type { RuntimeSummary } from "
|
|
7
|
-
import type { CodexAuthState } from "
|
|
8
|
-
import { getAuthStateLabel } from "
|
|
9
|
-
import * as renderDebug from "
|
|
10
|
-
import { useTheme } from "
|
|
11
|
-
import { clampVisualText, isDecorativeLayoutMode, type Layout, useAppLayoutBudget } from "
|
|
12
|
-
import { getTextWidth } from "
|
|
3
|
+
import { HEADER_CONFIG_DEFAULTS, type HeaderConfig } from "../../config/settings.js";
|
|
4
|
+
import { formatCodexaBrandLabel } from "../../core/version/channel.js";
|
|
5
|
+
import { CODEXA_UPDATE_COMMAND, formatVersionLabel } from "../../core/version/updateCheck.js";
|
|
6
|
+
import type { RuntimeSummary } from "../../config/runtimeConfig.js";
|
|
7
|
+
import type { CodexAuthState } from "../../core/auth/codexAuth.js";
|
|
8
|
+
import { getAuthStateLabel } from "../../core/auth/codexAuth.js";
|
|
9
|
+
import * as renderDebug from "../../core/perf/renderDebug.js";
|
|
10
|
+
import { useTheme } from "../theme.js";
|
|
11
|
+
import { clampVisualText, isDecorativeLayoutMode, type Layout, useAppLayoutBudget } from "../layout.js";
|
|
12
|
+
import { getTextWidth } from "../render/textLayout.js";
|
|
13
13
|
import { UPDATE_CARD_ROWS, UpdateAvailableCard } from "./UpdateAvailableCard.js";
|
|
14
14
|
import {
|
|
15
15
|
LOGO_LARGE,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
LOGO_LARGE_MIN_COLS,
|
|
19
19
|
LOGO_LARGE_MIN_ROWS,
|
|
20
20
|
getLogoWidth,
|
|
21
|
-
} from "
|
|
21
|
+
} from "../render/logoVariants.js";
|
|
22
22
|
|
|
23
23
|
// Re-exported for backward compatibility with existing tests.
|
|
24
24
|
export const HEADER_WORDMARK_LINES = LOGO_LARGE;
|
|
@@ -58,6 +58,7 @@ type HeaderMetadataLine = { key: string; text: string; color: string; bold: bool
|
|
|
58
58
|
export interface UpdateAvailableInfo {
|
|
59
59
|
latestVersion: string;
|
|
60
60
|
currentVersion: string;
|
|
61
|
+
updateCommand?: string;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
interface TopHeaderProps {
|
|
@@ -343,6 +344,7 @@ export function TopHeader({
|
|
|
343
344
|
<UpdateAvailableCard
|
|
344
345
|
latestVersion={updateAvailable.latestVersion}
|
|
345
346
|
currentVersion={updateAvailable.currentVersion}
|
|
347
|
+
updateCommand={updateAvailable.updateCommand}
|
|
346
348
|
width={metadataWidth}
|
|
347
349
|
/>
|
|
348
350
|
<Box height={UPDATE_CARD_GAP_ROWS} />
|
|
@@ -359,7 +361,7 @@ export function TopHeader({
|
|
|
359
361
|
)}
|
|
360
362
|
{metadataColumn}
|
|
361
363
|
{updateAvailable && (
|
|
362
|
-
<Text color={theme.warning} wrap="truncate">{`Update available: Codexa ${formatVersionLabel(updateAvailable.latestVersion)} — Run:
|
|
364
|
+
<Text color={theme.warning} wrap="truncate">{`Update available: Codexa ${formatVersionLabel(updateAvailable.latestVersion)} — Run: ${updateAvailable.updateCommand ?? CODEXA_UPDATE_COMMAND}`}</Text>
|
|
363
365
|
)}
|
|
364
366
|
</Box>
|
|
365
367
|
)}
|
|
@@ -434,4 +436,4 @@ export const MemoizedTopHeader = memo(TopHeader, (prev, next) => {
|
|
|
434
436
|
export const MIN_LOGO_TERMINAL_WIDTH = LOGO_COMPACT_MIN_COLS;
|
|
435
437
|
|
|
436
438
|
// Re-export for consumers that reference these constants directly.
|
|
437
|
-
export { LOGO_LARGE_MIN_COLS, LOGO_MEDIUM_MIN_COLS, LOGO_COMPACT_MIN_COLS } from "
|
|
439
|
+
export { LOGO_LARGE_MIN_COLS, LOGO_MEDIUM_MIN_COLS, LOGO_COMPACT_MIN_COLS } from "../render/logoVariants.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { CODEXA_UPDATE_COMMAND, formatVersionLabel } from "
|
|
4
|
-
import { clampVisualText } from "
|
|
5
|
-
import { useTheme } from "
|
|
3
|
+
import { CODEXA_UPDATE_COMMAND, formatVersionLabel } from "../../core/version/updateCheck.js";
|
|
4
|
+
import { clampVisualText } from "../layout.js";
|
|
5
|
+
import { useTheme } from "../theme.js";
|
|
6
6
|
|
|
7
7
|
export const UPDATE_CARD_CONTENT_ROWS = 4; // title + available + using + command
|
|
8
8
|
export const UPDATE_CARD_ROWS = UPDATE_CARD_CONTENT_ROWS + 2; // +2 for top/bottom border rows
|
|
@@ -10,13 +10,14 @@ export const UPDATE_CARD_ROWS = UPDATE_CARD_CONTENT_ROWS + 2; // +2 for top/bott
|
|
|
10
10
|
export interface UpdateAvailableCardProps {
|
|
11
11
|
latestVersion: string;
|
|
12
12
|
currentVersion: string;
|
|
13
|
+
updateCommand?: string;
|
|
13
14
|
/** Total box width including borders. Long lines are truncated to fit. */
|
|
14
15
|
width?: number;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export function UpdateAvailableCard({ latestVersion, currentVersion, width }: UpdateAvailableCardProps) {
|
|
18
|
+
export function UpdateAvailableCard({ latestVersion, currentVersion, updateCommand = CODEXA_UPDATE_COMMAND, width }: UpdateAvailableCardProps) {
|
|
18
19
|
const theme = useTheme();
|
|
19
|
-
const command = `Run: ${
|
|
20
|
+
const command = `Run: ${updateCommand}`;
|
|
20
21
|
// Inner content width = boxWidth - 2 (left/right border cols)
|
|
21
22
|
const innerWidth = width !== undefined ? Math.max(8, width - 2) : undefined;
|
|
22
23
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatTerminalAnswerInline } from "
|
|
1
|
+
import { formatTerminalAnswerInline } from "../render/terminalAnswerFormat.js";
|
|
2
2
|
|
|
3
3
|
function stripOuterQuotes(s: string): string {
|
|
4
4
|
if ((s.startsWith("'") && s.endsWith("'")) || (s.startsWith('"') && s.endsWith('"'))) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { WrappedTextRow } from "
|
|
2
|
-
import { getTextWidth, normalizeLineBreaks, wrapTextRows } from "
|
|
3
|
-
import { sanitizeTerminalInput } from "
|
|
1
|
+
import type { WrappedTextRow } from "../render/textLayout.js";
|
|
2
|
+
import { getTextWidth, normalizeLineBreaks, wrapTextRows } from "../render/textLayout.js";
|
|
3
|
+
import { sanitizeTerminalInput } from "../../core/terminal/terminalSanitize.js";
|
|
4
4
|
|
|
5
5
|
export type WrappedInputRow = WrappedTextRow;
|
|
6
6
|
|
|
@@ -24,6 +24,7 @@ export const SLASH_COMMANDS = [
|
|
|
24
24
|
{ cmd: "/auth", desc: "Manage authentication" },
|
|
25
25
|
{ cmd: "/workspace", desc: "Show the locked workspace" },
|
|
26
26
|
{ cmd: "/copy", desc: "Copy the full conversation transcript to clipboard" },
|
|
27
|
+
{ cmd: "/update", desc: "Check for updates and install the latest Codexa" },
|
|
27
28
|
{ cmd: "/mouse", desc: "Toggle mouse capture for wheel scrolling (off by default)" },
|
|
28
29
|
{ cmd: "/exit", desc: "Quit the application" },
|
|
29
30
|
] as const satisfies readonly SlashCommandSuggestion[];
|
|
@@ -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,10 +4,10 @@ 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 "
|
|
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
11
|
import {
|
|
12
12
|
clampVisualText,
|
|
13
13
|
getShellWidth,
|
|
@@ -19,10 +19,10 @@ import {
|
|
|
19
19
|
type ActivePanelLayout,
|
|
20
20
|
type PanelLayout,
|
|
21
21
|
usePanelLayout,
|
|
22
|
-
} from "
|
|
23
|
-
import { calculateListWindow } from "
|
|
24
|
-
import { useTheme } from "
|
|
25
|
-
import type { GeminiModelSelection } from "
|
|
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";
|
|
26
26
|
|
|
27
27
|
// ─── Types & helpers ─────────────────────────────────────────────────────────
|
|
28
28
|
|
|
@@ -498,7 +498,9 @@ export function ModelPickerScreen({
|
|
|
498
498
|
>
|
|
499
499
|
{models.length === 0 ? (
|
|
500
500
|
<Text color={theme.textMuted}>
|
|
501
|
-
{isLoading
|
|
501
|
+
{isLoading
|
|
502
|
+
? `Discovering models from ${activeProviderLabel === "OpenAI" ? "the Codex runtime" : activeProviderLabel}...`
|
|
503
|
+
: (emptyMessage ?? "No models available.")}
|
|
502
504
|
</Text>
|
|
503
505
|
) : (
|
|
504
506
|
visibleModels.map((model, index) => {
|
|
@@ -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
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useMemo, useState } from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
|
-
import type { ProviderConfig, ProviderId, ProviderPickerAction } from "
|
|
4
|
-
import { traceInputDebug } from "
|
|
5
|
-
import { FOCUS_IDS } from "
|
|
3
|
+
import type { ProviderConfig, ProviderId, ProviderPickerAction } from "../../core/providerLauncher/types.js";
|
|
4
|
+
import { traceInputDebug } from "../../core/debug/inputDebug.js";
|
|
5
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
6
6
|
import {
|
|
7
7
|
clampVisualText,
|
|
8
8
|
getShellWidth,
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
type ActivePanelLayout,
|
|
15
15
|
type PanelLayout,
|
|
16
16
|
usePanelLayout,
|
|
17
|
-
} from "
|
|
18
|
-
import { calculateListWindow } from "
|
|
19
|
-
import { useTheme } from "
|
|
17
|
+
} from "../layout.js";
|
|
18
|
+
import { calculateListWindow } from "../timeline/layoutListWindow.js";
|
|
19
|
+
import { useTheme } from "../theme.js";
|
|
20
20
|
|
|
21
21
|
// ─── Types & helpers ─────────────────────────────────────────────────────────
|
|
22
22
|
|
|
@@ -247,7 +247,9 @@ export function ProviderPicker({
|
|
|
247
247
|
return;
|
|
248
248
|
}
|
|
249
249
|
if (key.return && selectedProvider) {
|
|
250
|
-
|
|
250
|
+
const action = actions[actionIndex];
|
|
251
|
+
if (action?.disabledReason) return;
|
|
252
|
+
onAction(selectedProvider.id, action?.value ?? "cancel");
|
|
251
253
|
}
|
|
252
254
|
}, { isActive: isFocused });
|
|
253
255
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type ReasoningEffortCapability } from "
|
|
3
|
-
import { formatReasoningLabel } from "
|
|
4
|
-
import { FOCUS_IDS } from "
|
|
2
|
+
import { type ReasoningEffortCapability } from "../../core/models/codexModelCapabilities.js";
|
|
3
|
+
import { formatReasoningLabel } from "../../config/settings.js";
|
|
4
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
5
5
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
6
6
|
|
|
7
7
|
interface ReasoningPickerProps {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useMemo, useState } from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
|
-
import type { SettingDefinition } from "
|
|
4
|
-
import type { FocusTargetId } from "
|
|
5
|
-
import { useTheme } from "
|
|
3
|
+
import type { SettingDefinition } from "../../config/settings.js";
|
|
4
|
+
import type { FocusTargetId } from "../input/focus.js";
|
|
5
|
+
import { useTheme } from "../theme.js";
|
|
6
6
|
|
|
7
7
|
export interface SettingsPanelProps<TKey extends string> {
|
|
8
8
|
focusId: FocusTargetId;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import React, { useMemo, useState } from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
|
-
import type { FocusTargetId } from "
|
|
4
|
-
import { useTheme } from "
|
|
5
|
-
import { stripMouseEscapes } from "
|
|
3
|
+
import type { FocusTargetId } from "../input/focus.js";
|
|
4
|
+
import { useTheme } from "../theme.js";
|
|
5
|
+
import { stripMouseEscapes } from "../input/inputBuffer.js";
|
|
6
6
|
|
|
7
7
|
interface TextEntryPanelProps {
|
|
8
8
|
focusId: FocusTargetId;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { AVAILABLE_THEMES, formatThemeLabel } from "
|
|
3
|
-
import { FOCUS_IDS } from "
|
|
2
|
+
import { AVAILABLE_THEMES, formatThemeLabel } from "../../config/settings.js";
|
|
3
|
+
import { FOCUS_IDS } from "../input/focus.js";
|
|
4
4
|
import { SelectionPanel } from "./SelectionPanel.js";
|
|
5
5
|
|
|
6
6
|
interface ThemePickerProps {
|
|
@@ -1,31 +1,45 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from "react";
|
|
2
2
|
import { Box, Text, useFocus, useInput } from "ink";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
4
|
+
import { CODEXA_NPM_PACKAGE, formatVersionLabel } from "../../core/version/updateCheck.js";
|
|
5
|
+
import {
|
|
6
|
+
formatPermissionGuidance,
|
|
7
|
+
getUpdateCommand,
|
|
8
|
+
isPermissionError,
|
|
9
|
+
runUpdateCommand,
|
|
10
|
+
type GlobalPackageManager,
|
|
11
|
+
} from "../../core/version/packageManager.js";
|
|
12
|
+
import type { CommandResult, CommandStreamHandlers } from "../../core/process/CommandRunner.js";
|
|
6
13
|
|
|
7
14
|
type Phase = "menu" | "running" | "done" | "error";
|
|
8
15
|
|
|
16
|
+
export type RunUpdateFn = (
|
|
17
|
+
pm: GlobalPackageManager,
|
|
18
|
+
handlers?: CommandStreamHandlers,
|
|
19
|
+
) => { result: Promise<CommandResult>; cancel: () => void };
|
|
20
|
+
|
|
9
21
|
const MENU_ITEMS = [
|
|
10
22
|
{ label: "Update now" },
|
|
11
|
-
{ label: "
|
|
12
|
-
{ label: "Skip until next version" },
|
|
23
|
+
{ label: "Later" },
|
|
13
24
|
] as const;
|
|
14
25
|
|
|
15
26
|
interface UpdatePromptPanelProps {
|
|
16
27
|
focusId: string;
|
|
17
28
|
currentVersion: string;
|
|
18
29
|
latestVersion: string;
|
|
30
|
+
packageManager: GlobalPackageManager;
|
|
31
|
+
/** Test seam — defaults to the real cross-platform runner. */
|
|
32
|
+
runUpdate?: RunUpdateFn;
|
|
19
33
|
onSkip: () => void;
|
|
20
|
-
onSkipUntilNextVersion: (version: string) => void;
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
export function UpdatePromptPanel({
|
|
24
37
|
focusId,
|
|
25
38
|
currentVersion,
|
|
26
39
|
latestVersion,
|
|
40
|
+
packageManager,
|
|
41
|
+
runUpdate,
|
|
27
42
|
onSkip,
|
|
28
|
-
onSkipUntilNextVersion,
|
|
29
43
|
}: UpdatePromptPanelProps) {
|
|
30
44
|
const theme = useTheme();
|
|
31
45
|
const { isFocused } = useFocus({ id: focusId, autoFocus: true });
|
|
@@ -35,7 +49,7 @@ export function UpdatePromptPanel({
|
|
|
35
49
|
const [outputLines, setOutputLines] = useState<string[]>([]);
|
|
36
50
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
37
51
|
|
|
38
|
-
const
|
|
52
|
+
const runStartedRef = useRef(false);
|
|
39
53
|
|
|
40
54
|
useInput((input, key) => {
|
|
41
55
|
if (key.escape) {
|
|
@@ -54,10 +68,8 @@ export function UpdatePromptPanel({
|
|
|
54
68
|
if (key.return) {
|
|
55
69
|
if (selectedIndex === 0) {
|
|
56
70
|
setPhase("running");
|
|
57
|
-
} else if (selectedIndex === 1) {
|
|
58
|
-
onSkip();
|
|
59
71
|
} else {
|
|
60
|
-
|
|
72
|
+
onSkip();
|
|
61
73
|
}
|
|
62
74
|
return;
|
|
63
75
|
}
|
|
@@ -70,42 +82,42 @@ export function UpdatePromptPanel({
|
|
|
70
82
|
|
|
71
83
|
useEffect(() => {
|
|
72
84
|
if (phase !== "running") return;
|
|
73
|
-
if (
|
|
74
|
-
|
|
85
|
+
if (runStartedRef.current) return;
|
|
86
|
+
runStartedRef.current = true;
|
|
75
87
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const appendLines = (buf: Buffer) => {
|
|
82
|
-
const lines = buf.toString("utf8").split(/\r?\n/).filter(Boolean);
|
|
88
|
+
const appendLines = (text: string) => {
|
|
89
|
+
const lines = text.split(/\r?\n/).filter(Boolean);
|
|
83
90
|
if (lines.length > 0) {
|
|
84
91
|
setOutputLines((prev) => [...prev, ...lines]);
|
|
85
92
|
}
|
|
86
93
|
};
|
|
87
94
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
setErrorMessage(err.message);
|
|
93
|
-
setPhase("error");
|
|
95
|
+
const runner = runUpdate ?? runUpdateCommand;
|
|
96
|
+
const { result, cancel } = runner(packageManager, {
|
|
97
|
+
onStdout: appendLines,
|
|
98
|
+
onStderr: appendLines,
|
|
94
99
|
});
|
|
95
100
|
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
let disposed = false;
|
|
102
|
+
void result.then((res) => {
|
|
103
|
+
if (disposed) return;
|
|
104
|
+
if (res.status === "completed" && res.exitCode === 0) {
|
|
98
105
|
setPhase("done");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (isPermissionError(res)) {
|
|
109
|
+
setErrorMessage(formatPermissionGuidance(packageManager));
|
|
99
110
|
} else {
|
|
100
|
-
setErrorMessage(
|
|
101
|
-
setPhase("error");
|
|
111
|
+
setErrorMessage(res.userMessage);
|
|
102
112
|
}
|
|
113
|
+
setPhase("error");
|
|
103
114
|
});
|
|
104
115
|
|
|
105
116
|
return () => {
|
|
106
|
-
|
|
117
|
+
disposed = true;
|
|
118
|
+
cancel();
|
|
107
119
|
};
|
|
108
|
-
}, [phase]);
|
|
120
|
+
}, [phase, packageManager, runUpdate]);
|
|
109
121
|
|
|
110
122
|
const footerText = phase === "menu"
|
|
111
123
|
? "Esc to close · Enter to confirm"
|
|
@@ -122,16 +134,16 @@ export function UpdatePromptPanel({
|
|
|
122
134
|
flexDirection="column"
|
|
123
135
|
>
|
|
124
136
|
<Box>
|
|
125
|
-
<Text color={theme.accent} bold>{`Update available: Codexa ${
|
|
137
|
+
<Text color={theme.accent} bold>{`Update available: Codexa ${latestVersion}`}</Text>
|
|
126
138
|
</Box>
|
|
127
139
|
<Box marginTop={1}>
|
|
128
|
-
<Text color={theme.text}>{
|
|
140
|
+
<Text color={theme.text}>{`Current version: ${currentVersion}`}</Text>
|
|
129
141
|
</Box>
|
|
130
142
|
<Box>
|
|
131
143
|
<Text color={theme.textMuted}>{`Package: ${CODEXA_NPM_PACKAGE}`}</Text>
|
|
132
144
|
</Box>
|
|
133
145
|
<Box>
|
|
134
|
-
<Text color={theme.textMuted}>{`Run: ${
|
|
146
|
+
<Text color={theme.textMuted}>{`Run: ${getUpdateCommand(packageManager).displayCommand}`}</Text>
|
|
135
147
|
</Box>
|
|
136
148
|
</Box>
|
|
137
149
|
|
|
@@ -146,19 +158,17 @@ export function UpdatePromptPanel({
|
|
|
146
158
|
>
|
|
147
159
|
{phase === "menu" && (
|
|
148
160
|
<>
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
<Text color={index === selectedIndex ? theme.accent : theme.textMuted}>
|
|
152
|
-
{index === selectedIndex ? "› " : " "}
|
|
153
|
-
</Text>
|
|
161
|
+
<Box>
|
|
162
|
+
{MENU_ITEMS.map((item, index) => (
|
|
154
163
|
<Text
|
|
164
|
+
key={item.label}
|
|
155
165
|
color={index === selectedIndex ? theme.text : theme.textMuted}
|
|
156
166
|
bold={index === selectedIndex}
|
|
157
167
|
>
|
|
158
|
-
{
|
|
168
|
+
{`[ ${item.label} ]${index === 0 ? " " : ""}`}
|
|
159
169
|
</Text>
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
))}
|
|
171
|
+
</Box>
|
|
162
172
|
</>
|
|
163
173
|
)}
|
|
164
174
|
|
|
@@ -173,7 +183,7 @@ export function UpdatePromptPanel({
|
|
|
173
183
|
|
|
174
184
|
{phase === "done" && (
|
|
175
185
|
<>
|
|
176
|
-
<Text color={theme.success}>{
|
|
186
|
+
<Text color={theme.success}>{`Codexa ${formatVersionLabel(latestVersion)} installed successfully.`}</Text>
|
|
177
187
|
<Text color={theme.textMuted}>{"Restart Codexa to use the new version."}</Text>
|
|
178
188
|
</>
|
|
179
189
|
)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
import { useTheme } from "
|
|
4
|
-
import { Panel } from "
|
|
3
|
+
import { useTheme } from "../theme.js";
|
|
4
|
+
import { Panel } from "../panels/Panel.js";
|
|
5
5
|
import { maybeRenderDiff, type DiffRenderLineType } from "./diffRenderer.js";
|
|
6
6
|
import { formatLocalPathForTerminal, formatTerminalAnswerInline } from "./terminalAnswerFormat.js";
|
|
7
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isNoiseLine } from "
|
|
2
|
-
import { sanitizeTerminalOutput } from "
|
|
1
|
+
import { isNoiseLine } from "../../core/providers/codexTranscript.js";
|
|
2
|
+
import { sanitizeTerminalOutput } from "../../core/terminal/terminalSanitize.js";
|
|
3
3
|
import { parseMarkdown, type Segment } from "./Markdown.js";
|
|
4
4
|
|
|
5
5
|
/**
|