@namzu/cli 13.0.0 → 14.0.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.
- package/README.md +11 -2
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +79 -21
- package/dist/commands/login.js.map +1 -1
- package/dist/doctor/checks/credentials.d.ts.map +1 -1
- package/dist/doctor/checks/credentials.js +7 -1
- package/dist/doctor/checks/credentials.js.map +1 -1
- package/dist/integrations/providers/codex-device-login.d.ts +27 -0
- package/dist/integrations/providers/codex-device-login.d.ts.map +1 -0
- package/dist/integrations/providers/codex-device-login.js +195 -0
- package/dist/integrations/providers/codex-device-login.js.map +1 -0
- package/dist/integrations/providers/codex-oauth.d.ts +10 -0
- package/dist/integrations/providers/codex-oauth.d.ts.map +1 -0
- package/dist/integrations/providers/codex-oauth.js +95 -0
- package/dist/integrations/providers/codex-oauth.js.map +1 -0
- package/dist/integrations/providers/credential-store.d.ts +23 -4
- package/dist/integrations/providers/credential-store.d.ts.map +1 -1
- package/dist/integrations/providers/credential-store.js +125 -19
- package/dist/integrations/providers/credential-store.js.map +1 -1
- package/dist/integrations/providers/discover.d.ts +25 -13
- package/dist/integrations/providers/discover.d.ts.map +1 -1
- package/dist/integrations/providers/discover.js +98 -44
- package/dist/integrations/providers/discover.js.map +1 -1
- package/dist/integrations/providers/harness-credentials.d.ts +36 -0
- package/dist/integrations/providers/harness-credentials.d.ts.map +1 -0
- package/dist/integrations/providers/harness-credentials.js +146 -0
- package/dist/integrations/providers/harness-credentials.js.map +1 -0
- package/dist/integrations/providers/identity.d.ts +8 -15
- package/dist/integrations/providers/identity.d.ts.map +1 -1
- package/dist/integrations/providers/identity.js +8 -15
- package/dist/integrations/providers/identity.js.map +1 -1
- package/dist/integrations/providers/index.d.ts +5 -2
- package/dist/integrations/providers/index.d.ts.map +1 -1
- package/dist/integrations/providers/index.js +4 -1
- package/dist/integrations/providers/index.js.map +1 -1
- package/dist/integrations/providers/oauth.d.ts +2 -2
- package/dist/integrations/providers/oauth.d.ts.map +1 -1
- package/dist/integrations/providers/oauth.js +8 -5
- package/dist/integrations/providers/oauth.js.map +1 -1
- package/dist/integrations/providers/register.d.ts.map +1 -1
- package/dist/integrations/providers/register.js +9 -1
- package/dist/integrations/providers/register.js.map +1 -1
- package/dist/integrations/providers/registry.d.ts +8 -1
- package/dist/integrations/providers/registry.d.ts.map +1 -1
- package/dist/integrations/providers/registry.js +29 -0
- package/dist/integrations/providers/registry.js.map +1 -1
- package/dist/tui/App.d.ts.map +1 -1
- package/dist/tui/App.js +77 -64
- package/dist/tui/App.js.map +1 -1
- package/dist/tui/Picker.d.ts +5 -3
- package/dist/tui/Picker.d.ts.map +1 -1
- package/dist/tui/Picker.js +70 -22
- package/dist/tui/Picker.js.map +1 -1
- package/dist/tui/agent.d.ts.map +1 -1
- package/dist/tui/agent.js +107 -16
- package/dist/tui/agent.js.map +1 -1
- package/dist/tui/login-prompt.d.ts +5 -0
- package/dist/tui/login-prompt.d.ts.map +1 -1
- package/dist/tui/login-prompt.js +14 -0
- package/dist/tui/login-prompt.js.map +1 -1
- package/dist/tui/slashCommands.js +1 -1
- package/dist/tui/slashCommands.js.map +1 -1
- package/package.json +5 -5
|
@@ -15,7 +15,25 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
15
15
|
envVars: ['ANTHROPIC_API_KEY', 'ANTHROPIC_TOKEN', 'CLAUDE_CODE_OAUTH_TOKEN'],
|
|
16
16
|
defaultModel: 'claude-opus-5',
|
|
17
17
|
requiresApiKey: true,
|
|
18
|
+
acceptsTypedCredential: true,
|
|
19
|
+
subscriptionLogin: 'browser',
|
|
18
20
|
constructible: true,
|
|
21
|
+
driverPackage: '@namzu/anthropic',
|
|
22
|
+
},
|
|
23
|
+
codex: {
|
|
24
|
+
id: 'codex',
|
|
25
|
+
label: 'OpenAI (Codex subscription)',
|
|
26
|
+
// A Codex subscription token is never accepted through an environment
|
|
27
|
+
// variable here. It is a Responses credential with account routing, not
|
|
28
|
+
// an OpenAI API key; discovery reads its complete owned envelope instead.
|
|
29
|
+
envVars: [],
|
|
30
|
+
defaultBaseUrl: 'https://chatgpt.com/backend-api/codex',
|
|
31
|
+
defaultModel: 'gpt-5.6-sol',
|
|
32
|
+
requiresApiKey: true,
|
|
33
|
+
acceptsTypedCredential: false,
|
|
34
|
+
subscriptionLogin: 'device',
|
|
35
|
+
constructible: true,
|
|
36
|
+
driverPackage: '@namzu/openai',
|
|
19
37
|
},
|
|
20
38
|
openai: {
|
|
21
39
|
id: 'openai',
|
|
@@ -23,7 +41,9 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
23
41
|
envVars: ['OPENAI_API_KEY'],
|
|
24
42
|
defaultModel: 'gpt-4o',
|
|
25
43
|
requiresApiKey: true,
|
|
44
|
+
acceptsTypedCredential: true,
|
|
26
45
|
constructible: true,
|
|
46
|
+
driverPackage: '@namzu/openai',
|
|
27
47
|
},
|
|
28
48
|
deepseek: {
|
|
29
49
|
id: 'deepseek',
|
|
@@ -35,7 +55,9 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
35
55
|
// were discontinued on 2026-07-24 and resolve to nothing.
|
|
36
56
|
defaultModel: 'deepseek-v4-flash',
|
|
37
57
|
requiresApiKey: true,
|
|
58
|
+
acceptsTypedCredential: true,
|
|
38
59
|
constructible: true,
|
|
60
|
+
driverPackage: '@namzu/deepseek',
|
|
39
61
|
},
|
|
40
62
|
openrouter: {
|
|
41
63
|
id: 'openrouter',
|
|
@@ -44,7 +66,9 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
44
66
|
defaultBaseUrl: 'https://openrouter.ai/api/v1',
|
|
45
67
|
defaultModel: 'anthropic/claude-opus-5',
|
|
46
68
|
requiresApiKey: true,
|
|
69
|
+
acceptsTypedCredential: true,
|
|
47
70
|
constructible: true,
|
|
71
|
+
driverPackage: '@namzu/openrouter',
|
|
48
72
|
},
|
|
49
73
|
ollama: {
|
|
50
74
|
id: 'ollama',
|
|
@@ -54,7 +78,9 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
54
78
|
probeUrl: 'http://localhost:11434/api/tags',
|
|
55
79
|
defaultModel: 'llama3.2',
|
|
56
80
|
requiresApiKey: false,
|
|
81
|
+
acceptsTypedCredential: false,
|
|
57
82
|
constructible: true,
|
|
83
|
+
driverPackage: '@namzu/ollama',
|
|
58
84
|
},
|
|
59
85
|
lmstudio: {
|
|
60
86
|
id: 'lmstudio',
|
|
@@ -64,6 +90,7 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
64
90
|
probeUrl: 'http://localhost:1234/v1/models',
|
|
65
91
|
defaultModel: 'auto',
|
|
66
92
|
requiresApiKey: false,
|
|
93
|
+
acceptsTypedCredential: false,
|
|
67
94
|
constructible: false,
|
|
68
95
|
},
|
|
69
96
|
bedrock: {
|
|
@@ -81,6 +108,7 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
81
108
|
// means this build cannot construct the driver at all.
|
|
82
109
|
defaultModel: 'anthropic.claude-opus-4-7-v1:0',
|
|
83
110
|
requiresApiKey: true,
|
|
111
|
+
acceptsTypedCredential: true,
|
|
84
112
|
constructible: false,
|
|
85
113
|
},
|
|
86
114
|
http: {
|
|
@@ -91,6 +119,7 @@ export const PROVIDER_REGISTRY = Object.freeze({
|
|
|
91
119
|
envVars: [],
|
|
92
120
|
defaultModel: 'gpt-4o',
|
|
93
121
|
requiresApiKey: true,
|
|
122
|
+
acceptsTypedCredential: true,
|
|
94
123
|
constructible: false,
|
|
95
124
|
},
|
|
96
125
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/integrations/providers/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/tui/App.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/tui/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAMN,KAAK,OAAO,EAYZ,MAAM,YAAY,CAAA;AA+GnB,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAG/D,MAAM,WAAW,QAAQ;IACxB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CACxB;AA2CD,sEAAsE;AACtE,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,MAAM,EAAE,MAAM,MAAM,EACpB,iBAAiB,GAAE,SAAS,MAAM,EAAO,GACvC,SAAS,iBAAiB,EAAE,CA4D9B;AAgED,wBAAgB,GAAG,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,QAAQ,2CA+vGhD"}
|
package/dist/tui/App.js
CHANGED
|
@@ -11,45 +11,45 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
11
11
|
* 4. If discovery returned zero providers → show <Picker/> in
|
|
12
12
|
* empty-state mode (explains where to put credentials).
|
|
13
13
|
*/
|
|
14
|
-
import { DiskMessageFeedbackStore, GoalRoundLimitError, HostCommandRegistry, SessionGoalActivation, StaleGoalError, kernelHostCommands, createAssistantMessage, createUserMessage, generateRunId, isCompactionMessage, } from '@namzu/sdk';
|
|
15
|
-
import { Box, Text, useApp, useInput, useStdout } from 'ink';
|
|
16
14
|
import { join, relative } from 'node:path';
|
|
15
|
+
import { DiskMessageFeedbackStore, GoalRoundLimitError, HostCommandRegistry, SessionGoalActivation, StaleGoalError, createAssistantMessage, createUserMessage, generateRunId, isCompactionMessage, kernelHostCommands, } from '@namzu/sdk';
|
|
16
|
+
import { Box, Text, useApp, useInput, useStdout } from 'ink';
|
|
17
17
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
18
|
-
import { visibleProjectInstructionPath } from '../context/project-path.js';
|
|
19
18
|
import { pinTrustedProjectPath, resolveTrustedProjectContext, } from '../config/trusted-project-context.js';
|
|
20
|
-
import {
|
|
19
|
+
import { visibleProjectInstructionPath } from '../context/project-path.js';
|
|
21
20
|
import { writeClipboardText } from '../integrations/clipboard/text.js';
|
|
22
21
|
import { terminalNotificationEnabled, writeTerminalNotification, } from '../integrations/notifications/terminal.js';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
22
|
+
import { beginCodexDeviceLogin, beginSubscriptionLogin, clearAllStoredCredentials, credentialsPath, primaryProvider, readStoredCodexCredential, readStoredSubscriptionCredential, writePreferences, } from '../integrations/providers/index.js';
|
|
23
|
+
import { appendMessages, forkConversation, forkConversationBeforeUser, listRecent, loadConversation, openSessions, replaceConversation, requireWritableConversation, setTitle, startConversation, titleOf, } from '../integrations/sessions/store.js';
|
|
24
|
+
import { conversationMarkdown, writeConversationExport, } from '../integrations/sessions/transcript-export.js';
|
|
25
25
|
import { isTrusted, trustDir } from '../integrations/trust/store.js';
|
|
26
|
+
import { checkUpdates } from '../integrations/updates.js';
|
|
26
27
|
import { appendMemory, composeMemoryPrompt, readMemory } from '../memory/store.js';
|
|
27
28
|
import { composeSkillsPrompt, discoverSkills, loadSkillBody } from '../skills/store.js';
|
|
28
|
-
import {
|
|
29
|
-
import { LiveActivity, formatElapsed } from './LiveActivity.js';
|
|
30
|
-
import { bottomSpacerRows } from './bottom-spacer.js';
|
|
31
|
-
import { expandFileMentions } from './mentions.js';
|
|
29
|
+
import { discoverUserCommands } from '../user-commands/store.js';
|
|
32
30
|
import { Composer } from './Composer.js';
|
|
33
31
|
import { EditPromptPicker } from './EditPromptPicker.js';
|
|
34
|
-
import {
|
|
35
|
-
import { NAMZU_MARK, NAMZU_MARK_COLOR, NAMZU_WORDMARK, NAMZU_WORDMARK_GRADIENT, NAMZU_WORDMARK_MIN_WIDTH, } from './logo.js';
|
|
32
|
+
import { LiveActivity, formatElapsed } from './LiveActivity.js';
|
|
36
33
|
import { PermissionOverlay } from './PermissionOverlay.js';
|
|
37
|
-
import { approvalIsDeliberate } from './consent-timing.js';
|
|
38
34
|
import { Picker } from './Picker.js';
|
|
35
|
+
import { ResumePicker } from './ResumePicker.js';
|
|
39
36
|
import { StatusBar } from './StatusBar.js';
|
|
40
37
|
import { Transcript, willCollapse } from './Transcript.js';
|
|
41
|
-
import {
|
|
42
|
-
import { appendMessages, forkConversation, forkConversationBeforeUser, listRecent, loadConversation, openSessions, replaceConversation, requireWritableConversation, setTitle, startConversation, titleOf, } from '../integrations/sessions/store.js';
|
|
43
|
-
import { conversationMarkdown, writeConversationExport, } from '../integrations/sessions/transcript-export.js';
|
|
38
|
+
import { TrustPrompt } from './TrustPrompt.js';
|
|
44
39
|
import { createAgentSession, probeAgentSession, } from './agent.js';
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
40
|
+
import { bottomSpacerRows } from './bottom-spacer.js';
|
|
41
|
+
import { keepRecentRows } from './compact-transcript.js';
|
|
42
|
+
import { approvalIsDeliberate } from './consent-timing.js';
|
|
47
43
|
import { planTurnPublication } from './conversation-history.js';
|
|
48
|
-
import {
|
|
44
|
+
import { editablePrompts } from './edit-prompts.js';
|
|
45
|
+
import { liveWindow, transcriptLines } from './live-window.js';
|
|
46
|
+
import { describeCodexDeviceLoginStart, describeLoginOutcome, describeLoginStart, describeLogout, } from './login-prompt.js';
|
|
47
|
+
import { NAMZU_MARK, NAMZU_MARK_COLOR, NAMZU_WORDMARK, NAMZU_WORDMARK_GRADIENT, NAMZU_WORDMARK_MIN_WIDTH, } from './logo.js';
|
|
48
|
+
import { expandFileMentions } from './mentions.js';
|
|
49
|
+
import { openInBrowser } from './open-browser.js';
|
|
49
50
|
import { hostCommandNames, kernelCommandDescriptors, mergeHostCommands, renderOutcome, reviewPrompt, runSlash, } from './slashCommands.js';
|
|
50
51
|
import { splitCompleteBlocks } from './stream-blocks.js';
|
|
51
52
|
import { theme } from './theme.js';
|
|
52
|
-
import { keepRecentRows } from './compact-transcript.js';
|
|
53
53
|
import { renderWorkspaceDiff, workspaceDiff } from './workspace-diff.js';
|
|
54
54
|
/** Last non-empty assistant text in a durable conversation, newest first. */
|
|
55
55
|
function latestAssistantOutput(messages) {
|
|
@@ -213,6 +213,8 @@ export function App({ ctx: initialCtx }) {
|
|
|
213
213
|
* chosen yet would be answering a question that was not asked.
|
|
214
214
|
*/
|
|
215
215
|
const [keyEntryFor, setKeyEntryFor] = useState(null);
|
|
216
|
+
/** Which decision owns the next picker mount. */
|
|
217
|
+
const [pickerInitialView, setPickerInitialView] = useState('providers');
|
|
216
218
|
/** The chain read from disk, held while the picker repairs its credential. */
|
|
217
219
|
const savedPrefsRef = useRef(null);
|
|
218
220
|
/**
|
|
@@ -328,12 +330,15 @@ export function App({ ctx: initialCtx }) {
|
|
|
328
330
|
* which the code that comes back cannot be exchanged for anything.
|
|
329
331
|
*/
|
|
330
332
|
const loginRef = useRef(null);
|
|
333
|
+
const codexLoginRef = useRef(null);
|
|
331
334
|
const loginAbortCleanupRef = useRef(null);
|
|
332
335
|
const cancelPendingLogin = useCallback(() => {
|
|
333
336
|
loginAbortCleanupRef.current?.();
|
|
334
337
|
loginAbortCleanupRef.current = null;
|
|
335
338
|
loginRef.current?.cancel();
|
|
336
339
|
loginRef.current = null;
|
|
340
|
+
codexLoginRef.current?.cancel();
|
|
341
|
+
codexLoginRef.current = null;
|
|
337
342
|
}, []);
|
|
338
343
|
const runProbeRef = useRef(null);
|
|
339
344
|
useEffect(() => cancelPendingLogin, [cancelPendingLogin]);
|
|
@@ -651,9 +656,9 @@ export function App({ ctx: initialCtx }) {
|
|
|
651
656
|
/**
|
|
652
657
|
* Sign in to a subscription without leaving namzu.
|
|
653
658
|
*
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
*
|
|
659
|
+
* A bare `/login` no longer guesses a provider: it mounts the subscription
|
|
660
|
+
* picker first. The argument form remains the paste-completion half of the
|
|
661
|
+
* browser-callback attempt already in flight.
|
|
657
662
|
*
|
|
658
663
|
* ## Why it re-probes instead of installing the credential directly
|
|
659
664
|
*
|
|
@@ -681,46 +686,17 @@ export function App({ ctx: initialCtx }) {
|
|
|
681
686
|
loginAbortCleanupRef.current?.();
|
|
682
687
|
loginAbortCleanupRef.current = null;
|
|
683
688
|
pushMessage('system', describeLoginOutcome(outcome));
|
|
684
|
-
if (outcome.ok)
|
|
689
|
+
if (outcome.ok) {
|
|
690
|
+
setPickerInitialView('providers');
|
|
685
691
|
await runProbeRef.current?.();
|
|
692
|
+
}
|
|
686
693
|
return;
|
|
687
694
|
}
|
|
688
695
|
cancelPendingLogin();
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
catch (err) {
|
|
694
|
-
pushMessage('system', `Could not start a sign-in: ${err instanceof Error ? err.message : String(err)}`);
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
loginRef.current = start;
|
|
698
|
-
pushMessage('system', describeLoginStart({
|
|
699
|
-
url: start.url,
|
|
700
|
-
loopback: start.loopback,
|
|
701
|
-
browserOpened: openInBrowser(start.url),
|
|
702
|
-
}));
|
|
703
|
-
// The automatic half, when there is one. Not awaited by the caller:
|
|
704
|
-
// the composer stays live throughout, so the operator can paste
|
|
705
|
-
// instead — or type anything else — while this waits.
|
|
706
|
-
const waiting = start.waitForCallback();
|
|
707
|
-
if (!waiting)
|
|
708
|
-
return;
|
|
709
|
-
const outcome = await waiting;
|
|
710
|
-
if (loginRef.current !== start)
|
|
711
|
-
return; // superseded, or finished by paste
|
|
712
|
-
loginRef.current = null;
|
|
713
|
-
loginAbortCleanupRef.current?.();
|
|
714
|
-
loginAbortCleanupRef.current = null;
|
|
715
|
-
start.cancel();
|
|
716
|
-
// A cancelled listener resolves to a refusal, and saying "sign-in
|
|
717
|
-
// failed" when the operator finished it another way would be a lie
|
|
718
|
-
// about their own successful login.
|
|
719
|
-
if (!outcome.ok && outcome.reason.includes('cancelled'))
|
|
720
|
-
return;
|
|
721
|
-
pushMessage('system', describeLoginOutcome(outcome));
|
|
722
|
-
if (outcome.ok)
|
|
723
|
-
await runProbeRef.current?.();
|
|
696
|
+
setPickerNotice(null);
|
|
697
|
+
setKeyEntryFor(null);
|
|
698
|
+
setPickerInitialView('subscriptions');
|
|
699
|
+
setPhase('picker');
|
|
724
700
|
}, [cancelPendingLogin, pushMessage]);
|
|
725
701
|
/**
|
|
726
702
|
* Sign in from the PICKER, where the transcript does not exist.
|
|
@@ -737,10 +713,43 @@ export function App({ ctx: initialCtx }) {
|
|
|
737
713
|
* no-browser case is handed to `namzu login`, which reads the pasted
|
|
738
714
|
* address from standard input and exists for exactly that machine.
|
|
739
715
|
*/
|
|
740
|
-
const startLoginFromPicker = useCallback(async (signal) => {
|
|
716
|
+
const startLoginFromPicker = useCallback(async (provider, signal) => {
|
|
741
717
|
if (signal.aborted)
|
|
742
718
|
return;
|
|
743
719
|
cancelPendingLogin();
|
|
720
|
+
if (provider === 'codex') {
|
|
721
|
+
let start;
|
|
722
|
+
try {
|
|
723
|
+
start = await beginCodexDeviceLogin({ signal });
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (!signal.aborted) {
|
|
727
|
+
setPickerNotice(`Could not start Codex sign-in: ${error instanceof Error ? error.message : String(error)}`);
|
|
728
|
+
}
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
if (signal.aborted) {
|
|
732
|
+
start.cancel();
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
codexLoginRef.current = start;
|
|
736
|
+
setPickerNotice(describeCodexDeviceLoginStart({
|
|
737
|
+
url: start.url,
|
|
738
|
+
userCode: start.userCode,
|
|
739
|
+
browserOpened: openInBrowser(start.url),
|
|
740
|
+
}));
|
|
741
|
+
const outcome = await start.waitForCompletion();
|
|
742
|
+
if (codexLoginRef.current !== start || signal.aborted)
|
|
743
|
+
return;
|
|
744
|
+
codexLoginRef.current = null;
|
|
745
|
+
start.cancel();
|
|
746
|
+
setPickerNotice(describeLoginOutcome(outcome));
|
|
747
|
+
if (outcome.ok) {
|
|
748
|
+
setPickerInitialView('providers');
|
|
749
|
+
await runProbeRef.current?.(signal);
|
|
750
|
+
}
|
|
751
|
+
return;
|
|
752
|
+
}
|
|
744
753
|
let start;
|
|
745
754
|
try {
|
|
746
755
|
start = await beginSubscriptionLogin({ signal });
|
|
@@ -793,8 +802,10 @@ export function App({ ctx: initialCtx }) {
|
|
|
793
802
|
if (!outcome.ok && outcome.reason.includes('cancelled'))
|
|
794
803
|
return;
|
|
795
804
|
setPickerNotice(describeLoginOutcome(outcome));
|
|
796
|
-
if (outcome.ok)
|
|
805
|
+
if (outcome.ok) {
|
|
806
|
+
setPickerInitialView('providers');
|
|
797
807
|
await runProbeRef.current?.(signal);
|
|
808
|
+
}
|
|
798
809
|
}, [cancelPendingLogin]);
|
|
799
810
|
const runProbe = useCallback(async (signal) => {
|
|
800
811
|
try {
|
|
@@ -1948,6 +1959,7 @@ export function App({ ctx: initialCtx }) {
|
|
|
1948
1959
|
// been solved — the session behind this picker is running.
|
|
1949
1960
|
setPickerNotice(null);
|
|
1950
1961
|
setKeyEntryFor(null);
|
|
1962
|
+
setPickerInitialView('providers');
|
|
1951
1963
|
setPhase('picker');
|
|
1952
1964
|
return;
|
|
1953
1965
|
case 'permission-mode': {
|
|
@@ -2007,9 +2019,9 @@ export function App({ ctx: initialCtx }) {
|
|
|
2007
2019
|
return;
|
|
2008
2020
|
case 'logout': {
|
|
2009
2021
|
const path = credentialsPath();
|
|
2010
|
-
const had = readStoredSubscriptionCredential() !== null;
|
|
2022
|
+
const had = readStoredSubscriptionCredential() !== null || readStoredCodexCredential() !== null;
|
|
2011
2023
|
try {
|
|
2012
|
-
|
|
2024
|
+
clearAllStoredCredentials();
|
|
2013
2025
|
}
|
|
2014
2026
|
catch (err) {
|
|
2015
2027
|
pushMessage('system', `Could not remove ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -2729,6 +2741,7 @@ export function App({ ctx: initialCtx }) {
|
|
|
2729
2741
|
* what the empty picker's own footer has always claimed `esc` does.
|
|
2730
2742
|
*/
|
|
2731
2743
|
const handlePickerCancel = useCallback(() => {
|
|
2744
|
+
setPickerInitialView('providers');
|
|
2732
2745
|
if (session?.hasProvider) {
|
|
2733
2746
|
setPhase('ready');
|
|
2734
2747
|
return;
|
|
@@ -2930,7 +2943,7 @@ export function App({ ctx: initialCtx }) {
|
|
|
2930
2943
|
// Background is left natural — we inherit the terminal's own background
|
|
2931
2944
|
// and only theme the foreground. Forcing
|
|
2932
2945
|
// a filled bg left mismatched patches around bordered areas, so we don't.
|
|
2933
|
-
return (_jsxs(Box, { flexDirection: "column", children: [phase !== 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : null, _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'edit' ? (_jsx(EditPromptPicker, { prompts: editList, selected: selectedEdit })) : phase === 'picker' ? (_jsx(Picker, { detected: detected, currentProvider: currentProvider, currentModel: session?.modelSummary ?? null, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential, onLogin: (signal) => void startLoginFromPicker(signal), keyEntryFor: keyEntryFor, notice: pickerNotice })) : (_jsxs(_Fragment, { children: [_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: finalized, pending: messages.find((m) => m.pending) ?? null, state: state, settled: window.settled, resetKey: resetKey, raw: rawOutput, header: phase === 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : undefined }) }), spacerRows > 0 ? _jsx(Box, { height: spacerRows }) : null, _jsx(LiveActivity, { activeTools: activeTools, thinking: state === 'thinking' && !messages.some((m) => m.pending) }), permission ? _jsx(PermissionOverlay, { toolCalls: permission.toolCalls }) : null, _jsxs(ComposerFrame, { focus: state === 'idle' && phase === 'ready' && conversationMutation === null, hidden: permission !== null, children: [queued.length > 0 && permission === null ? (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: theme.text.muted, children: [queuePause ? '⏸' : '⏎', " ", queued.length, " message", queued.length > 1 ? 's' : '', " queued \u2014", ' ', queuePause
|
|
2946
|
+
return (_jsxs(Box, { flexDirection: "column", children: [phase !== 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : null, _jsxs(Box, { flexDirection: "column", paddingX: 1, children: [phase === 'trust' ? (_jsx(TrustPrompt, { cwd: ctx.cwd })) : phase === 'resume' ? (_jsx(ResumePicker, { conversations: resumeList, selected: selectedResume })) : phase === 'edit' ? (_jsx(EditPromptPicker, { prompts: editList, selected: selectedEdit })) : phase === 'picker' ? (_jsx(Picker, { detected: detected, currentProvider: currentProvider, currentModel: session?.modelSummary ?? null, initialView: pickerInitialView, onSubmit: handlePickerSubmit, onCancel: handlePickerCancel, onCredential: handleTypedCredential, onLogin: (provider, signal) => void startLoginFromPicker(provider, signal), keyEntryFor: keyEntryFor, notice: pickerNotice })) : (_jsxs(_Fragment, { children: [_jsx(TranscriptFrame, { children: _jsx(Transcript, { messages: finalized, pending: messages.find((m) => m.pending) ?? null, state: state, settled: window.settled, resetKey: resetKey, raw: rawOutput, header: phase === 'ready' ? (_jsx(Banner, { version: ctx.version, session: session, permissionMode: permissionMode, cwd: ctx.cwd })) : undefined }) }), spacerRows > 0 ? _jsx(Box, { height: spacerRows }) : null, _jsx(LiveActivity, { activeTools: activeTools, thinking: state === 'thinking' && !messages.some((m) => m.pending) }), permission ? _jsx(PermissionOverlay, { toolCalls: permission.toolCalls }) : null, _jsxs(ComposerFrame, { focus: state === 'idle' && phase === 'ready' && conversationMutation === null, hidden: permission !== null, children: [queued.length > 0 && permission === null ? (_jsx(Box, { paddingX: 1, children: _jsxs(Text, { color: theme.text.muted, children: [queuePause ? '⏸' : '⏎', " ", queued.length, " message", queued.length > 1 ? 's' : '', " queued \u2014", ' ', queuePause
|
|
2934
2947
|
? `paused after a ${queuePause.outcome} turn; send a message or change model to continue`
|
|
2935
2948
|
: 'sending when ready'] }) })) : null, _jsx(Composer, { disabled: phase !== 'ready' ||
|
|
2936
2949
|
state === 'awaiting-permission' ||
|