praxis-agent 0.43.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +48 -47
  2. package/dist/application/native-session-projection.d.ts +4 -0
  3. package/dist/application/native-session-projection.js +135 -0
  4. package/dist/application/session-service.d.ts +0 -1
  5. package/dist/application/session-service.js +9 -170
  6. package/dist/application/top-level-agent-manager.d.ts +7 -0
  7. package/dist/application/top-level-agent-manager.js +21 -3
  8. package/dist/cli/controls.js +4 -0
  9. package/dist/cli/interactive.js +112 -156
  10. package/dist/cli/protocol.d.ts +5 -0
  11. package/dist/cli/protocol.js +45 -0
  12. package/dist/cli/provider-auth-command.d.ts +32 -0
  13. package/dist/cli/provider-auth-command.js +249 -0
  14. package/dist/cli/tui/ansi-frame-renderer.d.ts +2 -0
  15. package/dist/cli/tui/ansi-frame-renderer.js +109 -21
  16. package/dist/cli/tui/ansi-surface.d.ts +6 -22
  17. package/dist/cli/tui/ansi-surface.js +6 -126
  18. package/dist/cli/tui/ansi-theme.d.ts +3 -2
  19. package/dist/cli/tui/ansi-theme.js +22 -1
  20. package/dist/cli/tui/quiet-choice-rows.d.ts +26 -0
  21. package/dist/cli/tui/quiet-choice-rows.js +302 -0
  22. package/dist/cli/tui/quiet-frame-adapter.d.ts +18 -0
  23. package/dist/cli/tui/quiet-frame-adapter.js +90 -0
  24. package/dist/cli/tui/quiet-frame.d.ts +43 -0
  25. package/dist/cli/tui/quiet-frame.js +346 -0
  26. package/dist/cli/tui/quiet-operational-rows.d.ts +17 -0
  27. package/dist/cli/tui/quiet-operational-rows.js +413 -0
  28. package/dist/cli/tui/quiet-screen-projector.d.ts +25 -0
  29. package/dist/cli/tui/quiet-screen-projector.js +110 -0
  30. package/dist/cli/tui/quiet-settings-rows.d.ts +17 -0
  31. package/dist/cli/tui/quiet-settings-rows.js +490 -0
  32. package/dist/cli/tui/status-line.d.ts +15 -9
  33. package/dist/cli/tui/status-line.js +15 -6
  34. package/dist/cli/tui/theme.js +20 -20
  35. package/dist/cli/tui/transcript-viewport.d.ts +5 -0
  36. package/dist/cli/tui/transcript-viewport.js +213 -78
  37. package/dist/cli/tui/tui-row-ir.js +4 -4
  38. package/dist/cli/workspace-trust-prompt.js +2 -2
  39. package/dist/cli-runtime.d.ts +34 -1
  40. package/dist/cli-runtime.js +587 -184
  41. package/dist/maintenance/doctor.js +100 -22
  42. package/dist/persistence/in-memory-transcript-store.js +1 -7
  43. package/dist/persistence/native-transcript-store.d.ts +0 -9
  44. package/dist/persistence/native-transcript-store.js +4 -38
  45. package/dist/persistence/provider-credential-vault.d.ts +72 -0
  46. package/dist/persistence/provider-credential-vault.js +498 -0
  47. package/dist/providers/codex-oauth.d.ts +104 -0
  48. package/dist/providers/codex-oauth.js +770 -0
  49. package/dist/providers/codex-subscription.d.ts +33 -0
  50. package/dist/providers/codex-subscription.js +849 -0
  51. package/dist/providers/provider-auth.d.ts +71 -0
  52. package/dist/providers/provider-auth.js +149 -0
  53. package/dist/providers/provider-registry.d.ts +52 -0
  54. package/dist/providers/provider-registry.js +187 -0
  55. package/dist/providers/provider-settings.d.ts +38 -0
  56. package/dist/providers/provider-settings.js +334 -0
  57. package/dist/security/workspace-trust.d.ts +4 -3
  58. package/dist/security/workspace-trust.js +35 -1
  59. package/package.json +8 -4
@@ -1,18 +1,17 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { randomUUID } from 'node:crypto';
3
3
  import { existsSync } from 'node:fs';
4
4
  import { mkdir, readFile, writeFile } from 'node:fs/promises';
5
5
  import { homedir } from 'node:os';
6
6
  import { join, resolve } from 'node:path';
7
7
  import { fileURLToPath } from 'node:url';
8
- import { useEffect, useMemo, useReducer, useRef, useState, } from 'react';
9
- import { Box, Text, render, useApp, useInput } from 'ink';
8
+ import { useEffect, useMemo, useReducer, useRef, useState } from 'react';
9
+ import { render, useApp, useInput } from 'ink';
10
10
  import { permissionRuleValueToString } from '../permissions/permission-updates.js';
11
11
  import { resolveDataPlane, resolveDataPlaneRoot, } from '../persistence/data-plane.js';
12
12
  import { AgentRunCancelledError } from '../core/runtime.js';
13
13
  import { claudePermissionActionKey, claudePermissionRuleMatches, } from '../permissions/claude-permission-resolver.js';
14
14
  import { redactSensitiveText, sensitiveEnvironmentValues, } from '../platform/sensitive-data.js';
15
- import { CommandPalette, BtwPanel, Composer, DiffDashboard, DialogFrame, LeafSurface, ExternalEditorWait, HelpMenu, HookDashboard, ListDashboard, MemoryDashboard, MentionPicker, ModelMenu, EffortMenu, SessionPicker, ThemePicker, CustomThemeEditor, SessionIdentity, Transcript, WelcomePanel, } from './tui/claude-style.js';
16
15
  import { projectTuiEffortSurface, projectTuiModelSurface, } from './tui/model-effort-surface-model.js';
17
16
  import { projectTuiLeafSurface, } from './tui/leaf-surface-model.js';
18
17
  import { projectTuiThemeSurface, } from './tui/theme-surface-model.js';
@@ -24,12 +23,14 @@ import { tuiInkRenderOptions, useTuiPresentationEnvironment, } from './tui/prese
24
23
  import { StreamingFrameBuffer } from './tui/streaming-frame-buffer.js';
25
24
  import { createTuiStoreState, reduceTuiStore } from './tui/kernel/tui-store.js';
26
25
  import { TuiEffectRunner } from './tui/kernel/tui-effect-runner.js';
27
- import { createClaudeStatusLineInput, StatusLine } from './tui/status-line.js';
26
+ import { createClaudeStatusLineInput, formatClaudeStatusLineState, useClaudeStatusLine, } from './tui/status-line.js';
28
27
  import { createTuiAppendHistoryChange } from './tui/transcript-window-model.js';
29
28
  import { createTuiHistoryChange, resolveTuiRenderer, } from './tui/tui-view-model.js';
30
29
  import { projectTuiScreen, } from './tui/tui-screen-model.js';
31
- import { supportsAnsiSurface, TuiAnsiSurface } from './tui/ansi-surface.js';
32
- import { projectTuiHelpSurface, } from './tui/help-surface-model.js';
30
+ import { TuiAnsiSurface } from './tui/ansi-surface.js';
31
+ import { QuietInkFrame } from './tui/quiet-frame-adapter.js';
32
+ import { projectQuietScreenFrame, } from './tui/quiet-screen-projector.js';
33
+ import { projectTuiHelpSurface } from './tui/help-surface-model.js';
33
34
  import { projectTuiHooksSurface, } from './tui/hooks-surface-model.js';
34
35
  import { loadGitDiff } from './tui/git-diff.js';
35
36
  import { projectTuiDiffSurface, } from './tui/diff-surface-model.js';
@@ -56,34 +57,30 @@ import { defaultTuiKeybindings, ensureTuiKeybindingsFile, hasTuiKeybindingPrefix
56
57
  import { completeTuiWorkspaceDirectory, resolveTuiWorkspaceDirectory, } from './tui/workspace-directories.js';
57
58
  import { conversationExportPath, conversationExportText, defaultConversationExportFilename, writeConversationExport, } from './tui/conversation-export.js';
58
59
  import { loadTuiThemeSettings, saveTuiThemeSettings, themeSettingsWithCustomTheme, } from './tui/theme-settings.js';
59
- import { DEFAULT_TUI_THEME_SETTINGS, TUI_THEMES, TuiThemeProvider, useTuiTheme, } from './tui/theme.js';
60
+ import { DEFAULT_TUI_THEME_SETTINGS, TUI_THEMES, TuiThemeProvider, } from './tui/theme.js';
60
61
  import { CUSTOM_THEME_TOKENS, createTuiCustomTheme, deleteTuiCustomTheme, loadTuiCustomThemes, updateTuiCustomTheme, } from './tui/custom-themes.js';
61
62
  import { setupTuiTerminal, terminalSetupTuiSlashCommand, } from './tui/terminal-setup.js';
62
- import { commitElicitationText, createTuiElicitationForm, elicitationFormIsValid, elicitationTextValue, expandElicitationOptions, focusedElicitationField, ElicitationSurface, moveElicitationFocus, moveElicitationOption, selectElicitationOption, toggleElicitationBoolean, typeaheadElicitationOption, unsetElicitationField, validateTuiElicitationForm, } from './tui/mcp-elicitation.js';
63
+ import { commitElicitationText, createTuiElicitationForm, elicitationFormIsValid, elicitationTextValue, expandElicitationOptions, focusedElicitationField, moveElicitationFocus, moveElicitationOption, selectElicitationOption, toggleElicitationBoolean, typeaheadElicitationOption, unsetElicitationField, validateTuiElicitationForm, } from './tui/mcp-elicitation.js';
63
64
  import { projectTuiElicitationSurface, } from './tui/mcp-elicitation-surface-model.js';
64
65
  import { openTuiUrl } from './tui/open-url.js';
65
66
  import { projectTuiToolPermission } from './tui/tool-permission.js';
66
67
  import { projectTuiPermissionSurface, } from './tui/permission-surface-model.js';
67
- import { PermissionSurface } from './tui/permission-surface.js';
68
68
  import { projectTuiDecisionSurface, } from './tui/decision-surface-model.js';
69
- import { DecisionSurface } from './tui/decision-surface.js';
70
- import { ConfigDashboard, projectConfigRows } from './tui/config-dashboard.js';
69
+ import { projectConfigRows } from './tui/config-dashboard.js';
71
70
  import { projectTuiConfigSurface, } from './tui/config-surface-model.js';
72
- import { DoctorDashboard } from './tui/doctor-dashboard.js';
73
71
  import { projectTuiDoctorSurface, } from './tui/doctor-surface-model.js';
74
72
  import { projectTuiMemorySurface, } from './tui/memory-surface-model.js';
75
- import { SandboxDashboard, tuiSandboxTabs } from './tui/sandbox-dashboard.js';
73
+ import { tuiSandboxTabs } from './tui/sandbox-dashboard.js';
76
74
  import { projectTuiSandboxSurface, } from './tui/sandbox-surface-model.js';
77
75
  import { createTuiSandboxStore, } from './tui/sandbox-settings.js';
78
76
  import { loadConfigSettings, saveConfigSetting, configSettingDefinition, resolveConfigSettingsLocation, } from './tui/config-settings.js';
79
77
  import { projectRuntimeSettings, loadRuntimeSettings, } from './tui/runtime-settings.js';
80
- import { autoUpdateTarget, copyCandidates, externalEditorInitialContent, formatTurnDuration, questionTimeoutMilliseconds, sessionRecap, spinnerTip, shouldShowCopyPicker, } from './tui/runtime-interactions.js';
78
+ import { autoUpdateTarget, copyCandidates, externalEditorInitialContent, questionTimeoutMilliseconds, sessionRecap, spinnerTip, shouldShowCopyPicker, } from './tui/runtime-interactions.js';
81
79
  import { notifyTerminal, } from './tui/terminal-notifications.js';
82
- import { McpPanel } from './tui/mcp-panel.js';
83
80
  import { McpPanelController, mcpRuntimeFromSession, } from './tui/mcp-panel-controller.js';
84
81
  import { initialTuiMcpPanelState, } from './tui/mcp-panel-projector.js';
85
82
  import { projectTuiMcpSurface, } from './tui/mcp-surface-model.js';
86
- import { TaskPanel, initialTuiTaskPanelState, projectTuiTasks, reconcileTuiTaskPanelState, updateTuiTaskPanelState, } from './tui/task-panel.js';
83
+ import { initialTuiTaskPanelState, projectTuiTasks, reconcileTuiTaskPanelState, updateTuiTaskPanelState, } from './tui/task-panel.js';
87
84
  import { projectTuiTaskSurface, } from './tui/task-surface-model.js';
88
85
  import { ClaudeMcpManagement } from '../mcp/claude-mcp-management.js';
89
86
  const EMPTY_SLASH_COMMANDS = [];
@@ -241,25 +238,6 @@ const HIDDEN_TUI_SLASH_COMMANDS = new Set([
241
238
  'update',
242
239
  'usage',
243
240
  ]);
244
- function RewindWarning() {
245
- const theme = useTuiTheme();
246
- return (_jsx(Text, { ...theme.text.warning, children: "\u26A0 Rewinding does not affect files edited manually or via bash." }));
247
- }
248
- function ExitWarning() {
249
- const theme = useTuiTheme();
250
- return _jsx(Text, { ...theme.text.warning, children: "Press Ctrl-C again to exit" });
251
- }
252
- function DecisionOption({ selected, screenReader, children, selectedPrefix = '❯ ', unselectedPrefix = ' ', }) {
253
- const theme = useTuiTheme();
254
- const accessible = screenReader || theme.noColor;
255
- return (_jsxs(Text, { ...(selected ? theme.text.selectedRow : {}), children: [selected
256
- ? accessible
257
- ? 'Selected: '
258
- : selectedPrefix
259
- : accessible
260
- ? ''
261
- : unselectedPrefix, children] }));
262
- }
263
241
  /** Advances the React-owned transcript plus its exact local mutation fact. */
264
242
  export function advanceInteractiveHistoryState(current, items, changedFrom) {
265
243
  if (!Number.isInteger(changedFrom) ||
@@ -359,7 +337,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
359
337
  : { viewportOverride: { columns: terminalWidth } }),
360
338
  });
361
339
  const width = presentation.viewport.columns;
362
- const rows = presentation.viewport.rows;
363
340
  const fixedViewport = presentation.fixedViewport;
364
341
  const runtimeSettingsRef = useRef(runtimeSettings);
365
342
  runtimeSettingsRef.current = runtimeSettings;
@@ -386,9 +363,9 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
386
363
  const statusLineSessionId = useRef(resume?.sessionId ?? randomUUID());
387
364
  const sessionIdRef = useRef(resume?.sessionId ?? null);
388
365
  sessionIdRef.current = sessionId;
389
- const [sessionColor, setSessionColor] = useState(initialSessionColor);
366
+ const [, setSessionColor] = useState(initialSessionColor);
390
367
  const [sessionName, setSessionName] = useState(null);
391
- const [activeSessionSummary, setActiveSessionSummary] = useState(() => resume?.sessionId
368
+ const [, setActiveSessionSummary] = useState(() => resume?.sessionId
392
369
  ? initialSessions.find((session) => session.sessionId === resume.sessionId)
393
370
  : undefined);
394
371
  const [pendingFork, setPendingFork] = useState(resume?.forkSession === true);
@@ -406,7 +383,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
406
383
  const themeEffectRunnerRef = useRef(null);
407
384
  if (themeEffectRunnerRef.current === null)
408
385
  themeEffectRunnerRef.current = new TuiEffectRunner();
409
- const [clipboardBusy, setClipboardBusy] = useState(false);
386
+ const [, setClipboardBusy] = useState(false);
410
387
  const stashedInputRef = useRef('');
411
388
  const lastEscapeAtRef = useRef(0);
412
389
  const [commandPaletteOpen, setCommandPaletteOpen] = useState(false);
@@ -476,7 +453,7 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
476
453
  });
477
454
  }
478
455
  const [thinkingExpanded, setThinkingExpanded] = useState(false);
479
- const [turnDuration, setTurnDuration] = useState();
456
+ const [, setTurnDuration] = useState();
480
457
  const [usage, setUsage] = useState();
481
458
  const [costUsd, setCostUsd] = useState();
482
459
  const [contextWindowTokens, setContextWindowTokens] = useState(display.contextWindowTokens);
@@ -646,17 +623,6 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
646
623
  query: commandQuery ?? '',
647
624
  selectedIndex: commandSelection,
648
625
  }), [allSlashCommands, commandQuery, commandSelection]);
649
- const commandArgumentHint = useMemo(() => {
650
- if (shellMode || !input.startsWith('/'))
651
- return undefined;
652
- if (inputCursor !== input.length)
653
- return undefined;
654
- const match = /^\/(\S+) $/u.exec(input);
655
- if (!match?.[1])
656
- return undefined;
657
- const command = allSlashCommands.find((candidate) => candidate.name === match[1]);
658
- return command?.argumentHint;
659
- }, [allSlashCommands, input, inputCursor, shellMode]);
660
626
  const commandPaletteVisible = !busy &&
661
627
  !permission &&
662
628
  !planApproval &&
@@ -1089,7 +1055,9 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
1089
1055
  return null;
1090
1056
  }, [menu, input, compactProgress]);
1091
1057
  const secondarySurface = menu === null
1092
- ? undefined
1058
+ ? shortcutsVisible
1059
+ ? shortcutHelpSurface
1060
+ : undefined
1093
1061
  : menu.kind === 'help'
1094
1062
  ? (helpSurface ?? undefined)
1095
1063
  : menu.kind === 'diff'
@@ -1216,23 +1184,11 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
1216
1184
  sessionId,
1217
1185
  screenSurfaces,
1218
1186
  ]);
1219
- const ansiActive = ansiRequested && supportsAnsiSurface(screen);
1187
+ const ansiActive = ansiRequested;
1220
1188
  useEffect(() => {
1221
1189
  previousTuiScreenRef.current = screen;
1222
1190
  }, [screen]);
1223
1191
  const conversationScreen = screen.body.kind === 'conversation' ? screen.body : undefined;
1224
- const selectedPriority = conversationScreen?.foreground.kind === 'priority'
1225
- ? conversationScreen.foreground.surface
1226
- : undefined;
1227
- const selectedSecondarySurface = conversationScreen?.foreground.kind === 'secondary'
1228
- ? (conversationScreen.foreground.surface ?? null)
1229
- : null;
1230
- const selectedOverlays = conversationScreen?.foreground.kind === 'compose'
1231
- ? conversationScreen.foreground.overlays
1232
- : [];
1233
- const selectedCommandPalette = selectedOverlays.find((overlay) => overlay.kind === 'command-palette');
1234
- const selectedFilePicker = selectedOverlays.find((overlay) => overlay.kind === 'mention-picker');
1235
- const selectedExitConfirmation = selectedOverlays.find((overlay) => overlay.kind === 'exit-confirmation');
1236
1192
  const transcriptPageRows = conversationScreen?.transcript.pageRows ?? 2;
1237
1193
  const maxTranscriptScrollOffset = conversationScreen?.transcript.maxScrollOffset ?? 0;
1238
1194
  const permissionOptions = useMemo(() => [
@@ -6501,94 +6457,93 @@ export function InteractiveApp({ dataPlane = resolveDataPlane(), configRoot: sup
6501
6457
  return;
6502
6458
  }
6503
6459
  });
6504
- return (_jsx(TuiThemeProvider, { settings: themeSettings, screenReader: axScreenReader, children: _jsx(Box, { flexDirection: "column", ...(!fixedViewport
6505
- ? {}
6506
- : { height: rows, overflowY: 'hidden' }), children: ansiActive ? (_jsx(TuiAnsiSurface, { screen: screen, width: width, rows: rows, input: shellMode ? input.slice(1) : input, busy: busy, status: status, display: runtimeDisplay, ...(conversationScreen?.sessionLabel === undefined
6507
- ? {}
6508
- : { sessionLabel: conversationScreen.sessionLabel }), cursor: shellMode ? Math.max(0, inputCursor - 1) : inputCursor, screenReader: axScreenReader, onError: () => setAnsiRendererFailed(true) })) : screen.body.kind === 'session-picker' ? (_jsx(SessionPicker, { model: screen.body.surface, screenReader: axScreenReader })) : (_jsxs(_Fragment, { children: [screen.body.intro === 'welcome' ? (_jsx(WelcomePanel, { display: runtimeDisplay, width: width, showTips: runtimeSettings.tips })) : null, screen.body.sessionLabel ? (_jsxs(Text, { dimColor: true, children: ["Session ", screen.body.sessionLabel] })) : null, screen.body.intro === 'identity' ? (_jsx(SessionIdentity, { display: runtimeDisplay, width: width })) : null, _jsx(Box, { ...(fixedViewport
6509
- ? {
6510
- flexShrink: 1,
6511
- minHeight: 0,
6512
- overflowY: 'hidden',
6513
- }
6514
- : {}), children: _jsx(Transcript, { entries: screen.body.transcript.entries, activeText: screen.body.transcript.active.text, activeThinking: screen.body.transcript.active.thinking, activeStreamVisible: screen.body.transcript.active.visible, thinkingExpanded: thinkingExpanded, detailedTranscript: screen.body.transcript.readingMode !== 'normal', screenReader: axScreenReader }) }), selectedPriority?.kind === 'editor-wait' ? (_jsx(ExternalEditorWait, { screenReader: axScreenReader })) : selectedPriority?.kind === 'permission' ? (_jsx(PermissionSurface, { model: selectedPriority.surface, width: width, screenReader: axScreenReader })) : selectedPriority?.kind === 'plan-approval' ? (_jsx(DecisionSurface, { model: selectedPriority, width: width, screenReader: axScreenReader })) : selectedPriority?.kind === 'question' ? (_jsx(DecisionSurface, { model: selectedPriority, width: width, screenReader: axScreenReader })) : selectedPriority?.kind === 'elicitation' ? (_jsx(ElicitationSurface, { model: selectedPriority.surface, screenReader: axScreenReader })) : selectedSecondarySurface?.kind === 'model-input' ||
6515
- selectedSecondarySurface?.kind === 'export' ||
6516
- selectedSecondarySurface?.kind === 'copy' ||
6517
- selectedSecondarySurface?.kind === 'export-filename' ||
6518
- selectedSecondarySurface?.kind === 'compact-progress' ? (_jsx(LeafSurface, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface?.kind === 'rewind-panel' ? (selectedSecondarySurface.view === 'points' ? (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: " Rewind" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: [' ', "Restore the code and/or conversation to the point before\u2026"] }), _jsx(Text, { children: " " }), selectedSecondarySurface.window.start > 0 ? (_jsxs(Text, { dimColor: true, children: [' ', "\u2191 ", selectedSecondarySurface.window.start, " more above"] })) : null, selectedSecondarySurface.points
6519
- .slice(selectedSecondarySurface.window.start, selectedSecondarySurface.window.end)
6520
- .map((point, offset) => {
6521
- const index = selectedSecondarySurface.window.start + offset;
6522
- return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsx(DecisionOption, { selected: selectedSecondarySurface.selectedIndex === index, screenReader: axScreenReader, selectedPrefix: " \u276F ", unselectedPrefix: " ", children: point.prompt.replace(/\s+/gu, ' ').slice(0, 72) }), _jsxs(Text, { dimColor: true, children: [' ', point.fileChanges.length > 0
6523
- ? point.fileChanges
6524
- .map((path) => path.startsWith(`${runtimeCwd}/`)
6525
- ? path.slice(runtimeCwd.length + 1)
6526
- : path)
6527
- .join(', ')
6528
- : point.fileRestoreAvailable
6529
- ? 'No code changes'
6530
- : '⚠ No code restore'] })] }, point.messageId));
6531
- }), selectedSecondarySurface.window.end <
6532
- selectedSecondarySurface.points.length ? (_jsxs(Text, { dimColor: true, children: [' ', "\u2193", ' ', selectedSecondarySurface.points.length -
6533
- selectedSecondarySurface.window.end, ' ', "more below"] })) : null, _jsx(DecisionOption, { selected: selectedSecondarySurface.selectedIndex ===
6534
- selectedSecondarySurface.points.length, screenReader: axScreenReader, selectedPrefix: " \u276F ", unselectedPrefix: " ", children: "(current)" }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Enter to continue \u00B7 Esc to cancel" })] })) : selectedSecondarySurface.view === 'confirm' ? (_jsxs(DialogFrame, { title: "Confirm restore point", screenReader: axScreenReader, children: [_jsxs(Text, { children: ["\u2502 ", selectedSecondarySurface.point.prompt] }), _jsx(Text, { children: " " }), _jsx(Text, { children: "The conversation will be forked." }), _jsxs(Text, { children: ["The code will", ' ', selectedSecondarySurface.point.fileChanges.length > 0
6535
- ? `restore ${selectedSecondarySurface.point.fileChanges.join(', ')}.`
6536
- : 'be unchanged.'] }), _jsx(Text, { children: " " }), selectedSecondarySurface.actions.map((option, index) => (_jsxs(DecisionOption, { selected: selectedSecondarySurface.selectedIndex === index, screenReader: axScreenReader, children: [index + 1, ". ", option.label] }, option.action))), _jsx(Text, { children: " " }), _jsx(RewindWarning, {})] })) : (_jsxs(DialogFrame, { title: `Summarize ${selectedSecondarySurface.direction === 'from' ? 'from' : 'up to'} here`, screenReader: axScreenReader, children: [_jsx(Text, { children: selectedSecondarySurface.direction === 'from'
6537
- ? 'Messages after this point will be summarized.'
6538
- : 'Messages up to this point will be summarized.' }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["add context (optional): ", selectedSecondarySurface.context] }), _jsx(Text, { dimColor: true, children: "Enter to summarize \u00B7 Esc to go back" })] }))) : selectedSecondarySurface !== null && menu !== null ? (selectedSecondarySurface.kind === 'permission-dashboard' ||
6539
- selectedSecondarySurface.kind === 'permission-rule-input' ||
6540
- selectedSecondarySurface.kind === 'permission-scope' ||
6541
- selectedSecondarySurface.kind === 'permission-delete' ||
6542
- selectedSecondarySurface.kind === 'workspace-directory-input' ||
6543
- selectedSecondarySurface.kind === 'workspace-directory-delete' ? (_jsx(PermissionSurface, { model: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'mcp-panel' ? (_jsx(McpPanel, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'help' ? (_jsx(HelpMenu, { model: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'diff' ? (_jsx(DiffDashboard, { model: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'tasks-panel' ? (_jsx(TaskPanel, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'doctor-panel' ? (_jsx(DoctorDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'memory-panel' ? (_jsx(MemoryDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'hooks-panel' ? (_jsx(HookDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'config-panel' ? (_jsx(ConfigDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'sandbox-panel' ? (_jsx(SandboxDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'list-panel' ? (_jsx(ListDashboard, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'btw-panel' ? (_jsx(BtwPanel, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'model-panel' ? (_jsx(ModelMenu, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'effort-panel' ? (_jsx(EffortMenu, { surface: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'theme-panel' ? (_jsx(ThemePicker, { model: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'custom-theme-create' ? (_jsxs(DialogFrame, { title: "New custom theme", screenReader: axScreenReader, children: [_jsxs(Text, { children: ["Name: ", selectedSecondarySurface.name || 'my-theme'] }), _jsxs(Text, { children: ["based on ", selectedSecondarySurface.base, " \u00B7 saved to ~/", settingsDirectory, "/themes/theme.json"] }), _jsx(Text, { dimColor: true, children: "Enter to create \u00B7 Esc to cancel" })] })) : selectedSecondarySurface.kind === 'custom-theme-editor' ||
6544
- selectedSecondarySurface.kind === 'custom-theme-token' ? (_jsx(CustomThemeEditor, { model: selectedSecondarySurface, width: width, screenReader: axScreenReader })) : selectedSecondarySurface.kind === 'custom-theme-delete' ? (_jsxs(DialogFrame, { title: "Delete custom theme", screenReader: axScreenReader, children: [_jsxs(Text, { children: ["Delete ", selectedSecondarySurface.theme.name, " permanently?"] }), _jsx(Text, { dimColor: true, children: "Enter to confirm \u00B7 Esc to cancel" })] })) : null) : (_jsxs(_Fragment, { children: [selectedCommandPalette !== undefined ? (_jsx(CommandPalette, { model: selectedCommandPalette, width: width, screenReader: axScreenReader })) : null, selectedFilePicker !== undefined ? (_jsx(MentionPicker, { model: selectedFilePicker, width: width, screenReader: axScreenReader })) : null, selectedExitConfirmation !== undefined ? (_jsx(ExitWarning, {})) : null, fixedViewport ? _jsx(Box, { flexGrow: 1 }) : null, _jsx(Composer, { input: shellMode ? input.slice(1) : input, cursor: shellMode ? Math.max(0, inputCursor - 1) : inputCursor, shellMode: shellMode, ...(sessionColor === undefined ? {} : { sessionColor }), ...(commandArgumentHint === undefined
6545
- ? {}
6546
- : { commandArgumentHint }), busy: busy, clipboardBusy: clipboardBusy, status: status, display: runtimeDisplay, ...(usage === undefined ? {} : { usage }), ...(costUsd === undefined ? {} : { costUsd }), width: width, screenReader: axScreenReader, hasThinking: hasDetailedTranscript, thinkingExpanded: thinkingExpanded, reduceMotion: runtimeSettings.reduceMotion, progressBar: runtimeSettings.progressBar, ...(runtimeSettings.turnDuration
6547
- ? (() => {
6548
- const duration = formatTurnDuration(turnDuration);
6549
- return duration === undefined
6550
- ? {}
6551
- : { turnDuration: duration };
6552
- })()
6553
- : {}), editorMode: runtimeSettings.editor, ...(runtimeSettings.prStatus &&
6554
- activeSessionSummary?.prNumber
6555
- ? { prStatus: `PR #${activeSessionSummary.prNumber}` }
6556
- : {}), shortcutsVisible: shortcutsVisible, shortcutHelp: shortcutHelpSurface, ...(editorFooterMessage === undefined
6557
- ? {}
6558
- : { footerMessage: editorFooterMessage }) }), _jsx(StatusLine, { configRoot: keybindingsRoot, cwd: runtimeCwd, dataPlane: dataPlane, input: createClaudeStatusLineInput({
6559
- configRoot: keybindingsRoot,
6560
- cwd: runtimeCwd,
6561
- projectDir: display.cwd,
6562
- sessionId: sessionId ?? statusLineSessionId.current,
6563
- sessionName,
6564
- ...(runtimeDisplay.model === undefined
6565
- ? {}
6566
- : { model: runtimeDisplay.model }),
6567
- version: runtimeDisplay.version,
6568
- outputStyle: runtimeSettings.outputStyle,
6569
- permissionMode: runtimePreferences.permissionMode,
6570
- additionalDirectories: runtimePreferences.additionalDirectories,
6571
- dataPlane,
6572
- ...(usage === undefined ? {} : { usage }),
6573
- ...(costUsd === undefined ? {} : { costUsd }),
6574
- ...(runtimeDisplay.contextWindowTokens === undefined
6575
- ? {}
6576
- : {
6577
- contextWindowTokens: runtimeDisplay.contextWindowTokens,
6578
- }),
6579
- ...(runtimeSettings.editor === 'vim'
6580
- ? { vimMode: vimInsertMode ? 'INSERT' : 'NORMAL' }
6581
- : {}),
6582
- }), refreshKey: [
6583
- history.length,
6584
- runtimePreferences.permissionMode,
6585
- runtimeDisplay.model,
6586
- runtimeSettings.outputStyle,
6587
- vimInsertMode,
6588
- sessionName,
6589
- usage?.inputTokens,
6590
- usage?.outputTokens,
6591
- ].join(':'), width: width, ...(settingSources === undefined ? {} : { settingSources }) })] }))] })) }) }));
6460
+ const statusLineInput = useMemo(() => createClaudeStatusLineInput({
6461
+ configRoot: keybindingsRoot,
6462
+ cwd: runtimeCwd,
6463
+ projectDir: display.cwd,
6464
+ sessionId: sessionId ?? statusLineSessionId.current,
6465
+ sessionName,
6466
+ ...(runtimeDisplay.model === undefined
6467
+ ? {}
6468
+ : { model: runtimeDisplay.model }),
6469
+ version: runtimeDisplay.version,
6470
+ outputStyle: runtimeSettings.outputStyle,
6471
+ permissionMode: runtimePreferences.permissionMode,
6472
+ additionalDirectories: runtimePreferences.additionalDirectories,
6473
+ dataPlane,
6474
+ ...(usage === undefined ? {} : { usage }),
6475
+ ...(costUsd === undefined ? {} : { costUsd }),
6476
+ ...(runtimeDisplay.contextWindowTokens === undefined
6477
+ ? {}
6478
+ : { contextWindowTokens: runtimeDisplay.contextWindowTokens }),
6479
+ ...(runtimeSettings.editor === 'vim'
6480
+ ? { vimMode: vimInsertMode ? 'INSERT' : 'NORMAL' }
6481
+ : {}),
6482
+ }), [
6483
+ keybindingsRoot,
6484
+ runtimeCwd,
6485
+ display.cwd,
6486
+ sessionId,
6487
+ sessionName,
6488
+ runtimeDisplay.model,
6489
+ runtimeDisplay.version,
6490
+ runtimeSettings.outputStyle,
6491
+ runtimePreferences.permissionMode,
6492
+ runtimePreferences.additionalDirectories,
6493
+ dataPlane,
6494
+ usage,
6495
+ costUsd,
6496
+ runtimeDisplay.contextWindowTokens,
6497
+ runtimeSettings.editor,
6498
+ vimInsertMode,
6499
+ ]);
6500
+ const statusLineRefreshKey = [
6501
+ history.length,
6502
+ runtimePreferences.permissionMode,
6503
+ runtimeDisplay.model,
6504
+ runtimeSettings.outputStyle,
6505
+ vimInsertMode,
6506
+ sessionName,
6507
+ usage?.inputTokens,
6508
+ usage?.outputTokens,
6509
+ ].join(':');
6510
+ const configuredStatusLine = useClaudeStatusLine({
6511
+ configRoot: keybindingsRoot,
6512
+ cwd: runtimeCwd,
6513
+ dataPlane,
6514
+ input: statusLineInput,
6515
+ refreshKey: statusLineRefreshKey,
6516
+ width,
6517
+ ...(settingSources === undefined ? {} : { settingSources }),
6518
+ });
6519
+ const configuredStatusText = formatClaudeStatusLineState(configuredStatusLine, width);
6520
+ const conciseStatus = [
6521
+ status,
6522
+ editorFooterMessage
6523
+ ? `${editorFooterMessage.isError ? 'Error: ' : ''}${editorFooterMessage.text}`
6524
+ : undefined,
6525
+ configuredStatusText,
6526
+ ]
6527
+ .filter((value, index, values) => Boolean(value) && (index === 0 || value !== values[index - 1]))
6528
+ .join(' · ');
6529
+ const quietFrame = useMemo(() => projectQuietScreenFrame({
6530
+ screen,
6531
+ composerText: shellMode ? input.slice(1) : input,
6532
+ composerCursor: shellMode ? Math.max(0, inputCursor - 1) : inputCursor,
6533
+ shellMode,
6534
+ busy,
6535
+ status: conciseStatus,
6536
+ display: runtimeDisplay,
6537
+ }), [
6538
+ screen,
6539
+ shellMode,
6540
+ input,
6541
+ inputCursor,
6542
+ busy,
6543
+ conciseStatus,
6544
+ runtimeDisplay,
6545
+ ]);
6546
+ return (_jsx(TuiThemeProvider, { settings: themeSettings, screenReader: axScreenReader, children: ansiActive ? (_jsx(TuiAnsiSurface, { frame: quietFrame, onError: () => setAnsiRendererFailed(true) })) : (_jsx(QuietInkFrame, { frame: quietFrame, screenReader: axScreenReader })) }));
6592
6547
  }
6593
6548
  /**
6594
6549
  * Whether the user explicitly saved a `tui` renderer value in configuration.
@@ -6624,10 +6579,11 @@ export async function runInteractive(options) {
6624
6579
  // fallback for screen-reader and non-interactive execution, and an explicit
6625
6580
  // renderer saved in configuration is honored over the default.
6626
6581
  const rendererExplicitlyConfigured = await tuiRendererExplicitlyConfigured(runtimeSettingsTarget);
6582
+ const interactiveTty = process.stdin.isTTY === true && process.stdout.isTTY === true;
6627
6583
  let currentRenderer = resolveTuiRenderer({
6628
6584
  configured: currentRuntimeSettings.tui,
6629
6585
  explicitlyConfigured: rendererExplicitlyConfigured,
6630
- interactiveTty: process.stdin.isTTY === true,
6586
+ interactiveTty,
6631
6587
  screenReader: options.axScreenReader ?? false,
6632
6588
  });
6633
6589
  if (currentRenderer !== currentRuntimeSettings.tui) {
@@ -6726,7 +6682,7 @@ export async function runInteractive(options) {
6726
6682
  let backgrounded;
6727
6683
  rendererChange = null;
6728
6684
  const ansiRendererEnabled = currentRenderer === 'fullscreen' &&
6729
- process.stdin.isTTY === true &&
6685
+ interactiveTty &&
6730
6686
  options.axScreenReader !== true;
6731
6687
  const instance = render(_jsx(InteractiveApp, { dataPlane: dataPlane, configRoot: configRoot, statePath: statePath, factory: options.factory, initialSessions: initialSessions, slashCommands: initialSlashCommands, agents: initialAgents, initialHistory: history, ...(initialSessionColor === undefined ? {} : { initialSessionColor }), runtimeSettings: currentRuntimeSettings, runtimeSettingsTarget: runtimeSettingsTarget, ...(options.settingSources === undefined
6732
6688
  ? {}
@@ -52,6 +52,8 @@ export interface CliControls {
52
52
  rewindFiles?: string;
53
53
  name: string | undefined;
54
54
  sessionPersistence: boolean;
55
+ provider?: string;
56
+ providerProfile?: string;
55
57
  model?: string;
56
58
  effort?: 'low' | 'medium' | 'high' | 'xhigh' | 'max';
57
59
  thinking?: CliThinkingMode;
@@ -114,6 +116,9 @@ export interface CliInvocation extends CliControls {
114
116
  mcpClientSecret: boolean;
115
117
  mcpNoBrowser: boolean;
116
118
  mcpDebug: boolean;
119
+ /** Auth-command-only profile selector; distinct from providerProfile. */
120
+ authProfile?: string;
121
+ authDevice: boolean;
117
122
  }
118
123
  export interface StreamUserMessage {
119
124
  message: {
@@ -387,6 +387,8 @@ export function parseCliInvocation(argv) {
387
387
  let worktreeRequested = false;
388
388
  let tmux;
389
389
  let model;
390
+ let provider;
391
+ let providerProfile;
390
392
  let effort;
391
393
  let thinking;
392
394
  let maxThinkingTokens;
@@ -404,6 +406,8 @@ export function parseCliInvocation(argv) {
404
406
  let mcpClientSecret = false;
405
407
  let mcpNoBrowser = false;
406
408
  let mcpDebug = false;
409
+ let authProfile;
410
+ let authDevice = false;
407
411
  for (let index = 0; index < argv.length; index += 1) {
408
412
  const value = argv[index];
409
413
  if (value === undefined)
@@ -444,6 +448,30 @@ export function parseCliInvocation(argv) {
444
448
  index += selectedModel.consumed;
445
449
  continue;
446
450
  }
451
+ const selectedProvider = optionValue(argv, index, '--provider');
452
+ if (selectedProvider) {
453
+ if (provider !== undefined)
454
+ throw new Error('--provider may only be specified once');
455
+ provider = selectedProvider.value;
456
+ index += selectedProvider.consumed;
457
+ continue;
458
+ }
459
+ const selectedProviderProfile = optionValue(argv, index, '--provider-profile');
460
+ if (selectedProviderProfile) {
461
+ if (providerProfile !== undefined)
462
+ throw new Error('--provider-profile may only be specified once');
463
+ providerProfile = selectedProviderProfile.value;
464
+ index += selectedProviderProfile.consumed;
465
+ continue;
466
+ }
467
+ const selectedAuthProfile = optionValue(argv, index, '--profile');
468
+ if (selectedAuthProfile) {
469
+ if (authProfile !== undefined)
470
+ throw new Error('--profile may only be specified once');
471
+ authProfile = selectedAuthProfile.value;
472
+ index += selectedAuthProfile.consumed;
473
+ continue;
474
+ }
447
475
  const selectedAutocompact = optionValue(argv, index, '--autocompact');
448
476
  if (selectedAutocompact) {
449
477
  if (autocompact !== undefined)
@@ -1123,6 +1151,10 @@ export function parseCliInvocation(argv) {
1123
1151
  mcpNoBrowser = true;
1124
1152
  continue;
1125
1153
  }
1154
+ if (value === '--device') {
1155
+ authDevice = true;
1156
+ continue;
1157
+ }
1126
1158
  if (value === '--json') {
1127
1159
  legacyJson = true;
1128
1160
  continue;
@@ -1174,6 +1206,14 @@ export function parseCliInvocation(argv) {
1174
1206
  if (debug !== undefined && args[0] === 'mcp' && args[1] === 'serve') {
1175
1207
  mcpDebug = true;
1176
1208
  }
1209
+ if (authProfile !== undefined && args[0] !== 'auth')
1210
+ throw new Error('--profile is only valid with auth commands');
1211
+ if (authDevice && !(args[0] === 'auth' && args[1] === 'login'))
1212
+ throw new Error('--device is only valid with auth login');
1213
+ if (mcpNoBrowser &&
1214
+ !((args[0] === 'mcp' && args[1] === 'login') ||
1215
+ (args[0] === 'auth' && args[1] === 'login')))
1216
+ throw new Error('--no-browser is only valid with mcp login or auth login');
1177
1217
  if (background && print) {
1178
1218
  throw new Error("--bg and --print conflict: --print never starts the interactive session that `claude agents` attaches to, so the job would be unattachable. The prompt is the positional — drop --print: `claude --bg '<task>'`.");
1179
1219
  }
@@ -1215,6 +1255,7 @@ export function parseCliInvocation(argv) {
1215
1255
  'plugin',
1216
1256
  'doctor',
1217
1257
  'import',
1258
+ 'auth',
1218
1259
  ].includes(args[0] ?? '');
1219
1260
  if (promptSuggestions &&
1220
1261
  !managementCommand &&
@@ -1385,6 +1426,8 @@ export function parseCliInvocation(argv) {
1385
1426
  ...(worktreeRequested ? { worktreeRequested: true } : {}),
1386
1427
  ...(tmux === undefined ? {} : { tmux }),
1387
1428
  ...(model === undefined ? {} : { model }),
1429
+ ...(provider === undefined ? {} : { provider }),
1430
+ ...(providerProfile === undefined ? {} : { providerProfile }),
1388
1431
  ...(effort === undefined ? {} : { effort }),
1389
1432
  ...(thinking === undefined ? {} : { thinking }),
1390
1433
  ...(maxThinkingTokens === undefined ? {} : { maxThinkingTokens }),
@@ -1402,6 +1445,8 @@ export function parseCliInvocation(argv) {
1402
1445
  mcpClientSecret,
1403
1446
  mcpNoBrowser,
1404
1447
  mcpDebug,
1448
+ ...(authProfile === undefined ? {} : { authProfile }),
1449
+ authDevice,
1405
1450
  };
1406
1451
  }
1407
1452
  function parseUserMessage(value, lineNumber) {
@@ -0,0 +1,32 @@
1
+ import { type ProviderCredentialKey, type ProviderCredentialMetadata, type ProviderCredentialInput, type ProviderCredentialRecord } from '../persistence/provider-credential-vault.js';
2
+ import { deviceLoginWithCodexOAuth, loginWithCodexOAuth } from '../providers/codex-oauth.js';
3
+ export interface ProviderAuthCommandIO {
4
+ stdout(message: string): void;
5
+ stderr?(message: string): void;
6
+ readSecret?(prompt: string, signal?: AbortSignal): Promise<string>;
7
+ }
8
+ export interface ProviderAuthVault {
9
+ read(key: ProviderCredentialKey): Promise<ProviderCredentialRecord | undefined>;
10
+ list(): Promise<ProviderCredentialMetadata[]>;
11
+ modify(key: ProviderCredentialKey, callback: (current: ProviderCredentialRecord | undefined) => ProviderCredentialInput | undefined | Promise<ProviderCredentialInput | undefined>): Promise<ProviderCredentialRecord | undefined>;
12
+ delete(key: ProviderCredentialKey): Promise<void>;
13
+ }
14
+ export interface ProviderAuthCommandOptions {
15
+ io: ProviderAuthCommandIO;
16
+ vault?: ProviderAuthVault;
17
+ configRoot?: string;
18
+ cwd?: string;
19
+ environment?: Readonly<Record<string, string | undefined>>;
20
+ signal?: AbortSignal;
21
+ profile?: string;
22
+ providerProfile?: string;
23
+ noBrowser?: boolean;
24
+ json?: boolean;
25
+ device?: boolean;
26
+ loginWithCodexOAuth?: typeof loginWithCodexOAuth;
27
+ deviceLoginWithCodexOAuth?: typeof deviceLoginWithCodexOAuth;
28
+ assertCodexLoginEnabled?: (profileId: string) => Promise<void>;
29
+ }
30
+ export declare function secretLine(value: string): string;
31
+ export declare function executeProviderAuthCommand(args: readonly string[], options: ProviderAuthCommandOptions): Promise<number>;
32
+ //# sourceMappingURL=provider-auth-command.d.ts.map