dexto 1.14.4 → 2.0.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 (253) hide show
  1. package/dist/cli/auth/billing.d.ts +0 -6
  2. package/dist/cli/auth/billing.d.ts.map +1 -1
  3. package/dist/cli/auth/billing.js +0 -23
  4. package/dist/cli/auth/constants.d.ts +3 -31
  5. package/dist/cli/auth/constants.d.ts.map +1 -1
  6. package/dist/cli/auth/constants.js +9 -33
  7. package/dist/cli/auth/index.d.ts +2 -9
  8. package/dist/cli/auth/index.d.ts.map +1 -1
  9. package/dist/cli/auth/index.js +2 -7
  10. package/dist/cli/auth/sign-in-runtime.d.ts +12 -0
  11. package/dist/cli/auth/sign-in-runtime.d.ts.map +1 -0
  12. package/dist/cli/auth/sign-in-runtime.js +59 -0
  13. package/dist/cli/cloud/app-scopes.d.ts +4 -0
  14. package/dist/cli/cloud/app-scopes.d.ts.map +1 -0
  15. package/dist/cli/cloud/app-scopes.js +19 -0
  16. package/dist/cli/cloud/command.d.ts +143 -0
  17. package/dist/cli/cloud/command.d.ts.map +1 -0
  18. package/dist/cli/cloud/command.js +202 -0
  19. package/dist/cli/cloud/commands/account.d.ts +11 -0
  20. package/dist/cli/cloud/commands/account.d.ts.map +1 -0
  21. package/dist/cli/cloud/commands/account.js +128 -0
  22. package/dist/cli/cloud/commands/agents.d.ts +3 -0
  23. package/dist/cli/cloud/commands/agents.d.ts.map +1 -0
  24. package/dist/cli/cloud/commands/agents.js +524 -0
  25. package/dist/cli/cloud/commands/api.d.ts +3 -0
  26. package/dist/cli/cloud/commands/api.d.ts.map +1 -0
  27. package/dist/cli/cloud/commands/api.js +26 -0
  28. package/dist/cli/cloud/commands/app-files.d.ts +29 -0
  29. package/dist/cli/cloud/commands/app-files.d.ts.map +1 -0
  30. package/dist/cli/cloud/commands/app-files.js +72 -0
  31. package/dist/cli/cloud/commands/automations.d.ts +3 -0
  32. package/dist/cli/cloud/commands/automations.d.ts.map +1 -0
  33. package/dist/cli/cloud/commands/automations.js +232 -0
  34. package/dist/cli/cloud/commands/chats.d.ts +3 -0
  35. package/dist/cli/cloud/commands/chats.d.ts.map +1 -0
  36. package/dist/cli/cloud/commands/chats.js +189 -0
  37. package/dist/cli/cloud/commands/data-deletions.d.ts +3 -0
  38. package/dist/cli/cloud/commands/data-deletions.d.ts.map +1 -0
  39. package/dist/cli/cloud/commands/data-deletions.js +54 -0
  40. package/dist/cli/cloud/commands/deploys.d.ts +10 -0
  41. package/dist/cli/cloud/commands/deploys.d.ts.map +1 -0
  42. package/dist/cli/cloud/commands/deploys.js +223 -0
  43. package/dist/cli/cloud/commands/drive.d.ts +12 -0
  44. package/dist/cli/cloud/commands/drive.d.ts.map +1 -0
  45. package/dist/cli/cloud/commands/drive.js +320 -0
  46. package/dist/cli/cloud/commands/files.d.ts +24 -0
  47. package/dist/cli/cloud/commands/files.d.ts.map +1 -0
  48. package/dist/cli/cloud/commands/files.js +282 -0
  49. package/dist/cli/cloud/commands/find.d.ts +3 -0
  50. package/dist/cli/cloud/commands/find.d.ts.map +1 -0
  51. package/dist/cli/cloud/commands/find.js +63 -0
  52. package/dist/cli/cloud/commands/models.d.ts +3 -0
  53. package/dist/cli/cloud/commands/models.d.ts.map +1 -0
  54. package/dist/cli/cloud/commands/models.js +248 -0
  55. package/dist/cli/cloud/commands/profile.d.ts +3 -0
  56. package/dist/cli/cloud/commands/profile.d.ts.map +1 -0
  57. package/dist/cli/cloud/commands/profile.js +119 -0
  58. package/dist/cli/cloud/commands/projects.d.ts +5 -0
  59. package/dist/cli/cloud/commands/projects.d.ts.map +1 -0
  60. package/dist/cli/cloud/commands/projects.js +66 -0
  61. package/dist/cli/cloud/commands/publish.d.ts +3 -0
  62. package/dist/cli/cloud/commands/publish.d.ts.map +1 -0
  63. package/dist/cli/cloud/commands/publish.js +138 -0
  64. package/dist/cli/cloud/commands/sandboxes.d.ts +3 -0
  65. package/dist/cli/cloud/commands/sandboxes.d.ts.map +1 -0
  66. package/dist/cli/cloud/commands/sandboxes.js +265 -0
  67. package/dist/cli/cloud/commands/secrets.d.ts +3 -0
  68. package/dist/cli/cloud/commands/secrets.d.ts.map +1 -0
  69. package/dist/cli/cloud/commands/secrets.js +110 -0
  70. package/dist/cli/cloud/commands/skills.d.ts +3 -0
  71. package/dist/cli/cloud/commands/skills.d.ts.map +1 -0
  72. package/dist/cli/cloud/commands/skills.js +202 -0
  73. package/dist/cli/cloud/commands/web.d.ts +3 -0
  74. package/dist/cli/cloud/commands/web.d.ts.map +1 -0
  75. package/dist/cli/cloud/commands/web.js +53 -0
  76. package/dist/cli/cloud/commands/workspace-apps.d.ts +58 -0
  77. package/dist/cli/cloud/commands/workspace-apps.d.ts.map +1 -0
  78. package/dist/cli/cloud/commands/workspace-apps.js +656 -0
  79. package/dist/cli/cloud/commands/workspace.d.ts +36 -0
  80. package/dist/cli/cloud/commands/workspace.d.ts.map +1 -0
  81. package/dist/cli/cloud/commands/workspace.js +279 -0
  82. package/dist/cli/cloud/connection.d.ts +33 -0
  83. package/dist/cli/cloud/connection.d.ts.map +1 -0
  84. package/dist/cli/cloud/connection.js +38 -0
  85. package/dist/cli/cloud/events.d.ts +63 -0
  86. package/dist/cli/cloud/events.d.ts.map +1 -0
  87. package/dist/cli/cloud/events.js +72 -0
  88. package/dist/cli/cloud/host.d.ts +9 -0
  89. package/dist/cli/cloud/host.d.ts.map +1 -0
  90. package/dist/cli/cloud/host.js +105 -0
  91. package/dist/cli/cloud/local-chats.d.ts +73 -0
  92. package/dist/cli/cloud/local-chats.d.ts.map +1 -0
  93. package/dist/cli/cloud/local-chats.js +441 -0
  94. package/dist/cli/cloud/output.d.ts +34 -0
  95. package/dist/cli/cloud/output.d.ts.map +1 -0
  96. package/dist/cli/cloud/output.js +76 -0
  97. package/dist/cli/cloud/run.d.ts +26 -0
  98. package/dist/cli/cloud/run.d.ts.map +1 -0
  99. package/dist/cli/cloud/run.js +444 -0
  100. package/dist/cli/cloud/runtime.d.ts +33 -0
  101. package/dist/cli/cloud/runtime.d.ts.map +1 -0
  102. package/dist/cli/cloud/runtime.js +86 -0
  103. package/dist/cli/cloud/tar.d.ts +9 -0
  104. package/dist/cli/cloud/tar.d.ts.map +1 -0
  105. package/dist/cli/cloud/tar.js +69 -0
  106. package/dist/cli/cloud/transfer.d.ts +13 -0
  107. package/dist/cli/cloud/transfer.d.ts.map +1 -0
  108. package/dist/cli/cloud/transfer.js +35 -0
  109. package/dist/cli/cloud/v1.d.ts +19 -0
  110. package/dist/cli/cloud/v1.d.ts.map +1 -0
  111. package/dist/cli/cloud/v1.js +65 -0
  112. package/dist/cli/cloud/zip.d.ts +8 -0
  113. package/dist/cli/cloud/zip.d.ts.map +1 -0
  114. package/dist/cli/cloud/zip.js +66 -0
  115. package/dist/cli/commands/auth/sign-in-commands.d.ts +62 -0
  116. package/dist/cli/commands/auth/sign-in-commands.d.ts.map +1 -0
  117. package/dist/cli/commands/auth/sign-in-commands.js +247 -0
  118. package/dist/cli/commands/auth/sign-in-context.d.ts +16 -0
  119. package/dist/cli/commands/auth/sign-in-context.d.ts.map +1 -0
  120. package/dist/cli/commands/auth/sign-in-context.js +68 -0
  121. package/dist/cli/commands/cloud/register.d.ts +5 -0
  122. package/dist/cli/commands/cloud/register.d.ts.map +1 -1
  123. package/dist/cli/commands/cloud/register.js +42 -24
  124. package/dist/cli/commands/create-app.js +5 -6
  125. package/dist/cli/commands/create-image.d.ts.map +1 -1
  126. package/dist/cli/commands/create-image.js +9 -10
  127. package/dist/cli/commands/index.d.ts +0 -2
  128. package/dist/cli/commands/index.d.ts.map +1 -1
  129. package/dist/cli/commands/index.js +0 -2
  130. package/dist/cli/commands/init.d.ts +0 -2
  131. package/dist/cli/commands/init.d.ts.map +1 -1
  132. package/dist/cli/commands/init.js +5 -26
  133. package/dist/cli/commands/run/headless.js +2 -2
  134. package/dist/cli/commands/run/output.d.ts +29 -10
  135. package/dist/cli/commands/run/output.d.ts.map +1 -1
  136. package/dist/cli/commands/run/output.js +44 -22
  137. package/dist/cli/commands/run/register.d.ts.map +1 -1
  138. package/dist/cli/commands/run/register.js +21 -9
  139. package/dist/cli/commands/session/register.d.ts.map +1 -1
  140. package/dist/cli/commands/session/register.js +51 -21
  141. package/dist/cli/commands/session-commands.js +1 -1
  142. package/dist/cli/commands/setup.js +17 -14
  143. package/dist/cli/help-json.d.ts +22 -0
  144. package/dist/cli/help-json.d.ts.map +1 -0
  145. package/dist/cli/help-json.js +20 -0
  146. package/dist/cli/modes/cli.d.ts.map +1 -1
  147. package/dist/cli/modes/cli.js +42 -9
  148. package/dist/cli/modes/server.js +8 -8
  149. package/dist/cli/modes/web.js +3 -3
  150. package/dist/cli/utils/dexto-auth-check.d.ts +1 -1
  151. package/dist/cli/utils/dexto-auth-check.d.ts.map +1 -1
  152. package/dist/cli/utils/dexto-auth-check.js +4 -5
  153. package/dist/cli/utils/dexto-setup.d.ts +4 -5
  154. package/dist/cli/utils/dexto-setup.d.ts.map +1 -1
  155. package/dist/cli/utils/dexto-setup.js +17 -14
  156. package/dist/cli/utils/provider-setup.js +1 -1
  157. package/dist/cli/utils/scaffolding-utils.d.ts +9 -3
  158. package/dist/cli/utils/scaffolding-utils.d.ts.map +1 -1
  159. package/dist/cli/utils/scaffolding-utils.js +48 -40
  160. package/dist/cli/utils/version-check.d.ts.map +1 -1
  161. package/dist/cli/utils/version-check.js +2 -1
  162. package/dist/index-main.js +33 -65
  163. package/package.json +8 -7
  164. package/dist/cli/auth/api-client.d.ts +0 -125
  165. package/dist/cli/auth/api-client.d.ts.map +0 -1
  166. package/dist/cli/auth/api-client.js +0 -585
  167. package/dist/cli/auth/device.d.ts +0 -14
  168. package/dist/cli/auth/device.d.ts.map +0 -1
  169. package/dist/cli/auth/device.js +0 -84
  170. package/dist/cli/auth/dexto-api-key.d.ts +0 -34
  171. package/dist/cli/auth/dexto-api-key.d.ts.map +0 -1
  172. package/dist/cli/auth/dexto-api-key.js +0 -160
  173. package/dist/cli/auth/login-persistence.d.ts +0 -15
  174. package/dist/cli/auth/login-persistence.d.ts.map +0 -1
  175. package/dist/cli/auth/login-persistence.js +0 -72
  176. package/dist/cli/auth/oauth.d.ts +0 -39
  177. package/dist/cli/auth/oauth.d.ts.map +0 -1
  178. package/dist/cli/auth/oauth.js +0 -434
  179. package/dist/cli/auth/service.d.ts +0 -24
  180. package/dist/cli/auth/service.d.ts.map +0 -1
  181. package/dist/cli/auth/service.js +0 -161
  182. package/dist/cli/auth/types.d.ts +0 -11
  183. package/dist/cli/auth/types.d.ts.map +0 -1
  184. package/dist/cli/auth/types.js +0 -1
  185. package/dist/cli/cloud-chat.d.ts +0 -18
  186. package/dist/cli/cloud-chat.d.ts.map +0 -1
  187. package/dist/cli/cloud-chat.js +0 -734
  188. package/dist/cli/commands/auth/index.d.ts +0 -4
  189. package/dist/cli/commands/auth/index.d.ts.map +0 -1
  190. package/dist/cli/commands/auth/index.js +0 -4
  191. package/dist/cli/commands/auth/login.d.ts +0 -12
  192. package/dist/cli/commands/auth/login.d.ts.map +0 -1
  193. package/dist/cli/commands/auth/login.js +0 -153
  194. package/dist/cli/commands/auth/logout.d.ts +0 -5
  195. package/dist/cli/commands/auth/logout.d.ts.map +0 -1
  196. package/dist/cli/commands/auth/logout.js +0 -81
  197. package/dist/cli/commands/auth/register.d.ts +0 -3
  198. package/dist/cli/commands/auth/register.d.ts.map +0 -1
  199. package/dist/cli/commands/auth/register.js +0 -96
  200. package/dist/cli/commands/auth/status.d.ts +0 -2
  201. package/dist/cli/commands/auth/status.d.ts.map +0 -1
  202. package/dist/cli/commands/auth/status.js +0 -22
  203. package/dist/cli/commands/billing/index.d.ts +0 -2
  204. package/dist/cli/commands/billing/index.d.ts.map +0 -1
  205. package/dist/cli/commands/billing/index.js +0 -2
  206. package/dist/cli/commands/billing/register.d.ts +0 -3
  207. package/dist/cli/commands/billing/register.d.ts.map +0 -1
  208. package/dist/cli/commands/billing/register.js +0 -20
  209. package/dist/cli/commands/billing/status.d.ts +0 -8
  210. package/dist/cli/commands/billing/status.d.ts.map +0 -1
  211. package/dist/cli/commands/billing/status.js +0 -71
  212. package/dist/cli/commands/cloud/discovery.d.ts +0 -17
  213. package/dist/cli/commands/cloud/discovery.d.ts.map +0 -1
  214. package/dist/cli/commands/cloud/discovery.js +0 -88
  215. package/dist/cli/commands/deploy/client.d.ts +0 -113
  216. package/dist/cli/commands/deploy/client.d.ts.map +0 -1
  217. package/dist/cli/commands/deploy/client.js +0 -519
  218. package/dist/cli/commands/deploy/config.d.ts +0 -37
  219. package/dist/cli/commands/deploy/config.d.ts.map +0 -1
  220. package/dist/cli/commands/deploy/config.js +0 -144
  221. package/dist/cli/commands/deploy/entry-agent.d.ts +0 -3
  222. package/dist/cli/commands/deploy/entry-agent.d.ts.map +0 -1
  223. package/dist/cli/commands/deploy/entry-agent.js +0 -70
  224. package/dist/cli/commands/deploy/index.d.ts +0 -12
  225. package/dist/cli/commands/deploy/index.d.ts.map +0 -1
  226. package/dist/cli/commands/deploy/index.js +0 -370
  227. package/dist/cli/commands/deploy/links.d.ts +0 -3
  228. package/dist/cli/commands/deploy/links.d.ts.map +0 -1
  229. package/dist/cli/commands/deploy/links.js +0 -53
  230. package/dist/cli/commands/deploy/register.d.ts +0 -6
  231. package/dist/cli/commands/deploy/register.d.ts.map +0 -1
  232. package/dist/cli/commands/deploy/register.js +0 -128
  233. package/dist/cli/commands/deploy/snapshot.d.ts +0 -12
  234. package/dist/cli/commands/deploy/snapshot.d.ts.map +0 -1
  235. package/dist/cli/commands/deploy/snapshot.js +0 -76
  236. package/dist/cli/commands/deploy/state.d.ts +0 -13
  237. package/dist/cli/commands/deploy/state.d.ts.map +0 -1
  238. package/dist/cli/commands/deploy/state.js +0 -122
  239. package/dist/cli/commands/span/register.d.ts +0 -6
  240. package/dist/cli/commands/span/register.d.ts.map +0 -1
  241. package/dist/cli/commands/span/register.js +0 -25
  242. package/dist/cli/commands/trace/client.d.ts +0 -98
  243. package/dist/cli/commands/trace/client.d.ts.map +0 -1
  244. package/dist/cli/commands/trace/client.js +0 -150
  245. package/dist/cli/commands/trace/format.d.ts +0 -5
  246. package/dist/cli/commands/trace/format.d.ts.map +0 -1
  247. package/dist/cli/commands/trace/format.js +0 -58
  248. package/dist/cli/commands/trace/index.d.ts +0 -21
  249. package/dist/cli/commands/trace/index.d.ts.map +0 -1
  250. package/dist/cli/commands/trace/index.js +0 -49
  251. package/dist/cli/commands/trace/register.d.ts +0 -6
  252. package/dist/cli/commands/trace/register.d.ts.map +0 -1
  253. package/dist/cli/commands/trace/register.js +0 -71
@@ -1,434 +0,0 @@
1
- // packages/cli/src/cli/auth/oauth.ts
2
- // OAuth flow implementation with local callback server
3
- //
4
- // TODO: Add CSRF protection via Device Code Flow (RFC 8628)
5
- // Current localhost callback pattern lacks CSRF protection. We attempted to add
6
- // a `state` parameter but Supabase uses `state` internally for its own OAuth CSRF
7
- // with Google, causing conflicts. The proper solution is Device Code Flow:
8
- // 1. CLI requests device code from server
9
- // 2. User visits URL and enters code
10
- // 3. CLI polls for authorization completion
11
- // This is what Supabase CLI, GitHub CLI, and others use for secure CLI auth.
12
- import * as http from 'http';
13
- import * as url from 'url';
14
- import * as querystring from 'querystring';
15
- import chalk from 'chalk';
16
- import * as p from '@clack/prompts';
17
- import { logger } from '@dexto/core';
18
- import { getDextoPackageRoot } from '@dexto/agent-management';
19
- import { existsSync, readFileSync } from 'node:fs';
20
- import path from 'node:path';
21
- import { SUPABASE_URL, SUPABASE_ANON_KEY } from './constants.js';
22
- // Track active OAuth callback servers by port for cleanup
23
- const oauthStateStore = new Map();
24
- function resolveLogoPath() {
25
- const packageRoot = getDextoPackageRoot();
26
- if (packageRoot) {
27
- const standaloneAssetPath = path.join(packageRoot, 'dist', 'cli', 'assets', 'dexto-logo.svg');
28
- if (existsSync(standaloneAssetPath)) {
29
- return standaloneAssetPath;
30
- }
31
- }
32
- try {
33
- const localAssetPath = new URL('../assets/dexto-logo.svg', import.meta.url);
34
- const resolvedPath = url.fileURLToPath(localAssetPath);
35
- if (existsSync(resolvedPath)) {
36
- return resolvedPath;
37
- }
38
- }
39
- catch {
40
- // Ignore URL/path errors and return null.
41
- }
42
- return null;
43
- }
44
- const DEXTO_LOGO_DATA_URL = (() => {
45
- try {
46
- const logoPath = resolveLogoPath();
47
- if (!logoPath) {
48
- return '';
49
- }
50
- const svg = readFileSync(logoPath, 'utf-8');
51
- return `data:image/svg+xml;base64,${Buffer.from(svg).toString('base64')}`;
52
- }
53
- catch (error) {
54
- logger.debug(`Failed to load Dexto logo asset for OAuth screen: ${error instanceof Error ? error.message : String(error)}`);
55
- return '';
56
- }
57
- })();
58
- const LOGO_FALLBACK_TEXT = DEXTO_LOGO_DATA_URL ? '' : 'D';
59
- const LOGO_HTML = `<div class="logo">${LOGO_FALLBACK_TEXT}</div>`;
60
- // Pre-generate HTML strings with logo
61
- const ERROR_HTML = `${LOGO_HTML}<div class="error-icon">✕</div><h1 class="error-title">Authentication Failed</h1><p>You can close this window and try again in your terminal.</p>`;
62
- const SUCCESS_HTML = `${LOGO_HTML}<div class="success-icon">✓</div><h1 class="success-title">Login Successful!</h1><p>Welcome to Dexto! You can close this window and return to your terminal.</p>`;
63
- const NO_DATA_HTML = `${LOGO_HTML}<div class="error-icon">✕</div><h1 class="error-title">No Authentication Data</h1><p>Please try the login process again in your terminal.</p>`;
64
- // Fixed port for OAuth callback - must match Supabase redirect URL config
65
- const OAUTH_CALLBACK_PORT = 48102;
66
- /**
67
- * Check if fixed port is available, throw if not
68
- */
69
- function ensurePortAvailable(port) {
70
- return new Promise((resolve, reject) => {
71
- const server = http.createServer();
72
- server.listen(port, () => {
73
- server.close(() => resolve(port));
74
- });
75
- server.on('error', (err) => {
76
- if (err.code === 'EADDRINUSE') {
77
- reject(new Error(`Port ${port} is already in use. Please close the application using it and try again.`));
78
- }
79
- else {
80
- reject(err);
81
- }
82
- });
83
- });
84
- }
85
- function resolveCallbackServerOptions(options) {
86
- return {
87
- timeoutMs: options.timeoutMs ?? 5 * 60 * 1000,
88
- signal: options.signal ?? null,
89
- };
90
- }
91
- /**
92
- * Start local HTTP server to receive OAuth callback
93
- */
94
- function startCallbackServer(port, config, options) {
95
- return new Promise((resolve, reject) => {
96
- let settled = false;
97
- const timeoutMs = options.timeoutMs;
98
- let timeoutHandle = null;
99
- let abortHandler = () => { };
100
- const safeCloseServer = (server) => {
101
- try {
102
- if (server.listening) {
103
- server.close();
104
- }
105
- }
106
- catch (_error) {
107
- // ignore
108
- }
109
- };
110
- const cleanup = () => {
111
- if (timeoutHandle) {
112
- clearTimeout(timeoutHandle);
113
- }
114
- oauthStateStore.delete(port);
115
- options.signal?.removeEventListener('abort', abortHandler);
116
- };
117
- const safeResolve = (result) => {
118
- if (settled)
119
- return;
120
- settled = true;
121
- cleanup();
122
- resolve(result);
123
- };
124
- const safeReject = (error) => {
125
- if (settled)
126
- return;
127
- settled = true;
128
- cleanup();
129
- reject(error);
130
- };
131
- const server = http.createServer(async (req, res) => {
132
- try {
133
- if (!req.url) {
134
- res.writeHead(400);
135
- res.end('Bad Request');
136
- return;
137
- }
138
- const parsedUrl = url.parse(req.url, true);
139
- if (req.method === 'GET') {
140
- res.writeHead(200, { 'Content-Type': 'text/html' });
141
- res.end(`
142
- <html>
143
- <head>
144
- <meta charset="utf-8" />
145
- <title>Dexto Authentication</title>
146
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
147
- <link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet">
148
- <style>
149
- * { margin: 0; padding: 0; box-sizing: border-box; }
150
- body {
151
- font-family: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
152
- background: linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 100%);
153
- color: #fafafa;
154
- min-height: 100vh;
155
- display: flex;
156
- align-items: center;
157
- justify-content: center;
158
- padding: 20px;
159
- }
160
- .container {
161
- background: #141414;
162
- border: 1px solid #262626;
163
- padding: 48px;
164
- border-radius: 12px;
165
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
166
- max-width: 450px;
167
- width: 100%;
168
- text-align: center;
169
- }
170
- .logo {
171
- width: 240px;
172
- height: 70px;
173
- margin: 0 auto 32px;
174
- background-image: ${DEXTO_LOGO_DATA_URL ? `url("${DEXTO_LOGO_DATA_URL}")` : 'none'};
175
- background-repeat: no-repeat;
176
- background-position: center;
177
- background-size: contain;
178
- display: flex;
179
- align-items: center;
180
- justify-content: center;
181
- font-size: 28px;
182
- font-weight: 600;
183
- color: #4ec9b0;
184
- }
185
- .spinner {
186
- font-size: 48px;
187
- margin-bottom: 24px;
188
- animation: pulse 2s infinite;
189
- }
190
- @keyframes pulse {
191
- 0%, 100% { opacity: 1; }
192
- 50% { opacity: 0.6; }
193
- }
194
- h1 { font-size: 24px; font-weight: 600; margin-bottom: 12px; color: #fafafa; }
195
- p { color: #a1a1aa; font-size: 16px; line-height: 1.5; }
196
- .success-icon { color: #22c55e; font-size: 64px; margin-bottom: 24px; }
197
- .error-icon { color: #dc2626; font-size: 64px; margin-bottom: 24px; }
198
- .success-title { color: #22c55e; }
199
- .error-title { color: #dc2626; }
200
- </style>
201
- </head>
202
- <body>
203
- <div class="container">
204
- ${LOGO_HTML}
205
- <div class="spinner">◐</div>
206
- <h1>Processing Authentication...</h1>
207
- <p>Please wait while we complete your Dexto login.</p>
208
- </div>
209
- <script>
210
- const hashParams = new URLSearchParams(window.location.hash.substring(1));
211
- const urlParams = new URLSearchParams(window.location.search);
212
- const accessToken = hashParams.get('access_token') || urlParams.get('access_token');
213
- const refreshToken = hashParams.get('refresh_token') || urlParams.get('refresh_token');
214
- const expiresIn = hashParams.get('expires_in') || urlParams.get('expires_in');
215
- const error = hashParams.get('error') || urlParams.get('error');
216
-
217
- if (window.location.hash || window.location.search) {
218
- window.history.replaceState(null, document.title, window.location.pathname);
219
- }
220
-
221
- if (error) {
222
- fetch('/callback', {
223
- method: 'POST',
224
- headers: { 'Content-Type': 'application/json' },
225
- body: JSON.stringify({ error: error })
226
- }).then(() => {
227
- document.querySelector('.container').innerHTML = ${JSON.stringify(ERROR_HTML)};
228
- });
229
- } else if (accessToken) {
230
- fetch('/callback', {
231
- method: 'POST',
232
- headers: { 'Content-Type': 'application/json' },
233
- body: JSON.stringify({
234
- access_token: accessToken,
235
- refresh_token: refreshToken,
236
- expires_in: expiresIn ? parseInt(expiresIn) : undefined
237
- })
238
- }).then(() => {
239
- document.querySelector('.container').innerHTML = ${JSON.stringify(SUCCESS_HTML)};
240
- });
241
- } else {
242
- document.querySelector('.container').innerHTML = ${JSON.stringify(NO_DATA_HTML)};
243
- }
244
- </script>
245
- </body>
246
- </html>
247
- `);
248
- }
249
- else if (req.method === 'POST' && parsedUrl.pathname === '/callback') {
250
- let body = '';
251
- const MAX_BODY_SIZE = 10 * 1024; // 10KB - plenty for OAuth tokens
252
- req.on('data', (chunk) => {
253
- if (body.length + chunk.length > MAX_BODY_SIZE) {
254
- req.destroy();
255
- res.writeHead(413);
256
- res.end('Request too large');
257
- return;
258
- }
259
- body += chunk.toString();
260
- });
261
- req.on('end', async () => {
262
- try {
263
- const data = JSON.parse(body);
264
- if (data.error) {
265
- res.writeHead(200);
266
- res.end('OK');
267
- safeCloseServer(server);
268
- safeReject(new Error(`OAuth error: ${data.error}`));
269
- return;
270
- }
271
- if (data.access_token) {
272
- const userResponse = await fetch(`${config.authUrl}/auth/v1/user`, {
273
- headers: {
274
- Authorization: `Bearer ${data.access_token}`,
275
- apikey: config.clientId,
276
- },
277
- });
278
- const userData = userResponse.ok ? await userResponse.json() : null;
279
- const result = {
280
- accessToken: data.access_token,
281
- refreshToken: data.refresh_token,
282
- expiresIn: data.expires_in,
283
- user: userData
284
- ? {
285
- id: userData.id,
286
- email: userData.email,
287
- name: userData.user_metadata?.full_name ||
288
- userData.email,
289
- }
290
- : undefined,
291
- };
292
- res.writeHead(200);
293
- res.end('OK');
294
- safeCloseServer(server);
295
- safeResolve(result);
296
- }
297
- else {
298
- res.writeHead(400);
299
- res.end('Missing tokens');
300
- safeCloseServer(server);
301
- safeReject(new Error('No access token received'));
302
- }
303
- }
304
- catch (_err) {
305
- res.writeHead(400);
306
- res.end('Invalid data');
307
- safeCloseServer(server);
308
- safeReject(new Error('Invalid callback data'));
309
- }
310
- });
311
- }
312
- else {
313
- res.writeHead(404);
314
- res.end('Not Found');
315
- }
316
- }
317
- catch (error) {
318
- logger.error(`Callback server error: ${error}`);
319
- res.writeHead(500);
320
- res.end('Internal Server Error');
321
- safeCloseServer(server);
322
- safeReject(error);
323
- }
324
- });
325
- timeoutHandle = setTimeout(() => {
326
- safeCloseServer(server);
327
- safeReject(new Error('Authentication timed out'));
328
- }, timeoutMs);
329
- abortHandler = () => {
330
- const reason = options.signal?.reason;
331
- const error = reason instanceof Error
332
- ? reason
333
- : new Error(typeof reason === 'string' ? reason : 'Authentication cancelled');
334
- safeCloseServer(server);
335
- safeReject(error);
336
- };
337
- server.listen(port, 'localhost', () => {
338
- logger.debug(`OAuth callback server listening on http://localhost:${port}`);
339
- });
340
- server.on('error', (error) => {
341
- safeCloseServer(server);
342
- safeReject(new Error(`Failed to start callback server: ${error.message}`));
343
- });
344
- if (options.signal) {
345
- if (options.signal.aborted) {
346
- abortHandler();
347
- }
348
- else {
349
- options.signal.addEventListener('abort', abortHandler, { once: true });
350
- }
351
- }
352
- });
353
- }
354
- export async function beginOAuthLogin(config, options = {}) {
355
- const resolvedOptions = resolveCallbackServerOptions(options);
356
- const port = await ensurePortAvailable(OAUTH_CALLBACK_PORT);
357
- const redirectUri = `http://localhost:${port}`;
358
- oauthStateStore.set(port, 'active');
359
- logger.debug(`Registered OAuth callback server on port ${port}`);
360
- const provider = config.provider || 'google';
361
- const authParams = querystring.stringify({
362
- redirect_to: redirectUri,
363
- });
364
- const authUrl = `${config.authUrl}/auth/v1/authorize?provider=${provider}&${authParams}`;
365
- const abortController = new AbortController();
366
- let upstreamAbortHandler = null;
367
- if (resolvedOptions.signal) {
368
- const handler = () => abortController.abort(resolvedOptions.signal?.reason);
369
- upstreamAbortHandler = handler;
370
- if (resolvedOptions.signal.aborted) {
371
- handler();
372
- }
373
- else {
374
- resolvedOptions.signal.addEventListener('abort', handler, { once: true });
375
- }
376
- }
377
- const result = startCallbackServer(port, config, {
378
- timeoutMs: resolvedOptions.timeoutMs,
379
- signal: abortController.signal,
380
- }).finally(() => {
381
- if (resolvedOptions.signal && upstreamAbortHandler) {
382
- resolvedOptions.signal.removeEventListener('abort', upstreamAbortHandler);
383
- }
384
- });
385
- return {
386
- authUrl,
387
- result,
388
- cancel: () => abortController.abort(new Error('Authentication cancelled')),
389
- };
390
- }
391
- /**
392
- * Perform OAuth login flow with Supabase
393
- */
394
- export async function performOAuthLogin(config, options = {}) {
395
- try {
396
- const session = await beginOAuthLogin(config);
397
- console.log(chalk.cyan('🌐 Opening browser for authentication...'));
398
- try {
399
- const { default: open } = await import('open');
400
- await open(session.authUrl);
401
- console.log(chalk.green('✅ Browser opened'));
402
- }
403
- catch (error) {
404
- if (options.failOnBrowserOpenError) {
405
- session.cancel();
406
- throw new Error(`Browser launch failed: ${error instanceof Error ? error.message : String(error)}`);
407
- }
408
- console.log(chalk.yellow(`💡 Please open manually: ${session.authUrl}`));
409
- }
410
- const spinner = p.spinner();
411
- spinner.start('Waiting for authentication...');
412
- try {
413
- const result = await session.result;
414
- spinner.stop('Authentication successful!');
415
- return result;
416
- }
417
- catch (error) {
418
- spinner.stop('Authentication failed');
419
- throw error;
420
- }
421
- }
422
- catch (_error) {
423
- throw new Error(`OAuth login failed: ${_error instanceof Error ? _error.message : String(_error)}`);
424
- }
425
- }
426
- /**
427
- * Default Supabase OAuth configuration for Dexto CLI
428
- */
429
- export const DEFAULT_OAUTH_CONFIG = {
430
- authUrl: SUPABASE_URL,
431
- clientId: SUPABASE_ANON_KEY,
432
- provider: 'google',
433
- scopes: ['openid', 'email', 'profile'],
434
- };
@@ -1,24 +0,0 @@
1
- export interface AuthConfig {
2
- /** Supabase access token from OAuth login (optional if using --api-key) */
3
- token?: string | undefined;
4
- refreshToken?: string | undefined;
5
- userId?: string | undefined;
6
- email?: string | undefined;
7
- expiresAt?: number | undefined;
8
- createdAt: number;
9
- /** Dexto API key for gateway access (from --api-key or provisioned after OAuth) */
10
- dextoApiKey?: string | undefined;
11
- dextoKeyId?: string | undefined;
12
- /** Application origin that issued the saved API key; absent for legacy credentials. */
13
- dextoPlatformUrl?: string | undefined;
14
- dextoApiKeySource?: 'provisioned' | 'user-supplied' | undefined;
15
- }
16
- export declare function storeAuth(config: AuthConfig): Promise<void>;
17
- export declare function loadAuth(): Promise<AuthConfig | null>;
18
- export declare function removeAuth(): Promise<void>;
19
- export declare function isAuthenticated(): Promise<boolean>;
20
- export declare function getAuthToken(): Promise<string | null>;
21
- export declare function getAuthTokenQuietly(): Promise<string | null>;
22
- export declare function getDextoApiKey(): Promise<string | null>;
23
- export declare function getAuthFilePath(): string;
24
- //# sourceMappingURL=service.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/service.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,UAAU;IACvB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,uFAAuF;IACvF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iBAAiB,CAAC,EAAE,aAAa,GAAG,eAAe,GAAG,SAAS,CAAC;CACnE;AAmBD,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAQjE;AAED,wBAAsB,QAAQ,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CA4B3D;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAOhD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD;AAsDD,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE3D;AAED,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAElE;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAQ7D;AA8CD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -1,161 +0,0 @@
1
- // packages/cli/src/cli/auth/service.ts
2
- // Auth storage, token management, and refresh logic
3
- import chalk from 'chalk';
4
- import { existsSync, promises as fs } from 'fs';
5
- import { z } from 'zod';
6
- import { getDextoGlobalPath, logger } from '@dexto/core';
7
- import { SUPABASE_URL, SUPABASE_ANON_KEY } from './constants.js';
8
- const AUTH_CONFIG_FILE = 'auth.json';
9
- const AuthConfigSchema = z
10
- .object({
11
- token: z.string().min(1).optional(),
12
- refreshToken: z.string().optional(),
13
- userId: z.string().optional(),
14
- email: z.string().email().optional(),
15
- expiresAt: z.number().optional(),
16
- createdAt: z.number(),
17
- dextoApiKey: z.string().optional(),
18
- dextoKeyId: z.string().optional(),
19
- dextoPlatformUrl: z.string().url().optional(),
20
- dextoApiKeySource: z.enum(['provisioned', 'user-supplied']).optional(),
21
- })
22
- .refine((data) => data.token || data.dextoApiKey, {
23
- message: 'Either token (from OAuth) or dextoApiKey (from --api-key) is required',
24
- });
25
- export async function storeAuth(config) {
26
- const authPath = getDextoGlobalPath('', AUTH_CONFIG_FILE);
27
- const dextoDir = getDextoGlobalPath('', '');
28
- await fs.mkdir(dextoDir, { recursive: true });
29
- await fs.writeFile(authPath, JSON.stringify(config, null, 2), { mode: 0o600 });
30
- logger.debug(`Stored auth config at: ${authPath}`);
31
- }
32
- export async function loadAuth() {
33
- const authPath = getDextoGlobalPath('', AUTH_CONFIG_FILE);
34
- if (!existsSync(authPath)) {
35
- return null;
36
- }
37
- try {
38
- const content = await fs.readFile(authPath, 'utf-8');
39
- const config = JSON.parse(content);
40
- const validated = AuthConfigSchema.parse(config);
41
- if (validated.expiresAt && validated.expiresAt < Date.now()) {
42
- // Only remove auth if there's no refresh token available
43
- // If refresh token exists, return the expired auth and let getAuthToken() handle refresh
44
- if (!validated.refreshToken) {
45
- await removeAuth();
46
- return null;
47
- }
48
- }
49
- return validated;
50
- }
51
- catch (error) {
52
- logger.warn(`Invalid auth config, removing: ${error}`);
53
- await removeAuth();
54
- return null;
55
- }
56
- }
57
- export async function removeAuth() {
58
- const authPath = getDextoGlobalPath('', AUTH_CONFIG_FILE);
59
- if (existsSync(authPath)) {
60
- await fs.unlink(authPath);
61
- logger.debug(`Removed auth config from: ${authPath}`);
62
- }
63
- }
64
- export async function isAuthenticated() {
65
- const auth = await loadAuth();
66
- return auth !== null;
67
- }
68
- async function resolveAuthToken(options) {
69
- const auth = await loadAuth();
70
- if (!auth) {
71
- return null;
72
- }
73
- const now = Date.now();
74
- const fiveMinutes = 5 * 60 * 1000;
75
- const isExpiringSoon = auth.expiresAt && auth.expiresAt < now + fiveMinutes;
76
- if (!isExpiringSoon) {
77
- return auth.token ?? null;
78
- }
79
- if (!auth.refreshToken) {
80
- logger.debug('Token expired but no refresh token available');
81
- await removeAuth();
82
- return null;
83
- }
84
- logger.debug('Access token expired or expiring soon, refreshing...');
85
- if (!options.quiet) {
86
- console.log(chalk.cyan('🔄 Access token expiring soon, refreshing...'));
87
- }
88
- const refreshResult = await refreshAccessToken(auth.refreshToken);
89
- if (!refreshResult) {
90
- logger.debug('Token refresh failed, removing auth');
91
- if (!options.quiet) {
92
- console.log(chalk.red('❌ Token refresh failed. Please login again.'));
93
- }
94
- await removeAuth();
95
- return null;
96
- }
97
- const newExpiresAt = Date.now() + refreshResult.expiresIn * 1000;
98
- await storeAuth({
99
- ...auth,
100
- token: refreshResult.accessToken,
101
- refreshToken: refreshResult.refreshToken,
102
- expiresAt: newExpiresAt,
103
- });
104
- logger.debug('Token refreshed successfully');
105
- if (!options.quiet) {
106
- console.log(chalk.green('✅ Access token refreshed successfully'));
107
- }
108
- return refreshResult.accessToken;
109
- }
110
- export async function getAuthToken() {
111
- return resolveAuthToken({ quiet: false });
112
- }
113
- export async function getAuthTokenQuietly() {
114
- return resolveAuthToken({ quiet: true });
115
- }
116
- export async function getDextoApiKey() {
117
- // Explicit env var takes priority (for CI, testing, account override)
118
- if (process.env.DEXTO_API_KEY?.trim()) {
119
- return process.env.DEXTO_API_KEY;
120
- }
121
- // Fall back to auth.json (from `dexto login`)
122
- const auth = await loadAuth();
123
- return auth?.dextoApiKey || null;
124
- }
125
- async function refreshAccessToken(refreshToken) {
126
- try {
127
- const response = await fetch(`${SUPABASE_URL}/auth/v1/token?grant_type=refresh_token`, {
128
- method: 'POST',
129
- headers: {
130
- 'Content-Type': 'application/json',
131
- apikey: SUPABASE_ANON_KEY,
132
- },
133
- body: JSON.stringify({
134
- refresh_token: refreshToken,
135
- }),
136
- signal: AbortSignal.timeout(10_000),
137
- });
138
- if (!response.ok) {
139
- logger.debug(`Token refresh failed: ${response.status}`);
140
- return null;
141
- }
142
- const data = await response.json();
143
- if (!data.access_token || !data.refresh_token) {
144
- logger.debug('Token refresh response missing required tokens');
145
- return null;
146
- }
147
- logger.debug('Successfully refreshed access token');
148
- return {
149
- accessToken: data.access_token,
150
- refreshToken: data.refresh_token,
151
- expiresIn: data.expires_in || 3600,
152
- };
153
- }
154
- catch (error) {
155
- logger.debug(`Token refresh error: ${error instanceof Error ? error.message : String(error)}`);
156
- return null;
157
- }
158
- }
159
- export function getAuthFilePath() {
160
- return getDextoGlobalPath('', AUTH_CONFIG_FILE);
161
- }
@@ -1,11 +0,0 @@
1
- export interface AuthenticatedUser {
2
- id: string;
3
- email: string;
4
- name?: string | undefined;
5
- }
6
- export interface DeviceApiKeyLoginResult {
7
- dextoApiKey: string;
8
- dextoKeyId: string;
9
- dextoKeyDisplay: string;
10
- }
11
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CAC3B"}
@@ -1 +0,0 @@
1
- export {};
@@ -1,18 +0,0 @@
1
- import { type AgentEventMap } from '@dexto/core';
2
- import { type TuiAgentBackend } from '@dexto/tui';
3
- import { createDeployClient } from './commands/deploy/client.js';
4
- export interface StartCloudChatCliOptions {
5
- cloudAgentId?: string;
6
- initialPrompt?: string;
7
- resume?: string;
8
- continueMostRecent?: boolean;
9
- workspaceRoot?: string;
10
- }
11
- type DeployClient = ReturnType<typeof createDeployClient>;
12
- type CloudApprovalDecision = Parameters<DeployClient['submitCloudAgentApproval']>[2];
13
- type CloudChatBackend = TuiAgentBackend;
14
- export declare function buildCloudApprovalDecision(approval: AgentEventMap['approval:response']): CloudApprovalDecision | null;
15
- export declare function createCloudAgentBackend(client: DeployClient, cloudAgentId: string): CloudChatBackend;
16
- export declare function startCloudChatCli(options: StartCloudChatCliOptions): Promise<void>;
17
- export {};
18
- //# sourceMappingURL=cloud-chat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloud-chat.d.ts","sourceRoot":"","sources":["../../src/cli/cloud-chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAIH,KAAK,aAAa,EASrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAyB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAGjE,MAAM,WAAW,wBAAwB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,aAAa,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAK1D,KAAK,qBAAqB,GAAG,UAAU,CAAC,YAAY,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AASrF,KAAK,gBAAgB,GAAG,eAAe,CAAC;AAmNxC,wBAAgB,0BAA0B,CACtC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,GAC7C,qBAAqB,GAAG,IAAI,CAsB9B;AA4CD,wBAAgB,uBAAuB,CACnC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,MAAM,GACrB,gBAAgB,CAimBlB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBxF"}