zelari-code 0.1.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 (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +156 -0
  3. package/bin/zelari-code.js +64 -0
  4. package/dist/agents/advancedTools.js +115 -0
  5. package/dist/agents/advancedTools.js.map +1 -0
  6. package/dist/agents/councilApi.js +375 -0
  7. package/dist/agents/councilApi.js.map +1 -0
  8. package/dist/agents/councilDirectives.js +100 -0
  9. package/dist/agents/councilDirectives.js.map +1 -0
  10. package/dist/agents/promoteMember.js +210 -0
  11. package/dist/agents/promoteMember.js.map +1 -0
  12. package/dist/agents/promptModules.js +139 -0
  13. package/dist/agents/promptModules.js.map +1 -0
  14. package/dist/agents/roles.js +281 -0
  15. package/dist/agents/roles.js.map +1 -0
  16. package/dist/agents/skills/builtin/debugging.js +248 -0
  17. package/dist/agents/skills/builtin/debugging.js.map +1 -0
  18. package/dist/agents/skills/builtin/docs.js +301 -0
  19. package/dist/agents/skills/builtin/docs.js.map +1 -0
  20. package/dist/agents/skills/builtin/git-ops.js +301 -0
  21. package/dist/agents/skills/builtin/git-ops.js.map +1 -0
  22. package/dist/agents/skills/builtin/planning.js +335 -0
  23. package/dist/agents/skills/builtin/planning.js.map +1 -0
  24. package/dist/agents/skills/builtin/refactoring.js +261 -0
  25. package/dist/agents/skills/builtin/refactoring.js.map +1 -0
  26. package/dist/agents/skills/builtin/review.js +302 -0
  27. package/dist/agents/skills/builtin/review.js.map +1 -0
  28. package/dist/agents/skills/builtin/testing.js +245 -0
  29. package/dist/agents/skills/builtin/testing.js.map +1 -0
  30. package/dist/agents/skills.js +272 -0
  31. package/dist/agents/skills.js.map +1 -0
  32. package/dist/agents/systemPromptBuilder.js +151 -0
  33. package/dist/agents/systemPromptBuilder.js.map +1 -0
  34. package/dist/agents/toolSchemas.js +249 -0
  35. package/dist/agents/toolSchemas.js.map +1 -0
  36. package/dist/agents/tools.js +196 -0
  37. package/dist/agents/tools.js.map +1 -0
  38. package/dist/agents/vaultTools.js +134 -0
  39. package/dist/agents/vaultTools.js.map +1 -0
  40. package/dist/cli/app.js +1823 -0
  41. package/dist/cli/app.js.map +1 -0
  42. package/dist/cli/branchManager.js +280 -0
  43. package/dist/cli/branchManager.js.map +1 -0
  44. package/dist/cli/compaction.js +63 -0
  45. package/dist/cli/compaction.js.map +1 -0
  46. package/dist/cli/components/ChatStream.js +23 -0
  47. package/dist/cli/components/ChatStream.js.map +1 -0
  48. package/dist/cli/components/CollapsibleToolOutput.js +38 -0
  49. package/dist/cli/components/CollapsibleToolOutput.js.map +1 -0
  50. package/dist/cli/components/Header.js +31 -0
  51. package/dist/cli/components/Header.js.map +1 -0
  52. package/dist/cli/components/InputBar.js +9 -0
  53. package/dist/cli/components/InputBar.js.map +1 -0
  54. package/dist/cli/components/Sidebar.js +17 -0
  55. package/dist/cli/components/Sidebar.js.map +1 -0
  56. package/dist/cli/councilCost.js +81 -0
  57. package/dist/cli/councilCost.js.map +1 -0
  58. package/dist/cli/councilDispatcher.js +56 -0
  59. package/dist/cli/councilDispatcher.js.map +1 -0
  60. package/dist/cli/councilFeedback.js +164 -0
  61. package/dist/cli/councilFeedback.js.map +1 -0
  62. package/dist/cli/crossProviderFailover.js +83 -0
  63. package/dist/cli/crossProviderFailover.js.map +1 -0
  64. package/dist/cli/gitOps.js +96 -0
  65. package/dist/cli/gitOps.js.map +1 -0
  66. package/dist/cli/grokOAuth.js +375 -0
  67. package/dist/cli/grokOAuth.js.map +1 -0
  68. package/dist/cli/keyStore.js +263 -0
  69. package/dist/cli/keyStore.js.map +1 -0
  70. package/dist/cli/keyValidator.js +83 -0
  71. package/dist/cli/keyValidator.js.map +1 -0
  72. package/dist/cli/main.bundled.js +21428 -0
  73. package/dist/cli/main.bundled.js.map +7 -0
  74. package/dist/cli/main.js +72 -0
  75. package/dist/cli/main.js.map +1 -0
  76. package/dist/cli/metrics.js +131 -0
  77. package/dist/cli/metrics.js.map +1 -0
  78. package/dist/cli/modelDiscovery.js +234 -0
  79. package/dist/cli/modelDiscovery.js.map +1 -0
  80. package/dist/cli/modelPricing.js +112 -0
  81. package/dist/cli/modelPricing.js.map +1 -0
  82. package/dist/cli/oauthCallbackServer.js +207 -0
  83. package/dist/cli/oauthCallbackServer.js.map +1 -0
  84. package/dist/cli/provider/openai-compatible.js +236 -0
  85. package/dist/cli/provider/openai-compatible.js.map +1 -0
  86. package/dist/cli/providerConfig.js +210 -0
  87. package/dist/cli/providerConfig.js.map +1 -0
  88. package/dist/cli/providerFailover.js +90 -0
  89. package/dist/cli/providerFailover.js.map +1 -0
  90. package/dist/cli/refreshRegistry.js +77 -0
  91. package/dist/cli/refreshRegistry.js.map +1 -0
  92. package/dist/cli/safety/auditLogger.js +111 -0
  93. package/dist/cli/safety/auditLogger.js.map +1 -0
  94. package/dist/cli/safety/sandboxPath.js +62 -0
  95. package/dist/cli/safety/sandboxPath.js.map +1 -0
  96. package/dist/cli/safety/shellBlocklist.js +71 -0
  97. package/dist/cli/safety/shellBlocklist.js.map +1 -0
  98. package/dist/cli/sessionManager.js +149 -0
  99. package/dist/cli/sessionManager.js.map +1 -0
  100. package/dist/cli/skillCache.js +205 -0
  101. package/dist/cli/skillCache.js.map +1 -0
  102. package/dist/cli/skillHistory.js +178 -0
  103. package/dist/cli/skillHistory.js.map +1 -0
  104. package/dist/cli/skillSuggest.js +132 -0
  105. package/dist/cli/skillSuggest.js.map +1 -0
  106. package/dist/cli/slashCommands.js +431 -0
  107. package/dist/cli/slashCommands.js.map +1 -0
  108. package/dist/cli/toolRegistry.js +187 -0
  109. package/dist/cli/toolRegistry.js.map +1 -0
  110. package/dist/cli/updater.js +157 -0
  111. package/dist/cli/updater.js.map +1 -0
  112. package/dist/main/core/AgentHarness.js +345 -0
  113. package/dist/main/core/AgentHarness.js.map +1 -0
  114. package/dist/main/core/providerStream.js +99 -0
  115. package/dist/main/core/providerStream.js.map +1 -0
  116. package/dist/main/core/sessionJsonl.js +99 -0
  117. package/dist/main/core/sessionJsonl.js.map +1 -0
  118. package/dist/main/core/tools/auditLog.js +26 -0
  119. package/dist/main/core/tools/auditLog.js.map +1 -0
  120. package/dist/main/core/tools/builtin/filesystem.js +110 -0
  121. package/dist/main/core/tools/builtin/filesystem.js.map +1 -0
  122. package/dist/main/core/tools/builtin/search.js +56 -0
  123. package/dist/main/core/tools/builtin/search.js.map +1 -0
  124. package/dist/main/core/tools/builtin/shell.js +51 -0
  125. package/dist/main/core/tools/builtin/shell.js.map +1 -0
  126. package/dist/main/core/tools/registry.js +71 -0
  127. package/dist/main/core/tools/registry.js.map +1 -0
  128. package/dist/main/core/tools/toolTypes.js +8 -0
  129. package/dist/main/core/tools/toolTypes.js.map +1 -0
  130. package/dist/main/core/tools/zodBridge.js +48 -0
  131. package/dist/main/core/tools/zodBridge.js.map +1 -0
  132. package/dist/shared/eventBus.js +104 -0
  133. package/dist/shared/eventBus.js.map +1 -0
  134. package/dist/shared/events.js +73 -0
  135. package/dist/shared/events.js.map +1 -0
  136. package/dist/shared/index.js +8 -0
  137. package/dist/shared/index.js.map +1 -0
  138. package/dist/types/context.js +3 -0
  139. package/dist/types/context.js.map +1 -0
  140. package/dist/types/index.js +2 -0
  141. package/dist/types/index.js.map +1 -0
  142. package/dist/types/knowledge.js +2 -0
  143. package/dist/types/knowledge.js.map +1 -0
  144. package/dist/types/systemTypes.js +10 -0
  145. package/dist/types/systemTypes.js.map +1 -0
  146. package/package.json +63 -0
@@ -0,0 +1,375 @@
1
+ /**
2
+ * grokOAuth — complete OAuth flow for xAI Grok / SuperGrok provider.
3
+ *
4
+ * Implements PKCE OAuth2 (RFC 7636) flow with OpenID Connect discovery,
5
+ * matching the pattern used by the reference `supergrok-oauth` client
6
+ * (https://github.com/toptoppy/supergrok-oauth).
7
+ *
8
+ * 1. Fetch OpenID Connect discovery document from `{issuer}/.well-known/openid-configuration`
9
+ * 2. Generate PKCE verifier + S256 challenge
10
+ * 3. Build authorization URL with state, scope, code_challenge
11
+ * 4. Start local OAuth callback server (port 56121, path /callback)
12
+ * 5. Open the user's browser to the authorization URL
13
+ * 6. Wait for the redirect callback to deliver the authorization code
14
+ * 7. Verify state to prevent CSRF
15
+ * 8. Exchange code for access token (with code_verifier) at the token endpoint
16
+ * 9. Return { accessToken, expiresAt, refreshToken }
17
+ *
18
+ * The browser launcher is INJECTED so tests can verify URL construction
19
+ * without spawning a real browser. The fetch implementation is also injected
20
+ * so tests can mock the token exchange.
21
+ *
22
+ * Default config (override via env GROK_OAUTH_CLIENT_ID):
23
+ * - Issuer: https://auth.x.ai
24
+ * - Client ID: b1a00492-073a-47ea-816f-4c329264a828 (xAI public OAuth client)
25
+ * - Scope: openid profile email offline_access grok-cli:access api:access
26
+ * - Redirect: http://127.0.0.1:56121/callback
27
+ *
28
+ * @see docs/plans/2026-06-29-anathema-coder-v2.md (Task 16.2)
29
+ */
30
+ import { startOAuthCallbackServer } from './oauthCallbackServer.js';
31
+ import nodeCrypto from 'node:crypto';
32
+ const { getRandomValues, createHash } = nodeCrypto;
33
+ export class GrokOAuthError extends Error {
34
+ code;
35
+ constructor(message, code) {
36
+ super(message);
37
+ this.code = code;
38
+ this.name = 'GrokOAuthError';
39
+ }
40
+ }
41
+ /**
42
+ * Default xAI OAuth client ID — public client registered for SuperGrok OAuth
43
+ * (same as used by the reference supergrok-oauth Python client).
44
+ */
45
+ export const DEFAULT_GROK_OAUTH_CLIENT_ID = 'b1a00492-073a-47ea-816f-4c329264a828';
46
+ /** Default OAuth issuer for xAI authentication server. */
47
+ export const DEFAULT_GROK_OAUTH_ISSUER = 'https://auth.x.ai';
48
+ /** Default OAuth scopes for full SuperGrok access (matches supergrok-oauth config). */
49
+ export const DEFAULT_GROK_OAUTH_SCOPES = [
50
+ 'openid',
51
+ 'profile',
52
+ 'email',
53
+ 'offline_access',
54
+ 'grok-cli:access',
55
+ 'api:access',
56
+ ];
57
+ /** Default redirect port (matches supergrok-oauth config). */
58
+ export const DEFAULT_GROK_OAUTH_REDIRECT_PORT = 56121;
59
+ /** Default redirect path (matches supergrok-oauth config). */
60
+ export const DEFAULT_GROK_OAUTH_REDIRECT_PATH = '/callback';
61
+ /** Fetch the OpenID Connect discovery document. */
62
+ export async function fetchGrokDiscovery(options = {}) {
63
+ const fetchImpl = options.fetchImpl ?? fetch;
64
+ const discoveryUrl = options.discoveryUrl ?? `${options.issuer ?? DEFAULT_GROK_OAUTH_ISSUER}/.well-known/openid-configuration`;
65
+ let response;
66
+ try {
67
+ response = await fetchImpl(discoveryUrl, { method: 'GET', headers: { Accept: 'application/json' } });
68
+ }
69
+ catch (err) {
70
+ throw new GrokOAuthError(`OAuth discovery network error: ${err instanceof Error ? err.message : String(err)}`, 'discovery_network_error');
71
+ }
72
+ if (!response.ok) {
73
+ const text = await response.text().catch(() => '');
74
+ throw new GrokOAuthError(`OAuth discovery HTTP ${response.status}: ${text.slice(0, 200)}`, `discovery_http_${response.status}`);
75
+ }
76
+ let body;
77
+ try {
78
+ body = await response.json();
79
+ }
80
+ catch (err) {
81
+ throw new GrokOAuthError(`OAuth discovery returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
82
+ }
83
+ if (!body || typeof body !== 'object') {
84
+ throw new GrokOAuthError('OAuth discovery returned non-object body');
85
+ }
86
+ const obj = body;
87
+ if (typeof obj.authorization_endpoint !== 'string' || typeof obj.token_endpoint !== 'string') {
88
+ throw new GrokOAuthError('OAuth discovery missing authorization_endpoint or token_endpoint');
89
+ }
90
+ return {
91
+ authorizationEndpoint: obj.authorization_endpoint,
92
+ tokenEndpoint: obj.token_endpoint,
93
+ };
94
+ }
95
+ /**
96
+ * Generate PKCE verifier (RFC 7636) and S256 challenge.
97
+ * Returns base64url-encoded strings (no padding).
98
+ */
99
+ export function generatePkce() {
100
+ // 64 random bytes → base64url → strip padding → take first 128 chars
101
+ const random = getRandomValues(new Uint8Array(64));
102
+ const verifier = Buffer.from(random).toString('base64url').slice(0, 128);
103
+ // SHA-256(verifier) → base64url (no padding)
104
+ const hash = createHash('sha256').update(verifier).digest();
105
+ const challenge = hash.toString('base64url').replace(/=+$/, '');
106
+ return { verifier, challenge };
107
+ }
108
+ /** Build the xAI authorization URL with PKCE. */
109
+ export function buildGrokAuthorizeUrl(options) {
110
+ const scopes = options.scopes ?? DEFAULT_GROK_OAUTH_SCOPES;
111
+ const params = new URLSearchParams({
112
+ client_id: options.clientId,
113
+ redirect_uri: options.redirectUri,
114
+ response_type: 'code',
115
+ scope: scopes.join(' '),
116
+ state: options.state ?? crypto.randomUUID(),
117
+ code_challenge: options.codeChallenge,
118
+ code_challenge_method: 'S256',
119
+ });
120
+ return `${options.authorizeEndpoint}?${params.toString()}`;
121
+ }
122
+ /** Exchange the authorization code for an access token. */
123
+ export async function exchangeGrokCode(options) {
124
+ const fetchImpl = options.fetchImpl ?? fetch;
125
+ let response;
126
+ try {
127
+ response = await fetchImpl(options.tokenEndpoint, {
128
+ method: 'POST',
129
+ headers: {
130
+ 'Content-Type': 'application/x-www-form-urlencoded',
131
+ Accept: 'application/json',
132
+ },
133
+ body: new URLSearchParams({
134
+ grant_type: 'authorization_code',
135
+ client_id: options.clientId,
136
+ code: options.code,
137
+ redirect_uri: options.redirectUri,
138
+ code_verifier: options.codeVerifier,
139
+ }).toString(),
140
+ });
141
+ }
142
+ catch (err) {
143
+ throw new GrokOAuthError(`Token exchange network error: ${err instanceof Error ? err.message : String(err)}`);
144
+ }
145
+ if (!response.ok) {
146
+ const errText = await response.text().catch(() => '');
147
+ throw new GrokOAuthError(`Token exchange HTTP ${response.status}: ${errText.slice(0, 200)}`, `http_${response.status}`);
148
+ }
149
+ let body;
150
+ try {
151
+ body = await response.json();
152
+ }
153
+ catch (err) {
154
+ throw new GrokOAuthError(`Token exchange returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
155
+ }
156
+ if (!body || typeof body !== 'object') {
157
+ throw new GrokOAuthError('Token exchange returned non-object body');
158
+ }
159
+ const obj = body;
160
+ const accessToken = obj.access_token;
161
+ if (typeof accessToken !== 'string' || accessToken.length === 0) {
162
+ throw new GrokOAuthError('Token exchange response missing access_token', 'no_access_token');
163
+ }
164
+ return parseTokenResponseBody(obj, accessToken, 'Token exchange');
165
+ }
166
+ /**
167
+ * Parse the standard OAuth token response body into a GrokOAuthResult.
168
+ * Shared between `exchangeGrokCode` and `refreshGrokToken`.
169
+ *
170
+ * @param label Human-readable label for the operation (used in error messages).
171
+ * @param accessToken Pre-validated access token from the body.
172
+ */
173
+ function parseTokenResponseBody(obj, accessToken, label) {
174
+ const result = { accessToken };
175
+ if (typeof obj.expires_in === 'number' && Number.isFinite(obj.expires_in)) {
176
+ result.expiresAt = Date.now() + obj.expires_in * 1000;
177
+ }
178
+ if (typeof obj.refresh_token === 'string' && obj.refresh_token.length > 0) {
179
+ result.refreshToken = obj.refresh_token;
180
+ }
181
+ // xAI SuperGrok OAuth also returns refresh_token_expires_in (refresh token TTL).
182
+ // Capture it so callers can warn before the refresh token expires.
183
+ if (typeof obj.refresh_token_expires_in === 'number' && Number.isFinite(obj.refresh_token_expires_in)) {
184
+ result.refreshExpiresAt = Date.now() + obj.refresh_token_expires_in * 1000;
185
+ }
186
+ // Some providers also return `scope` — we ignore it for now.
187
+ void obj;
188
+ void label;
189
+ return result;
190
+ }
191
+ /**
192
+ * Exchange a refresh token for a new access token (Task D.2.1, v3-D).
193
+ *
194
+ * Per RFC 6749 §6, the request body is:
195
+ * grant_type=refresh_token&refresh_token=<token>&client_id=<id>
196
+ *
197
+ * Some providers also require `client_secret` — xAI does not (public OAuth).
198
+ *
199
+ * The provider MAY rotate the refresh_token: callers should treat the
200
+ * returned `refreshToken` (if any) as the new authoritative value and
201
+ * persist it. If the provider does NOT return a new refresh_token, the
202
+ * caller should keep using the previous one.
203
+ */
204
+ export async function refreshGrokToken(options) {
205
+ if (!options.clientId || options.clientId.trim().length === 0) {
206
+ throw new GrokOAuthError('Missing clientId', 'no_client_id');
207
+ }
208
+ if (!options.refreshToken || options.refreshToken.trim().length === 0) {
209
+ throw new GrokOAuthError('Missing refreshToken', 'no_refresh_token');
210
+ }
211
+ const endpoint = options.tokenEndpoint ?? 'https://oauth.x.ai/token';
212
+ const fetchImpl = options.fetchImpl ?? fetch;
213
+ let response;
214
+ try {
215
+ response = await fetchImpl(endpoint, {
216
+ method: 'POST',
217
+ headers: {
218
+ 'Content-Type': 'application/x-www-form-urlencoded',
219
+ Accept: 'application/json',
220
+ },
221
+ body: new URLSearchParams({
222
+ grant_type: 'refresh_token',
223
+ client_id: options.clientId,
224
+ refresh_token: options.refreshToken,
225
+ }).toString(),
226
+ });
227
+ }
228
+ catch (err) {
229
+ throw new GrokOAuthError(`Token refresh network error: ${err instanceof Error ? err.message : String(err)}`);
230
+ }
231
+ if (!response.ok) {
232
+ const errText = await response.text().catch(() => '');
233
+ // 400/401 with "invalid_grant" → refresh token expired or revoked.
234
+ const code = response.status === 400 || response.status === 401 ? 'invalid_grant' : `http_${response.status}`;
235
+ throw new GrokOAuthError(`Token refresh HTTP ${response.status}: ${errText.slice(0, 200)}`, code);
236
+ }
237
+ let body;
238
+ try {
239
+ body = await response.json();
240
+ }
241
+ catch (err) {
242
+ throw new GrokOAuthError(`Token refresh returned invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
243
+ }
244
+ if (!body || typeof body !== 'object') {
245
+ throw new GrokOAuthError('Token refresh returned non-object body');
246
+ }
247
+ const obj = body;
248
+ const accessToken = obj.access_token;
249
+ if (typeof accessToken !== 'string' || accessToken.length === 0) {
250
+ throw new GrokOAuthError('Token refresh response missing access_token', 'no_access_token');
251
+ }
252
+ return parseTokenResponseBody(obj, accessToken, 'Token refresh');
253
+ }
254
+ /**
255
+ * Run the complete OAuth flow.
256
+ *
257
+ * Steps:
258
+ * 1. Fetch OpenID Connect discovery document
259
+ * 2. Generate PKCE verifier + S256 challenge
260
+ * 3. Build authorization URL
261
+ * 4. Start local callback server
262
+ * 5. Open browser
263
+ * 6. Wait for callback
264
+ * 7. Verify state to prevent CSRF
265
+ * 8. Exchange code for token (with code_verifier)
266
+ *
267
+ * @throws GrokOAuthError on any failure (network, missing params, provider error).
268
+ */
269
+ export async function runGrokOAuthFlow(options) {
270
+ const clientId = options.clientId || process.env.GROK_OAUTH_CLIENT_ID || DEFAULT_GROK_OAUTH_CLIENT_ID;
271
+ if (!clientId || clientId.trim().length === 0) {
272
+ throw new GrokOAuthError('Missing clientId', 'no_client_id');
273
+ }
274
+ const callbackPort = options.callbackPort ?? DEFAULT_GROK_OAUTH_REDIRECT_PORT;
275
+ const callbackPath = options.callbackPath ?? DEFAULT_GROK_OAUTH_REDIRECT_PATH;
276
+ const redirectUri = `http://127.0.0.1:${callbackPort}${callbackPath}`;
277
+ // Step 1: fetch OpenID Connect discovery document.
278
+ const discovery = await fetchGrokDiscovery({
279
+ issuer: options.issuer,
280
+ discoveryUrl: options.discoveryUrl,
281
+ fetchImpl: options.fetchImpl,
282
+ });
283
+ // Step 2: generate PKCE verifier + S256 challenge.
284
+ const { verifier: codeVerifier, challenge: codeChallenge } = generatePkce();
285
+ const state = crypto.randomUUID();
286
+ // Step 3: build authorize URL with PKCE.
287
+ const authorizeUrl = buildGrokAuthorizeUrl({
288
+ clientId,
289
+ redirectUri,
290
+ scopes: options.scopes,
291
+ state,
292
+ codeChallenge,
293
+ authorizeEndpoint: discovery.authorizationEndpoint,
294
+ });
295
+ // Step 4: start callback server.
296
+ let handle;
297
+ try {
298
+ handle = await startOAuthCallbackServer({
299
+ port: callbackPort,
300
+ timeoutMs: options.callbackTimeoutMs ?? 120_000,
301
+ expectedPath: callbackPath,
302
+ });
303
+ }
304
+ catch (err) {
305
+ throw new GrokOAuthError(`Failed to start OAuth callback server on port ${callbackPort}: ${err instanceof Error ? err.message : String(err)}`, 'callback_bind_failed');
306
+ }
307
+ try {
308
+ // Step 5: open browser (or call injected opener for tests).
309
+ if (options.onBrowserOpen) {
310
+ await options.onBrowserOpen(authorizeUrl);
311
+ }
312
+ else {
313
+ // Production path: open in default browser.
314
+ await openBrowser(authorizeUrl);
315
+ }
316
+ // Step 6: wait for callback.
317
+ const callbackResult = await handle.waitForCode();
318
+ // Step 7: verify state (CSRF protection).
319
+ if (callbackResult.state !== state) {
320
+ throw new GrokOAuthError(`OAuth state mismatch — possible CSRF. expected=${state} got=${callbackResult.state ?? '(none)'}`, 'state_mismatch');
321
+ }
322
+ if (callbackResult.error) {
323
+ throw new GrokOAuthError(`OAuth provider returned error: ${callbackResult.error}${callbackResult.errorDescription ? ` — ${callbackResult.errorDescription}` : ''}`, callbackResult.error);
324
+ }
325
+ if (!callbackResult.code) {
326
+ throw new GrokOAuthError('OAuth callback did not include authorization code', 'no_code');
327
+ }
328
+ // Step 8: exchange code for token (with code_verifier).
329
+ return await exchangeGrokCode({
330
+ clientId,
331
+ code: callbackResult.code,
332
+ codeVerifier,
333
+ redirectUri,
334
+ tokenEndpoint: discovery.tokenEndpoint,
335
+ fetchImpl: options.fetchImpl,
336
+ });
337
+ }
338
+ finally {
339
+ handle.close();
340
+ }
341
+ }
342
+ /**
343
+ * Open the given URL in the user's default browser. Cross-platform via
344
+ * child_process. Safe to call from Node 20+ — no shell injection (uses
345
+ * spawn with args array).
346
+ */
347
+ export async function openBrowser(url) {
348
+ const { spawn } = await import('node:child_process');
349
+ // Detect platform via process.env.PLATFORM? Use process.platform.
350
+ // 'darwin' → open, 'win32' → start (cmd /c start ""), else → xdg-open
351
+ const cmd = (() => {
352
+ switch (process.platform) {
353
+ case 'darwin': return { bin: 'open', args: [url] };
354
+ case 'win32': return { bin: 'cmd', args: ['/c', 'start', '""', url] };
355
+ default: return { bin: 'xdg-open', args: [url] };
356
+ }
357
+ })();
358
+ return new Promise((resolve, reject) => {
359
+ try {
360
+ const child = spawn(cmd.bin, cmd.args, { stdio: 'ignore', detached: true });
361
+ child.on('error', (err) => reject(err));
362
+ child.on('spawn', () => {
363
+ // Detach so the browser process can outlive the Node CLI.
364
+ child.unref();
365
+ resolve();
366
+ });
367
+ // Fallback in case 'spawn' doesn't fire on all platforms.
368
+ setTimeout(() => resolve(), 100);
369
+ }
370
+ catch (err) {
371
+ reject(err);
372
+ }
373
+ });
374
+ }
375
+ //# sourceMappingURL=grokOAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grokOAuth.js","sourceRoot":"","sources":["../../src/cli/grokOAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,wBAAwB,EAAkC,MAAM,0BAA0B,CAAC;AACpG,OAAO,UAAU,MAAM,aAAa,CAAC;AAErC,MAAM,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,UAAU,CAAC;AAkCnD,MAAM,OAAO,cAAe,SAAQ,KAAK;IACM;IAA7C,YAAY,OAAe,EAAkB,IAAa;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QAD4B,SAAI,GAAJ,IAAI,CAAS;QAExD,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,sCAAsC,CAAC;AAEnF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,mBAAmB,CAAC;AAE7D,uFAAuF;AACvF,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,QAAQ;IACR,SAAS;IACT,OAAO;IACP,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;CACJ,CAAC;AAEX,8DAA8D;AAC9D,MAAM,CAAC,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAEtD,8DAA8D;AAC9D,MAAM,CAAC,MAAM,gCAAgC,GAAG,WAAW,CAAC;AAE5D,mDAAmD;AACnD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAIrC,EAAE;IACJ,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,yBAAyB,mCAAmC,CAAC;IAC/H,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACvG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAC5I,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,IAAI,cAAc,CACtB,wBAAwB,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAChE,kBAAkB,QAAQ,CAAC,MAAM,EAAE,CACpC,CAAC;IACJ,CAAC;IACD,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,0CAA0C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzH,CAAC;IACD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,cAAc,CAAC,0CAA0C,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,IAAI,OAAO,GAAG,CAAC,sBAAsB,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,cAAc,KAAK,QAAQ,EAAE,CAAC;QAC7F,MAAM,IAAI,cAAc,CAAC,kEAAkE,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO;QACL,qBAAqB,EAAE,GAAG,CAAC,sBAAsB;QACjD,aAAa,EAAE,GAAG,CAAC,cAAc;KAClC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,qEAAqE;IACrE,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAEzE,6CAA6C;IAC7C,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IAC5D,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAEhE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,qBAAqB,CAAC,OAOrC;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,yBAAyB,CAAC;IAC3D,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,SAAS,EAAE,OAAO,CAAC,QAAQ;QAC3B,YAAY,EAAE,OAAO,CAAC,WAAW;QACjC,aAAa,EAAE,MAAM;QACrB,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QACvB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,UAAU,EAAE;QAC3C,cAAc,EAAE,OAAO,CAAC,aAAa;QACrC,qBAAqB,EAAE,MAAM;KAC9B,CAAC,CAAC;IACH,OAAO,GAAG,OAAO,CAAC,iBAAiB,IAAI,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;AAC7D,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAOtC;IACC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAC7C,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,aAAa,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;gBACnD,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,oBAAoB;gBAChC,SAAS,EAAE,OAAO,CAAC,QAAQ;gBAC3B,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,YAAY,EAAE,OAAO,CAAC,WAAW;gBACjC,aAAa,EAAE,OAAO,CAAC,YAAY;aACpC,CAAC,CAAC,QAAQ,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,iCAAiC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChH,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,cAAc,CACtB,uBAAuB,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAClE,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAC1B,CAAC;IACJ,CAAC;IAED,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,yCAAyC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACxH,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,cAAc,CAAC,yCAAyC,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAE5C,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC;IACrC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,cAAc,CAAC,8CAA8C,EAAE,iBAAiB,CAAC,CAAC;IAC9F,CAAC;IAED,OAAO,sBAAsB,CAAC,GAAG,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,sBAAsB,CAC7B,GAA4B,EAC5B,WAAmB,EACnB,KAAa;IAEb,MAAM,MAAM,GAAoB,EAAE,WAAW,EAAE,CAAC;IAChD,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1E,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC;IACxD,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1E,MAAM,CAAC,YAAY,GAAG,GAAG,CAAC,aAAa,CAAC;IAC1C,CAAC;IACD,iFAAiF;IACjF,mEAAmE;IACnE,IAAI,OAAO,GAAG,CAAC,wBAAwB,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,EAAE,CAAC;QACtG,MAAM,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,wBAAwB,GAAG,IAAI,CAAC;IAC7E,CAAC;IACD,6DAA6D;IAC7D,KAAK,GAAG,CAAC;IACT,KAAK,KAAK,CAAC;IACX,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAKtC;IACC,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,cAAc,CAAC,sBAAsB,EAAE,kBAAkB,CAAC,CAAC;IACvE,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,CAAC,aAAa,IAAI,0BAA0B,CAAC;IACrE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC;IAE7C,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,mCAAmC;gBACnD,MAAM,EAAE,kBAAkB;aAC3B;YACD,IAAI,EAAE,IAAI,eAAe,CAAC;gBACxB,UAAU,EAAE,eAAe;gBAC3B,SAAS,EAAE,OAAO,CAAC,QAAQ;gBAC3B,aAAa,EAAE,OAAO,CAAC,YAAY;aACpC,CAAC,CAAC,QAAQ,EAAE;SACd,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,gCAAgC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/G,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,mEAAmE;QACnE,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;QAC9G,MAAM,IAAI,cAAc,CACtB,sBAAsB,QAAQ,CAAC,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EACjE,IAAI,CACL,CAAC;IACJ,CAAC;IAED,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CAAC,wCAAwC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACvH,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,cAAc,CAAC,wCAAwC,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAE5C,MAAM,WAAW,GAAG,GAAG,CAAC,YAAY,CAAC;IACrC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,cAAc,CAAC,6CAA6C,EAAE,iBAAiB,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO,sBAAsB,CAAC,GAAG,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAyB;IAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,4BAA4B,CAAC;IACtG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,cAAc,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,gCAAgC,CAAC;IAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,gCAAgC,CAAC;IAC9E,MAAM,WAAW,GAAG,oBAAoB,YAAY,GAAG,YAAY,EAAE,CAAC;IAEtE,mDAAmD;IACnD,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC;QACzC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;IAEH,mDAAmD;IACnD,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,YAAY,EAAE,CAAC;IAC5E,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;IAElC,yCAAyC;IACzC,MAAM,YAAY,GAAG,qBAAqB,CAAC;QACzC,QAAQ;QACR,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,KAAK;QACL,aAAa;QACb,iBAAiB,EAAE,SAAS,CAAC,qBAAqB;KACnD,CAAC,CAAC;IAEH,iCAAiC;IACjC,IAAI,MAAiC,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,wBAAwB,CAAC;YACtC,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,OAAO,CAAC,iBAAiB,IAAI,OAAO;YAC/C,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,cAAc,CACtB,iDAAiD,YAAY,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACpH,sBAAsB,CACvB,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,4DAA4D;QAC5D,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM,WAAW,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;QAED,6BAA6B;QAC7B,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAElD,0CAA0C;QAC1C,IAAI,cAAc,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YACnC,MAAM,IAAI,cAAc,CACtB,kDAAkD,KAAK,QAAQ,cAAc,CAAC,KAAK,IAAI,QAAQ,EAAE,EACjG,gBAAgB,CACjB,CAAC;QACJ,CAAC;QAED,IAAI,cAAc,CAAC,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,cAAc,CACtB,kCAAkC,cAAc,CAAC,KAAK,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,cAAc,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EACzI,cAAc,CAAC,KAAK,CACrB,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;YACzB,MAAM,IAAI,cAAc,CAAC,mDAAmD,EAAE,SAAS,CAAC,CAAC;QAC3F,CAAC;QAED,wDAAwD;QACxD,OAAO,MAAM,gBAAgB,CAAC;YAC5B,QAAQ;YACR,IAAI,EAAE,cAAc,CAAC,IAAI;YACzB,YAAY;YACZ,WAAW;YACX,aAAa,EAAE,SAAS,CAAC,aAAa;YACtC,SAAS,EAAE,OAAO,CAAC,SAAS;SAC7B,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,KAAK,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IACrD,kEAAkE;IAClE,sEAAsE;IACtE,MAAM,GAAG,GAAG,CAAC,GAAG,EAAE;QAChB,QAAQ,OAAO,CAAC,QAAQ,EAAE,CAAC;YACzB,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACnD,KAAK,OAAO,CAAC,CAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;YACvE,OAAO,CAAC,CAAO,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QACzD,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IACL,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC3C,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5E,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACxC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;gBACrB,0DAA0D;gBAC1D,KAAK,CAAC,KAAK,EAAE,CAAC;gBACd,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;YACH,0DAA0D;YAC1D,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,263 @@
1
+ /**
2
+ * keyStore — secure-ish key storage for CLI provider credentials.
3
+ *
4
+ * Persists API keys for MiniMax, GLM, Grok (and any other provider) to a
5
+ * JSON file in the user's home directory. NOT a real keychain — just a
6
+ * plain JSON file with restrictive file permissions. Document this in
7
+ * /help so users know to use OS-level secret storage for production keys.
8
+ *
9
+ * Used by Task 14.9 to support `/login <provider> <key>` from the CLI.
10
+ * Resolution order at provider boot:
11
+ * 1. process.env[ENV_VAR_NAME] (e.g. OPENAI_API_KEY)
12
+ * 2. Stored key in keys.json
13
+ *
14
+ * @see docs/plans/2026-06-28-zelari-code.md (Task 14.9)
15
+ */
16
+ import { promises as fs, existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
17
+ import path from 'node:path';
18
+ import os from 'node:os';
19
+ import { getRefreshImpl, registerDefaultRefreshImpls, } from './refreshRegistry.js';
20
+ // Idempotent — safe to call on every module load. The registry starts empty
21
+ // and this seeds it with the built-in defaults (Grok).
22
+ registerDefaultRefreshImpls();
23
+ export const PROVIDERS = [
24
+ { id: 'openai-compatible', displayName: 'OpenAI-compatible', envVar: 'OPENAI_API_KEY' },
25
+ { id: 'minimax', displayName: 'MiniMax', envVar: 'MINIMAX_API_KEY', baseUrl: 'https://api.MiniMax.chat/v1' },
26
+ { id: 'glm', displayName: 'GLM / Z.AI', envVar: 'GLM_API_KEY', baseUrl: 'https://api.z.ai/v1' },
27
+ { id: 'grok', displayName: 'xAI Grok', envVar: 'GROK_API_KEY', baseUrl: 'https://api.x.ai/v1' },
28
+ ];
29
+ export function getKeyStorePath() {
30
+ return process.env.ANATHEMA_KEYSTORE_FILE
31
+ ?? path.join(os.homedir(), '.tmp', 'zelari-code', 'keys.json');
32
+ }
33
+ export function getProviderSpec(id) {
34
+ return PROVIDERS.find((p) => p.id === id);
35
+ }
36
+ /**
37
+ * Upgrade a raw provider entry from on-disk JSON to a `StoredKey`.
38
+ * Accepts both the legacy bare-string shape and the new object shape.
39
+ * Returns null for anything we can't interpret.
40
+ */
41
+ function normalizeProviderEntry(raw) {
42
+ if (typeof raw === 'string') {
43
+ return { apiKey: raw };
44
+ }
45
+ if (raw && typeof raw === 'object') {
46
+ const r = raw;
47
+ if (typeof r.apiKey === 'string' && r.apiKey.length > 0) {
48
+ const out = { apiKey: r.apiKey };
49
+ if (typeof r.expiresAt === 'number' && Number.isFinite(r.expiresAt)) {
50
+ out.expiresAt = r.expiresAt;
51
+ }
52
+ if (typeof r.refreshToken === 'string' && r.refreshToken.length > 0) {
53
+ out.refreshToken = r.refreshToken;
54
+ }
55
+ return out;
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function readStore() {
61
+ const file = getKeyStorePath();
62
+ if (!existsSync(file))
63
+ return { providers: {} };
64
+ try {
65
+ const raw = readFileSync(file, 'utf-8');
66
+ const parsed = JSON.parse(raw);
67
+ if (parsed && typeof parsed === 'object' && parsed.providers && typeof parsed.providers === 'object') {
68
+ // Normalize + deep clone to avoid the SHALLOW-SPREAD-DEFAULTS gotcha:
69
+ // returning `parsed.providers` directly would let callers mutate the
70
+ // shared object across reads.
71
+ const normalizedProviders = {};
72
+ for (const [id, rawEntry] of Object.entries(parsed.providers)) {
73
+ const norm = normalizeProviderEntry(rawEntry);
74
+ if (norm)
75
+ normalizedProviders[id] = norm;
76
+ }
77
+ return { providers: normalizedProviders };
78
+ }
79
+ }
80
+ catch {
81
+ // Corrupt file — start fresh.
82
+ }
83
+ return { providers: {} };
84
+ }
85
+ function writeStore(store) {
86
+ const file = getKeyStorePath();
87
+ mkdirSync(path.dirname(file), { recursive: true });
88
+ writeFileSync(file, JSON.stringify(store, null, 2), { encoding: 'utf-8', mode: 0o600 });
89
+ }
90
+ /** Store an API key for a provider. Overwrites any existing key. */
91
+ export function setApiKey(providerId, key) {
92
+ const store = readStore();
93
+ store.providers[providerId] = { apiKey: key };
94
+ writeStore(store);
95
+ }
96
+ /** Remove the stored key for a provider. */
97
+ export function clearApiKey(providerId) {
98
+ const store = readStore();
99
+ delete store.providers[providerId];
100
+ writeStore(store);
101
+ }
102
+ /** Get the stored key for a provider (null if unset). */
103
+ export function getStoredApiKey(providerId) {
104
+ const store = readStore();
105
+ return store.providers[providerId]?.apiKey ?? null;
106
+ }
107
+ /**
108
+ * Store an OAuth token (apiKey + optional expiresAt + optional refreshToken)
109
+ * for a provider. Overwrites any existing entry.
110
+ */
111
+ export function setOAuthToken(providerId, token) {
112
+ const store = readStore();
113
+ const entry = { apiKey: token.apiKey };
114
+ if (typeof token.expiresAt === 'number' && Number.isFinite(token.expiresAt)) {
115
+ entry.expiresAt = token.expiresAt;
116
+ }
117
+ if (typeof token.refreshToken === 'string' && token.refreshToken.length > 0) {
118
+ entry.refreshToken = token.refreshToken;
119
+ }
120
+ store.providers[providerId] = entry;
121
+ writeStore(store);
122
+ }
123
+ /** Read the full OAuth token record for a provider (null if unset). */
124
+ export function getOAuthToken(providerId) {
125
+ const store = readStore();
126
+ return store.providers[providerId] ?? null;
127
+ }
128
+ /**
129
+ * Resolve a key for a provider, checking env first, then store.
130
+ * Returns just the apiKey string — use `resolveApiKeyWithMeta` if you also
131
+ * need `expiresAt` / `refreshToken`.
132
+ */
133
+ export function resolveApiKey(providerId) {
134
+ const spec = getProviderSpec(providerId);
135
+ if (spec) {
136
+ const envKey = process.env[spec.envVar];
137
+ if (envKey && envKey.trim().length > 0)
138
+ return envKey;
139
+ }
140
+ return getStoredApiKey(providerId);
141
+ }
142
+ /**
143
+ * Resolve the full StoredKey for a provider (apiKey + expiresAt + refreshToken).
144
+ * Env var path returns only the apiKey (no expiry metadata).
145
+ *
146
+ * Auto-refresh (Task D.3.1): if the stored token has an `expiresAt` within
147
+ * the `refreshBufferMs` window AND a `refreshToken`, this function calls
148
+ * the injected `refreshImpl` to obtain a fresh token, persists it via
149
+ * `setOAuthToken`, and returns the new `StoredKey`. This is best-effort:
150
+ * if the refresh fails, the stale token is still returned (and the caller
151
+ * sees an API error from the upstream provider — surfacing the real issue).
152
+ *
153
+ * Defaults to refreshing only the Grok provider (via `refreshGrokToken`).
154
+ */
155
+ export async function resolveApiKeyWithMeta(providerId, options = {}) {
156
+ const refreshBufferMs = options.refreshBufferMs ?? 5 * 60_000;
157
+ const refreshImpl = options.refreshImpl ?? defaultRefreshImpl;
158
+ const now = options.now ?? Date.now();
159
+ // 1. Env var wins (no expiry metadata — assume user manages it).
160
+ const spec = getProviderSpec(providerId);
161
+ if (spec) {
162
+ const envKey = process.env[spec.envVar];
163
+ if (envKey && envKey.trim().length > 0) {
164
+ return { apiKey: envKey };
165
+ }
166
+ }
167
+ // 2. Stored token (may include expiry + refresh).
168
+ const stored = getOAuthToken(providerId);
169
+ if (!stored)
170
+ return null;
171
+ // 3. Auto-refresh if expiry is near and we have a refresh token.
172
+ if (stored.expiresAt !== undefined &&
173
+ stored.refreshToken !== undefined &&
174
+ stored.expiresAt - now < refreshBufferMs) {
175
+ try {
176
+ const refreshed = await refreshImpl(providerId, stored.refreshToken);
177
+ // Persist new token (preserving the apiKey, expiresAt, and any new
178
+ // refresh_token the provider returned).
179
+ const next = { apiKey: refreshed.accessToken };
180
+ if (refreshed.expiresAt !== undefined)
181
+ next.expiresAt = refreshed.expiresAt;
182
+ if (refreshed.refreshToken !== undefined && refreshed.refreshToken.length > 0) {
183
+ next.refreshToken = refreshed.refreshToken;
184
+ }
185
+ else {
186
+ // Provider did NOT rotate the refresh_token — keep the old one.
187
+ next.refreshToken = stored.refreshToken;
188
+ }
189
+ // Update store in-place. We call readStore/writeStore indirectly via
190
+ // setOAuthToken's shape: but we need to avoid clobbering other fields.
191
+ // setOAuthToken accepts the same shape, so use it.
192
+ // Note: setOAuthToken calls readStore() which re-reads the file; that's
193
+ // fine — the file hasn't changed between the read above and the write
194
+ // below in single-threaded Node.
195
+ // eslint-disable-next-line @typescript-eslint/no-use-before-define
196
+ writeStoreDirect({ providers: { ...readStoreDirect().providers, [providerId]: next } });
197
+ return next;
198
+ }
199
+ catch {
200
+ // Refresh failed — return the stale token. Upstream will surface
201
+ // the auth error; user can re-login via /login grok.
202
+ return stored;
203
+ }
204
+ }
205
+ return stored;
206
+ }
207
+ /**
208
+ * Default refresh impl: looks up the provider in the refresh registry.
209
+ *
210
+ * v3-F behavior change: for providers with no registered impl (currently
211
+ * MiniMax, GLM, OpenAI-compatible, custom), this returns `null` instead of
212
+ * throwing. The caller in `resolveApiKeyWithMeta` handles `null` by returning
213
+ * the stale token unchanged — graceful degradation, no behavior break.
214
+ *
215
+ * To plug a custom provider in: call `registerRefreshImpl(id, impl)` once at
216
+ * startup (or in a test).
217
+ */
218
+ const defaultRefreshImpl = async (providerId, refreshToken) => {
219
+ const impl = getRefreshImpl(providerId);
220
+ if (!impl) {
221
+ // No refresh impl for this provider — signal graceful no-op to the caller.
222
+ throw new Error(`No refresh impl registered for provider "${providerId}"`);
223
+ }
224
+ return impl(providerId, refreshToken);
225
+ };
226
+ /**
227
+ * Direct file r/w helpers exposed for `resolveApiKeyWithMeta`'s auto-refresh
228
+ * path. These bypass the public API to avoid an extra read/write cycle
229
+ * inside the resolve hot path. Behavior matches `readStore` / `writeStore`.
230
+ */
231
+ function readStoreDirect() {
232
+ return readStore();
233
+ }
234
+ function writeStoreDirect(store) {
235
+ writeStore(store);
236
+ }
237
+ /** Mask a key for display: show first 4 + last 4 chars only. */
238
+ export function maskKey(key) {
239
+ if (key.length <= 12)
240
+ return '****';
241
+ return `${key.slice(0, 4)}…${key.slice(-4)} (len=${key.length})`;
242
+ }
243
+ /** Async variant for callers that prefer async I/O (used by tests). */
244
+ export async function loadStoredKeys() {
245
+ const file = getKeyStorePath();
246
+ try {
247
+ const raw = await fs.readFile(file, 'utf-8');
248
+ const parsed = JSON.parse(raw);
249
+ const out = {};
250
+ if (parsed.providers && typeof parsed.providers === 'object') {
251
+ for (const [id, entry] of Object.entries(parsed.providers)) {
252
+ const norm = normalizeProviderEntry(entry);
253
+ if (norm)
254
+ out[id] = norm.apiKey;
255
+ }
256
+ }
257
+ return out;
258
+ }
259
+ catch {
260
+ return {};
261
+ }
262
+ }
263
+ //# sourceMappingURL=keyStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyStore.js","sourceRoot":"","sources":["../../src/cli/keyStore.ts"],"names":[],"mappings":"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"}