@dexto/tui 1.14.4 → 1.15.0-beta.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 (36) hide show
  1. package/dist/components/Footer.cjs +31 -0
  2. package/dist/components/Footer.d.ts.map +1 -1
  3. package/dist/components/Footer.js +31 -0
  4. package/dist/components/Footer.test.cjs +44 -0
  5. package/dist/components/Footer.test.js +44 -0
  6. package/dist/components/overlays/InsufficientCreditsOverlay.cjs +19 -4
  7. package/dist/components/overlays/InsufficientCreditsOverlay.d.ts +2 -0
  8. package/dist/components/overlays/InsufficientCreditsOverlay.d.ts.map +1 -1
  9. package/dist/components/overlays/InsufficientCreditsOverlay.js +19 -4
  10. package/dist/components/overlays/LoginOverlay.cjs +25 -61
  11. package/dist/components/overlays/LoginOverlay.d.ts +1 -3
  12. package/dist/components/overlays/LoginOverlay.d.ts.map +1 -1
  13. package/dist/components/overlays/LoginOverlay.js +26 -66
  14. package/dist/components/overlays/LogoutOverlay.cjs +8 -17
  15. package/dist/components/overlays/LogoutOverlay.d.ts +1 -0
  16. package/dist/components/overlays/LogoutOverlay.d.ts.map +1 -1
  17. package/dist/components/overlays/LogoutOverlay.js +10 -31
  18. package/dist/components/overlays/custom-model-wizard/provider-config.cjs +4 -4
  19. package/dist/components/overlays/custom-model-wizard/provider-config.js +4 -4
  20. package/dist/containers/OverlayContainer.cjs +30 -40
  21. package/dist/containers/OverlayContainer.d.ts.map +1 -1
  22. package/dist/containers/OverlayContainer.js +30 -40
  23. package/dist/host/index.cjs +22 -49
  24. package/dist/host/index.d.ts +18 -72
  25. package/dist/host/index.d.ts.map +1 -1
  26. package/dist/host/index.js +18 -42
  27. package/dist/host/index.test.cjs +21 -35
  28. package/dist/host/index.test.js +22 -40
  29. package/dist/index.d.cts +13 -52
  30. package/dist/services/processStream.cjs +2 -2
  31. package/dist/services/processStream.js +2 -2
  32. package/dist/services/processStream.test.cjs +1 -1
  33. package/dist/services/processStream.test.js +1 -1
  34. package/dist/utils/llm-provider-display.cjs +1 -1
  35. package/dist/utils/llm-provider-display.js +1 -1
  36. package/package.json +3 -3
@@ -8,17 +8,12 @@ import {
8
8
  useState
9
9
  } from "react";
10
10
  import { Box, Text } from "ink";
11
- import {
12
- loadAuth,
13
- performDeviceCodeLogin,
14
- persistDeviceApiKeyLoginResult
15
- } from "../../host/index.js";
11
+ import { currentSignIn, signIn } from "../../host/index.js";
16
12
  const LoginOverlay = forwardRef(function LoginOverlay2({ isVisible, onDone }, ref) {
17
13
  const [step, setStep] = useState("checking");
18
14
  const [existingUser, setExistingUser] = useState(null);
19
- const [authUrl, setAuthUrl] = useState(null);
20
- const [devicePrompt, setDevicePrompt] = useState(null);
21
- const [status, setStatus] = useState("Preparing login...");
15
+ const [signInNote, setSignInNote] = useState(null);
16
+ const [status, setStatus] = useState("Preparing sign-in...");
22
17
  const [error, setError] = useState(null);
23
18
  const abortControllerRef = useRef(null);
24
19
  const isActiveRef = useRef(false);
@@ -30,47 +25,24 @@ const LoginOverlay = forwardRef(function LoginOverlay2({ isVisible, onDone }, re
30
25
  abortControllerRef.current?.abort(new Error("Authentication cancelled"));
31
26
  abortControllerRef.current = null;
32
27
  }, []);
33
- const runDeviceLogin = useCallback(
34
- async (abortController) => {
35
- setStep("starting");
36
- safeSetStatus("Starting device code login...");
37
- setAuthUrl(null);
38
- setDevicePrompt(null);
39
- return performDeviceCodeLogin({
40
- signal: abortController.signal,
41
- onPrompt: (prompt) => {
42
- if (!isActiveRef.current || abortController.signal.aborted) {
43
- return;
44
- }
45
- setDevicePrompt(prompt);
46
- setAuthUrl(prompt.verificationUrlComplete ?? prompt.verificationUrl);
47
- setStep("waiting");
48
- safeSetStatus("Open the URL below and approve login.");
49
- }
50
- });
51
- },
52
- [safeSetStatus]
53
- );
54
28
  const startLogin = useCallback(async () => {
55
29
  cancelInFlight();
56
30
  setError(null);
57
- setAuthUrl(null);
58
- setDevicePrompt(null);
31
+ setSignInNote(null);
32
+ setStep("signing-in");
33
+ safeSetStatus("Signing in...");
59
34
  const abortController = new AbortController();
60
35
  abortControllerRef.current = abortController;
61
36
  try {
62
- const result = await runDeviceLogin(abortController);
63
- if (!result || !isActiveRef.current || abortController.signal.aborted) return;
64
- setStep("finalizing");
65
- safeSetStatus("Finalizing login...");
66
- const persisted = await persistDeviceApiKeyLoginResult(result);
67
- if (!isActiveRef.current || abortController.signal.aborted) return;
68
- onDone({
69
- outcome: "success",
70
- email: persisted.email,
71
- keyId: persisted.keyId,
72
- hasDextoApiKey: persisted.hasDextoApiKey
37
+ const summary = await signIn({
38
+ signal: abortController.signal,
39
+ onNote: (text) => {
40
+ if (!isActiveRef.current || abortController.signal.aborted) return;
41
+ setSignInNote(text);
42
+ }
73
43
  });
44
+ if (!isActiveRef.current || abortController.signal.aborted) return;
45
+ onDone({ outcome: "success", summary });
74
46
  } catch (err) {
75
47
  if (abortController.signal.aborted) {
76
48
  return;
@@ -78,28 +50,27 @@ const LoginOverlay = forwardRef(function LoginOverlay2({ isVisible, onDone }, re
78
50
  setStep("error");
79
51
  const errorMessage = err instanceof Error ? err.message : String(err);
80
52
  setError(errorMessage);
81
- safeSetStatus("Login failed");
53
+ safeSetStatus("Sign-in failed");
82
54
  } finally {
83
55
  abortControllerRef.current = null;
84
56
  }
85
- }, [cancelInFlight, onDone, runDeviceLogin, safeSetStatus]);
57
+ }, [cancelInFlight, onDone, safeSetStatus]);
86
58
  useEffect(() => {
87
59
  if (!isVisible) return;
88
60
  isActiveRef.current = true;
89
61
  setStep("checking");
90
62
  setExistingUser(null);
91
- setAuthUrl(null);
92
- setDevicePrompt(null);
93
- setStatus("Preparing login...");
63
+ setSignInNote(null);
64
+ setStatus("Preparing sign-in...");
94
65
  setError(null);
95
66
  void (async () => {
96
67
  try {
97
- const auth = await loadAuth();
68
+ const signedInAs = await currentSignIn();
98
69
  if (!isActiveRef.current) return;
99
- if (auth) {
100
- setExistingUser(auth.email || auth.userId || "user");
70
+ if (signedInAs !== null) {
71
+ setExistingUser(signedInAs);
101
72
  setStep("already-authenticated");
102
- setStatus("You are already logged in");
73
+ setStatus("You are already signed in");
103
74
  return;
104
75
  }
105
76
  await startLogin();
@@ -139,7 +110,7 @@ const LoginOverlay = forwardRef(function LoginOverlay2({ isVisible, onDone }, re
139
110
  [cancelInFlight, isVisible, onDone, startLogin, step]
140
111
  );
141
112
  if (!isVisible) return null;
142
- const hint = step === "already-authenticated" ? "Enter to login again \u2022 Esc to close" : step === "error" ? "Enter to retry \u2022 Esc to close" : "Esc to cancel";
113
+ const hint = step === "already-authenticated" ? "Enter to sign in again \u2022 Esc to close" : step === "error" ? "Enter to retry \u2022 Esc to close" : "Esc to cancel";
143
114
  return /* @__PURE__ */ jsxs(
144
115
  Box,
145
116
  {
@@ -149,27 +120,16 @@ const LoginOverlay = forwardRef(function LoginOverlay2({ isVisible, onDone }, re
149
120
  paddingX: 1,
150
121
  marginTop: 1,
151
122
  children: [
152
- /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Login to Dexto" }) }),
123
+ /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Sign in to Dexto" }) }),
153
124
  existingUser && step === "already-authenticated" && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "green", children: [
154
- "\u2705 Already logged in as: ",
125
+ "Signed in as ",
155
126
  existingUser
156
127
  ] }) }),
157
128
  /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
158
129
  /* @__PURE__ */ jsx(Text, { color: "gray", children: "Status: " }),
159
130
  /* @__PURE__ */ jsx(Text, { children: status })
160
131
  ] }),
161
- devicePrompt && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
162
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "Open this URL on any device:" }),
163
- /* @__PURE__ */ jsx(Text, { color: "yellowBright", children: devicePrompt.verificationUrlComplete ?? devicePrompt.verificationUrl }),
164
- /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
165
- "Code: ",
166
- devicePrompt.userCode
167
- ] })
168
- ] }),
169
- authUrl && !devicePrompt && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
170
- /* @__PURE__ */ jsx(Text, { color: "gray", children: "If your browser didn't open, use this URL:" }),
171
- /* @__PURE__ */ jsx(Text, { color: "yellowBright", children: authUrl })
172
- ] }),
132
+ signInNote && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { children: signInNote }) }),
173
133
  error && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs(Text, { color: "red", children: [
174
134
  "Error: ",
175
135
  error
@@ -30,20 +30,12 @@ const LogoutOverlay = (0, import_react.forwardRef)(function LogoutOverlay2({ isV
30
30
  const [userLabel, setUserLabel] = (0, import_react.useState)(null);
31
31
  const [usingDextoCredits, setUsingDextoCredits] = (0, import_react.useState)(false);
32
32
  const [error, setError] = (0, import_react.useState)(null);
33
- const provisionedApiKeyRef = (0, import_react.useRef)(null);
34
33
  const performLogout = (0, import_react.useCallback)(async () => {
35
34
  setError(null);
36
35
  setStep("logging-out");
37
36
  try {
38
- const auth = await (0, import_host.loadAuth)();
39
- if (auth?.dextoApiKey && auth.dextoApiKeySource === "provisioned") {
40
- provisionedApiKeyRef.current = auth.dextoApiKey;
41
- }
42
- await (0, import_host.removeAuth)();
43
- if (provisionedApiKeyRef.current) {
44
- await (0, import_host.removeDextoApiKeyFromEnv)({ expectedValue: provisionedApiKeyRef.current });
45
- }
46
- onDone({ outcome: "success", wasUsingDextoCredits: usingDextoCredits });
37
+ const summary = await (0, import_host.signOut)();
38
+ onDone({ outcome: "success", summary, wasUsingDextoCredits: usingDextoCredits });
47
39
  } catch (err) {
48
40
  setStep("error");
49
41
  setError(err instanceof Error ? err.message : String(err));
@@ -52,24 +44,23 @@ const LogoutOverlay = (0, import_react.forwardRef)(function LogoutOverlay2({ isV
52
44
  (0, import_react.useEffect)(() => {
53
45
  if (!isVisible) return;
54
46
  let cancelled = false;
55
- provisionedApiKeyRef.current = null;
56
47
  setStep("checking");
57
48
  setUserLabel(null);
58
49
  setUsingDextoCredits(false);
59
50
  setError(null);
60
51
  void (async () => {
61
52
  try {
62
- const auth = await (0, import_host.loadAuth)();
53
+ const signedInAs = await (0, import_host.currentSignIn)();
63
54
  if (cancelled) return;
64
- if (!auth) {
55
+ if (signedInAs === null) {
65
56
  setStep("not-authenticated");
66
57
  return;
67
58
  }
68
- setUserLabel(auth.email || auth.userId || "user");
59
+ setUserLabel(signedInAs);
69
60
  } catch {
70
61
  if (!cancelled) {
71
62
  setStep("error");
72
- setError("Failed to load authentication state");
63
+ setError("Failed to read the sign-in");
73
64
  }
74
65
  return;
75
66
  }
@@ -117,12 +108,12 @@ const LogoutOverlay = (0, import_react.forwardRef)(function LogoutOverlay2({ isV
117
108
  marginTop: 1,
118
109
  children: [
119
110
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { bold: true, color: "cyan", children: "Logout" }) }),
120
- step === "not-authenticated" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "yellow", children: "\u2139\uFE0F Not currently logged in" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { marginBottom: 1, children: [
111
+ step === "not-authenticated" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "yellow", children: "Not signed in" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { marginBottom: 1, children: [
121
112
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: "Account: " }),
122
113
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { children: userLabel ?? "..." })
123
114
  ] }),
124
115
  usingDextoCredits && step !== "not-authenticated" && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ink.Box, { flexDirection: "column", marginBottom: 1, children: [
125
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "yellow", children: "\u26A0\uFE0F You are configured to use Dexto Nova credits (provider: Dexto Nova)." }),
116
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "yellow", children: "\u26A0\uFE0F You are configured to use Dexto models, which run on this sign-in." }),
126
117
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", dimColor: true, children: "After logout, you will need to run `/login` to authenticate again, or `dexto setup` to configure a different provider." })
127
118
  ] }),
128
119
  step === "logging-out" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginBottom: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Text, { color: "gray", children: "Logging out..." }) }),
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import type { Key } from '../../hooks/useInputOrchestrator.js';
3
3
  export type LogoutOverlayOutcome = {
4
4
  outcome: 'success';
5
+ summary: string;
5
6
  wasUsingDextoCredits: boolean;
6
7
  } | {
7
8
  outcome: 'cancelled';
@@ -1 +1 @@
1
- {"version":3,"file":"LogoutOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/LogoutOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAQ/D,MAAM,MAAM,oBAAoB,GAC1B;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,oBAAoB,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,GACxB;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAID,QAAA,MAAM,aAAa,gGAwKjB,CAAC;AAEH,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"LogoutOverlay.d.ts","sourceRoot":"","sources":["../../../src/components/overlays/LogoutOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4E,MAAM,OAAO,CAAC;AAEjG,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,qCAAqC,CAAC;AAG/D,MAAM,MAAM,oBAAoB,GAC1B;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,OAAO,CAAA;CAAE,GACtE;IAAE,OAAO,EAAE,WAAW,CAAA;CAAE,GACxB;IAAE,OAAO,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE5B,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAID,QAAA,MAAM,aAAa,gGA4JjB,CAAC;AAEH,eAAe,aAAa,CAAC"}
@@ -1,38 +1,18 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import {
3
- forwardRef,
4
- useCallback,
5
- useEffect,
6
- useImperativeHandle,
7
- useRef,
8
- useState
9
- } from "react";
2
+ import { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
10
3
  import { Box, Text } from "ink";
11
- import {
12
- loadAuth,
13
- removeAuth,
14
- removeDextoApiKeyFromEnv,
15
- isUsingDextoCredits
16
- } from "../../host/index.js";
4
+ import { currentSignIn, isUsingDextoCredits, signOut } from "../../host/index.js";
17
5
  const LogoutOverlay = forwardRef(function LogoutOverlay2({ isVisible, onDone }, ref) {
18
6
  const [step, setStep] = useState("checking");
19
7
  const [userLabel, setUserLabel] = useState(null);
20
8
  const [usingDextoCredits, setUsingDextoCredits] = useState(false);
21
9
  const [error, setError] = useState(null);
22
- const provisionedApiKeyRef = useRef(null);
23
10
  const performLogout = useCallback(async () => {
24
11
  setError(null);
25
12
  setStep("logging-out");
26
13
  try {
27
- const auth = await loadAuth();
28
- if (auth?.dextoApiKey && auth.dextoApiKeySource === "provisioned") {
29
- provisionedApiKeyRef.current = auth.dextoApiKey;
30
- }
31
- await removeAuth();
32
- if (provisionedApiKeyRef.current) {
33
- await removeDextoApiKeyFromEnv({ expectedValue: provisionedApiKeyRef.current });
34
- }
35
- onDone({ outcome: "success", wasUsingDextoCredits: usingDextoCredits });
14
+ const summary = await signOut();
15
+ onDone({ outcome: "success", summary, wasUsingDextoCredits: usingDextoCredits });
36
16
  } catch (err) {
37
17
  setStep("error");
38
18
  setError(err instanceof Error ? err.message : String(err));
@@ -41,24 +21,23 @@ const LogoutOverlay = forwardRef(function LogoutOverlay2({ isVisible, onDone },
41
21
  useEffect(() => {
42
22
  if (!isVisible) return;
43
23
  let cancelled = false;
44
- provisionedApiKeyRef.current = null;
45
24
  setStep("checking");
46
25
  setUserLabel(null);
47
26
  setUsingDextoCredits(false);
48
27
  setError(null);
49
28
  void (async () => {
50
29
  try {
51
- const auth = await loadAuth();
30
+ const signedInAs = await currentSignIn();
52
31
  if (cancelled) return;
53
- if (!auth) {
32
+ if (signedInAs === null) {
54
33
  setStep("not-authenticated");
55
34
  return;
56
35
  }
57
- setUserLabel(auth.email || auth.userId || "user");
36
+ setUserLabel(signedInAs);
58
37
  } catch {
59
38
  if (!cancelled) {
60
39
  setStep("error");
61
- setError("Failed to load authentication state");
40
+ setError("Failed to read the sign-in");
62
41
  }
63
42
  return;
64
43
  }
@@ -106,12 +85,12 @@ const LogoutOverlay = forwardRef(function LogoutOverlay2({ isVisible, onDone },
106
85
  marginTop: 1,
107
86
  children: [
108
87
  /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Logout" }) }),
109
- step === "not-authenticated" ? /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u2139\uFE0F Not currently logged in" }) }) : /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
88
+ step === "not-authenticated" ? /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Not signed in" }) }) : /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
110
89
  /* @__PURE__ */ jsx(Text, { color: "gray", children: "Account: " }),
111
90
  /* @__PURE__ */ jsx(Text, { children: userLabel ?? "..." })
112
91
  ] }),
113
92
  usingDextoCredits && step !== "not-authenticated" && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
114
- /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u26A0\uFE0F You are configured to use Dexto Nova credits (provider: Dexto Nova)." }),
93
+ /* @__PURE__ */ jsx(Text, { color: "yellow", children: "\u26A0\uFE0F You are configured to use Dexto models, which run on this sign-in." }),
115
94
  /* @__PURE__ */ jsx(Text, { color: "gray", dimColor: true, children: "After logout, you will need to run `/login` to authenticate again, or `dexto setup` to configure a different provider." })
116
95
  ] }),
117
96
  step === "logging-out" && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Logging out..." }) }),
@@ -446,7 +446,7 @@ const PROVIDER_CONFIGS = {
446
446
  }
447
447
  },
448
448
  "dexto-nova": {
449
- displayName: "Dexto Nova",
449
+ displayName: "Dexto",
450
450
  description: "Access 100+ models with Nova credits",
451
451
  steps: [
452
452
  {
@@ -493,14 +493,14 @@ const PROVIDER_CONFIGS = {
493
493
  }
494
494
  }
495
495
  if (status === "invalid") {
496
- return `Model '${modelId}' not found. Dexto Nova uses OpenRouter model IDs - check https://openrouter.ai/models`;
496
+ return `Model '${modelId}' not found. Dexto uses OpenRouter model IDs - check https://openrouter.ai/models`;
497
497
  }
498
498
  return null;
499
499
  }
500
500
  },
501
501
  setupInfo: {
502
- title: "Dexto Nova Setup",
503
- description: "Add OpenRouter-format models that use your Dexto Nova credits. Requires login: run `/login` first.",
502
+ title: "Dexto Models",
503
+ description: "Add OpenRouter-format models that use your Dexto credits. Requires a sign-in: run dexto login --scope cloud:write first.",
504
504
  docsUrl: "https://openrouter.ai/models"
505
505
  }
506
506
  }
@@ -411,7 +411,7 @@ const PROVIDER_CONFIGS = {
411
411
  }
412
412
  },
413
413
  "dexto-nova": {
414
- displayName: "Dexto Nova",
414
+ displayName: "Dexto",
415
415
  description: "Access 100+ models with Nova credits",
416
416
  steps: [
417
417
  {
@@ -458,14 +458,14 @@ const PROVIDER_CONFIGS = {
458
458
  }
459
459
  }
460
460
  if (status === "invalid") {
461
- return `Model '${modelId}' not found. Dexto Nova uses OpenRouter model IDs - check https://openrouter.ai/models`;
461
+ return `Model '${modelId}' not found. Dexto uses OpenRouter model IDs - check https://openrouter.ai/models`;
462
462
  }
463
463
  return null;
464
464
  }
465
465
  },
466
466
  setupInfo: {
467
- title: "Dexto Nova Setup",
468
- description: "Add OpenRouter-format models that use your Dexto Nova credits. Requires login: run `/login` first.",
467
+ title: "Dexto Models",
468
+ description: "Add OpenRouter-format models that use your Dexto credits. Requires a sign-in: run dexto login --scope cloud:write first.",
469
469
  docsUrl: "https://openrouter.ai/models"
470
470
  }
471
471
  }
@@ -85,7 +85,6 @@ var import_idGenerator = require("../utils/idGenerator.js");
85
85
  var import_host = require("../host/index.js");
86
86
  var import_FocusOverlayFrame = require("../components/shared/FocusOverlayFrame.js");
87
87
  var import_overlayPresentation = require("../utils/overlayPresentation.js");
88
- var import_dexto_auth_refresh = require("../utils/dexto-auth-refresh.js");
89
88
  function isLLMProvider(value) {
90
89
  if (typeof value !== "string") return false;
91
90
  for (const provider of import_llm.LLM_PROVIDERS) {
@@ -386,7 +385,7 @@ const OverlayContainer = (0, import_react.forwardRef)(
386
385
  {
387
386
  id: (0, import_idGenerator.generateMessageId)("system"),
388
387
  role: "system",
389
- content: "Cannot switch to Dexto Nova model - authentication required. Run /login to authenticate.",
388
+ content: "Dexto models need a sign-in that may spend credits. Run dexto login --scope cloud:write, or pick another model.",
390
389
  timestamp: /* @__PURE__ */ new Date()
391
390
  }
392
391
  ]);
@@ -398,7 +397,7 @@ const OverlayContainer = (0, import_react.forwardRef)(
398
397
  {
399
398
  id: (0, import_idGenerator.generateMessageId)("error"),
400
399
  role: "system",
401
- content: `Failed to verify Dexto Nova auth: ${error instanceof Error ? error.message : String(error)}`,
400
+ content: `Failed to check the Dexto sign-in: ${error instanceof Error ? error.message : String(error)}`,
402
401
  timestamp: /* @__PURE__ */ new Date()
403
402
  }
404
403
  ]);
@@ -661,6 +660,13 @@ const OverlayContainer = (0, import_react.forwardRef)(
661
660
  insufficientCredits: null
662
661
  }));
663
662
  }, [setUi]);
663
+ const handleInsufficientCreditsChooseOwnModel = (0, import_react.useCallback)(() => {
664
+ setUi((prev) => ({
665
+ ...prev,
666
+ activeOverlay: "model-selector",
667
+ insufficientCredits: null
668
+ }));
669
+ }, [setUi]);
664
670
  const handleInsufficientCreditsResolved = (0, import_react.useCallback)(() => {
665
671
  setUi((prev) => ({
666
672
  ...prev,
@@ -1130,50 +1136,33 @@ ${result.context}`,
1130
1136
  }, [setUi]);
1131
1137
  const handleLoginDone = (0, import_react.useCallback)(
1132
1138
  (outcome) => {
1133
- void (async () => {
1134
- handleClose();
1135
- if (outcome.outcome === "closed") {
1136
- return;
1137
- }
1138
- if (outcome.outcome === "cancelled") {
1139
- setMessages((prev) => [
1140
- ...prev,
1141
- {
1142
- id: (0, import_idGenerator.generateMessageId)("system"),
1143
- role: "system",
1144
- content: "Login cancelled.",
1145
- timestamp: /* @__PURE__ */ new Date()
1146
- }
1147
- ]);
1148
- return;
1149
- }
1150
- let refreshWarning = null;
1151
- if (outcome.hasDextoApiKey) {
1152
- try {
1153
- await (0, import_dexto_auth_refresh.refreshDextoNovaAuthAfterLogin)(agent, session.id || void 0);
1154
- } catch (error) {
1155
- refreshWarning = `Logged in, but failed to refresh the active Dexto Nova session: ${error instanceof Error ? error.message : String(error)}`;
1156
- }
1157
- }
1158
- const userLabel = outcome.email ? ` as ${outcome.email}` : "";
1159
- const keyLine = outcome.hasDextoApiKey ? `\u{1F511} DEXTO_API_KEY ready${outcome.keyId ? ` (Key ID: ${outcome.keyId})` : ""}` : "\u26A0\uFE0F Failed to provision DEXTO_API_KEY (you can still use your own API keys)";
1160
- const content = [
1161
- `\u2705 Logged in${userLabel}`,
1162
- keyLine,
1163
- ...refreshWarning ? [`\u26A0\uFE0F ${refreshWarning}`] : []
1164
- ].join("\n");
1139
+ handleClose();
1140
+ if (outcome.outcome === "closed") {
1141
+ return;
1142
+ }
1143
+ if (outcome.outcome === "cancelled") {
1165
1144
  setMessages((prev) => [
1166
1145
  ...prev,
1167
1146
  {
1168
1147
  id: (0, import_idGenerator.generateMessageId)("system"),
1169
1148
  role: "system",
1170
- content,
1149
+ content: "Sign-in cancelled.",
1171
1150
  timestamp: /* @__PURE__ */ new Date()
1172
1151
  }
1173
1152
  ]);
1174
- })();
1153
+ return;
1154
+ }
1155
+ setMessages((prev) => [
1156
+ ...prev,
1157
+ {
1158
+ id: (0, import_idGenerator.generateMessageId)("system"),
1159
+ role: "system",
1160
+ content: outcome.summary,
1161
+ timestamp: /* @__PURE__ */ new Date()
1162
+ }
1163
+ ]);
1175
1164
  },
1176
- [agent, handleClose, session.id, setMessages]
1165
+ [handleClose, setMessages]
1177
1166
  );
1178
1167
  const handleLogoutDone = (0, import_react.useCallback)(
1179
1168
  (outcome) => {
@@ -1199,7 +1188,7 @@ ${result.context}`,
1199
1188
  {
1200
1189
  id: (0, import_idGenerator.generateMessageId)("system"),
1201
1190
  role: "system",
1202
- content: `\u2705 Successfully logged out${warning}`,
1191
+ content: `${outcome.summary}${warning}`,
1203
1192
  timestamp: /* @__PURE__ */ new Date()
1204
1193
  }
1205
1194
  ]);
@@ -2496,7 +2485,8 @@ Use /${data.name} to run it.`,
2496
2485
  isVisible: true,
2497
2486
  initialBalanceUsd: ui.insufficientCredits.balanceUsd,
2498
2487
  onResolved: handleInsufficientCreditsResolved,
2499
- onClose: handleInsufficientCreditsClose
2488
+ onClose: handleInsufficientCreditsClose,
2489
+ onChooseOwnModel: handleInsufficientCreditsChooseOwnModel
2500
2490
  }
2501
2491
  ) }),
2502
2492
  ui.activeOverlay === "login" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ink.Box, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayContainer.d.ts","sourceRoot":"","sources":["../../src/containers/OverlayContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAyE,MAAM,OAAO,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,iCAAiC,CAAC;AAuGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAuC3D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAuC3D,MAAM,WAAW,sBAAsB;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,qBAAqB;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAC1E,KAAK,EAAE,eAAe,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,sGA6/F5B,CAAC"}
1
+ {"version":3,"file":"OverlayContainer.d.ts","sourceRoot":"","sources":["../../src/containers/OverlayContainer.tsx"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAyE,MAAM,OAAO,CAAC;AAI9F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kCAAkC,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACpF,OAAO,EAGH,KAAK,eAAe,EACvB,MAAM,iCAAiC,CAAC;AAuGzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAuC3D,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAsC3D,MAAM,WAAW,sBAAsB;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC;CACrD;AAED,UAAU,qBAAqB;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,EAAE,UAAU,CAAC;IAClB,OAAO,EAAE,YAAY,CAAC;IACtB,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3D,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAC7D,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,gBAAgB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC;IAC1E,KAAK,EAAE,eAAe,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClE;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,sGA++F5B,CAAC"}
@@ -67,7 +67,6 @@ import { generateMessageId } from "../utils/idGenerator.js";
67
67
  import { canUseDextoProvider, captureAnalytics } from "../host/index.js";
68
68
  import { FocusOverlayFrame } from "../components/shared/FocusOverlayFrame.js";
69
69
  import { shouldHideCliChrome } from "../utils/overlayPresentation.js";
70
- import { refreshDextoNovaAuthAfterLogin } from "../utils/dexto-auth-refresh.js";
71
70
  function isLLMProvider(value) {
72
71
  if (typeof value !== "string") return false;
73
72
  for (const provider of LLM_PROVIDERS) {
@@ -368,7 +367,7 @@ const OverlayContainer = forwardRef(
368
367
  {
369
368
  id: generateMessageId("system"),
370
369
  role: "system",
371
- content: "Cannot switch to Dexto Nova model - authentication required. Run /login to authenticate.",
370
+ content: "Dexto models need a sign-in that may spend credits. Run dexto login --scope cloud:write, or pick another model.",
372
371
  timestamp: /* @__PURE__ */ new Date()
373
372
  }
374
373
  ]);
@@ -380,7 +379,7 @@ const OverlayContainer = forwardRef(
380
379
  {
381
380
  id: generateMessageId("error"),
382
381
  role: "system",
383
- content: `Failed to verify Dexto Nova auth: ${error instanceof Error ? error.message : String(error)}`,
382
+ content: `Failed to check the Dexto sign-in: ${error instanceof Error ? error.message : String(error)}`,
384
383
  timestamp: /* @__PURE__ */ new Date()
385
384
  }
386
385
  ]);
@@ -643,6 +642,13 @@ const OverlayContainer = forwardRef(
643
642
  insufficientCredits: null
644
643
  }));
645
644
  }, [setUi]);
645
+ const handleInsufficientCreditsChooseOwnModel = useCallback(() => {
646
+ setUi((prev) => ({
647
+ ...prev,
648
+ activeOverlay: "model-selector",
649
+ insufficientCredits: null
650
+ }));
651
+ }, [setUi]);
646
652
  const handleInsufficientCreditsResolved = useCallback(() => {
647
653
  setUi((prev) => ({
648
654
  ...prev,
@@ -1112,50 +1118,33 @@ ${result.context}`,
1112
1118
  }, [setUi]);
1113
1119
  const handleLoginDone = useCallback(
1114
1120
  (outcome) => {
1115
- void (async () => {
1116
- handleClose();
1117
- if (outcome.outcome === "closed") {
1118
- return;
1119
- }
1120
- if (outcome.outcome === "cancelled") {
1121
- setMessages((prev) => [
1122
- ...prev,
1123
- {
1124
- id: generateMessageId("system"),
1125
- role: "system",
1126
- content: "Login cancelled.",
1127
- timestamp: /* @__PURE__ */ new Date()
1128
- }
1129
- ]);
1130
- return;
1131
- }
1132
- let refreshWarning = null;
1133
- if (outcome.hasDextoApiKey) {
1134
- try {
1135
- await refreshDextoNovaAuthAfterLogin(agent, session.id || void 0);
1136
- } catch (error) {
1137
- refreshWarning = `Logged in, but failed to refresh the active Dexto Nova session: ${error instanceof Error ? error.message : String(error)}`;
1138
- }
1139
- }
1140
- const userLabel = outcome.email ? ` as ${outcome.email}` : "";
1141
- const keyLine = outcome.hasDextoApiKey ? `\u{1F511} DEXTO_API_KEY ready${outcome.keyId ? ` (Key ID: ${outcome.keyId})` : ""}` : "\u26A0\uFE0F Failed to provision DEXTO_API_KEY (you can still use your own API keys)";
1142
- const content = [
1143
- `\u2705 Logged in${userLabel}`,
1144
- keyLine,
1145
- ...refreshWarning ? [`\u26A0\uFE0F ${refreshWarning}`] : []
1146
- ].join("\n");
1121
+ handleClose();
1122
+ if (outcome.outcome === "closed") {
1123
+ return;
1124
+ }
1125
+ if (outcome.outcome === "cancelled") {
1147
1126
  setMessages((prev) => [
1148
1127
  ...prev,
1149
1128
  {
1150
1129
  id: generateMessageId("system"),
1151
1130
  role: "system",
1152
- content,
1131
+ content: "Sign-in cancelled.",
1153
1132
  timestamp: /* @__PURE__ */ new Date()
1154
1133
  }
1155
1134
  ]);
1156
- })();
1135
+ return;
1136
+ }
1137
+ setMessages((prev) => [
1138
+ ...prev,
1139
+ {
1140
+ id: generateMessageId("system"),
1141
+ role: "system",
1142
+ content: outcome.summary,
1143
+ timestamp: /* @__PURE__ */ new Date()
1144
+ }
1145
+ ]);
1157
1146
  },
1158
- [agent, handleClose, session.id, setMessages]
1147
+ [handleClose, setMessages]
1159
1148
  );
1160
1149
  const handleLogoutDone = useCallback(
1161
1150
  (outcome) => {
@@ -1181,7 +1170,7 @@ ${result.context}`,
1181
1170
  {
1182
1171
  id: generateMessageId("system"),
1183
1172
  role: "system",
1184
- content: `\u2705 Successfully logged out${warning}`,
1173
+ content: `${outcome.summary}${warning}`,
1185
1174
  timestamp: /* @__PURE__ */ new Date()
1186
1175
  }
1187
1176
  ]);
@@ -2478,7 +2467,8 @@ Use /${data.name} to run it.`,
2478
2467
  isVisible: true,
2479
2468
  initialBalanceUsd: ui.insufficientCredits.balanceUsd,
2480
2469
  onResolved: handleInsufficientCreditsResolved,
2481
- onClose: handleInsufficientCreditsClose
2470
+ onClose: handleInsufficientCreditsClose,
2471
+ onChooseOwnModel: handleInsufficientCreditsChooseOwnModel
2482
2472
  }
2483
2473
  ) }),
2484
2474
  ui.activeOverlay === "login" && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(