workos 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/login.js +2 -1
- package/dist/commands/login.js.map +1 -1
- package/dist/doctor/checks/auth-patterns.js +10 -5
- package/dist/doctor/checks/auth-patterns.js.map +1 -1
- package/dist/lib/agent-interface.js.map +1 -1
- package/dist/lib/config-store.js +8 -7
- package/dist/lib/config-store.js.map +1 -1
- package/dist/lib/credential-store.js +8 -2
- package/dist/lib/credential-store.js.map +1 -1
- package/dist/lib/ensure-auth.js +9 -21
- package/dist/lib/ensure-auth.js.map +1 -1
- package/package.json +1 -1
- package/skills/workos-authkit-tanstack-start/SKILL.md +49 -12
package/dist/commands/login.js
CHANGED
|
@@ -3,6 +3,7 @@ import clack from '../utils/clack.js';
|
|
|
3
3
|
import { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';
|
|
4
4
|
import { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';
|
|
5
5
|
import { refreshAccessToken } from '../lib/token-refresh-client.js';
|
|
6
|
+
import { logInfo } from '../utils/debug.js';
|
|
6
7
|
/**
|
|
7
8
|
* Parse JWT payload
|
|
8
9
|
*/
|
|
@@ -61,8 +62,8 @@ export async function runLogin() {
|
|
|
61
62
|
const result = await refreshAccessToken(authkitDomain, clientId);
|
|
62
63
|
if (result.accessToken && result.expiresAt) {
|
|
63
64
|
updateTokens(result.accessToken, result.expiresAt, result.refreshToken);
|
|
65
|
+
logInfo('[login] Session refreshed via refresh token');
|
|
64
66
|
clack.log.info(`Already logged in as ${existingCreds.email ?? 'unknown'}`);
|
|
65
|
-
clack.log.info('(Session refreshed)');
|
|
66
67
|
clack.log.info('Run `workos logout` to log out');
|
|
67
68
|
return;
|
|
68
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\nimport { refreshAccessToken } from '../lib/token-refresh-client.js';\n\n/**\n * Parse JWT payload\n */\nfunction parseJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Extract expiry time from JWT token\n */\nfunction getJwtExpiry(token: string): number | null {\n const payload = parseJwt(token);\n if (!payload || typeof payload.exp !== 'number') return null;\n return payload.exp * 1000;\n}\n\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Get Connect OAuth endpoints from AuthKit domain\n */\nfunction getConnectEndpoints() {\n const domain = getAuthkitDomain();\n return {\n deviceAuthorization: `${domain}/oauth2/device_authorization`,\n token: `${domain}/oauth2/token`,\n };\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface ConnectTokenResponse {\n access_token: string;\n id_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n}\n\ninterface AuthErrorResponse {\n error: string;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n if (!clientId) {\n clack.log.error('CLI auth not configured. Set WORKOS_CLI_CLIENT_ID environment variable.');\n process.exit(1);\n }\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n clack.log.info(`Already logged in as ${creds?.email ?? 'unknown'}`);\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n\n // Try to refresh if we have expired credentials with a refresh token\n const existingCreds = getCredentials();\n if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {\n try {\n const authkitDomain = getAuthkitDomain();\n const result = await refreshAccessToken(authkitDomain, clientId);\n if (result.accessToken && result.expiresAt) {\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n clack.log.info(`Already logged in as ${existingCreds.email ?? 'unknown'}`);\n clack.log.info('(Session refreshed)');\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n } catch {\n // Refresh failed, proceed with fresh login\n }\n }\n\n clack.log.step('Starting authentication...');\n\n const endpoints = getConnectEndpoints();\n\n const authResponse = await fetch(endpoints.deviceAuthorization, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: clientId,\n scope: 'openid email staging-environment:credentials:read offline_access',\n }),\n });\n\n if (!authResponse.ok) {\n clack.log.error(`Failed to start authentication: ${authResponse.status}`);\n process.exit(1);\n }\n\n const deviceAuth = (await authResponse.json()) as DeviceAuthResponse;\n const pollIntervalMs = (deviceAuth.interval || 5) * 1000;\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n open(deviceAuth.verification_uri_complete);\n clack.log.info('Browser opened automatically');\n } catch {\n // User can open manually\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n const startTime = Date.now();\n let currentInterval = pollIntervalMs;\n\n while (Date.now() - startTime < POLL_TIMEOUT_MS) {\n await sleep(currentInterval);\n\n try {\n const tokenResponse = await fetch(endpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceAuth.device_code,\n client_id: clientId,\n }),\n });\n\n const data = await tokenResponse.json();\n\n if (tokenResponse.ok) {\n const result = data as ConnectTokenResponse;\n\n // Parse user info from id_token JWT\n const idTokenPayload = parseJwt(result.id_token);\n const userId = (idTokenPayload?.sub as string) || 'unknown';\n const email = (idTokenPayload?.email as string) || undefined;\n\n // Extract actual expiry from access token JWT, fallback to response or 15 min\n const jwtExpiry = getJwtExpiry(result.access_token);\n const expiresAt =\n jwtExpiry ?? (result.expires_in ? Date.now() + result.expires_in * 1000 : Date.now() + 15 * 60 * 1000);\n\n const expiresInSec = Math.round((expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.access_token,\n expiresAt,\n userId,\n email,\n refreshToken: result.refresh_token,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${email || userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n return;\n }\n\n const errorData = data as AuthErrorResponse;\n if (errorData.error === 'authorization_pending') continue;\n if (errorData.error === 'slow_down') {\n currentInterval += 5000;\n continue;\n }\n\n spinner.stop('Authentication failed');\n clack.log.error(`Authentication error: ${errorData.error}`);\n process.exit(1);\n } catch {\n continue;\n }\n }\n\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n process.exit(1);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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","sourcesContent":["import open from 'opn';\nimport clack from '../utils/clack.js';\nimport { saveCredentials, getCredentials, getAccessToken, isTokenExpired, updateTokens } from '../lib/credentials.js';\nimport { getCliAuthClientId, getAuthkitDomain } from '../lib/settings.js';\nimport { refreshAccessToken } from '../lib/token-refresh-client.js';\nimport { logInfo } from '../utils/debug.js';\n\n/**\n * Parse JWT payload\n */\nfunction parseJwt(token: string): Record<string, unknown> | null {\n try {\n const parts = token.split('.');\n if (parts.length !== 3) return null;\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));\n } catch {\n return null;\n }\n}\n\n/**\n * Extract expiry time from JWT token\n */\nfunction getJwtExpiry(token: string): number | null {\n const payload = parseJwt(token);\n if (!payload || typeof payload.exp !== 'number') return null;\n return payload.exp * 1000;\n}\n\nconst POLL_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n/**\n * Get Connect OAuth endpoints from AuthKit domain\n */\nfunction getConnectEndpoints() {\n const domain = getAuthkitDomain();\n return {\n deviceAuthorization: `${domain}/oauth2/device_authorization`,\n token: `${domain}/oauth2/token`,\n };\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n expires_in: number;\n interval: number;\n}\n\ninterface ConnectTokenResponse {\n access_token: string;\n id_token: string;\n token_type: string;\n expires_in: number;\n refresh_token?: string;\n}\n\ninterface AuthErrorResponse {\n error: string;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n if (!clientId) {\n clack.log.error('CLI auth not configured. Set WORKOS_CLI_CLIENT_ID environment variable.');\n process.exit(1);\n }\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n clack.log.info(`Already logged in as ${creds?.email ?? 'unknown'}`);\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n\n // Try to refresh if we have expired credentials with a refresh token\n const existingCreds = getCredentials();\n if (existingCreds?.refreshToken && isTokenExpired(existingCreds)) {\n try {\n const authkitDomain = getAuthkitDomain();\n const result = await refreshAccessToken(authkitDomain, clientId);\n if (result.accessToken && result.expiresAt) {\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n logInfo('[login] Session refreshed via refresh token');\n clack.log.info(`Already logged in as ${existingCreds.email ?? 'unknown'}`);\n clack.log.info('Run `workos logout` to log out');\n return;\n }\n } catch {\n // Refresh failed, proceed with fresh login\n }\n }\n\n clack.log.step('Starting authentication...');\n\n const endpoints = getConnectEndpoints();\n\n const authResponse = await fetch(endpoints.deviceAuthorization, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n client_id: clientId,\n scope: 'openid email staging-environment:credentials:read offline_access',\n }),\n });\n\n if (!authResponse.ok) {\n clack.log.error(`Failed to start authentication: ${authResponse.status}`);\n process.exit(1);\n }\n\n const deviceAuth = (await authResponse.json()) as DeviceAuthResponse;\n const pollIntervalMs = (deviceAuth.interval || 5) * 1000;\n\n clack.log.info(`\\nOpen this URL in your browser:\\n`);\n console.log(` ${deviceAuth.verification_uri}`);\n console.log(`\\nEnter code: ${deviceAuth.user_code}\\n`);\n\n try {\n open(deviceAuth.verification_uri_complete);\n clack.log.info('Browser opened automatically');\n } catch {\n // User can open manually\n }\n\n const spinner = clack.spinner();\n spinner.start('Waiting for authentication...');\n\n const startTime = Date.now();\n let currentInterval = pollIntervalMs;\n\n while (Date.now() - startTime < POLL_TIMEOUT_MS) {\n await sleep(currentInterval);\n\n try {\n const tokenResponse = await fetch(endpoints.token, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n device_code: deviceAuth.device_code,\n client_id: clientId,\n }),\n });\n\n const data = await tokenResponse.json();\n\n if (tokenResponse.ok) {\n const result = data as ConnectTokenResponse;\n\n // Parse user info from id_token JWT\n const idTokenPayload = parseJwt(result.id_token);\n const userId = (idTokenPayload?.sub as string) || 'unknown';\n const email = (idTokenPayload?.email as string) || undefined;\n\n // Extract actual expiry from access token JWT, fallback to response or 15 min\n const jwtExpiry = getJwtExpiry(result.access_token);\n const expiresAt =\n jwtExpiry ?? (result.expires_in ? Date.now() + result.expires_in * 1000 : Date.now() + 15 * 60 * 1000);\n\n const expiresInSec = Math.round((expiresAt - Date.now()) / 1000);\n\n saveCredentials({\n accessToken: result.access_token,\n expiresAt,\n userId,\n email,\n refreshToken: result.refresh_token,\n });\n\n spinner.stop('Authentication successful!');\n clack.log.success(`Logged in as ${email || userId}`);\n clack.log.info(`Token expires in ${expiresInSec} seconds`);\n return;\n }\n\n const errorData = data as AuthErrorResponse;\n if (errorData.error === 'authorization_pending') continue;\n if (errorData.error === 'slow_down') {\n currentInterval += 5000;\n continue;\n }\n\n spinner.stop('Authentication failed');\n clack.log.error(`Authentication error: ${errorData.error}`);\n process.exit(1);\n } catch {\n continue;\n }\n }\n\n spinner.stop('Authentication timed out');\n clack.log.error('Authentication timed out. Please try again.');\n process.exit(1);\n}\n"]}
|
|
@@ -256,13 +256,16 @@ function checkCallbackRouteMissing(ctx) {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
else if (ctx.framework.name === 'TanStack Start') {
|
|
259
|
-
//
|
|
259
|
+
// Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx
|
|
260
|
+
// Both conventions work in both src/ and app/ directories
|
|
260
261
|
const segments = callbackPath.replace(/^\//, '').split('/');
|
|
261
262
|
const flat = segments.join('.');
|
|
262
263
|
const nested = segments.join('/');
|
|
263
|
-
for (const
|
|
264
|
-
|
|
265
|
-
|
|
264
|
+
for (const prefix of ['src', 'app']) {
|
|
265
|
+
for (const ext of ['tsx', 'jsx', 'ts', 'js']) {
|
|
266
|
+
possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));
|
|
267
|
+
possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));
|
|
268
|
+
}
|
|
266
269
|
}
|
|
267
270
|
}
|
|
268
271
|
if (possiblePaths.length === 0)
|
|
@@ -365,7 +368,9 @@ function checkMissingAuthkitMiddleware(ctx) {
|
|
|
365
368
|
severity: 'warning',
|
|
366
369
|
message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',
|
|
367
370
|
filePath: relative(ctx.installDir, startFile),
|
|
368
|
-
remediation: 'Add authkitMiddleware to
|
|
371
|
+
remediation: 'Add authkitMiddleware to requestMiddleware in src/start.ts:\n' +
|
|
372
|
+
' import { authkitMiddleware } from "@workos/authkit-tanstack-react-start";\n' +
|
|
373
|
+
' export default createStart({ requestMiddleware: [authkitMiddleware()] });',
|
|
369
374
|
},
|
|
370
375
|
];
|
|
371
376
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Modern flat: src/routes/api.auth.callback.tsx Legacy nested: app/routes/api/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'src', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation: 'Add authkitMiddleware to your start.ts server middleware configuration.',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split('\\n').some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"auth-patterns.js","sourceRoot":"","sources":["../../../src/doctor/checks/auth-patterns.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport type {\n AuthPatternFinding,\n AuthPatternInfo,\n FrameworkInfo,\n EnvironmentInfo,\n SdkInfo,\n DoctorOptions,\n} from '../types.js';\n\n// --- Helpers ---\n\n/** Return the first path that exists, or null */\nfunction findFile(paths: string[]): string | null {\n for (const p of paths) {\n if (existsSync(p)) return p;\n }\n return null;\n}\n\n/** Read file content safely, return null on any error */\nfunction readFileSafe(filePath: string): string | null {\n try {\n return readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/** Test if a file exists and its content matches a regex */\nfunction fileContains(filePath: string, pattern: RegExp): boolean {\n const content = readFileSafe(filePath);\n if (!content) return false;\n return pattern.test(content);\n}\n\nconst SKIP_DIRS = new Set(['node_modules', '.next', '.turbo', 'dist', '.git', 'coverage']);\n\n/**\n * Find files matching a name pattern in a directory tree, limited to maxDepth levels.\n * Skips node_modules, .next, dist, etc.\n */\nfunction findFilesShallow(dir: string, namePattern: RegExp, maxDepth = 3): string[] {\n const results: string[] = [];\n if (!existsSync(dir)) return results;\n\n function walk(currentDir: string, depth: number) {\n if (depth > maxDepth) return;\n try {\n const dirents = readdirSync(currentDir, { withFileTypes: true });\n for (const dirent of dirents) {\n const fullPath = join(currentDir, dirent.name);\n if (dirent.isDirectory()) {\n if (!SKIP_DIRS.has(dirent.name)) {\n walk(fullPath, depth + 1);\n }\n } else if (dirent.isFile() && namePattern.test(dirent.name)) {\n results.push(fullPath);\n }\n }\n } catch {\n // Directory unreadable\n }\n }\n\n walk(dir, 0);\n return results;\n}\n\nfunction parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const entry = trimmed.startsWith('export ') ? trimmed.slice(7) : trimmed;\n const eqIndex = entry.indexOf('=');\n if (eqIndex === -1) continue;\n const key = entry.slice(0, eqIndex).trim();\n let value = entry.slice(eqIndex + 1).trim();\n if ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n result[key] = value;\n }\n return result;\n}\n\n/** Load all env vars from .env and .env.local files */\nfunction loadProjectEnvRaw(installDir: string): Record<string, string> {\n const env: Record<string, string> = {};\n for (const file of ['.env', '.env.local']) {\n const content = readFileSafe(join(installDir, file));\n if (content) Object.assign(env, parseEnvFile(content));\n }\n return env;\n}\n\n// --- Check Context ---\n\ninterface CheckContext {\n framework: FrameworkInfo;\n environment: EnvironmentInfo;\n sdk: SdkInfo;\n installDir: string;\n}\n\n// --- Individual Checks ---\n\n/** Resolve the app directory root (app/ or src/app/) for Next.js */\nfunction resolveAppDir(installDir: string): string | null {\n const srcApp = join(installDir, 'src', 'app');\n if (existsSync(srcApp)) return srcApp;\n const app = join(installDir, 'app');\n if (existsSync(app)) return app;\n return null;\n}\n\nfunction checkSignoutGetHandler(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const routeFiles = findFilesShallow(appDir, /^route\\.(ts|tsx|js|jsx)$/);\n const signoutRoutes = routeFiles.filter((f) => /[/\\\\](sign-?out|logout)[/\\\\]/.test(f));\n\n const findings: AuthPatternFinding[] = [];\n const GET_EXPORT = /export\\s+(async\\s+)?function\\s+GET|export\\s+const\\s+GET/;\n\n for (const route of signoutRoutes) {\n if (fileContains(route, GET_EXPORT)) {\n findings.push({\n code: 'SIGNOUT_GET_HANDLER',\n severity: 'error',\n message: 'Signout/logout route uses GET handler — vulnerable to CSRF and prefetch-triggered logouts',\n filePath: relative(ctx.installDir, route),\n remediation:\n 'Convert to a POST server action. GET routes with side effects are vulnerable to CSRF and will be triggered by Next.js link prefetching.',\n docsUrl: 'https://workos.com/docs/authkit/sign-out',\n });\n }\n }\n return findings;\n}\n\nfunction checkSignoutLinkPrefetch(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n const appDir = resolveAppDir(ctx.installDir);\n if (!appDir) return [];\n\n const tsxFiles = findFilesShallow(appDir, /\\.(tsx|jsx)$/);\n // Match <Link>, <NextLink>, or other common aliases\n const LINK_PATTERN = /<(?:Next)?Link\\s[^>]*href\\s*=\\s*[\"'{`/]*(\\/sign-?out|\\/logout)/;\n\n const findings: AuthPatternFinding[] = [];\n for (const file of tsxFiles) {\n if (fileContains(file, LINK_PATTERN)) {\n findings.push({\n code: 'SIGNOUT_LINK_PREFETCH',\n severity: 'warning',\n message:\n 'Link component points to signout/logout — Next.js will prefetch this in production, potentially triggering logouts',\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Use a <form> with a server action or <button> with onClick handler instead of <Link> for signout.',\n });\n }\n }\n return findings;\n}\n\nfunction checkMissingMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const middlewarePaths = [\n 'middleware.ts',\n 'middleware.js',\n 'proxy.ts',\n 'proxy.js',\n 'src/middleware.ts',\n 'src/middleware.js',\n 'src/proxy.ts',\n 'src/proxy.js',\n ].map((p) => join(ctx.installDir, p));\n\n if (findFile(middlewarePaths)) return [];\n\n return [\n {\n code: 'MISSING_MIDDLEWARE',\n severity: 'error',\n message: 'No middleware.ts or proxy.ts found — AuthKit session handling requires middleware',\n remediation: 'Create middleware.ts at the project root with authkitMiddleware() from @workos-inc/authkit-nextjs.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMiddlewareWrongLocation(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'Next.js') return [];\n\n const wrongPaths = ['app/middleware.ts', 'app/middleware.js', 'src/app/middleware.ts', 'src/app/middleware.js'].map(\n (p) => join(ctx.installDir, p),\n );\n\n const found = findFile(wrongPaths);\n if (!found) return [];\n\n return [\n {\n code: 'MIDDLEWARE_WRONG_LOCATION',\n severity: 'warning',\n message: 'middleware.ts found inside app/ directory — must be at project root or src/',\n filePath: relative(ctx.installDir, found),\n remediation: 'Move middleware.ts to the project root (or src/ if using src/ directory).',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/middleware',\n },\n ];\n}\n\nfunction checkMissingAuthKitProvider(ctx: CheckContext): AuthPatternFinding[] {\n const layoutPaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n layoutPaths.push(\n join(ctx.installDir, 'app', 'layout.tsx'),\n join(ctx.installDir, 'app', 'layout.jsx'),\n join(ctx.installDir, 'src', 'app', 'layout.tsx'),\n join(ctx.installDir, 'src', 'app', 'layout.jsx'),\n );\n } else if (ctx.framework.name === 'React Router' && ctx.framework.variant === 'declarative') {\n layoutPaths.push(\n join(ctx.installDir, 'src', 'App.tsx'),\n join(ctx.installDir, 'src', 'App.jsx'),\n join(ctx.installDir, 'app', 'root.tsx'),\n join(ctx.installDir, 'app', 'root.jsx'),\n );\n } else {\n return [];\n }\n\n const layoutFile = findFile(layoutPaths);\n if (!layoutFile) return []; // Can't check if layout doesn't exist\n\n if (fileContains(layoutFile, /AuthKitProvider/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_PROVIDER',\n severity: 'warning',\n message: 'AuthKitProvider not found in root layout — required for AuthKit session management',\n filePath: relative(ctx.installDir, layoutFile),\n remediation: 'Wrap your app with <AuthKitProvider> in the root layout.',\n docsUrl: 'https://workos.com/docs/authkit/nextjs/setup',\n },\n ];\n}\n\n/** Extract callback path from redirect URI env vars or framework default */\nfunction resolveCallbackPath(ctx: CheckContext): string | null {\n // Check env vars for actual redirect URI (including NEXT_PUBLIC_ variant)\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const redirectUri =\n projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI ?? ctx.environment.redirectUri;\n\n if (redirectUri) {\n try {\n return new URL(redirectUri).pathname;\n } catch {\n // Invalid URL, fall through to framework default\n }\n }\n\n return ctx.framework.expectedCallbackPath ?? null;\n}\n\nfunction checkCallbackRouteMissing(ctx: CheckContext): AuthPatternFinding[] {\n const callbackPath = resolveCallbackPath(ctx);\n if (!callbackPath) return [];\n\n // Build expected route file paths based on framework\n const possiblePaths: string[] = [];\n\n if (ctx.framework.name === 'Next.js') {\n // app/auth/callback/route.ts (or src/app/)\n const routeDir = callbackPath.replace(/^\\//, ''); // 'auth/callback'\n for (const prefix of ['app', 'src/app']) {\n for (const ext of ['ts', 'tsx', 'js', 'jsx']) {\n possiblePaths.push(join(ctx.installDir, prefix, routeDir, `route.${ext}`));\n }\n }\n } else if (ctx.framework.name === 'React Router') {\n // Flat: app/routes/auth.callback.tsx Nested: app/routes/auth/callback.tsx\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n } else if (ctx.framework.name === 'TanStack Start') {\n // Flat: routes/api.auth.callback.tsx Nested: routes/api/auth/callback.tsx\n // Both conventions work in both src/ and app/ directories\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n for (const prefix of ['src', 'app']) {\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, prefix, 'routes', nested + `.${ext}`));\n }\n }\n }\n\n if (possiblePaths.length === 0) return [];\n if (findFile(possiblePaths)) return [];\n\n return [\n {\n code: 'CALLBACK_ROUTE_MISSING',\n severity: 'error',\n message: `No callback route found at expected path ${callbackPath}`,\n remediation: `Create the callback route handler at the path matching your WORKOS_REDIRECT_URI.`,\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n ];\n}\n\nconst CLIENT_ENV_PREFIXES = ['NEXT_PUBLIC_', 'VITE_', 'REACT_APP_', 'EXPO_PUBLIC_'];\n\nfunction checkApiKeyLeakedToClient(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const findings: AuthPatternFinding[] = [];\n\n for (const [key, value] of Object.entries(projectEnv)) {\n const hasClientPrefix = CLIENT_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));\n if (!hasClientPrefix) continue;\n\n const isApiKey = key.includes('WORKOS_API_KEY');\n const isSecretValue = value?.startsWith('sk_test_') || value?.startsWith('sk_live_');\n\n if (isApiKey || isSecretValue) {\n findings.push({\n code: 'API_KEY_LEAKED_TO_CLIENT',\n severity: 'error',\n message: `Secret API key exposed via client-accessible env var ${key}`,\n remediation: `Remove the client prefix. WORKOS_API_KEY must be server-only (no NEXT_PUBLIC_, VITE_, REACT_APP_, or EXPO_PUBLIC_ prefix).`,\n });\n }\n }\n return findings;\n}\n\nfunction checkWrongCallbackLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n const callbackPath = ctx.framework.expectedCallbackPath;\n if (!callbackPath) return [];\n\n const segments = callbackPath.replace(/^\\//, '').split('/');\n const flat = segments.join('.');\n const nested = segments.join('/');\n\n const possiblePaths: string[] = [];\n for (const ext of ['tsx', 'jsx', 'ts', 'js']) {\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', `${flat}.${ext}`));\n possiblePaths.push(join(ctx.installDir, 'app', 'routes', nested + `.${ext}`));\n }\n\n const callbackFile = findFile(possiblePaths);\n if (!callbackFile) return []; // No callback route to check\n\n // authkitLoader is for regular routes; authLoader is for the callback\n if (fileContains(callbackFile, /authkitLoader/) && !fileContains(callbackFile, /authLoader/)) {\n return [\n {\n code: 'WRONG_CALLBACK_LOADER',\n severity: 'warning',\n message: 'Callback route uses authkitLoader instead of authLoader',\n filePath: relative(ctx.installDir, callbackFile),\n remediation:\n 'Use authLoader (not authkitLoader) for the callback route. authkitLoader is for regular routes that need auth context.',\n },\n ];\n }\n return [];\n}\n\nfunction checkMissingRootAuthLoader(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router') return [];\n\n const rootPaths = ['app/root.tsx', 'app/root.jsx', 'app/routes/_index.tsx', 'app/routes/_index.jsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const rootFile = findFile(rootPaths);\n if (!rootFile) return [];\n\n if (fileContains(rootFile, /authkitLoader/)) return [];\n\n return [\n {\n code: 'MISSING_ROOT_AUTH_LOADER',\n severity: 'warning',\n message: 'Root route does not use authkitLoader — child routes will not have auth context',\n filePath: relative(ctx.installDir, rootFile),\n remediation: 'Add authkitLoader to your root route so child routes can access auth state.',\n },\n ];\n}\n\nfunction checkMissingAuthkitMiddleware(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'TanStack Start') return [];\n\n const startPaths = ['src/start.ts', 'src/start.tsx', 'app/start.ts', 'app/start.tsx'].map((p) =>\n join(ctx.installDir, p),\n );\n\n const startFile = findFile(startPaths);\n if (!startFile) return []; // Can't check if start file doesn't exist\n\n if (fileContains(startFile, /authkitMiddleware/)) return [];\n\n return [\n {\n code: 'MISSING_AUTHKIT_MIDDLEWARE',\n severity: 'warning',\n message: 'start.ts does not reference authkitMiddleware — AuthKit session handling requires it',\n filePath: relative(ctx.installDir, startFile),\n remediation:\n 'Add authkitMiddleware to requestMiddleware in src/start.ts:\\n' +\n ' import { authkitMiddleware } from \"@workos/authkit-tanstack-react-start\";\\n' +\n ' export default createStart({ requestMiddleware: [authkitMiddleware()] });',\n },\n ];\n}\n\nfunction checkCookiePasswordTooShort(ctx: CheckContext): AuthPatternFinding[] {\n if (ctx.framework.name !== 'React Router' && ctx.framework.name !== 'TanStack Start') return [];\n\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const password = projectEnv.WORKOS_COOKIE_PASSWORD;\n\n // Only warn if password is set but too short; missing password is a separate concern\n if (!password || password.length >= 32) return [];\n\n return [\n {\n code: 'COOKIE_PASSWORD_TOO_SHORT',\n severity: 'warning',\n message: `WORKOS_COOKIE_PASSWORD is ${password.length} characters — minimum 32 required for secure encryption`,\n remediation: 'Set WORKOS_COOKIE_PASSWORD to a random string of at least 32 characters.',\n },\n ];\n}\n\nconst REACT_SPA_SDKS = new Set(['@workos-inc/authkit-react']);\n\nfunction checkMissingApiHostname(ctx: CheckContext): AuthPatternFinding[] {\n if (!ctx.sdk.name || !REACT_SPA_SDKS.has(ctx.sdk.name)) return [];\n\n const sourceFiles = findFilesShallow(ctx.installDir, /\\.(tsx|jsx|ts|js)$/, 4);\n const providerFiles = sourceFiles.filter((f) => fileContains(f, /AuthKitProvider/));\n if (providerFiles.length === 0) return [];\n\n const hasApiHostname = providerFiles.some((f) => fileContains(f, /apiHostname/));\n if (hasApiHostname) return [];\n\n return [\n {\n code: 'MISSING_API_HOSTNAME',\n severity: 'warning',\n message: 'AuthKitProvider does not specify apiHostname — authorize requests will route through api.workos.com',\n filePath: relative(ctx.installDir, providerFiles[0]),\n remediation:\n 'Set the apiHostname prop on AuthKitProvider to your custom Authentication API domain (e.g. auth.example.com) to avoid routing through api.workos.com.',\n docsUrl: 'https://workos.com/docs/custom-domains',\n },\n ];\n}\n\n// --- Cross-language checks (run for ALL projects, not just JS/AuthKit) ---\n\nconst SOURCE_EXTENSIONS = /\\.(ts|tsx|js|jsx|py|rb|go|java|kt|php|cs|swift|dart)$/;\n\nfunction checkApiKeyInSource(ctx: CheckContext): AuthPatternFinding[] {\n const API_KEY_PATTERN = /sk_(test|live)_[A-Za-z0-9]{10,}/;\n const sourceFiles = findFilesShallow(ctx.installDir, SOURCE_EXTENSIONS, 4);\n const findings: AuthPatternFinding[] = [];\n\n for (const file of sourceFiles) {\n const content = readFileSafe(file);\n if (!content) continue;\n if (API_KEY_PATTERN.test(content)) {\n findings.push({\n code: 'API_KEY_IN_SOURCE',\n severity: 'error',\n message: `WorkOS API key hardcoded in source file`,\n filePath: relative(ctx.installDir, file),\n remediation:\n 'Move the API key to an environment variable (WORKOS_API_KEY) and load it from .env or your secret manager.',\n });\n }\n }\n return findings;\n}\n\nfunction checkEnvFileNotGitignored(ctx: CheckContext): AuthPatternFinding[] {\n const envFiles = ['.env', '.env.local'].filter((f) => existsSync(join(ctx.installDir, f)));\n if (envFiles.length === 0) return [];\n\n const gitignorePath = join(ctx.installDir, '.gitignore');\n const gitignore = readFileSafe(gitignorePath);\n\n const findings: AuthPatternFinding[] = [];\n for (const envFile of envFiles) {\n const isIgnored =\n gitignore !== null &&\n gitignore.split('\\n').some((line) => {\n const trimmed = line.trim();\n if (trimmed.startsWith('#') || trimmed === '') return false;\n return trimmed === envFile || trimmed === '.env*' || trimmed === '.env.*' || trimmed === '.env';\n });\n\n if (!isIgnored) {\n findings.push({\n code: 'ENV_FILE_NOT_GITIGNORED',\n severity: 'warning',\n message: `${envFile} is not in .gitignore — secrets may be committed to version control`,\n filePath: envFile,\n remediation: `Add ${envFile} to your .gitignore file.`,\n });\n }\n }\n return findings;\n}\n\nfunction checkMixedEnvironmentCredentials(ctx: CheckContext): AuthPatternFinding[] {\n const projectEnv = loadProjectEnvRaw(ctx.installDir);\n const apiKey = projectEnv.WORKOS_API_KEY;\n const redirectUri = projectEnv.WORKOS_REDIRECT_URI ?? projectEnv.NEXT_PUBLIC_WORKOS_REDIRECT_URI;\n\n if (!apiKey || !redirectUri) return [];\n\n const isTestKey = apiKey.startsWith('sk_test_');\n const isLiveKey = apiKey.startsWith('sk_live_');\n\n let isProductionUri = false;\n try {\n const url = new URL(redirectUri);\n isProductionUri = url.hostname !== 'localhost' && !url.hostname.startsWith('127.0.0.');\n } catch {\n return [];\n }\n\n if (isTestKey && isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Staging API key (sk_test_) used with a production redirect URI',\n remediation:\n 'Use sk_live_ API key for production redirect URIs, or change the redirect URI to localhost for staging.',\n },\n ];\n }\n\n if (isLiveKey && !isProductionUri) {\n return [\n {\n code: 'MIXED_ENVIRONMENT',\n severity: 'warning',\n message: 'Production API key (sk_live_) used with a localhost redirect URI',\n remediation:\n 'Use sk_test_ API key for localhost development, or update the redirect URI to your production domain.',\n },\n ];\n }\n\n return [];\n}\n\n// --- Main Entry Point ---\n\ntype CheckFn = (ctx: CheckContext) => AuthPatternFinding[];\n\nconst CROSS_FRAMEWORK_CHECKS: CheckFn[] = [\n checkApiKeyLeakedToClient,\n checkApiKeyInSource,\n checkEnvFileNotGitignored,\n checkMixedEnvironmentCredentials,\n checkMissingApiHostname,\n];\n\nconst NEXTJS_CHECKS: CheckFn[] = [\n checkSignoutGetHandler,\n checkSignoutLinkPrefetch,\n checkMissingMiddleware,\n checkMiddlewareWrongLocation,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n];\n\nconst REACT_ROUTER_CHECKS: CheckFn[] = [\n checkWrongCallbackLoader,\n checkMissingRootAuthLoader,\n checkMissingAuthKitProvider,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nconst TANSTACK_CHECKS: CheckFn[] = [\n checkMissingAuthkitMiddleware,\n checkCallbackRouteMissing,\n checkCookiePasswordTooShort,\n];\n\nexport async function checkAuthPatterns(\n options: DoctorOptions,\n framework: FrameworkInfo,\n environment: EnvironmentInfo,\n sdk: SdkInfo,\n): Promise<AuthPatternInfo> {\n const ctx: CheckContext = {\n framework,\n environment,\n sdk,\n installDir: options.installDir,\n };\n\n const checks: CheckFn[] = [...CROSS_FRAMEWORK_CHECKS];\n\n switch (framework.name) {\n case 'Next.js':\n checks.push(...NEXTJS_CHECKS);\n break;\n case 'React Router':\n checks.push(...REACT_ROUTER_CHECKS);\n break;\n case 'TanStack Start':\n checks.push(...TANSTACK_CHECKS);\n break;\n }\n\n const findings: AuthPatternFinding[] = [];\n for (const check of checks) {\n findings.push(...check(ctx));\n }\n\n return {\n checksRun: checks.length,\n findings,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-interface.js","sourceRoot":"","sources":["../../src/lib/agent-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared agent interface for WorkOS wizards\n * Uses Claude Agent SDK directly with WorkOS MCP server\n */\n\nimport path from 'path';\nimport { getPackageRoot } from '../utils/paths.js';\nimport { debug, logInfo, logWarn, logError, initLogFile, getLogFilePath } from '../utils/debug.js';\nimport type { InstallerOptions } from '../utils/types.js';\nimport { analytics } from '../utils/analytics.js';\nimport { INSTALLER_INTERACTION_EVENT_NAME } from './constants.js';\nimport { LINTING_TOOLS } from './safe-tools.js';\nimport { getLlmGatewayUrlFromHost } from '../utils/urls.js';\nimport { getConfig } from './settings.js';\nimport { getCredentials, hasCredentials } from './credentials.js';\nimport { ensureValidToken } from './token-refresh.js';\nimport type { InstallerEventEmitter } from './events.js';\nimport { startCredentialProxy, type CredentialProxyHandle } from './credential-proxy.js';\nimport { getAuthkitDomain, getCliAuthClientId } from './settings.js';\nimport type {\n SDKMessage,\n SDKUserMessage,\n Options as AgentSDKOptions,\n PermissionResult,\n query as queryFn,\n} from '@anthropic-ai/claude-agent-sdk';\n\n// File content cache for computing edit diffs\nconst fileContentCache = new Map<string, string>();\n// Track pending Read operations by tool_use_id\nconst pendingReads = new Map<string, string>();\n// Track tool start times by tool_use_id for telemetry\nconst pendingToolCalls = new Map<string, { toolName: string; startTime: number }>();\n\n// Module-level variable to track proxy handle for cleanup\nlet activeProxyHandle: CredentialProxyHandle | null = null;\n\n// Dynamic import cache for ESM module\nlet _sdkModule: { query: typeof queryFn } | null = null;\nasync function getSDKModule(): Promise<{ query: typeof queryFn }> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nexport const AgentSignals = {\n /** Signal emitted when the agent reports progress to the user */\n STATUS: '[STATUS]',\n /** Signal emitted when the agent cannot access the WorkOS MCP server */\n ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',\n /** Signal emitted when the agent cannot access the setup resource */\n ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',\n} as const;\n\nexport type AgentSignal = (typeof AgentSignals)[keyof typeof AgentSignals];\n\n/**\n * Error types that can be returned from agent execution.\n * These correspond to the error signals that the agent emits.\n */\nexport enum AgentErrorType {\n /** Agent could not access the WorkOS MCP server */\n MCP_MISSING = 'INSTALLER_MCP_MISSING',\n /** Agent could not access the setup resource */\n RESOURCE_MISSING = 'INSTALLER_RESOURCE_MISSING',\n /** Agent execution failed (API error, auth error, etc.) */\n EXECUTION_ERROR = 'INSTALLER_EXECUTION_ERROR',\n}\n\nexport type AgentConfig = {\n workingDirectory: string;\n workOSApiKey: string;\n workOSApiHost: string;\n};\n\nexport interface RetryConfig {\n /** Max correction attempts after initial run. Default: 2 */\n maxRetries: number;\n /** Run between agent turns. Return null if passed, or error prompt if failed. */\n validateAndFormat: (workingDirectory: string) => Promise<string | null>;\n}\n\n/**\n * Configuration object for running the agent.\n * Built by initializeAgent (production) or constructed directly (evals).\n */\nexport type AgentRunConfig = {\n workingDirectory: string;\n mcpServers: AgentSDKOptions['mcpServers'];\n model: string;\n allowedTools: string[];\n sdkEnv: Record<string, string | undefined>;\n};\n\n/**\n * Package managers that can be used to run commands.\n * Includes JS and non-JS ecosystem package managers for multi-SDK support.\n */\nconst PACKAGE_MANAGERS = [\n // JavaScript\n 'npm',\n 'pnpm',\n 'yarn',\n 'bun',\n 'npx',\n 'pnpx',\n 'bunx',\n // Python\n 'pip',\n 'pip3',\n 'poetry',\n 'uv',\n 'pipx',\n 'python',\n 'python3',\n // Ruby\n 'gem',\n 'bundle',\n 'bundler',\n 'ruby',\n // PHP\n 'composer',\n 'php',\n // Go\n 'go',\n // .NET\n 'dotnet',\n 'nuget',\n // Elixir\n 'mix',\n 'hex',\n 'elixir',\n // Kotlin/Java\n 'gradle',\n 'gradlew',\n './gradlew',\n 'mvn',\n];\n\n/**\n * Safe scripts/commands that can be run with any package manager.\n * Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.\n * Note: Linting tools are in LINTING_TOOLS and checked separately.\n */\nconst SAFE_SCRIPTS = [\n // Package installation\n 'install',\n 'add',\n 'ci',\n // Build\n 'build',\n // Type checking (various naming conventions)\n 'tsc',\n 'typecheck',\n 'type-check',\n 'check-types',\n 'types',\n // Linting/formatting script names (actual tools are in LINTING_TOOLS)\n 'lint',\n 'format',\n // Common cross-language commands\n 'check',\n 'test',\n 'run',\n 'serve',\n 'dev',\n 'start',\n 'compile',\n 'vet',\n // Python-specific\n 'manage.py',\n 'pytest',\n // Ruby-specific\n 'rspec',\n 'rake',\n 'routes',\n // PHP-specific\n 'artisan',\n 'phpunit',\n // Elixir-specific\n 'deps.get',\n 'credo',\n 'dialyzer',\n // .NET-specific\n 'restore',\n];\n\n/**\n * Dangerous shell operators that could allow command injection.\n * Note: We handle `2>&1` and `| tail/head` separately as safe patterns.\n */\nconst DANGEROUS_OPERATORS = /[;`$()]/;\n\n/**\n * Check if command is an allowed package manager command.\n * Matches: <pkg-manager> [run|exec] <safe-script> [args...]\n */\nfunction matchesAllowedPrefix(command: string): boolean {\n const parts = command.split(/\\s+/);\n if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {\n return false;\n }\n\n // Skip 'run' or 'exec' if present\n let scriptIndex = 1;\n if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {\n scriptIndex++;\n }\n\n // Get the script/command portion (may include args)\n const scriptPart = parts.slice(scriptIndex).join(' ');\n\n // Check if script starts with any safe script name or linting tool\n return (\n SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) ||\n LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool))\n );\n}\n\n/**\n * Permission hook that allows only safe commands.\n * - Package manager install commands\n * - Build/typecheck/lint commands for verification\n * - Piping to tail/head for output limiting is allowed\n * - Stderr redirection (2>&1) is allowed\n */\nexport function installerCanUseTool(toolName: string, input: Record<string, unknown>): PermissionResult {\n // Allow all non-Bash tools\n if (toolName !== 'Bash') {\n return { behavior: 'allow', updatedInput: input };\n }\n\n const command = (typeof input.command === 'string' ? input.command : '').trim();\n\n // Block definitely dangerous operators: ; ` $ ( )\n if (DANGEROUS_OPERATORS.test(command)) {\n logWarn(`Denying bash command with dangerous operators: ${command}`);\n debug(`Denying bash command with dangerous operators: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'dangerous operators',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Shell operators like ; \\` $ ( ) are not permitted.`,\n };\n }\n\n // Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)\n const normalized = command.replace(/\\s*\\d*>&\\d+\\s*/g, ' ').trim();\n\n // Check for pipe to tail/head (safe output limiting)\n const pipeMatch = normalized.match(/^(.+?)\\s*\\|\\s*(tail|head)(\\s+\\S+)*\\s*$/);\n if (pipeMatch) {\n const baseCommand = pipeMatch[1].trim();\n\n // Block if base command has pipes or & (multiple chaining)\n if (/[|&]/.test(baseCommand)) {\n logWarn(`Denying bash command with multiple pipes: ${command}`);\n debug(`Denying bash command with multiple pipes: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'multiple pipes',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,\n };\n }\n\n if (matchesAllowedPrefix(baseCommand)) {\n logInfo(`Allowing bash command with output limiter: ${command}`);\n debug(`Allowing bash command with output limiter: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n }\n\n // Block remaining pipes and & (not covered by tail/head case above)\n if (/[|&]/.test(normalized)) {\n logWarn(`Denying bash command with pipe/&: ${command}`);\n debug(`Denying bash command with pipe/&: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'disallowed pipe',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,\n };\n }\n\n // Check if command starts with any allowed prefix\n if (matchesAllowedPrefix(normalized)) {\n logInfo(`Allowing bash command: ${command}`);\n debug(`Allowing bash command: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n\n logWarn(`Denying bash command: ${command}`);\n debug(`Denying bash command: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'not in allowlist',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only install, build, typecheck, lint, and formatting commands are permitted.`,\n };\n}\n\n/**\n * Initialize agent configuration for the LLM gateway\n */\nexport async function initializeAgent(config: AgentConfig, options: InstallerOptions): Promise<AgentRunConfig> {\n // Initialize log file for this run\n initLogFile();\n logInfo('Agent initialization starting');\n logInfo('Install directory:', options.installDir);\n\n // Emit status event for adapters to render\n options.emitter?.emit('status', { message: 'Initializing Claude agent...' });\n\n try {\n let authMode: string;\n // Build SDK env without mutating process.env\n const sdkEnv: Record<string, string | undefined> = {\n ...process.env,\n // Disable experimental betas (like input_examples) that the LLM gateway doesn't support\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // Disable SDK telemetry - our gateway doesn't proxy /api/event_logging/batch\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: 'true',\n };\n\n if (options.direct) {\n // Direct mode: use user's Anthropic API key, skip gateway\n if (!process.env.ANTHROPIC_API_KEY) {\n throw new Error(\n 'Direct mode requires ANTHROPIC_API_KEY environment variable.\\n' +\n 'Set it with: export ANTHROPIC_API_KEY=sk-ant-...\\n' +\n 'Get your key at: https://console.anthropic.com/settings/keys',\n );\n }\n\n // SDK defaults to api.anthropic.com when no base URL set\n delete sdkEnv.ANTHROPIC_BASE_URL;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = 'direct:api.anthropic.com';\n logInfo('Direct mode: using ANTHROPIC_API_KEY, bypassing llm-gateway');\n\n // Set analytics tag for direct mode\n analytics.setTag('api_mode', 'direct');\n } else {\n // Gateway mode (existing behavior)\n const gatewayUrl = getLlmGatewayUrlFromHost();\n\n // Check/refresh authentication for production (unless skipping auth)\n if (!options.skipAuth && !options.local) {\n if (!hasCredentials()) {\n throw new Error('Not authenticated. Run `workos login` to authenticate.');\n }\n\n const creds = getCredentials();\n if (!creds) {\n throw new Error('Not authenticated. Run `workos login` to authenticate.');\n }\n\n // Check if we have refresh token capability and proxy is not disabled\n if (creds.refreshToken && process.env.INSTALLER_DISABLE_PROXY !== '1') {\n // Start credential proxy with lazy refresh\n logInfo('[agent-interface] Starting credential proxy with lazy refresh...');\n const appConfig = getConfig();\n\n activeProxyHandle = await startCredentialProxy({\n upstreamUrl: gatewayUrl,\n refresh: {\n authkitDomain: getAuthkitDomain(),\n clientId: getCliAuthClientId(),\n refreshThresholdMs: appConfig.proxy.refreshThresholdMs,\n onRefreshSuccess: () => {\n options.emitter?.emit('status', { message: 'Session extended' });\n },\n onRefreshExpired: () => {\n logError('[agent-interface] Session expired, refresh token invalid');\n options.emitter?.emit('error', {\n message: 'Session expired. Run `workos login` to re-authenticate.',\n });\n },\n },\n });\n\n // Point SDK at proxy instead of direct gateway\n sdkEnv.ANTHROPIC_BASE_URL = activeProxyHandle.url;\n logInfo(`[agent-interface] Using credential proxy at ${activeProxyHandle.url}`);\n\n // Proxy handles auth, so we don't set ANTHROPIC_AUTH_TOKEN\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `proxy:${activeProxyHandle.url}→${gatewayUrl}`;\n } else {\n // No refresh token OR proxy disabled - fall back to old behavior (5 min limit)\n if (!creds.refreshToken) {\n logWarn('[agent-interface] No refresh token available, session limited to 5 minutes');\n logWarn('[agent-interface] Run `workos login` to enable extended sessions');\n options.emitter?.emit('status', {\n message: 'Note: Run `workos login` to enable extended sessions',\n });\n } else {\n logWarn('[agent-interface] Proxy disabled via INSTALLER_DISABLE_PROXY');\n }\n\n const refreshResult = await ensureValidToken();\n if (!refreshResult.success) {\n throw new Error(refreshResult.error || 'Authentication failed');\n }\n\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n sdkEnv.ANTHROPIC_AUTH_TOKEN = creds.accessToken;\n authMode = options.local ? `local-gateway:${gatewayUrl}` : `workos-gateway:${gatewayUrl}`;\n logInfo('Sending access token to gateway (legacy mode)');\n }\n } else if (options.skipAuth) {\n // Skip auth mode - direct to gateway without auth\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `skip-auth:${gatewayUrl}`;\n logInfo('Skipping auth - no token sent to gateway');\n } else {\n // Local mode without auth\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `local-gateway:${gatewayUrl}`;\n logInfo('Local mode - no token sent to gateway');\n }\n\n logInfo('Configured LLM gateway:', sdkEnv.ANTHROPIC_BASE_URL);\n\n // Set analytics tag for gateway mode\n analytics.setTag('api_mode', activeProxyHandle ? 'gateway-proxy' : 'gateway');\n }\n\n // Configure WorkOS MCP docs server for accessing WorkOS documentation\n const agentRunConfig: AgentRunConfig = {\n workingDirectory: config.workingDirectory,\n mcpServers: {\n workos: {\n command: 'npx',\n args: ['-y', '@workos/mcp-docs-server'],\n },\n },\n model: getConfig().model,\n allowedTools: ['Skill', 'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch'],\n sdkEnv,\n };\n\n const configInfo = { workingDirectory: agentRunConfig.workingDirectory, authMode, useMcp: false };\n logInfo('Agent config:', configInfo);\n debug('Agent config:', configInfo);\n\n // Emit status events for adapters to render\n const currentLogPath = getLogFilePath();\n if (currentLogPath) {\n options.emitter?.emit('status', { message: `Verbose logs: ${currentLogPath}` });\n }\n options.emitter?.emit('status', { message: \"Agent initialized. Let's get cooking!\" });\n\n return agentRunConfig;\n } catch (error) {\n // Clean up proxy if initialization fails\n if (activeProxyHandle) {\n logInfo('[agent-interface] Cleaning up proxy after init error');\n await activeProxyHandle.stop();\n activeProxyHandle = null;\n }\n logError('Agent initialization error:', error);\n throw error;\n }\n}\n\n/**\n * Execute an agent with the provided prompt and options\n * Handles the full lifecycle via event emissions - adapters handle UI rendering.\n *\n * @returns An object containing any error detected in the agent's output\n */\nexport async function runAgent(\n agentConfig: AgentRunConfig,\n prompt: string,\n options: InstallerOptions,\n config?: {\n spinnerMessage?: string;\n successMessage?: string;\n errorMessage?: string;\n },\n emitter?: InstallerEventEmitter,\n retryConfig?: RetryConfig,\n onMessage?: (message: SDKMessage) => void,\n): Promise<{ error?: AgentErrorType; errorMessage?: string; retryCount?: number }> {\n const { spinnerMessage = 'Setting up WorkOS AuthKit...' } = config ?? {};\n\n const { query } = await getSDKModule();\n\n // Emit progress for adapters to handle (e.g., CLI adapter starts spinner)\n emitter?.emit('agent:progress', { step: 'Starting', detail: 'This may take a few minutes. Grab some coffee!' });\n emitter?.emit('agent:progress', { step: spinnerMessage });\n\n logInfo('Starting agent run');\n logInfo('Prompt:', prompt);\n\n const startTime = Date.now();\n const collectedText: string[] = [];\n\n try {\n let retryCount = 0;\n const maxRetries = retryConfig?.maxRetries ?? 0;\n\n // Turn completion signals — resolveCurrentTurn is called when a 'result'\n // message arrives; the prompt generator awaits currentTurnDone between turns.\n let resolveCurrentTurn!: () => void;\n let currentTurnDone!: Promise<void>;\n\n function resetTurnSignal() {\n currentTurnDone = new Promise<void>((resolve) => {\n resolveCurrentTurn = resolve;\n });\n }\n resetTurnSignal();\n\n const createPromptStream = async function* (): AsyncGenerator<SDKUserMessage> {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n\n if (retryConfig && maxRetries > 0) {\n while (retryCount < maxRetries) {\n await currentTurnDone;\n\n emitter?.emit('validation:retry:start', { attempt: retryCount + 1 });\n\n let validationPrompt: string | null;\n try {\n validationPrompt = await retryConfig.validateAndFormat(agentConfig.workingDirectory);\n } catch (err) {\n // Don't block on validation bugs — treat as passed\n logError('validateAndFormat threw:', err);\n validationPrompt = null;\n }\n\n emitter?.emit('validation:retry:complete', {\n attempt: retryCount + 1,\n passed: validationPrompt === null,\n });\n\n if (validationPrompt === null) break;\n\n retryCount++;\n emitter?.emit('agent:retry', { attempt: retryCount, maxRetries });\n\n resetTurnSignal();\n\n yield {\n type: 'user',\n session_id: '',\n message: { role: 'user', content: validationPrompt },\n parent_tool_use_id: null,\n };\n }\n }\n\n await currentTurnDone;\n };\n\n // Load plugin with bundled skills\n const pluginPath = getPackageRoot(import.meta.url);\n logInfo('Loading plugin from:', pluginPath);\n\n const response = query({\n prompt: createPromptStream(),\n options: {\n model: agentConfig.model,\n cwd: agentConfig.workingDirectory,\n permissionMode: 'acceptEdits',\n mcpServers: agentConfig.mcpServers,\n env: agentConfig.sdkEnv,\n canUseTool: (toolName, input) => {\n logInfo('canUseTool called:', { toolName, input });\n const result = installerCanUseTool(toolName, input);\n logInfo('canUseTool result:', result);\n return Promise.resolve(result);\n },\n tools: { type: 'preset', preset: 'claude_code' },\n allowedTools: agentConfig.allowedTools,\n plugins: [{ type: 'local', path: pluginPath }],\n // Capture stderr from CLI subprocess for debugging\n stderr: (data: string) => {\n logInfo('CLI stderr:', data);\n if (options.debug) {\n debug('CLI stderr:', data);\n }\n },\n },\n });\n\n // Process the async generator\n let sdkError: string | undefined;\n for await (const message of response) {\n const messageError = handleSDKMessage(message, options, collectedText, emitter);\n if (messageError) {\n sdkError = messageError;\n }\n if (message.type === 'result') {\n resolveCurrentTurn();\n }\n try {\n onMessage?.(message);\n } catch {\n /* non-critical */\n }\n }\n\n const durationMs = Date.now() - startTime;\n const outputText = collectedText.join('\\n');\n\n // Check for SDK errors first (e.g., API errors, auth failures)\n // Return error type + message - caller decides whether to throw or emit events\n if (sdkError) {\n logError('Agent SDK error:', sdkError);\n return { error: AgentErrorType.EXECUTION_ERROR, errorMessage: sdkError };\n }\n\n // Check for error markers in the agent's output\n if (outputText.includes(AgentSignals.ERROR_MCP_MISSING)) {\n logError('Agent error: MCP_MISSING');\n return { error: AgentErrorType.MCP_MISSING, errorMessage: 'Could not access WorkOS MCP server' };\n }\n\n if (outputText.includes(AgentSignals.ERROR_RESOURCE_MISSING)) {\n logError('Agent error: RESOURCE_MISSING');\n return { error: AgentErrorType.RESOURCE_MISSING, errorMessage: 'Could not access setup resource' };\n }\n\n logInfo(`Agent run completed in ${Math.round(durationMs / 1000)}s (${retryCount} retries)`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'agent integration completed',\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n retry_count: retryCount,\n max_retries: maxRetries,\n passed_after_retry: retryCount > 0,\n });\n\n // Don't emit agent:success here - let the state machine handle lifecycle events\n return { retryCount };\n } catch (error) {\n // Don't emit events here - just log and re-throw for state machine to handle\n logError('Agent run failed:', error);\n debug('Full error:', error);\n throw error;\n } finally {\n // Always clean up proxy when agent run completes\n if (activeProxyHandle) {\n logInfo('[agent-interface] Stopping credential proxy');\n\n analytics.capture('installer.proxy', {\n action: 'stop',\n port: activeProxyHandle.port,\n });\n\n await activeProxyHandle.stop();\n activeProxyHandle = null;\n }\n }\n}\n\n/**\n * Handle SDK messages and emit events for adapters to render.\n * @returns Error message if this was an error result, undefined otherwise\n */\nfunction handleSDKMessage(\n message: SDKMessage,\n options: InstallerOptions,\n collectedText: string[],\n emitter?: InstallerEventEmitter,\n): string | undefined {\n logInfo(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));\n\n switch (message.type) {\n case 'assistant': {\n // Extract usage data from Anthropic API response for telemetry\n const usage = message.message?.usage;\n if (usage) {\n const inputTokens = usage.input_tokens ?? 0;\n const outputTokens = usage.output_tokens ?? 0;\n const model = message.message?.model ?? 'unknown';\n analytics.llmRequest(model, inputTokens, outputTokens);\n analytics.incrementAgentIterations();\n }\n\n // Extract text content from assistant messages\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text' && typeof block.text === 'string') {\n collectedText.push(block.text);\n\n // Emit output event for dashboard\n emitter?.emit('output', { text: block.text });\n\n // Check for [STATUS] markers and emit progress events\n const statusRegex = new RegExp(\n `^.*${AgentSignals.STATUS.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*(.+?)$`,\n 'm',\n );\n const statusMatch = block.text.match(statusRegex);\n if (statusMatch) {\n const statusText = statusMatch[1].trim();\n // Emit progress event - adapters handle spinner updates\n emitter?.emit('agent:progress', { step: statusText });\n emitter?.emit('status', { message: statusText });\n }\n }\n\n // Check for tool_use blocks (Write/Edit operations)\n if (block.type === 'tool_use') {\n const toolName = block.name as string;\n const toolUseId = block.id as string;\n const input = block.input as Record<string, unknown>;\n\n // Log tool usage for debugging\n logInfo(`Tool use: ${toolName}`);\n\n // Track tool start time for telemetry\n if (toolUseId) {\n pendingToolCalls.set(toolUseId, { toolName, startTime: Date.now() });\n }\n\n // Emit file:write event for Write tool\n if (toolName === 'Write' && input) {\n const filePath = input.file_path as string;\n const fileContent = input.content as string;\n if (filePath && fileContent) {\n emitter?.emit('file:write', { path: filePath, content: fileContent });\n }\n }\n\n // Emit file:edit event for Edit tool\n if (toolName === 'Edit' && input) {\n const filePath = input.file_path as string;\n const oldString = input.old_string as string;\n const newString = input.new_string as string;\n if (filePath && oldString !== undefined && newString !== undefined) {\n // Emit the actual strings being replaced, not reconstructed full file\n emitter?.emit('file:edit', {\n path: filePath,\n oldContent: oldString,\n newContent: newString,\n });\n }\n }\n\n // Track Read operations for caching file content later\n if (toolName === 'Read' && input && block.id) {\n const filePath = input.file_path as string;\n if (filePath) {\n pendingReads.set(block.id as string, filePath);\n }\n }\n }\n }\n }\n break;\n }\n\n case 'user': {\n // User messages contain tool results\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n // Tool results contain file content from Read operations\n if (block.type === 'tool_result' && block.tool_use_id) {\n const toolUseId = block.tool_use_id as string;\n\n // Emit telemetry for completed tool call\n const pendingTool = pendingToolCalls.get(toolUseId);\n if (pendingTool) {\n const durationMs = Date.now() - pendingTool.startTime;\n // Check if tool result indicates error (is_error field or error in content)\n const isError = block.is_error === true;\n analytics.toolCalled(pendingTool.toolName, durationMs, !isError);\n pendingToolCalls.delete(toolUseId);\n }\n\n const filePath = pendingReads.get(toolUseId);\n if (filePath) {\n // Extract content from the tool result\n let resultContent = '';\n if (typeof block.content === 'string') {\n resultContent = block.content;\n } else if (Array.isArray(block.content)) {\n // Content might be array of text blocks\n for (const item of block.content) {\n if (item.type === 'text' && item.text) {\n resultContent += item.text;\n }\n }\n }\n if (resultContent) {\n fileContentCache.set(filePath, resultContent);\n }\n pendingReads.delete(toolUseId);\n }\n }\n }\n }\n break;\n }\n\n case 'result': {\n if (message.subtype === 'success') {\n logInfo('Agent completed successfully');\n if (typeof message.result === 'string') {\n collectedText.push(message.result);\n }\n } else {\n // Error result\n logError('Agent error result:', message.subtype);\n if (message.errors && message.errors.length > 0) {\n for (const err of message.errors) {\n logError('ERROR:', err);\n // Emit error event - adapters handle rendering\n emitter?.emit('error', { message: err });\n }\n // Return the first error message\n return message.errors[0];\n }\n // Return generic error if subtype indicates failure but no errors array\n return `Agent execution failed: ${message.subtype}`;\n }\n break;\n }\n\n case 'system': {\n if (message.subtype === 'init') {\n logInfo('Agent session initialized', {\n model: message.model,\n tools: message.tools?.length,\n mcpServers: message.mcp_servers,\n });\n }\n break;\n }\n\n default:\n // Log other message types for debugging\n if (options.debug) {\n debug(`Unhandled message type: ${message.type}`);\n }\n break;\n }\n return undefined;\n}\n\n/**\n * Get the active proxy handle (for testing/debugging).\n */\nexport function getActiveProxyHandle(): CredentialProxyHandle | null {\n return activeProxyHandle;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-interface.js","sourceRoot":"","sources":["../../src/lib/agent-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared agent interface for WorkOS wizards\n * Uses Claude Agent SDK directly with WorkOS MCP server\n */\n\nimport { getPackageRoot } from '../utils/paths.js';\nimport { debug, logInfo, logWarn, logError, initLogFile, getLogFilePath } from '../utils/debug.js';\nimport type { InstallerOptions } from '../utils/types.js';\nimport { analytics } from '../utils/analytics.js';\nimport { INSTALLER_INTERACTION_EVENT_NAME } from './constants.js';\nimport { LINTING_TOOLS } from './safe-tools.js';\nimport { getLlmGatewayUrlFromHost } from '../utils/urls.js';\nimport { getConfig } from './settings.js';\nimport { getCredentials, hasCredentials } from './credentials.js';\nimport { ensureValidToken } from './token-refresh.js';\nimport type { InstallerEventEmitter } from './events.js';\nimport { startCredentialProxy, type CredentialProxyHandle } from './credential-proxy.js';\nimport { getAuthkitDomain, getCliAuthClientId } from './settings.js';\nimport type {\n SDKMessage,\n SDKUserMessage,\n Options as AgentSDKOptions,\n PermissionResult,\n query as queryFn,\n} from '@anthropic-ai/claude-agent-sdk';\n\n// File content cache for computing edit diffs\nconst fileContentCache = new Map<string, string>();\n// Track pending Read operations by tool_use_id\nconst pendingReads = new Map<string, string>();\n// Track tool start times by tool_use_id for telemetry\nconst pendingToolCalls = new Map<string, { toolName: string; startTime: number }>();\n\n// Module-level variable to track proxy handle for cleanup\nlet activeProxyHandle: CredentialProxyHandle | null = null;\n\n// Dynamic import cache for ESM module\nlet _sdkModule: { query: typeof queryFn } | null = null;\nasync function getSDKModule(): Promise<{ query: typeof queryFn }> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\nexport const AgentSignals = {\n /** Signal emitted when the agent reports progress to the user */\n STATUS: '[STATUS]',\n /** Signal emitted when the agent cannot access the WorkOS MCP server */\n ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',\n /** Signal emitted when the agent cannot access the setup resource */\n ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',\n} as const;\n\nexport type AgentSignal = (typeof AgentSignals)[keyof typeof AgentSignals];\n\n/**\n * Error types that can be returned from agent execution.\n * These correspond to the error signals that the agent emits.\n */\nexport enum AgentErrorType {\n /** Agent could not access the WorkOS MCP server */\n MCP_MISSING = 'INSTALLER_MCP_MISSING',\n /** Agent could not access the setup resource */\n RESOURCE_MISSING = 'INSTALLER_RESOURCE_MISSING',\n /** Agent execution failed (API error, auth error, etc.) */\n EXECUTION_ERROR = 'INSTALLER_EXECUTION_ERROR',\n}\n\nexport type AgentConfig = {\n workingDirectory: string;\n workOSApiKey: string;\n workOSApiHost: string;\n};\n\nexport interface RetryConfig {\n /** Max correction attempts after initial run. Default: 2 */\n maxRetries: number;\n /** Run between agent turns. Return null if passed, or error prompt if failed. */\n validateAndFormat: (workingDirectory: string) => Promise<string | null>;\n}\n\n/**\n * Configuration object for running the agent.\n * Built by initializeAgent (production) or constructed directly (evals).\n */\nexport type AgentRunConfig = {\n workingDirectory: string;\n mcpServers: AgentSDKOptions['mcpServers'];\n model: string;\n allowedTools: string[];\n sdkEnv: Record<string, string | undefined>;\n};\n\n/**\n * Package managers that can be used to run commands.\n * Includes JS and non-JS ecosystem package managers for multi-SDK support.\n */\nconst PACKAGE_MANAGERS = [\n // JavaScript\n 'npm',\n 'pnpm',\n 'yarn',\n 'bun',\n 'npx',\n 'pnpx',\n 'bunx',\n // Python\n 'pip',\n 'pip3',\n 'poetry',\n 'uv',\n 'pipx',\n 'python',\n 'python3',\n // Ruby\n 'gem',\n 'bundle',\n 'bundler',\n 'ruby',\n // PHP\n 'composer',\n 'php',\n // Go\n 'go',\n // .NET\n 'dotnet',\n 'nuget',\n // Elixir\n 'mix',\n 'hex',\n 'elixir',\n // Kotlin/Java\n 'gradle',\n 'gradlew',\n './gradlew',\n 'mvn',\n];\n\n/**\n * Safe scripts/commands that can be run with any package manager.\n * Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.\n * Note: Linting tools are in LINTING_TOOLS and checked separately.\n */\nconst SAFE_SCRIPTS = [\n // Package installation\n 'install',\n 'add',\n 'ci',\n // Build\n 'build',\n // Type checking (various naming conventions)\n 'tsc',\n 'typecheck',\n 'type-check',\n 'check-types',\n 'types',\n // Linting/formatting script names (actual tools are in LINTING_TOOLS)\n 'lint',\n 'format',\n // Common cross-language commands\n 'check',\n 'test',\n 'run',\n 'serve',\n 'dev',\n 'start',\n 'compile',\n 'vet',\n // Python-specific\n 'manage.py',\n 'pytest',\n // Ruby-specific\n 'rspec',\n 'rake',\n 'routes',\n // PHP-specific\n 'artisan',\n 'phpunit',\n // Elixir-specific\n 'deps.get',\n 'credo',\n 'dialyzer',\n // .NET-specific\n 'restore',\n];\n\n/**\n * Dangerous shell operators that could allow command injection.\n * Note: We handle `2>&1` and `| tail/head` separately as safe patterns.\n */\nconst DANGEROUS_OPERATORS = /[;`$()]/;\n\n/**\n * Check if command is an allowed package manager command.\n * Matches: <pkg-manager> [run|exec] <safe-script> [args...]\n */\nfunction matchesAllowedPrefix(command: string): boolean {\n const parts = command.split(/\\s+/);\n if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {\n return false;\n }\n\n // Skip 'run' or 'exec' if present\n let scriptIndex = 1;\n if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {\n scriptIndex++;\n }\n\n // Get the script/command portion (may include args)\n const scriptPart = parts.slice(scriptIndex).join(' ');\n\n // Check if script starts with any safe script name or linting tool\n return (\n SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) ||\n LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool))\n );\n}\n\n/**\n * Permission hook that allows only safe commands.\n * - Package manager install commands\n * - Build/typecheck/lint commands for verification\n * - Piping to tail/head for output limiting is allowed\n * - Stderr redirection (2>&1) is allowed\n */\nexport function installerCanUseTool(toolName: string, input: Record<string, unknown>): PermissionResult {\n // Allow all non-Bash tools\n if (toolName !== 'Bash') {\n return { behavior: 'allow', updatedInput: input };\n }\n\n const command = (typeof input.command === 'string' ? input.command : '').trim();\n\n // Block definitely dangerous operators: ; ` $ ( )\n if (DANGEROUS_OPERATORS.test(command)) {\n logWarn(`Denying bash command with dangerous operators: ${command}`);\n debug(`Denying bash command with dangerous operators: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'dangerous operators',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Shell operators like ; \\` $ ( ) are not permitted.`,\n };\n }\n\n // Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)\n const normalized = command.replace(/\\s*\\d*>&\\d+\\s*/g, ' ').trim();\n\n // Check for pipe to tail/head (safe output limiting)\n const pipeMatch = normalized.match(/^(.+?)\\s*\\|\\s*(tail|head)(\\s+\\S+)*\\s*$/);\n if (pipeMatch) {\n const baseCommand = pipeMatch[1].trim();\n\n // Block if base command has pipes or & (multiple chaining)\n if (/[|&]/.test(baseCommand)) {\n logWarn(`Denying bash command with multiple pipes: ${command}`);\n debug(`Denying bash command with multiple pipes: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'multiple pipes',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,\n };\n }\n\n if (matchesAllowedPrefix(baseCommand)) {\n logInfo(`Allowing bash command with output limiter: ${command}`);\n debug(`Allowing bash command with output limiter: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n }\n\n // Block remaining pipes and & (not covered by tail/head case above)\n if (/[|&]/.test(normalized)) {\n logWarn(`Denying bash command with pipe/&: ${command}`);\n debug(`Denying bash command with pipe/&: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'disallowed pipe',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,\n };\n }\n\n // Check if command starts with any allowed prefix\n if (matchesAllowedPrefix(normalized)) {\n logInfo(`Allowing bash command: ${command}`);\n debug(`Allowing bash command: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n\n logWarn(`Denying bash command: ${command}`);\n debug(`Denying bash command: ${command}`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'not in allowlist',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only install, build, typecheck, lint, and formatting commands are permitted.`,\n };\n}\n\n/**\n * Initialize agent configuration for the LLM gateway\n */\nexport async function initializeAgent(config: AgentConfig, options: InstallerOptions): Promise<AgentRunConfig> {\n // Initialize log file for this run\n initLogFile();\n logInfo('Agent initialization starting');\n logInfo('Install directory:', options.installDir);\n\n // Emit status event for adapters to render\n options.emitter?.emit('status', { message: 'Initializing Claude agent...' });\n\n try {\n let authMode: string;\n // Build SDK env without mutating process.env\n const sdkEnv: Record<string, string | undefined> = {\n ...process.env,\n // Disable experimental betas (like input_examples) that the LLM gateway doesn't support\n CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: 'true',\n // Disable SDK telemetry - our gateway doesn't proxy /api/event_logging/batch\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: 'true',\n };\n\n if (options.direct) {\n // Direct mode: use user's Anthropic API key, skip gateway\n if (!process.env.ANTHROPIC_API_KEY) {\n throw new Error(\n 'Direct mode requires ANTHROPIC_API_KEY environment variable.\\n' +\n 'Set it with: export ANTHROPIC_API_KEY=sk-ant-...\\n' +\n 'Get your key at: https://console.anthropic.com/settings/keys',\n );\n }\n\n // SDK defaults to api.anthropic.com when no base URL set\n delete sdkEnv.ANTHROPIC_BASE_URL;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = 'direct:api.anthropic.com';\n logInfo('Direct mode: using ANTHROPIC_API_KEY, bypassing llm-gateway');\n\n // Set analytics tag for direct mode\n analytics.setTag('api_mode', 'direct');\n } else {\n // Gateway mode (existing behavior)\n const gatewayUrl = getLlmGatewayUrlFromHost();\n\n // Check/refresh authentication for production (unless skipping auth)\n if (!options.skipAuth && !options.local) {\n if (!hasCredentials()) {\n throw new Error('Not authenticated. Run `workos login` to authenticate.');\n }\n\n const creds = getCredentials();\n if (!creds) {\n throw new Error('Not authenticated. Run `workos login` to authenticate.');\n }\n\n // Check if we have refresh token capability and proxy is not disabled\n if (creds.refreshToken && process.env.INSTALLER_DISABLE_PROXY !== '1') {\n // Start credential proxy with lazy refresh\n logInfo('[agent-interface] Starting credential proxy with lazy refresh...');\n const appConfig = getConfig();\n\n activeProxyHandle = await startCredentialProxy({\n upstreamUrl: gatewayUrl,\n refresh: {\n authkitDomain: getAuthkitDomain(),\n clientId: getCliAuthClientId(),\n refreshThresholdMs: appConfig.proxy.refreshThresholdMs,\n onRefreshSuccess: () => {\n options.emitter?.emit('status', { message: 'Session extended' });\n },\n onRefreshExpired: () => {\n logError('[agent-interface] Session expired, refresh token invalid');\n options.emitter?.emit('error', {\n message: 'Session expired. Run `workos login` to re-authenticate.',\n });\n },\n },\n });\n\n // Point SDK at proxy instead of direct gateway\n sdkEnv.ANTHROPIC_BASE_URL = activeProxyHandle.url;\n logInfo(`[agent-interface] Using credential proxy at ${activeProxyHandle.url}`);\n\n // Proxy handles auth, so we don't set ANTHROPIC_AUTH_TOKEN\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `proxy:${activeProxyHandle.url}→${gatewayUrl}`;\n } else {\n // No refresh token OR proxy disabled - fall back to old behavior (5 min limit)\n if (!creds.refreshToken) {\n logWarn('[agent-interface] No refresh token available, session limited to 5 minutes');\n logWarn('[agent-interface] Run `workos login` to enable extended sessions');\n options.emitter?.emit('status', {\n message: 'Note: Run `workos login` to enable extended sessions',\n });\n } else {\n logWarn('[agent-interface] Proxy disabled via INSTALLER_DISABLE_PROXY');\n }\n\n const refreshResult = await ensureValidToken();\n if (!refreshResult.success) {\n throw new Error(refreshResult.error || 'Authentication failed');\n }\n\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n sdkEnv.ANTHROPIC_AUTH_TOKEN = creds.accessToken;\n authMode = options.local ? `local-gateway:${gatewayUrl}` : `workos-gateway:${gatewayUrl}`;\n logInfo('Sending access token to gateway (legacy mode)');\n }\n } else if (options.skipAuth) {\n // Skip auth mode - direct to gateway without auth\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `skip-auth:${gatewayUrl}`;\n logInfo('Skipping auth - no token sent to gateway');\n } else {\n // Local mode without auth\n sdkEnv.ANTHROPIC_BASE_URL = gatewayUrl;\n delete sdkEnv.ANTHROPIC_AUTH_TOKEN;\n authMode = `local-gateway:${gatewayUrl}`;\n logInfo('Local mode - no token sent to gateway');\n }\n\n logInfo('Configured LLM gateway:', sdkEnv.ANTHROPIC_BASE_URL);\n\n // Set analytics tag for gateway mode\n analytics.setTag('api_mode', activeProxyHandle ? 'gateway-proxy' : 'gateway');\n }\n\n // Configure WorkOS MCP docs server for accessing WorkOS documentation\n const agentRunConfig: AgentRunConfig = {\n workingDirectory: config.workingDirectory,\n mcpServers: {\n workos: {\n command: 'npx',\n args: ['-y', '@workos/mcp-docs-server'],\n },\n },\n model: getConfig().model,\n allowedTools: ['Skill', 'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch'],\n sdkEnv,\n };\n\n const configInfo = { workingDirectory: agentRunConfig.workingDirectory, authMode, useMcp: false };\n logInfo('Agent config:', configInfo);\n debug('Agent config:', configInfo);\n\n // Emit status events for adapters to render\n const currentLogPath = getLogFilePath();\n if (currentLogPath) {\n options.emitter?.emit('status', { message: `Verbose logs: ${currentLogPath}` });\n }\n options.emitter?.emit('status', { message: \"Agent initialized. Let's get cooking!\" });\n\n return agentRunConfig;\n } catch (error) {\n // Clean up proxy if initialization fails\n if (activeProxyHandle) {\n logInfo('[agent-interface] Cleaning up proxy after init error');\n await activeProxyHandle.stop();\n activeProxyHandle = null;\n }\n logError('Agent initialization error:', error);\n throw error;\n }\n}\n\n/**\n * Execute an agent with the provided prompt and options\n * Handles the full lifecycle via event emissions - adapters handle UI rendering.\n *\n * @returns An object containing any error detected in the agent's output\n */\nexport async function runAgent(\n agentConfig: AgentRunConfig,\n prompt: string,\n options: InstallerOptions,\n config?: {\n spinnerMessage?: string;\n successMessage?: string;\n errorMessage?: string;\n },\n emitter?: InstallerEventEmitter,\n retryConfig?: RetryConfig,\n onMessage?: (message: SDKMessage) => void,\n): Promise<{ error?: AgentErrorType; errorMessage?: string; retryCount?: number }> {\n const { spinnerMessage = 'Setting up WorkOS AuthKit...' } = config ?? {};\n\n const { query } = await getSDKModule();\n\n // Emit progress for adapters to handle (e.g., CLI adapter starts spinner)\n emitter?.emit('agent:progress', { step: 'Starting', detail: 'This may take a few minutes. Grab some coffee!' });\n emitter?.emit('agent:progress', { step: spinnerMessage });\n\n logInfo('Starting agent run');\n logInfo('Prompt:', prompt);\n\n const startTime = Date.now();\n const collectedText: string[] = [];\n\n try {\n let retryCount = 0;\n const maxRetries = retryConfig?.maxRetries ?? 0;\n\n // Turn completion signals — resolveCurrentTurn is called when a 'result'\n // message arrives; the prompt generator awaits currentTurnDone between turns.\n let resolveCurrentTurn!: () => void;\n let currentTurnDone!: Promise<void>;\n\n function resetTurnSignal() {\n currentTurnDone = new Promise<void>((resolve) => {\n resolveCurrentTurn = resolve;\n });\n }\n resetTurnSignal();\n\n const createPromptStream = async function* (): AsyncGenerator<SDKUserMessage> {\n yield {\n type: 'user' as const,\n session_id: '',\n message: { role: 'user' as const, content: prompt },\n parent_tool_use_id: null,\n };\n\n if (retryConfig && maxRetries > 0) {\n while (retryCount < maxRetries) {\n await currentTurnDone;\n\n emitter?.emit('validation:retry:start', { attempt: retryCount + 1 });\n\n let validationPrompt: string | null;\n try {\n validationPrompt = await retryConfig.validateAndFormat(agentConfig.workingDirectory);\n } catch (err) {\n // Don't block on validation bugs — treat as passed\n logError('validateAndFormat threw:', err);\n validationPrompt = null;\n }\n\n emitter?.emit('validation:retry:complete', {\n attempt: retryCount + 1,\n passed: validationPrompt === null,\n });\n\n if (validationPrompt === null) break;\n\n retryCount++;\n emitter?.emit('agent:retry', { attempt: retryCount, maxRetries });\n\n resetTurnSignal();\n\n yield {\n type: 'user',\n session_id: '',\n message: { role: 'user', content: validationPrompt },\n parent_tool_use_id: null,\n };\n }\n }\n\n await currentTurnDone;\n };\n\n // Load plugin with bundled skills\n const pluginPath = getPackageRoot(import.meta.url);\n logInfo('Loading plugin from:', pluginPath);\n\n const response = query({\n prompt: createPromptStream(),\n options: {\n model: agentConfig.model,\n cwd: agentConfig.workingDirectory,\n permissionMode: 'acceptEdits',\n mcpServers: agentConfig.mcpServers,\n env: agentConfig.sdkEnv,\n canUseTool: (toolName, input) => {\n logInfo('canUseTool called:', { toolName, input });\n const result = installerCanUseTool(toolName, input);\n logInfo('canUseTool result:', result);\n return Promise.resolve(result);\n },\n tools: { type: 'preset', preset: 'claude_code' },\n allowedTools: agentConfig.allowedTools,\n plugins: [{ type: 'local', path: pluginPath }],\n // Capture stderr from CLI subprocess for debugging\n stderr: (data: string) => {\n logInfo('CLI stderr:', data);\n if (options.debug) {\n debug('CLI stderr:', data);\n }\n },\n },\n });\n\n // Process the async generator\n let sdkError: string | undefined;\n for await (const message of response) {\n const messageError = handleSDKMessage(message, options, collectedText, emitter);\n if (messageError) {\n sdkError = messageError;\n }\n if (message.type === 'result') {\n resolveCurrentTurn();\n }\n try {\n onMessage?.(message);\n } catch {\n /* non-critical */\n }\n }\n\n const durationMs = Date.now() - startTime;\n const outputText = collectedText.join('\\n');\n\n // Check for SDK errors first (e.g., API errors, auth failures)\n // Return error type + message - caller decides whether to throw or emit events\n if (sdkError) {\n logError('Agent SDK error:', sdkError);\n return { error: AgentErrorType.EXECUTION_ERROR, errorMessage: sdkError };\n }\n\n // Check for error markers in the agent's output\n if (outputText.includes(AgentSignals.ERROR_MCP_MISSING)) {\n logError('Agent error: MCP_MISSING');\n return { error: AgentErrorType.MCP_MISSING, errorMessage: 'Could not access WorkOS MCP server' };\n }\n\n if (outputText.includes(AgentSignals.ERROR_RESOURCE_MISSING)) {\n logError('Agent error: RESOURCE_MISSING');\n return { error: AgentErrorType.RESOURCE_MISSING, errorMessage: 'Could not access setup resource' };\n }\n\n logInfo(`Agent run completed in ${Math.round(durationMs / 1000)}s (${retryCount} retries)`);\n analytics.capture(INSTALLER_INTERACTION_EVENT_NAME, {\n action: 'agent integration completed',\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n retry_count: retryCount,\n max_retries: maxRetries,\n passed_after_retry: retryCount > 0,\n });\n\n // Don't emit agent:success here - let the state machine handle lifecycle events\n return { retryCount };\n } catch (error) {\n // Don't emit events here - just log and re-throw for state machine to handle\n logError('Agent run failed:', error);\n debug('Full error:', error);\n throw error;\n } finally {\n // Always clean up proxy when agent run completes\n if (activeProxyHandle) {\n logInfo('[agent-interface] Stopping credential proxy');\n\n analytics.capture('installer.proxy', {\n action: 'stop',\n port: activeProxyHandle.port,\n });\n\n await activeProxyHandle.stop();\n activeProxyHandle = null;\n }\n }\n}\n\n/**\n * Handle SDK messages and emit events for adapters to render.\n * @returns Error message if this was an error result, undefined otherwise\n */\nfunction handleSDKMessage(\n message: SDKMessage,\n options: InstallerOptions,\n collectedText: string[],\n emitter?: InstallerEventEmitter,\n): string | undefined {\n logInfo(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));\n\n switch (message.type) {\n case 'assistant': {\n // Extract usage data from Anthropic API response for telemetry\n const usage = message.message?.usage;\n if (usage) {\n const inputTokens = usage.input_tokens ?? 0;\n const outputTokens = usage.output_tokens ?? 0;\n const model = message.message?.model ?? 'unknown';\n analytics.llmRequest(model, inputTokens, outputTokens);\n analytics.incrementAgentIterations();\n }\n\n // Extract text content from assistant messages\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text' && typeof block.text === 'string') {\n collectedText.push(block.text);\n\n // Emit output event for dashboard\n emitter?.emit('output', { text: block.text });\n\n // Check for [STATUS] markers and emit progress events\n const statusRegex = new RegExp(\n `^.*${AgentSignals.STATUS.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*(.+?)$`,\n 'm',\n );\n const statusMatch = block.text.match(statusRegex);\n if (statusMatch) {\n const statusText = statusMatch[1].trim();\n // Emit progress event - adapters handle spinner updates\n emitter?.emit('agent:progress', { step: statusText });\n emitter?.emit('status', { message: statusText });\n }\n }\n\n // Check for tool_use blocks (Write/Edit operations)\n if (block.type === 'tool_use') {\n const toolName = block.name as string;\n const toolUseId = block.id as string;\n const input = block.input as Record<string, unknown>;\n\n // Log tool usage for debugging\n logInfo(`Tool use: ${toolName}`);\n\n // Track tool start time for telemetry\n if (toolUseId) {\n pendingToolCalls.set(toolUseId, { toolName, startTime: Date.now() });\n }\n\n // Emit file:write event for Write tool\n if (toolName === 'Write' && input) {\n const filePath = input.file_path as string;\n const fileContent = input.content as string;\n if (filePath && fileContent) {\n emitter?.emit('file:write', { path: filePath, content: fileContent });\n }\n }\n\n // Emit file:edit event for Edit tool\n if (toolName === 'Edit' && input) {\n const filePath = input.file_path as string;\n const oldString = input.old_string as string;\n const newString = input.new_string as string;\n if (filePath && oldString !== undefined && newString !== undefined) {\n // Emit the actual strings being replaced, not reconstructed full file\n emitter?.emit('file:edit', {\n path: filePath,\n oldContent: oldString,\n newContent: newString,\n });\n }\n }\n\n // Track Read operations for caching file content later\n if (toolName === 'Read' && input && block.id) {\n const filePath = input.file_path as string;\n if (filePath) {\n pendingReads.set(block.id as string, filePath);\n }\n }\n }\n }\n }\n break;\n }\n\n case 'user': {\n // User messages contain tool results\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n // Tool results contain file content from Read operations\n if (block.type === 'tool_result' && block.tool_use_id) {\n const toolUseId = block.tool_use_id as string;\n\n // Emit telemetry for completed tool call\n const pendingTool = pendingToolCalls.get(toolUseId);\n if (pendingTool) {\n const durationMs = Date.now() - pendingTool.startTime;\n // Check if tool result indicates error (is_error field or error in content)\n const isError = block.is_error === true;\n analytics.toolCalled(pendingTool.toolName, durationMs, !isError);\n pendingToolCalls.delete(toolUseId);\n }\n\n const filePath = pendingReads.get(toolUseId);\n if (filePath) {\n // Extract content from the tool result\n let resultContent = '';\n if (typeof block.content === 'string') {\n resultContent = block.content;\n } else if (Array.isArray(block.content)) {\n // Content might be array of text blocks\n for (const item of block.content) {\n if (item.type === 'text' && item.text) {\n resultContent += item.text;\n }\n }\n }\n if (resultContent) {\n fileContentCache.set(filePath, resultContent);\n }\n pendingReads.delete(toolUseId);\n }\n }\n }\n }\n break;\n }\n\n case 'result': {\n if (message.subtype === 'success') {\n logInfo('Agent completed successfully');\n if (typeof message.result === 'string') {\n collectedText.push(message.result);\n }\n } else {\n // Error result\n logError('Agent error result:', message.subtype);\n if (message.errors && message.errors.length > 0) {\n for (const err of message.errors) {\n logError('ERROR:', err);\n // Emit error event - adapters handle rendering\n emitter?.emit('error', { message: err });\n }\n // Return the first error message\n return message.errors[0];\n }\n // Return generic error if subtype indicates failure but no errors array\n return `Agent execution failed: ${message.subtype}`;\n }\n break;\n }\n\n case 'system': {\n if (message.subtype === 'init') {\n logInfo('Agent session initialized', {\n model: message.model,\n tools: message.tools?.length,\n mcpServers: message.mcp_servers,\n });\n }\n break;\n }\n\n default:\n // Log other message types for debugging\n if (options.debug) {\n debug(`Unhandled message type: ${message.type}`);\n }\n break;\n }\n return undefined;\n}\n\n/**\n * Get the active proxy handle (for testing/debugging).\n */\nexport function getActiveProxyHandle(): CredentialProxyHandle | null {\n return activeProxyHandle;\n}\n"]}
|
package/dist/lib/config-store.js
CHANGED
|
@@ -17,8 +17,10 @@ const SERVICE_NAME = 'workos-cli';
|
|
|
17
17
|
const ACCOUNT_NAME = 'config';
|
|
18
18
|
let fallbackWarningShown = false;
|
|
19
19
|
let forceInsecureStorage = false;
|
|
20
|
+
let migrationAttempted = false;
|
|
20
21
|
export function setInsecureConfigStorage(value) {
|
|
21
22
|
forceInsecureStorage = value;
|
|
23
|
+
migrationAttempted = false;
|
|
22
24
|
}
|
|
23
25
|
function getConfigDir() {
|
|
24
26
|
return path.join(os.homedir(), '.workos');
|
|
@@ -108,9 +110,10 @@ export function getConfig() {
|
|
|
108
110
|
return keyringConfig;
|
|
109
111
|
const fileConfig = readFromFile();
|
|
110
112
|
if (fileConfig) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
if (!migrationAttempted) {
|
|
114
|
+
migrationAttempted = true;
|
|
115
|
+
writeToKeyring(fileConfig);
|
|
116
|
+
}
|
|
114
117
|
return fileConfig;
|
|
115
118
|
}
|
|
116
119
|
return null;
|
|
@@ -118,10 +121,7 @@ export function getConfig() {
|
|
|
118
121
|
export function saveConfig(config) {
|
|
119
122
|
if (forceInsecureStorage)
|
|
120
123
|
return writeToFile(config);
|
|
121
|
-
if (writeToKeyring(config)) {
|
|
122
|
-
deleteFile();
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
124
|
+
if (!writeToKeyring(config)) {
|
|
125
125
|
showFallbackWarning();
|
|
126
126
|
writeToFile(config);
|
|
127
127
|
}
|
|
@@ -129,6 +129,7 @@ export function saveConfig(config) {
|
|
|
129
129
|
export function clearConfig() {
|
|
130
130
|
deleteFromKeyring();
|
|
131
131
|
deleteFile();
|
|
132
|
+
migrationAttempted = false;
|
|
132
133
|
}
|
|
133
134
|
export function getActiveEnvironment() {
|
|
134
135
|
const config = getConfig();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAe5C,MAAM,YAAY,GAAG,YAAY,CAAC;AAClC,MAAM,YAAY,GAAG,QAAQ,CAAC;AAE9B,IAAI,oBAAoB,GAAG,KAAK,CAAC;AACjC,IAAI,oBAAoB,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/lib/config-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * CLI config storage abstraction with keyring support and file fallback.\n *\n * Stores environment configurations (names, API keys, endpoints) separately\n * from OAuth credentials. Uses a second keyring entry under the same service.\n *\n * Storage priority:\n * 1. If insecure storage forced: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\n\nexport interface EnvironmentConfig {\n name: string;\n type: 'production' | 'sandbox';\n apiKey: string;\n clientId?: string;\n endpoint?: string;\n}\n\nexport interface CliConfig {\n activeEnvironment?: string;\n environments: Record<string, EnvironmentConfig>;\n}\n\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'config';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\nlet migrationAttempted = false;\n\nexport function setInsecureConfigStorage(value: boolean): void {\n forceInsecureStorage = value;\n migrationAttempted = false;\n}\n\nfunction getConfigDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getConfigFilePath(): string {\n return path.join(getConfigDir(), 'config.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getConfigFilePath());\n}\n\nfunction readFromFile(): CliConfig | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getConfigFilePath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read config file:', error);\n return null;\n }\n}\n\nfunction writeToFile(config: CliConfig): void {\n const dir = getConfigDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(getConfigFilePath(), JSON.stringify(config, null, 2), {\n mode: 0o600,\n });\n}\n\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getConfigFilePath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): CliConfig | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) return null;\n return JSON.parse(data);\n } catch (error) {\n logWarn('Failed to read config from keyring:', error);\n return null;\n }\n}\n\nfunction writeToKeyring(config: CliConfig): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(config));\n return true;\n } catch (error) {\n logWarn('Failed to write config to keyring:', error);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete config from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store config in system keyring. Using file storage.',\n 'Config saved to ~/.workos/config.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function getConfig(): CliConfig | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringConfig = readFromKeyring();\n if (keyringConfig) return keyringConfig;\n\n const fileConfig = readFromFile();\n if (fileConfig) {\n if (!migrationAttempted) {\n migrationAttempted = true;\n writeToKeyring(fileConfig);\n }\n return fileConfig;\n }\n\n return null;\n}\n\nexport function saveConfig(config: CliConfig): void {\n if (forceInsecureStorage) return writeToFile(config);\n\n if (!writeToKeyring(config)) {\n showFallbackWarning();\n writeToFile(config);\n }\n}\n\nexport function clearConfig(): void {\n deleteFromKeyring();\n deleteFile();\n migrationAttempted = false;\n}\n\nexport function getActiveEnvironment(): EnvironmentConfig | null {\n const config = getConfig();\n if (!config?.activeEnvironment) return null;\n return config.environments[config.activeEnvironment] ?? null;\n}\n\nexport function getConfigPath(): string {\n return getConfigFilePath();\n}\n"]}
|
|
@@ -14,8 +14,10 @@ const SERVICE_NAME = 'workos-cli';
|
|
|
14
14
|
const ACCOUNT_NAME = 'credentials';
|
|
15
15
|
let fallbackWarningShown = false;
|
|
16
16
|
let forceInsecureStorage = false;
|
|
17
|
+
let migrationAttempted = false;
|
|
17
18
|
export function setInsecureStorage(value) {
|
|
18
19
|
forceInsecureStorage = value;
|
|
20
|
+
migrationAttempted = false;
|
|
19
21
|
}
|
|
20
22
|
function getCredentialsDir() {
|
|
21
23
|
return path.join(os.homedir(), '.workos');
|
|
@@ -115,7 +117,10 @@ export function getCredentials() {
|
|
|
115
117
|
return keyringCreds;
|
|
116
118
|
const fileCreds = readFromFile();
|
|
117
119
|
if (fileCreds) {
|
|
118
|
-
|
|
120
|
+
if (!migrationAttempted) {
|
|
121
|
+
migrationAttempted = true;
|
|
122
|
+
writeToKeyring(fileCreds);
|
|
123
|
+
}
|
|
119
124
|
return fileCreds;
|
|
120
125
|
}
|
|
121
126
|
return null;
|
|
@@ -123,14 +128,15 @@ export function getCredentials() {
|
|
|
123
128
|
export function saveCredentials(creds) {
|
|
124
129
|
if (forceInsecureStorage)
|
|
125
130
|
return writeToFile(creds);
|
|
126
|
-
writeToFile(creds);
|
|
127
131
|
if (!writeToKeyring(creds)) {
|
|
128
132
|
showFallbackWarning();
|
|
133
|
+
writeToFile(creds);
|
|
129
134
|
}
|
|
130
135
|
}
|
|
131
136
|
export function clearCredentials() {
|
|
132
137
|
deleteFromKeyring();
|
|
133
138
|
deleteFile();
|
|
139
|
+
migrationAttempted = false;
|
|
134
140
|
}
|
|
135
141
|
export function updateTokens(accessToken, expiresAt, refreshToken) {
|
|
136
142
|
const creds = getCredentials();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/lib/credential-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage abstraction with keyring support and file fallback.\n *\n * Storage priority:\n * 1. If --insecure-storage: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\n\nexport interface StagingCache {\n clientId: string;\n apiKey: string;\n fetchedAt: number;\n}\n\nexport interface Credentials {\n accessToken: string;\n expiresAt: number;\n userId: string;\n email?: string;\n staging?: StagingCache;\n refreshToken?: string;\n}\n\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'credentials';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\n\nexport function setInsecureStorage(value: boolean): void {\n forceInsecureStorage = value;\n}\n\nfunction getCredentialsDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getCredentialsPath(): string {\n return path.join(getCredentialsDir(), 'credentials.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getCredentialsPath());\n}\n\nfunction readFromFile(): Credentials | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getCredentialsPath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read credentials file:', error);\n return null;\n }\n}\n\nfunction writeToFile(creds: Credentials): void {\n const dir = getCredentialsDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(getCredentialsPath(), JSON.stringify(creds, null, 2), {\n mode: 0o600,\n });\n}\n\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getCredentialsPath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): Credentials | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) {\n logWarn('[credential-store] keyring: entry exists but data is null/empty');\n return null;\n }\n return JSON.parse(data);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring read failed: ${msg}`);\n return null;\n }\n}\n\nfunction writeToKeyring(creds: Credentials): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(creds));\n return true;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring write failed: ${msg}`);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store credentials in system keyring. Using file storage.',\n 'Credentials saved to ~/.workos/credentials.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function hasCredentials(): boolean {\n if (forceInsecureStorage) {\n return fileExists();\n }\n return readFromKeyring() !== null || fileExists();\n}\n\nexport function getCredentials(): Credentials | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringCreds = readFromKeyring();\n if (keyringCreds) return keyringCreds;\n\n const fileCreds = readFromFile();\n if (fileCreds) {\n writeToKeyring(fileCreds);\n return fileCreds;\n }\n\n return null;\n}\n\nexport function saveCredentials(creds: Credentials): void {\n if (forceInsecureStorage) return writeToFile(creds);\n\n writeToFile(creds);\n if (!writeToKeyring(creds)) {\n showFallbackWarning();\n }\n}\n\nexport function clearCredentials(): void {\n deleteFromKeyring();\n deleteFile();\n}\n\nexport function updateTokens(accessToken: string, expiresAt: number, refreshToken?: string): void {\n const creds = getCredentials();\n if (!creds) {\n throw new Error('No existing credentials to update');\n }\n\n const updated: Credentials = {\n ...creds,\n accessToken,\n expiresAt,\n ...(refreshToken && { refreshToken }),\n };\n\n saveCredentials(updated);\n}\n\n/**\n * Diagnostic info about credential storage state — for debugging auth failures.\n */\nexport function diagnoseCredentials(): string[] {\n const lines: string[] = [];\n const filePath = getCredentialsPath();\n const filePresent = fileExists();\n\n lines.push(`file: ${filePath} (exists=${filePresent})`);\n\n if (filePresent) {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(content) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `file creds: userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } catch (e) {\n lines.push(`file creds: parse error — ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (data) {\n const parsed = JSON.parse(data) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `keyring: found, userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } else {\n lines.push('keyring: empty (getPassword returned null)');\n }\n } catch (e) {\n lines.push(`keyring: error — ${e instanceof Error ? e.message : String(e)}`);\n }\n\n lines.push(`insecureStorage=${forceInsecureStorage}`);\n return lines;\n}\n\nexport { getCredentialsPath };\n"]}
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../src/lib/credential-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Credential storage abstraction with keyring support and file fallback.\n *\n * Storage priority:\n * 1. If --insecure-storage: use file only\n * 2. Try keyring, fall back to file with warning if unavailable\n */\n\nimport { Entry } from '@napi-rs/keyring';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { logWarn } from '../utils/debug.js';\n\nexport interface StagingCache {\n clientId: string;\n apiKey: string;\n fetchedAt: number;\n}\n\nexport interface Credentials {\n accessToken: string;\n expiresAt: number;\n userId: string;\n email?: string;\n staging?: StagingCache;\n refreshToken?: string;\n}\n\nconst SERVICE_NAME = 'workos-cli';\nconst ACCOUNT_NAME = 'credentials';\n\nlet fallbackWarningShown = false;\nlet forceInsecureStorage = false;\nlet migrationAttempted = false;\n\nexport function setInsecureStorage(value: boolean): void {\n forceInsecureStorage = value;\n migrationAttempted = false;\n}\n\nfunction getCredentialsDir(): string {\n return path.join(os.homedir(), '.workos');\n}\n\nfunction getCredentialsPath(): string {\n return path.join(getCredentialsDir(), 'credentials.json');\n}\n\nfunction fileExists(): boolean {\n return fs.existsSync(getCredentialsPath());\n}\n\nfunction readFromFile(): Credentials | null {\n if (!fileExists()) return null;\n try {\n const content = fs.readFileSync(getCredentialsPath(), 'utf-8');\n return JSON.parse(content);\n } catch (error) {\n logWarn('Failed to read credentials file:', error);\n return null;\n }\n}\n\nfunction writeToFile(creds: Credentials): void {\n const dir = getCredentialsDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n fs.writeFileSync(getCredentialsPath(), JSON.stringify(creds, null, 2), {\n mode: 0o600,\n });\n}\n\nfunction deleteFile(): void {\n if (fileExists()) {\n fs.unlinkSync(getCredentialsPath());\n }\n}\n\nfunction getKeyringEntry(): Entry {\n return new Entry(SERVICE_NAME, ACCOUNT_NAME);\n}\n\nfunction readFromKeyring(): Credentials | null {\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (!data) {\n logWarn('[credential-store] keyring: entry exists but data is null/empty');\n return null;\n }\n return JSON.parse(data);\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring read failed: ${msg}`);\n return null;\n }\n}\n\nfunction writeToKeyring(creds: Credentials): boolean {\n try {\n const entry = getKeyringEntry();\n entry.setPassword(JSON.stringify(creds));\n return true;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n logWarn(`[credential-store] keyring write failed: ${msg}`);\n return false;\n }\n}\n\nfunction deleteFromKeyring(): void {\n try {\n const entry = getKeyringEntry();\n entry.deletePassword();\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n if (!msg.includes('not found') && !msg.includes('No such')) {\n logWarn('Failed to delete from keyring:', error);\n }\n }\n}\n\nfunction showFallbackWarning(): void {\n if (fallbackWarningShown || forceInsecureStorage) return;\n fallbackWarningShown = true;\n logWarn(\n 'Unable to store credentials in system keyring. Using file storage.',\n 'Credentials saved to ~/.workos/credentials.json',\n 'Use --insecure-storage to suppress this warning.',\n );\n}\n\nexport function hasCredentials(): boolean {\n if (forceInsecureStorage) {\n return fileExists();\n }\n return readFromKeyring() !== null || fileExists();\n}\n\nexport function getCredentials(): Credentials | null {\n if (forceInsecureStorage) return readFromFile();\n\n const keyringCreds = readFromKeyring();\n if (keyringCreds) return keyringCreds;\n\n const fileCreds = readFromFile();\n if (fileCreds) {\n if (!migrationAttempted) {\n migrationAttempted = true;\n writeToKeyring(fileCreds);\n }\n return fileCreds;\n }\n\n return null;\n}\n\nexport function saveCredentials(creds: Credentials): void {\n if (forceInsecureStorage) return writeToFile(creds);\n\n if (!writeToKeyring(creds)) {\n showFallbackWarning();\n writeToFile(creds);\n }\n}\n\nexport function clearCredentials(): void {\n deleteFromKeyring();\n deleteFile();\n migrationAttempted = false;\n}\n\nexport function updateTokens(accessToken: string, expiresAt: number, refreshToken?: string): void {\n const creds = getCredentials();\n if (!creds) {\n throw new Error('No existing credentials to update');\n }\n\n const updated: Credentials = {\n ...creds,\n accessToken,\n expiresAt,\n ...(refreshToken && { refreshToken }),\n };\n\n saveCredentials(updated);\n}\n\n/**\n * Diagnostic info about credential storage state — for debugging auth failures.\n */\nexport function diagnoseCredentials(): string[] {\n const lines: string[] = [];\n const filePath = getCredentialsPath();\n const filePresent = fileExists();\n\n lines.push(`file: ${filePath} (exists=${filePresent})`);\n\n if (filePresent) {\n try {\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed = JSON.parse(content) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `file creds: userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } catch (e) {\n lines.push(`file creds: parse error — ${e instanceof Error ? e.message : String(e)}`);\n }\n }\n\n try {\n const entry = getKeyringEntry();\n const data = entry.getPassword();\n if (data) {\n const parsed = JSON.parse(data) as Partial<Credentials>;\n const expired = parsed.expiresAt ? Date.now() >= parsed.expiresAt : 'unknown';\n lines.push(\n `keyring: found, userId=${parsed.userId ?? 'missing'}, expired=${expired}, hasRefreshToken=${!!parsed.refreshToken}`,\n );\n } else {\n lines.push('keyring: empty (getPassword returned null)');\n }\n } catch (e) {\n lines.push(`keyring: error — ${e instanceof Error ? e.message : String(e)}`);\n }\n\n lines.push(`insecureStorage=${forceInsecureStorage}`);\n return lines;\n}\n\nexport { getCredentialsPath };\n"]}
|
package/dist/lib/ensure-auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Startup auth guard - ensures valid authentication before command execution.
|
|
3
3
|
*/
|
|
4
|
-
import { getCredentials, updateTokens,
|
|
4
|
+
import { getCredentials, updateTokens, isTokenExpired, clearCredentials } from './credentials.js';
|
|
5
5
|
import { refreshAccessToken } from './token-refresh-client.js';
|
|
6
6
|
import { getCliAuthClientId, getAuthkitDomain } from './settings.js';
|
|
7
7
|
import { runLogin } from '../commands/login.js';
|
|
@@ -24,28 +24,17 @@ export async function ensureAuthenticated() {
|
|
|
24
24
|
loginTriggered: false,
|
|
25
25
|
tokenRefreshed: false,
|
|
26
26
|
};
|
|
27
|
-
// Case 1: No credentials
|
|
28
|
-
if (!hasCredentials()) {
|
|
29
|
-
if (isNonInteractiveEnvironment()) {
|
|
30
|
-
exitWithAuthRequired();
|
|
31
|
-
}
|
|
32
|
-
logInfo('[ensure-auth] No credentials found, triggering login');
|
|
33
|
-
await runLogin();
|
|
34
|
-
result.loginTriggered = true;
|
|
35
|
-
result.authenticated = hasCredentials();
|
|
36
|
-
return result;
|
|
37
|
-
}
|
|
27
|
+
// Case 1: No credentials or invalid credentials
|
|
38
28
|
const creds = getCredentials();
|
|
39
29
|
if (!creds) {
|
|
40
|
-
//
|
|
41
|
-
clearCredentials();
|
|
30
|
+
clearCredentials(); // Clean up any corrupt/empty files
|
|
42
31
|
if (isNonInteractiveEnvironment()) {
|
|
43
32
|
exitWithAuthRequired();
|
|
44
33
|
}
|
|
45
|
-
logInfo('[ensure-auth]
|
|
34
|
+
logInfo('[ensure-auth] No valid credentials found, triggering login');
|
|
46
35
|
await runLogin();
|
|
47
36
|
result.loginTriggered = true;
|
|
48
|
-
result.authenticated =
|
|
37
|
+
result.authenticated = getCredentials() !== null;
|
|
49
38
|
return result;
|
|
50
39
|
}
|
|
51
40
|
// Case 2: Access token still valid
|
|
@@ -75,18 +64,17 @@ export async function ensureAuthenticated() {
|
|
|
75
64
|
logInfo('[ensure-auth] Refresh token expired, triggering login');
|
|
76
65
|
await runLogin();
|
|
77
66
|
result.loginTriggered = true;
|
|
78
|
-
result.authenticated =
|
|
67
|
+
result.authenticated = getCredentials() !== null;
|
|
79
68
|
return result;
|
|
80
69
|
}
|
|
81
|
-
// Network or server error -
|
|
82
|
-
clearCredentials();
|
|
70
|
+
// Network or server error - keep credentials intact for retry
|
|
83
71
|
if (isNonInteractiveEnvironment()) {
|
|
84
72
|
exitWithAuthRequired(`Authentication refresh failed (${refreshResult.errorType}). Run \`workos login\` in an interactive terminal.`);
|
|
85
73
|
}
|
|
86
74
|
logInfo(`[ensure-auth] Refresh failed (${refreshResult.errorType}), triggering login`);
|
|
87
75
|
await runLogin();
|
|
88
76
|
result.loginTriggered = true;
|
|
89
|
-
result.authenticated =
|
|
77
|
+
result.authenticated = getCredentials() !== null;
|
|
90
78
|
return result;
|
|
91
79
|
}
|
|
92
80
|
}
|
|
@@ -98,7 +86,7 @@ export async function ensureAuthenticated() {
|
|
|
98
86
|
logInfo('[ensure-auth] No refresh token, triggering login');
|
|
99
87
|
await runLogin();
|
|
100
88
|
result.loginTriggered = true;
|
|
101
|
-
result.authenticated =
|
|
89
|
+
result.authenticated = getCredentials() !== null;
|
|
102
90
|
return result;
|
|
103
91
|
}
|
|
104
92
|
//# sourceMappingURL=ensure-auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ensure-auth.js","sourceRoot":"","sources":["../../src/lib/ensure-auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"ensure-auth.js","sourceRoot":"","sources":["../../src/lib/ensure-auth.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Startup auth guard - ensures valid authentication before command execution.\n */\n\nimport { getCredentials, updateTokens, isTokenExpired, clearCredentials } from './credentials.js';\nimport { refreshAccessToken } from './token-refresh-client.js';\nimport { getCliAuthClientId, getAuthkitDomain } from './settings.js';\nimport { runLogin } from '../commands/login.js';\nimport { logInfo } from '../utils/debug.js';\nimport { isNonInteractiveEnvironment } from '../utils/environment.js';\nimport { exitWithAuthRequired } from '../utils/exit-codes.js';\n\nexport interface EnsureAuthResult {\n /** Whether auth is now valid */\n authenticated: boolean;\n /** Whether login flow was triggered */\n loginTriggered: boolean;\n /** Whether token was refreshed */\n tokenRefreshed: boolean;\n}\n\n/**\n * Ensure valid authentication before command execution.\n *\n * - No credentials: triggers login flow\n * - Expired access token (valid refresh): silently refreshes\n * - Expired refresh token: triggers login flow\n *\n * @returns Result indicating what actions were taken\n * @throws Error if login fails or refresh fails unexpectedly\n */\nexport async function ensureAuthenticated(): Promise<EnsureAuthResult> {\n const result: EnsureAuthResult = {\n authenticated: false,\n loginTriggered: false,\n tokenRefreshed: false,\n };\n\n // Case 1: No credentials or invalid credentials\n const creds = getCredentials();\n if (!creds) {\n clearCredentials(); // Clean up any corrupt/empty files\n if (isNonInteractiveEnvironment()) {\n exitWithAuthRequired();\n }\n logInfo('[ensure-auth] No valid credentials found, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = getCredentials() !== null;\n return result;\n }\n\n // Case 2: Access token still valid\n if (!isTokenExpired(creds)) {\n result.authenticated = true;\n return result;\n }\n\n // Case 3: Access token expired, try refresh\n if (creds.refreshToken) {\n logInfo('[ensure-auth] Access token expired, attempting refresh');\n\n const clientId = getCliAuthClientId();\n const authkitDomain = getAuthkitDomain();\n\n if (clientId && authkitDomain) {\n const refreshResult = await refreshAccessToken(authkitDomain, clientId);\n\n if (refreshResult.success && refreshResult.accessToken && refreshResult.expiresAt) {\n updateTokens(refreshResult.accessToken, refreshResult.expiresAt, refreshResult.refreshToken);\n result.tokenRefreshed = true;\n result.authenticated = true;\n return result;\n }\n\n // Refresh failed - check if it's recoverable\n if (refreshResult.errorType === 'invalid_grant') {\n clearCredentials();\n if (isNonInteractiveEnvironment()) {\n exitWithAuthRequired('Session expired. Run `workos login` in an interactive terminal to re-authenticate.');\n }\n logInfo('[ensure-auth] Refresh token expired, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = getCredentials() !== null;\n return result;\n }\n\n // Network or server error - keep credentials intact for retry\n if (isNonInteractiveEnvironment()) {\n exitWithAuthRequired(\n `Authentication refresh failed (${refreshResult.errorType}). Run \\`workos login\\` in an interactive terminal.`,\n );\n }\n logInfo(`[ensure-auth] Refresh failed (${refreshResult.errorType}), triggering login`);\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = getCredentials() !== null;\n return result;\n }\n }\n\n // Case 4: No refresh token available — clear stale creds, must login\n clearCredentials();\n if (isNonInteractiveEnvironment()) {\n exitWithAuthRequired('Session expired. Run `workos login` in an interactive terminal to re-authenticate.');\n }\n logInfo('[ensure-auth] No refresh token, triggering login');\n await runLogin();\n result.loginTriggered = true;\n result.authenticated = getCredentials() !== null;\n return result;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -86,32 +86,35 @@ Default redirect URI: `http://localhost:3000/api/auth/callback`
|
|
|
86
86
|
|
|
87
87
|
**authkitMiddleware MUST be configured or auth will fail silently.**
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
**WARNING: Do NOT add middleware to `createRouter()` in `router.tsx` or `app.tsx`. That is TanStack Router (client-side only). Server middleware belongs in `start.ts` using `requestMiddleware`.**
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
import { authkitMiddleware } from '@workos/authkit-tanstack-react-start';
|
|
91
|
+
### If `start.ts` already exists
|
|
93
92
|
|
|
94
|
-
export
|
|
95
|
-
requestMiddleware: [authkitMiddleware()],
|
|
96
|
-
};
|
|
97
|
-
```
|
|
93
|
+
Read the existing file first. Add `authkitMiddleware` to the existing `requestMiddleware` array (or create the array if missing). Preserve the existing export style. Do not rewrite the file from scratch.
|
|
98
94
|
|
|
99
|
-
|
|
95
|
+
### If `start.ts` does not exist
|
|
96
|
+
|
|
97
|
+
Create `src/start.ts` (or `app/start.ts` for legacy) using `createStart`:
|
|
100
98
|
|
|
101
99
|
```typescript
|
|
102
100
|
import { createStart } from '@tanstack/react-start';
|
|
103
101
|
import { authkitMiddleware } from '@workos/authkit-tanstack-react-start';
|
|
104
102
|
|
|
105
|
-
export
|
|
103
|
+
export const startInstance = createStart(() => ({
|
|
106
104
|
requestMiddleware: [authkitMiddleware()],
|
|
107
|
-
});
|
|
105
|
+
}));
|
|
108
106
|
```
|
|
109
107
|
|
|
108
|
+
**Two things matter here:**
|
|
109
|
+
|
|
110
|
+
1. **Named export `startInstance`** — the build plugin generates `import type { startInstance }` from this file. A `default` export will cause a build error.
|
|
111
|
+
2. **`createStart` takes a function** returning the options object, not the options directly. `createStart({ ... })` will fail.
|
|
112
|
+
|
|
110
113
|
### Verification Checklist
|
|
111
114
|
|
|
112
115
|
- [ ] `authkitMiddleware` imported from `@workos/authkit-tanstack-react-start`
|
|
113
|
-
- [ ] Middleware in `requestMiddleware` array
|
|
114
|
-
- [ ]
|
|
116
|
+
- [ ] Middleware in `requestMiddleware` array (not `middleware`)
|
|
117
|
+
- [ ] Named export: `export const startInstance = createStart(...)` (not `export default`)
|
|
115
118
|
|
|
116
119
|
Verify: `grep -r "authkitMiddleware" src/ app/ 2>/dev/null`
|
|
117
120
|
|
|
@@ -208,6 +211,40 @@ function Profile() {
|
|
|
208
211
|
|
|
209
212
|
**Note:** Server-side `getAuth()` is preferred for most use cases.
|
|
210
213
|
|
|
214
|
+
## Finalize (REQUIRED before declaring success)
|
|
215
|
+
|
|
216
|
+
After creating/editing all files, run these steps in order. Skipping them is the most common cause of build failures.
|
|
217
|
+
|
|
218
|
+
### 1. Regenerate the route tree
|
|
219
|
+
|
|
220
|
+
Adding new route files (callback, signout, etc.) makes the existing `routeTree.gen.ts` stale. The build will fail with type errors about missing routes until it is regenerated.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pnpm build 2>/dev/null || npx tsr generate
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
The build itself triggers route tree regeneration. If it fails for other reasons, use `tsr generate` directly.
|
|
227
|
+
|
|
228
|
+
### 2. Ensure Vite type declarations exist
|
|
229
|
+
|
|
230
|
+
TanStack Start projects import CSS with `import styles from './styles.css?url'`. Without Vite's type declarations, TypeScript will error on these imports. Check if `src/vite-env.d.ts` (or `app/vite-env.d.ts`) exists — if not, create it now (before attempting the build):
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
/// <reference types="vite/client" />
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 3. Verify the build
|
|
237
|
+
|
|
238
|
+
```bash
|
|
239
|
+
pnpm build
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Do not skip this step. If the build fails, fix the errors before finishing. Common causes:
|
|
243
|
+
|
|
244
|
+
- Stale route tree → re-run step 1
|
|
245
|
+
- Missing Vite types → re-run step 2
|
|
246
|
+
- Wrong import paths → check package name is `@workos/authkit-tanstack-react-start`
|
|
247
|
+
|
|
211
248
|
## Error Recovery
|
|
212
249
|
|
|
213
250
|
### "AuthKit middleware is not configured"
|