workos 0.12.3 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 chalk from 'chalk';\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, logError } from '../utils/debug.js';\nimport { fetchStagingCredentials } from '../lib/staging-api.js';\nimport { getConfig, saveConfig } from '../lib/config-store.js';\nimport type { CliConfig } from '../lib/config-store.js';\nimport { formatWorkOSCommand } from '../utils/command-invocation.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\n/**\n * Auto-provision a staging environment after login.\n *\n * Fetches staging credentials using the access token, then saves them\n * as a \"staging\" environment in the config store. Non-fatal — logs a\n * hint on failure instead of throwing.\n */\nexport async function provisionStagingEnvironment(accessToken: string): Promise<boolean> {\n try {\n const staging = await fetchStagingCredentials(accessToken);\n\n const config: CliConfig = getConfig() ?? { environments: {} };\n const isFirst = Object.keys(config.environments).length === 0;\n\n config.environments['staging'] = {\n name: 'staging',\n type: 'sandbox',\n apiKey: staging.apiKey,\n clientId: staging.clientId,\n };\n\n if (isFirst || !config.activeEnvironment) {\n config.activeEnvironment = 'staging';\n }\n\n saveConfig(config);\n logInfo('[login] Staging environment auto-provisioned');\n return true;\n } catch (error) {\n logError('[login] Failed to auto-provision staging environment:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n console.log(chalk.green(`Already logged in as ${creds?.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth 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 console.log(chalk.green(`Already logged in as ${existingCreds.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth 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\n // Auto-provision staging environment\n const provisioned = await provisionStagingEnvironment(result.access_token);\n if (provisioned) {\n clack.log.success('Staging environment configured automatically');\n } else {\n clack.log.info(chalk.dim('Run `workos env add` to configure an environment manually'));\n }\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 chalk from 'chalk';\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, logError } from '../utils/debug.js';\nimport { fetchStagingCredentials } from '../lib/staging-api.js';\nimport { getConfig, saveConfig } from '../lib/config-store.js';\nimport type { CliConfig } from '../lib/config-store.js';\nimport { formatWorkOSCommand } from '../utils/command-invocation.js';\nimport { autoInstallSkills } from './install-skill.js';\nimport { isJsonMode } from '../utils/output.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\n/**\n * Best-effort skill install after a successful auth-login.\n *\n * Mirrors the install.ts hook copy, but wraps `autoInstallSkills` in its own\n * try/catch AND a 30s timeout so a skill install hang (e.g. blocked filesystem\n * call) never blocks login completion. Login already succeeded by the time\n * this runs — the user having a working session is the contract that must hold.\n *\n * Extracted from runLogin so it can be unit-tested without standing up the\n * device-auth polling loop.\n */\nexport const SKILL_INSTALL_TIMEOUT_MS = 30 * 1000;\n\nexport async function installSkillsAfterLogin(): Promise<void> {\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n try {\n const timeout = new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => resolve(null), SKILL_INSTALL_TIMEOUT_MS);\n // Don't keep the event loop alive on this timer — process should exit\n // immediately if everything else has resolved.\n timeoutHandle.unref?.();\n });\n const result = await Promise.race([autoInstallSkills(), timeout]);\n if (result && !isJsonMode()) {\n const skillWord = result.skills.length === 1 ? 'skill' : 'skills';\n clack.log.info(`Installed ${result.skills.length} WorkOS ${skillWord} for ${result.agents.join(', ')}.`);\n }\n } catch {\n // Skill install must never fail login.\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n }\n}\n\n/**\n * Auto-provision a staging environment after login.\n *\n * Fetches staging credentials using the access token, then saves them\n * as a \"staging\" environment in the config store. Non-fatal — logs a\n * hint on failure instead of throwing.\n */\nexport async function provisionStagingEnvironment(accessToken: string): Promise<boolean> {\n try {\n const staging = await fetchStagingCredentials(accessToken);\n\n const config: CliConfig = getConfig() ?? { environments: {} };\n const isFirst = Object.keys(config.environments).length === 0;\n\n config.environments['staging'] = {\n name: 'staging',\n type: 'sandbox',\n apiKey: staging.apiKey,\n clientId: staging.clientId,\n };\n\n if (isFirst || !config.activeEnvironment) {\n config.activeEnvironment = 'staging';\n }\n\n saveConfig(config);\n logInfo('[login] Staging environment auto-provisioned');\n return true;\n } catch (error) {\n logError('[login] Failed to auto-provision staging environment:', error instanceof Error ? error.message : error);\n return false;\n }\n}\n\nexport async function runLogin(): Promise<void> {\n const clientId = getCliAuthClientId();\n\n // Check if already logged in with valid token\n if (getAccessToken()) {\n const creds = getCredentials();\n console.log(chalk.green(`Already logged in as ${creds?.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth 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 console.log(chalk.green(`Already logged in as ${existingCreds.email ?? 'unknown'}`));\n console.log(chalk.dim(`Run \\`${formatWorkOSCommand('auth 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\n // Auto-provision staging environment\n const provisioned = await provisionStagingEnvironment(result.access_token);\n if (provisioned) {\n clack.log.success('Staging environment configured automatically');\n } else {\n clack.log.info(chalk.dim('Run `workos env add` to configure an environment manually'));\n }\n\n // Best-effort skill install. Wrapped helper guarantees login never\n // fails on skill errors.\n await installSkillsAfterLogin();\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"]}
@@ -0,0 +1,9 @@
1
+ import type { SkillsInfo } from '../types.js';
2
+ /**
3
+ * Check the freshness of auto-installed WorkOS skills across detected coding
4
+ * agents. Compares each agent's version marker (written by autoInstallSkills)
5
+ * against the bundled @workos/skills version the CLI ships with. Returns null
6
+ * when no agents have a WorkOS skill installed at all — no noise for users who
7
+ * never installed through the CLI.
8
+ */
9
+ export declare function checkSkills(home?: string): Promise<SkillsInfo | null>;
@@ -0,0 +1,84 @@
1
+ import { homedir } from 'node:os';
2
+ import { access, readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import semver from 'semver';
5
+ import { createAgents, getBundledSkillsVersion, SKILL_VERSION_MARKER_FILENAME } from '../../commands/install-skill.js';
6
+ async function pathExists(p) {
7
+ try {
8
+ await access(p);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ /**
16
+ * Stale = installed version is strictly older than the bundled version.
17
+ * String inequality would also fire when installed > bundled (user installed
18
+ * via a newer CLI then downgraded), and the SKILLS_OUTDATED remediation would
19
+ * silently downgrade their agent's skills. Use semver ordering so we only
20
+ * recommend an update when the bundled set is actually ahead.
21
+ *
22
+ * Falls back to string inequality when either version can't be parsed as
23
+ * semver — better to flag a possibly-stale skill than to ignore drift entirely.
24
+ */
25
+ function isStale(installed, bundled) {
26
+ const installedValid = semver.valid(installed);
27
+ const bundledValid = semver.valid(bundled);
28
+ if (installedValid && bundledValid) {
29
+ return semver.lt(installedValid, bundledValid);
30
+ }
31
+ return installed !== bundled;
32
+ }
33
+ /**
34
+ * Check the freshness of auto-installed WorkOS skills across detected coding
35
+ * agents. Compares each agent's version marker (written by autoInstallSkills)
36
+ * against the bundled @workos/skills version the CLI ships with. Returns null
37
+ * when no agents have a WorkOS skill installed at all — no noise for users who
38
+ * never installed through the CLI.
39
+ */
40
+ export async function checkSkills(home = homedir()) {
41
+ const bundledVersion = await getBundledSkillsVersion();
42
+ const agents = createAgents(home);
43
+ const statuses = [];
44
+ for (const [, agent] of Object.entries(agents)) {
45
+ // Only report on agents that actually have a WorkOS skill installed.
46
+ // An agent's `skills/` dir existing (e.g. for unrelated user-installed
47
+ // skills) doesn't mean WE installed — and `doctor --fix` would otherwise
48
+ // happily write `workos/` and `workos-widgets/` onto an agent that never
49
+ // opted in. The marker OR a workos/ / workos-widgets/ subdir is the signal
50
+ // (either is enough — older explicit installs of just `workos-widgets`
51
+ // shouldn't be invisible to doctor).
52
+ const markerPath = join(agent.globalSkillsDir, SKILL_VERSION_MARKER_FILENAME);
53
+ const workosSkillDir = join(agent.globalSkillsDir, 'workos');
54
+ const widgetsSkillDir = join(agent.globalSkillsDir, 'workos-widgets');
55
+ const [hasMarker, hasWorkos, hasWidgets] = await Promise.all([
56
+ pathExists(markerPath),
57
+ pathExists(workosSkillDir),
58
+ pathExists(widgetsSkillDir),
59
+ ]);
60
+ if (!hasMarker && !hasWorkos && !hasWidgets)
61
+ continue;
62
+ let installedVersion = null;
63
+ if (hasMarker) {
64
+ try {
65
+ installedVersion = (await readFile(markerPath, 'utf8')).trim() || null;
66
+ }
67
+ catch {
68
+ installedVersion = null;
69
+ }
70
+ }
71
+ statuses.push({
72
+ agent: agent.displayName,
73
+ installedVersion,
74
+ stale: Boolean(bundledVersion && installedVersion && isStale(installedVersion, bundledVersion)),
75
+ });
76
+ }
77
+ if (statuses.length === 0)
78
+ return null;
79
+ return {
80
+ bundledVersion,
81
+ agents: statuses,
82
+ };
83
+ }
84
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../../src/doctor/checks/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import { homedir } from 'node:os';\nimport { access, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport semver from 'semver';\nimport { createAgents, getBundledSkillsVersion, SKILL_VERSION_MARKER_FILENAME } from '../../commands/install-skill.js';\nimport type { SkillsInfo, SkillAgentStatus } from '../types.js';\n\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Stale = installed version is strictly older than the bundled version.\n * String inequality would also fire when installed > bundled (user installed\n * via a newer CLI then downgraded), and the SKILLS_OUTDATED remediation would\n * silently downgrade their agent's skills. Use semver ordering so we only\n * recommend an update when the bundled set is actually ahead.\n *\n * Falls back to string inequality when either version can't be parsed as\n * semver — better to flag a possibly-stale skill than to ignore drift entirely.\n */\nfunction isStale(installed: string, bundled: string): boolean {\n const installedValid = semver.valid(installed);\n const bundledValid = semver.valid(bundled);\n if (installedValid && bundledValid) {\n return semver.lt(installedValid, bundledValid);\n }\n return installed !== bundled;\n}\n\n/**\n * Check the freshness of auto-installed WorkOS skills across detected coding\n * agents. Compares each agent's version marker (written by autoInstallSkills)\n * against the bundled @workos/skills version the CLI ships with. Returns null\n * when no agents have a WorkOS skill installed at all — no noise for users who\n * never installed through the CLI.\n */\nexport async function checkSkills(home: string = homedir()): Promise<SkillsInfo | null> {\n const bundledVersion = await getBundledSkillsVersion();\n const agents = createAgents(home);\n\n const statuses: SkillAgentStatus[] = [];\n\n for (const [, agent] of Object.entries(agents)) {\n // Only report on agents that actually have a WorkOS skill installed.\n // An agent's `skills/` dir existing (e.g. for unrelated user-installed\n // skills) doesn't mean WE installed — and `doctor --fix` would otherwise\n // happily write `workos/` and `workos-widgets/` onto an agent that never\n // opted in. The marker OR a workos/ / workos-widgets/ subdir is the signal\n // (either is enough — older explicit installs of just `workos-widgets`\n // shouldn't be invisible to doctor).\n const markerPath = join(agent.globalSkillsDir, SKILL_VERSION_MARKER_FILENAME);\n const workosSkillDir = join(agent.globalSkillsDir, 'workos');\n const widgetsSkillDir = join(agent.globalSkillsDir, 'workos-widgets');\n const [hasMarker, hasWorkos, hasWidgets] = await Promise.all([\n pathExists(markerPath),\n pathExists(workosSkillDir),\n pathExists(widgetsSkillDir),\n ]);\n if (!hasMarker && !hasWorkos && !hasWidgets) continue;\n\n let installedVersion: string | null = null;\n if (hasMarker) {\n try {\n installedVersion = (await readFile(markerPath, 'utf8')).trim() || null;\n } catch {\n installedVersion = null;\n }\n }\n\n statuses.push({\n agent: agent.displayName,\n installedVersion,\n stale: Boolean(bundledVersion && installedVersion && isStale(installedVersion, bundledVersion)),\n });\n }\n\n if (statuses.length === 0) return null;\n\n return {\n bundledVersion,\n agents: statuses,\n };\n}\n"]}
@@ -1,4 +1,24 @@
1
- import type { DoctorOptions, DoctorReport } from './types.js';
1
+ import type { DoctorOptions, DoctorReport, SkillsRefreshResult } from './types.js';
2
+ /**
3
+ * Skills `--fix` is allowed to refresh. Hardcoded — NOT derived from
4
+ * discoverSkills — so future bundled skills require an explicit opt-in here
5
+ * before doctor will write to their target directory. This is the contract's
6
+ * promise that `--fix` only ever touches `workos/` and `workos-widgets/`.
7
+ */
8
+ export declare const FIXABLE_SKILLS: readonly ["workos", "workos-widgets"];
9
+ /**
10
+ * Refresh stale WorkOS skills if `--fix` is set and at least one agent is
11
+ * stale or has no marker. Always re-reads `checkSkills()` after a successful
12
+ * refresh so detectIssues sees the post-refresh state and we don't ship a
13
+ * doctor report that simultaneously claims "fixed" and "still stale".
14
+ *
15
+ * Extracted from runDoctor for unit testability — runDoctor itself depends on
16
+ * eight upstream checks that are expensive to mock.
17
+ */
18
+ export declare function maybeRefreshSkills(options: Pick<DoctorOptions, 'fix'>, skills: DoctorReport['skills']): Promise<{
19
+ skillsRefresh?: SkillsRefreshResult;
20
+ skills: DoctorReport['skills'];
21
+ }>;
2
22
  export declare function runDoctor(options: DoctorOptions): Promise<DoctorReport>;
3
23
  export declare function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void>;
4
24
  export { formatReport } from './output.js';
@@ -7,12 +7,52 @@ import { checkConnectivity } from './checks/connectivity.js';
7
7
  import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';
8
8
  import { checkAuthPatterns } from './checks/auth-patterns.js';
9
9
  import { checkAiAnalysis } from './checks/ai-analysis.js';
10
+ import { checkSkills } from './checks/skills.js';
11
+ import { refreshWorkOSSkills } from '../commands/install-skill.js';
10
12
  import { detectIssues } from './issues.js';
11
13
  import { formatReport } from './output.js';
12
14
  import { formatReportAsJson } from './json-output.js';
13
15
  import { copyToClipboard } from './clipboard.js';
14
16
  import Chalk from 'chalk';
15
17
  const DOCTOR_VERSION = '1.0.0';
18
+ /**
19
+ * Skills `--fix` is allowed to refresh. Hardcoded — NOT derived from
20
+ * discoverSkills — so future bundled skills require an explicit opt-in here
21
+ * before doctor will write to their target directory. This is the contract's
22
+ * promise that `--fix` only ever touches `workos/` and `workos-widgets/`.
23
+ */
24
+ export const FIXABLE_SKILLS = ['workos', 'workos-widgets'];
25
+ /**
26
+ * Refresh stale WorkOS skills if `--fix` is set and at least one agent is
27
+ * stale or has no marker. Always re-reads `checkSkills()` after a successful
28
+ * refresh so detectIssues sees the post-refresh state and we don't ship a
29
+ * doctor report that simultaneously claims "fixed" and "still stale".
30
+ *
31
+ * Extracted from runDoctor for unit testability — runDoctor itself depends on
32
+ * eight upstream checks that are expensive to mock.
33
+ */
34
+ export async function maybeRefreshSkills(options, skills) {
35
+ if (!options.fix || !skills)
36
+ return { skills };
37
+ const stalePresent = skills.agents.some((a) => a.stale || a.installedVersion === null);
38
+ if (!stalePresent)
39
+ return { skills };
40
+ const refresh = await refreshWorkOSSkills({
41
+ // Explicit allowlist — NOT discoverSkills — so the contract's
42
+ // workos/+workos-widgets-only constraint can't drift.
43
+ skills: [...FIXABLE_SKILLS],
44
+ });
45
+ if (!refresh)
46
+ return { skills };
47
+ return {
48
+ skillsRefresh: {
49
+ before: refresh.perAgentBefore,
50
+ after: refresh.perAgentAfter,
51
+ skillsInstalled: refresh.skills,
52
+ },
53
+ skills: (await checkSkills()) ?? undefined,
54
+ };
55
+ }
16
56
  export async function runDoctor(options) {
17
57
  // Environment check first - loads project's .env/.env.local files
18
58
  // Must run before connectivity so the resolved base URL is available
@@ -25,6 +65,14 @@ export async function runDoctor(options) {
25
65
  checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),
26
66
  checkLanguage(options.installDir),
27
67
  ]);
68
+ let skills = (await checkSkills()) ?? undefined;
69
+ // `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so
70
+ // every downstream consumer (issue detection, AI prompt context) sees the
71
+ // post-refresh skill state and doesn't reference a SKILLS_OUTDATED warning
72
+ // that was just resolved.
73
+ const refreshOutcome = await maybeRefreshSkills(options, skills);
74
+ const skillsRefresh = refreshOutcome.skillsRefresh;
75
+ skills = refreshOutcome.skills;
28
76
  // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)
29
77
  // AI analysis also receives early issues as context to avoid duplication
30
78
  const earlyIssues = detectIssues({
@@ -37,6 +85,7 @@ export async function runDoctor(options) {
37
85
  framework,
38
86
  environment,
39
87
  connectivity,
88
+ skills,
40
89
  });
41
90
  const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([
42
91
  checkDashboardSettings(options, environment.apiKeyType, envRaw),
@@ -73,8 +122,10 @@ export async function runDoctor(options) {
73
122
  redirectUris,
74
123
  authPatterns,
75
124
  aiAnalysis,
125
+ skills,
126
+ skillsRefresh,
76
127
  };
77
- // Detect issues based on collected data
128
+ // Detect issues based on (post-refresh) data.
78
129
  const issues = detectIssues(partialReport);
79
130
  // Calculate summary
80
131
  const errors = issues.filter((i) => i.severity === 'error').length;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkLanguage } from './checks/language.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { checkAuthPatterns } from './checks/auth-patterns.js';\nimport { checkAiAnalysis } from './checks/ai-analysis.js';\nimport { detectIssues } from './issues.js';\nimport { formatReport } from './output.js';\nimport { formatReportAsJson } from './json-output.js';\nimport { copyToClipboard } from './clipboard.js';\nimport Chalk from 'chalk';\nimport type { DoctorOptions, DoctorReport } from './types.js';\n\nconst DOCTOR_VERSION = '1.0.0';\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n // Environment check first - loads project's .env/.env.local files\n // Must run before connectivity so the resolved base URL is available\n const { info: environment, raw: envRaw } = checkEnvironment(options);\n\n // Run remaining checks concurrently\n const [sdk, framework, runtime, connectivity, language] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n checkLanguage(options.installDir),\n ]);\n\n // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)\n // AI analysis also receives early issues as context to avoid duplication\n const earlyIssues = detectIssues({\n version: DOCTOR_VERSION,\n timestamp: '',\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n });\n\n const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([\n checkDashboardSettings(options, environment.apiKeyType, envRaw),\n checkAuthPatterns(options, framework, environment, sdk),\n checkAiAnalysis(\n { installDir: options.installDir, language, framework, sdk, environment, existingIssues: earlyIssues },\n { skipAi: options.skipAi },\n ),\n ]);\n\n // Compute expected redirect URI from framework detection if not set in env\n const redirectUriSource: 'env' | 'inferred' = environment.redirectUri ? 'env' : 'inferred';\n const expectedRedirectUri =\n environment.redirectUri ??\n (framework.expectedCallbackPath && framework.detectedPort\n ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`\n : null);\n\n // Compare redirect URIs if we have dashboard data\n const redirectUris = dashboardResult.settings\n ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)\n : undefined;\n\n // Build partial report\n const partialReport = {\n version: DOCTOR_VERSION,\n timestamp: new Date().toISOString(),\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n credentialValidation: dashboardResult.credentialValidation,\n dashboardSettings: dashboardResult.settings ?? undefined,\n dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,\n redirectUris,\n authPatterns,\n aiAnalysis,\n };\n\n // Detect issues based on collected data\n const issues = detectIssues(partialReport);\n\n // Calculate summary\n const errors = issues.filter((i) => i.severity === 'error').length;\n const warnings = issues.filter((i) => i.severity === 'warning').length;\n\n const report: DoctorReport = {\n ...partialReport,\n issues,\n summary: {\n errors,\n warnings,\n healthy: errors === 0,\n },\n };\n\n return report;\n}\n\nexport async function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void> {\n if (options.json) {\n const json = formatReportAsJson(report);\n console.log(json);\n\n if (options.copy) {\n const success = await copyToClipboard(json);\n if (success) {\n console.error('(Copied to clipboard)');\n }\n }\n } else {\n formatReport(report, { verbose: options.verbose });\n\n if (options.copy) {\n const json = formatReportAsJson(report);\n const success = await copyToClipboard(json);\n if (success) {\n console.log(Chalk.dim('Report copied to clipboard'));\n }\n }\n }\n}\n\nexport { formatReport } from './output.js';\nexport { formatReportAsJson } from './json-output.js';\nexport type { DoctorReport, DoctorOptions } from './types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { checkSdk } from './checks/sdk.js';\nimport { checkFramework } from './checks/framework.js';\nimport { checkRuntime } from './checks/runtime.js';\nimport { checkLanguage } from './checks/language.js';\nimport { checkEnvironment } from './checks/environment.js';\nimport { checkConnectivity } from './checks/connectivity.js';\nimport { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.js';\nimport { checkAuthPatterns } from './checks/auth-patterns.js';\nimport { checkAiAnalysis } from './checks/ai-analysis.js';\nimport { checkSkills } from './checks/skills.js';\nimport { refreshWorkOSSkills } from '../commands/install-skill.js';\nimport { detectIssues } from './issues.js';\nimport { formatReport } from './output.js';\nimport { formatReportAsJson } from './json-output.js';\nimport { copyToClipboard } from './clipboard.js';\nimport Chalk from 'chalk';\nimport type { DoctorOptions, DoctorReport, SkillsRefreshResult } from './types.js';\n\nconst DOCTOR_VERSION = '1.0.0';\n\n/**\n * Skills `--fix` is allowed to refresh. Hardcoded — NOT derived from\n * discoverSkills — so future bundled skills require an explicit opt-in here\n * before doctor will write to their target directory. This is the contract's\n * promise that `--fix` only ever touches `workos/` and `workos-widgets/`.\n */\nexport const FIXABLE_SKILLS = ['workos', 'workos-widgets'] as const;\n\n/**\n * Refresh stale WorkOS skills if `--fix` is set and at least one agent is\n * stale or has no marker. Always re-reads `checkSkills()` after a successful\n * refresh so detectIssues sees the post-refresh state and we don't ship a\n * doctor report that simultaneously claims \"fixed\" and \"still stale\".\n *\n * Extracted from runDoctor for unit testability — runDoctor itself depends on\n * eight upstream checks that are expensive to mock.\n */\nexport async function maybeRefreshSkills(\n options: Pick<DoctorOptions, 'fix'>,\n skills: DoctorReport['skills'],\n): Promise<{\n skillsRefresh?: SkillsRefreshResult;\n skills: DoctorReport['skills'];\n}> {\n if (!options.fix || !skills) return { skills };\n\n const stalePresent = skills.agents.some((a) => a.stale || a.installedVersion === null);\n if (!stalePresent) return { skills };\n\n const refresh = await refreshWorkOSSkills({\n // Explicit allowlist — NOT discoverSkills — so the contract's\n // workos/+workos-widgets-only constraint can't drift.\n skills: [...FIXABLE_SKILLS],\n });\n if (!refresh) return { skills };\n\n return {\n skillsRefresh: {\n before: refresh.perAgentBefore,\n after: refresh.perAgentAfter,\n skillsInstalled: refresh.skills,\n },\n skills: (await checkSkills()) ?? undefined,\n };\n}\n\nexport async function runDoctor(options: DoctorOptions): Promise<DoctorReport> {\n // Environment check first - loads project's .env/.env.local files\n // Must run before connectivity so the resolved base URL is available\n const { info: environment, raw: envRaw } = checkEnvironment(options);\n\n // Run remaining checks concurrently\n const [sdk, framework, runtime, connectivity, language] = await Promise.all([\n checkSdk(options),\n checkFramework(options),\n checkRuntime(options),\n checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),\n checkLanguage(options.installDir),\n ]);\n\n let skills = (await checkSkills()) ?? undefined;\n\n // `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so\n // every downstream consumer (issue detection, AI prompt context) sees the\n // post-refresh skill state and doesn't reference a SKILLS_OUTDATED warning\n // that was just resolved.\n const refreshOutcome = await maybeRefreshSkills(options, skills);\n const skillsRefresh = refreshOutcome.skillsRefresh;\n skills = refreshOutcome.skills;\n\n // Dashboard settings + auth patterns + AI analysis (parallel, all need sdk/framework results)\n // AI analysis also receives early issues as context to avoid duplication\n const earlyIssues = detectIssues({\n version: DOCTOR_VERSION,\n timestamp: '',\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n skills,\n });\n\n const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([\n checkDashboardSettings(options, environment.apiKeyType, envRaw),\n checkAuthPatterns(options, framework, environment, sdk),\n checkAiAnalysis(\n { installDir: options.installDir, language, framework, sdk, environment, existingIssues: earlyIssues },\n { skipAi: options.skipAi },\n ),\n ]);\n\n // Compute expected redirect URI from framework detection if not set in env\n const redirectUriSource: 'env' | 'inferred' = environment.redirectUri ? 'env' : 'inferred';\n const expectedRedirectUri =\n environment.redirectUri ??\n (framework.expectedCallbackPath && framework.detectedPort\n ? `http://localhost:${framework.detectedPort}${framework.expectedCallbackPath}`\n : null);\n\n // Compare redirect URIs if we have dashboard data\n const redirectUris = dashboardResult.settings\n ? compareRedirectUris(expectedRedirectUri, dashboardResult.settings.redirectUris, redirectUriSource)\n : undefined;\n\n // Build partial report\n const partialReport = {\n version: DOCTOR_VERSION,\n timestamp: new Date().toISOString(),\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n connectivity,\n credentialValidation: dashboardResult.credentialValidation,\n dashboardSettings: dashboardResult.settings ?? undefined,\n dashboardError: dashboardResult.settings ? undefined : dashboardResult.error,\n redirectUris,\n authPatterns,\n aiAnalysis,\n skills,\n skillsRefresh,\n };\n\n // Detect issues based on (post-refresh) data.\n const issues = detectIssues(partialReport);\n\n // Calculate summary\n const errors = issues.filter((i) => i.severity === 'error').length;\n const warnings = issues.filter((i) => i.severity === 'warning').length;\n\n const report: DoctorReport = {\n ...partialReport,\n issues,\n summary: {\n errors,\n warnings,\n healthy: errors === 0,\n },\n };\n\n return report;\n}\n\nexport async function outputReport(report: DoctorReport, options: DoctorOptions): Promise<void> {\n if (options.json) {\n const json = formatReportAsJson(report);\n console.log(json);\n\n if (options.copy) {\n const success = await copyToClipboard(json);\n if (success) {\n console.error('(Copied to clipboard)');\n }\n }\n } else {\n formatReport(report, { verbose: options.verbose });\n\n if (options.copy) {\n const json = formatReportAsJson(report);\n const success = await copyToClipboard(json);\n if (success) {\n console.log(Chalk.dim('Report copied to clipboard'));\n }\n }\n }\n}\n\nexport { formatReport } from './output.js';\nexport { formatReportAsJson } from './json-output.js';\nexport type { DoctorReport, DoctorOptions } from './types.js';\n"]}
@@ -137,6 +137,21 @@ export function detectIssues(report) {
137
137
  });
138
138
  }
139
139
  }
140
+ // Skill freshness — warn when agent-installed skills trail the bundled version.
141
+ // Surfaced so users know their coding agent is using older WorkOS guidance.
142
+ if (report.skills?.bundledVersion) {
143
+ const stale = report.skills.agents.filter((a) => a.stale);
144
+ if (stale.length > 0) {
145
+ const agentList = stale.map((a) => `${a.agent} (${a.installedVersion ?? 'unknown'})`).join(', ');
146
+ issues.push({
147
+ code: 'SKILLS_OUTDATED',
148
+ severity: 'warning',
149
+ message: `WorkOS skills outdated for ${agentList} — bundled: ${report.skills.bundledVersion}`,
150
+ remediation: 'Run: workos skills install',
151
+ details: { bundledVersion: report.skills.bundledVersion, stale: stale.map((a) => a.agent) },
152
+ });
153
+ }
154
+ }
140
155
  return issues;
141
156
  }
142
157
  function getUpdateCommand(packageManager, sdkName) {
@@ -1 +1 @@
1
- {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/doctor/issues.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Issue, DoctorReport } from './types.js';\nimport { getInstallHint, languageToSdkLanguage } from './checks/language.js';\n\nexport const ISSUE_DEFINITIONS = {\n MISSING_API_KEY: {\n severity: 'error' as const,\n message: 'WORKOS_API_KEY environment variable not set',\n remediation: 'Set WORKOS_API_KEY in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n MISSING_CLIENT_ID: {\n severity: 'error' as const,\n message: 'WORKOS_CLIENT_ID environment variable not set',\n remediation: 'Set WORKOS_CLIENT_ID in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n SDK_OUTDATED: {\n severity: 'warning' as const,\n message: 'SDK version is outdated',\n // remediation generated dynamically\n },\n COOKIE_DOMAIN_NOT_SET: {\n severity: 'warning' as const,\n message: 'Cookie domain not explicitly set',\n remediation: 'Consider setting WORKOS_COOKIE_DOMAIN for cross-subdomain auth',\n docsUrl: 'https://workos.com/docs/authkit/cookie-domain',\n },\n NO_SDK_FOUND: {\n severity: 'error' as const,\n message: 'No WorkOS SDK found in dependencies',\n remediation: 'Install a WorkOS SDK: npm install @workos-inc/authkit-nextjs',\n docsUrl: 'https://workos.com/docs',\n },\n API_UNREACHABLE: {\n severity: 'warning' as const,\n message: 'Cannot reach WorkOS API',\n // remediation generated dynamically based on error\n },\n REDIRECT_URI_MISMATCH: {\n severity: 'warning' as const,\n message: 'Redirect URI not found in dashboard configuration',\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n PROD_API_CALL_BLOCKED: {\n severity: 'warning' as const,\n message: 'Dashboard settings not fetched (production API key)',\n remediation: 'Use a staging API key to fetch dashboard settings',\n },\n INVALID_API_KEY: {\n severity: 'error' as const,\n message: 'API key is invalid or expired',\n remediation: 'Check your WORKOS_API_KEY in the WorkOS dashboard',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n CLIENT_ID_MISMATCH: {\n severity: 'error' as const,\n message: 'Client ID does not match the API key environment',\n remediation: 'Ensure WORKOS_CLIENT_ID matches the environment for your API key',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n};\n\nexport function detectIssues(report: Omit<DoctorReport, 'issues' | 'summary'>): Issue[] {\n const issues: Issue[] = [];\n\n // SDK issues\n if (!report.sdk.name) {\n const lang = languageToSdkLanguage(report.language.name);\n const hint = getInstallHint(lang);\n issues.push({\n code: 'NO_SDK_FOUND',\n severity: 'error',\n message: 'No WorkOS SDK found in dependencies',\n remediation: `Install a WorkOS SDK: ${hint}`,\n docsUrl: 'https://workos.com/docs',\n });\n } else if (report.sdk.outdated && report.sdk.version && report.sdk.latest) {\n issues.push({\n code: 'SDK_OUTDATED',\n severity: 'warning',\n message: `SDK version outdated (${report.sdk.version} → ${report.sdk.latest})`,\n remediation: `Run: ${getUpdateCommand(report.runtime.packageManager, report.sdk.name)}`,\n details: { installed: report.sdk.version, latest: report.sdk.latest },\n });\n }\n\n // Environment issues\n if (!report.environment.apiKeyConfigured) {\n issues.push({ code: 'MISSING_API_KEY', ...ISSUE_DEFINITIONS.MISSING_API_KEY });\n }\n\n if (!report.environment.clientId) {\n issues.push({ code: 'MISSING_CLIENT_ID', ...ISSUE_DEFINITIONS.MISSING_CLIENT_ID });\n }\n\n if (report.sdk.isAuthKit && !report.environment.cookieDomain) {\n issues.push({ code: 'COOKIE_DOMAIN_NOT_SET', ...ISSUE_DEFINITIONS.COOKIE_DOMAIN_NOT_SET });\n }\n\n // Connectivity issues\n if (!report.connectivity.apiReachable && !report.connectivity.error?.includes('Skipped')) {\n issues.push({\n code: 'API_UNREACHABLE',\n severity: 'warning',\n message: `Cannot reach WorkOS API: ${report.connectivity.error}`,\n remediation: 'Check your network connection and firewall settings',\n });\n }\n\n // Note: Redirect URI mismatch detection disabled - WorkOS API doesn't expose\n // a public endpoint to list configured redirect URIs for verification\n\n // Production key warning (no dashboard data)\n if (report.environment.apiKeyType === 'production' && !report.dashboardSettings) {\n issues.push({\n code: 'PROD_API_CALL_BLOCKED',\n ...ISSUE_DEFINITIONS.PROD_API_CALL_BLOCKED,\n });\n }\n\n // Credential validation issues\n if (report.credentialValidation) {\n if (!report.credentialValidation.valid) {\n issues.push({\n code: 'INVALID_API_KEY',\n ...ISSUE_DEFINITIONS.INVALID_API_KEY,\n details: { error: report.credentialValidation.error },\n });\n } else if (!report.credentialValidation.clientIdMatch) {\n issues.push({\n code: 'CLIENT_ID_MISMATCH',\n ...ISSUE_DEFINITIONS.CLIENT_ID_MISMATCH,\n details: { error: report.credentialValidation.error },\n });\n }\n }\n\n // Auth pattern findings — map directly to issues\n if (report.authPatterns) {\n for (const finding of report.authPatterns.findings) {\n issues.push({\n code: finding.code,\n severity: finding.severity,\n message: finding.message,\n remediation: finding.remediation,\n docsUrl: finding.docsUrl,\n });\n }\n }\n\n return issues;\n}\n\nfunction getUpdateCommand(packageManager: string | null, sdkName: string): string {\n switch (packageManager) {\n case 'pnpm':\n return `pnpm update ${sdkName}`;\n case 'Yarn V1':\n case 'Yarn V2/3/4':\n return `yarn upgrade ${sdkName}`;\n case 'Bun':\n return `bun update ${sdkName}`;\n default:\n return `npm update ${sdkName}`;\n }\n}\n"]}
1
+ {"version":3,"file":"issues.js","sourceRoot":"","sources":["../../src/doctor/issues.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Issue, DoctorReport } from './types.js';\nimport { getInstallHint, languageToSdkLanguage } from './checks/language.js';\n\nexport const ISSUE_DEFINITIONS = {\n MISSING_API_KEY: {\n severity: 'error' as const,\n message: 'WORKOS_API_KEY environment variable not set',\n remediation: 'Set WORKOS_API_KEY in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n MISSING_CLIENT_ID: {\n severity: 'error' as const,\n message: 'WORKOS_CLIENT_ID environment variable not set',\n remediation: 'Set WORKOS_CLIENT_ID in your .env.local file',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n SDK_OUTDATED: {\n severity: 'warning' as const,\n message: 'SDK version is outdated',\n // remediation generated dynamically\n },\n COOKIE_DOMAIN_NOT_SET: {\n severity: 'warning' as const,\n message: 'Cookie domain not explicitly set',\n remediation: 'Consider setting WORKOS_COOKIE_DOMAIN for cross-subdomain auth',\n docsUrl: 'https://workos.com/docs/authkit/cookie-domain',\n },\n NO_SDK_FOUND: {\n severity: 'error' as const,\n message: 'No WorkOS SDK found in dependencies',\n remediation: 'Install a WorkOS SDK: npm install @workos-inc/authkit-nextjs',\n docsUrl: 'https://workos.com/docs',\n },\n API_UNREACHABLE: {\n severity: 'warning' as const,\n message: 'Cannot reach WorkOS API',\n // remediation generated dynamically based on error\n },\n REDIRECT_URI_MISMATCH: {\n severity: 'warning' as const,\n message: 'Redirect URI not found in dashboard configuration',\n docsUrl: 'https://workos.com/docs/authkit/redirect-uri',\n },\n PROD_API_CALL_BLOCKED: {\n severity: 'warning' as const,\n message: 'Dashboard settings not fetched (production API key)',\n remediation: 'Use a staging API key to fetch dashboard settings',\n },\n INVALID_API_KEY: {\n severity: 'error' as const,\n message: 'API key is invalid or expired',\n remediation: 'Check your WORKOS_API_KEY in the WorkOS dashboard',\n docsUrl: 'https://dashboard.workos.com/api-keys',\n },\n CLIENT_ID_MISMATCH: {\n severity: 'error' as const,\n message: 'Client ID does not match the API key environment',\n remediation: 'Ensure WORKOS_CLIENT_ID matches the environment for your API key',\n docsUrl: 'https://dashboard.workos.com/configuration',\n },\n};\n\nexport function detectIssues(report: Omit<DoctorReport, 'issues' | 'summary'>): Issue[] {\n const issues: Issue[] = [];\n\n // SDK issues\n if (!report.sdk.name) {\n const lang = languageToSdkLanguage(report.language.name);\n const hint = getInstallHint(lang);\n issues.push({\n code: 'NO_SDK_FOUND',\n severity: 'error',\n message: 'No WorkOS SDK found in dependencies',\n remediation: `Install a WorkOS SDK: ${hint}`,\n docsUrl: 'https://workos.com/docs',\n });\n } else if (report.sdk.outdated && report.sdk.version && report.sdk.latest) {\n issues.push({\n code: 'SDK_OUTDATED',\n severity: 'warning',\n message: `SDK version outdated (${report.sdk.version} → ${report.sdk.latest})`,\n remediation: `Run: ${getUpdateCommand(report.runtime.packageManager, report.sdk.name)}`,\n details: { installed: report.sdk.version, latest: report.sdk.latest },\n });\n }\n\n // Environment issues\n if (!report.environment.apiKeyConfigured) {\n issues.push({ code: 'MISSING_API_KEY', ...ISSUE_DEFINITIONS.MISSING_API_KEY });\n }\n\n if (!report.environment.clientId) {\n issues.push({ code: 'MISSING_CLIENT_ID', ...ISSUE_DEFINITIONS.MISSING_CLIENT_ID });\n }\n\n if (report.sdk.isAuthKit && !report.environment.cookieDomain) {\n issues.push({ code: 'COOKIE_DOMAIN_NOT_SET', ...ISSUE_DEFINITIONS.COOKIE_DOMAIN_NOT_SET });\n }\n\n // Connectivity issues\n if (!report.connectivity.apiReachable && !report.connectivity.error?.includes('Skipped')) {\n issues.push({\n code: 'API_UNREACHABLE',\n severity: 'warning',\n message: `Cannot reach WorkOS API: ${report.connectivity.error}`,\n remediation: 'Check your network connection and firewall settings',\n });\n }\n\n // Note: Redirect URI mismatch detection disabled - WorkOS API doesn't expose\n // a public endpoint to list configured redirect URIs for verification\n\n // Production key warning (no dashboard data)\n if (report.environment.apiKeyType === 'production' && !report.dashboardSettings) {\n issues.push({\n code: 'PROD_API_CALL_BLOCKED',\n ...ISSUE_DEFINITIONS.PROD_API_CALL_BLOCKED,\n });\n }\n\n // Credential validation issues\n if (report.credentialValidation) {\n if (!report.credentialValidation.valid) {\n issues.push({\n code: 'INVALID_API_KEY',\n ...ISSUE_DEFINITIONS.INVALID_API_KEY,\n details: { error: report.credentialValidation.error },\n });\n } else if (!report.credentialValidation.clientIdMatch) {\n issues.push({\n code: 'CLIENT_ID_MISMATCH',\n ...ISSUE_DEFINITIONS.CLIENT_ID_MISMATCH,\n details: { error: report.credentialValidation.error },\n });\n }\n }\n\n // Auth pattern findings — map directly to issues\n if (report.authPatterns) {\n for (const finding of report.authPatterns.findings) {\n issues.push({\n code: finding.code,\n severity: finding.severity,\n message: finding.message,\n remediation: finding.remediation,\n docsUrl: finding.docsUrl,\n });\n }\n }\n\n // Skill freshness — warn when agent-installed skills trail the bundled version.\n // Surfaced so users know their coding agent is using older WorkOS guidance.\n if (report.skills?.bundledVersion) {\n const stale = report.skills.agents.filter((a) => a.stale);\n if (stale.length > 0) {\n const agentList = stale.map((a) => `${a.agent} (${a.installedVersion ?? 'unknown'})`).join(', ');\n issues.push({\n code: 'SKILLS_OUTDATED',\n severity: 'warning',\n message: `WorkOS skills outdated for ${agentList} — bundled: ${report.skills.bundledVersion}`,\n remediation: 'Run: workos skills install',\n details: { bundledVersion: report.skills.bundledVersion, stale: stale.map((a) => a.agent) },\n });\n }\n }\n\n return issues;\n}\n\nfunction getUpdateCommand(packageManager: string | null, sdkName: string): string {\n switch (packageManager) {\n case 'pnpm':\n return `pnpm update ${sdkName}`;\n case 'Yarn V1':\n case 'Yarn V2/3/4':\n return `yarn upgrade ${sdkName}`;\n case 'Bun':\n return `bun update ${sdkName}`;\n default:\n return `npm update ${sdkName}`;\n }\n}\n"]}
@@ -1,4 +1,6 @@
1
1
  import Chalk from 'chalk';
2
+ import { homedir } from 'os';
3
+ import { createAgents } from '../commands/install-skill.js';
2
4
  import { renderSummaryBox } from '../utils/summary-box.js';
3
5
  export function formatReport(report, options) {
4
6
  console.log('');
@@ -135,6 +137,20 @@ export function formatReport(report, options) {
135
137
  }
136
138
  }
137
139
  }
140
+ // Skills refresh (--fix path)
141
+ if (report.skillsRefresh) {
142
+ const agents = createAgents(homedir());
143
+ const displayName = (slug) => agents[slug]?.displayName ?? slug;
144
+ const formatVersion = (v) => v ?? '(none)';
145
+ console.log('');
146
+ console.log('Skills');
147
+ const slugs = Object.keys(report.skillsRefresh.before);
148
+ for (const slug of slugs) {
149
+ const before = formatVersion(report.skillsRefresh.before[slug] ?? null);
150
+ const after = formatVersion(report.skillsRefresh.after[slug] ?? null);
151
+ console.log(` ${Chalk.green('✓')} Updated WorkOS skills for ${displayName(slug)}: ${before} → ${after}`);
152
+ }
153
+ }
138
154
  // Verbose mode additions
139
155
  if (options?.verbose) {
140
156
  console.log('');
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/doctor/output.ts"],"names":[],"mappings":"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","sourcesContent":["import Chalk from 'chalk';\nimport type { DoctorReport, Issue } from './types.js';\nimport { renderSummaryBox, type SummaryBoxItem } from '../utils/summary-box.js';\nimport type { LockExpression } from '../utils/lock-art.js';\n\nexport interface FormatOptions {\n verbose?: boolean;\n}\n\nexport function formatReport(report: DoctorReport, options?: FormatOptions): void {\n console.log('');\n console.log(Chalk.cyan('WorkOS Doctor'));\n console.log(Chalk.dim('━'.repeat(70)));\n\n // SDK & Project\n console.log('');\n console.log('SDK & Project Information');\n if (report.sdk.name) {\n console.log(` SDK: ${report.sdk.name}${report.sdk.version ? ` v${report.sdk.version}` : ''}`);\n } else {\n console.log(` SDK: ${Chalk.red('Not found')}`);\n }\n if (report.language.name !== 'Unknown') {\n console.log(` Language: ${report.language.name}`);\n }\n if (report.language.name === 'JavaScript/TypeScript' || report.language.name === 'Unknown') {\n console.log(` Runtime: Node.js ${report.runtime.nodeVersion}`);\n }\n if (report.framework.name) {\n const variant = report.framework.variant ? ` (${report.framework.variant})` : '';\n console.log(` Framework: ${report.framework.name} ${report.framework.version ?? ''}${variant}`);\n }\n if (report.language.packageManager) {\n console.log(` Package Manager: ${report.language.packageManager}`);\n } else if (report.runtime.packageManager) {\n console.log(` Package Manager: ${report.runtime.packageManager} ${report.runtime.packageManagerVersion ?? ''}`);\n }\n\n // Environment\n console.log('');\n console.log('Environment Configuration');\n const envType = report.environment.apiKeyType\n ? report.environment.apiKeyType.charAt(0).toUpperCase() + report.environment.apiKeyType.slice(1)\n : 'Unable to determine';\n console.log(` Environment: ${envType}`);\n console.log(` Client ID: ${report.environment.clientId ?? Chalk.red('Not set')}`);\n console.log(\n ` API Key: ${report.environment.apiKeyConfigured ? Chalk.green('configured') : Chalk.red('not set')}`,\n );\n console.log(` Base URL: ${report.environment.baseUrl} ${Chalk.green('✓')}`);\n\n // Connectivity & Credential Validation\n console.log('');\n console.log('Connectivity');\n if (report.connectivity.apiReachable) {\n console.log(` API: ${Chalk.green('✓')} Reachable (${report.connectivity.latencyMs}ms)`);\n } else if (report.connectivity.error?.includes('Skipped')) {\n console.log(` API: ${Chalk.dim('Skipped (--skip-api)')}`);\n } else {\n console.log(` API: ${Chalk.red('✗')} ${report.connectivity.error}`);\n }\n\n // Credential validation\n if (report.credentialValidation) {\n if (report.credentialValidation.valid && report.credentialValidation.clientIdMatch) {\n console.log(` Credentials: ${Chalk.green('✓')} Valid and matching`);\n } else if (!report.credentialValidation.valid) {\n console.log(` Credentials: ${Chalk.red('✗')} ${report.credentialValidation.error ?? 'Invalid'}`);\n } else if (!report.credentialValidation.clientIdMatch) {\n console.log(` Credentials: ${Chalk.red('✗')} Client ID mismatch`);\n }\n }\n\n // Dashboard Settings (if available)\n if (report.dashboardSettings) {\n console.log('');\n console.log('Dashboard Settings (Staging)');\n console.log(\n ` Auth Methods: ${report.dashboardSettings.authMethods.length > 0 ? report.dashboardSettings.authMethods.join(', ') : 'None configured'}`,\n );\n console.log(` Session Timeout: ${report.dashboardSettings.sessionTimeout ?? 'Default'}`);\n console.log(` MFA: ${formatMfa(report.dashboardSettings.mfa)}`);\n console.log(` Organizations: ${report.dashboardSettings.organizationCount} configured`);\n } else if (report.dashboardError) {\n console.log('');\n console.log('Dashboard Settings');\n console.log(` Status: ${Chalk.dim(report.dashboardError)}`);\n }\n\n // Redirect URI (can't verify against dashboard - no list API)\n if (report.redirectUris?.codeUri) {\n console.log('');\n const source = report.redirectUris.source === 'inferred' ? 'Inferred' : 'Configured';\n console.log(`Redirect URI (${source})`);\n console.log(` ${report.redirectUris.codeUri}`);\n }\n\n // Auth Patterns\n if (report.authPatterns) {\n console.log('');\n console.log('Auth Patterns');\n if (report.authPatterns.findings.length === 0) {\n console.log(` ${Chalk.green('✓')} ${report.authPatterns.checksRun} checks passed`);\n } else {\n console.log(\n ` ${report.authPatterns.checksRun} checked, ${Chalk.yellow(`${report.authPatterns.findings.length} finding(s)`)}`,\n );\n for (const finding of report.authPatterns.findings) {\n const icon = finding.severity === 'error' ? Chalk.red('✗') : Chalk.yellow('!');\n console.log(` ${icon} ${finding.message}`);\n if (finding.filePath) {\n console.log(` ${Chalk.dim('File:')} ${finding.filePath}`);\n }\n }\n }\n }\n\n // AI Analysis\n if (report.aiAnalysis) {\n console.log('');\n if (report.aiAnalysis.skipped) {\n console.log('AI Analysis');\n console.log(` ${Chalk.dim(report.aiAnalysis.skipReason ?? 'Skipped')}`);\n } else {\n const duration = (report.aiAnalysis.durationMs / 1000).toFixed(1);\n console.log(`AI Analysis ${Chalk.dim(`(${duration}s)`)}`);\n if (report.aiAnalysis.summary) {\n console.log(` ${report.aiAnalysis.summary}`);\n }\n console.log('');\n for (const finding of report.aiAnalysis.findings) {\n const icon =\n finding.severity === 'error'\n ? Chalk.red('✗')\n : finding.severity === 'warning'\n ? Chalk.yellow('!')\n : Chalk.dim('ℹ');\n const color =\n finding.severity === 'error' ? Chalk.red : finding.severity === 'warning' ? Chalk.yellow : Chalk.dim;\n console.log(` ${icon} ${color(finding.title)}`);\n console.log(` ${finding.detail}`);\n if (finding.remediation) {\n console.log(` ${Chalk.dim('→')} ${finding.remediation}`);\n }\n if (finding.filePath) {\n console.log(` ${Chalk.dim('File:')} ${finding.filePath}`);\n }\n console.log('');\n }\n }\n }\n\n // Verbose mode additions\n if (options?.verbose) {\n console.log('');\n console.log(Chalk.dim('Verbose Details'));\n console.log(` ${Chalk.dim('Project path:')} ${report.project.path}`);\n console.log(` ${Chalk.dim('Timestamp:')} ${report.timestamp}`);\n console.log(` ${Chalk.dim('Doctor version:')} ${report.version}`);\n }\n\n console.log('');\n console.log(Chalk.dim('━'.repeat(70)));\n\n // Issues\n if (report.issues.length > 0) {\n const errors = report.issues.filter((i) => i.severity === 'error');\n const warnings = report.issues.filter((i) => i.severity === 'warning');\n\n console.log('');\n if (errors.length > 0) {\n console.log(Chalk.red(`Critical Issues Found (${errors.length} errors)`));\n console.log('');\n for (const issue of errors) {\n formatIssue(issue);\n }\n }\n\n if (warnings.length > 0) {\n console.log(Chalk.yellow(`Warnings (${warnings.length})`));\n console.log('');\n for (const issue of warnings) {\n formatIssue(issue);\n }\n }\n }\n\n console.log('');\n\n // Summary box with lock character\n const expression: LockExpression = report.summary.healthy\n ? 'success'\n : report.summary.errors > 0\n ? 'error'\n : 'warning';\n\n const title = report.summary.healthy\n ? 'WorkOS Integration Healthy'\n : report.summary.errors > 0\n ? `${report.summary.errors} Issue(s) Found`\n : `${report.summary.warnings} Warning(s) to Review`;\n\n const items: SummaryBoxItem[] = report.issues.map((issue) => ({\n type: issue.severity === 'error' ? ('error' as const) : ('pending' as const),\n text: `${issue.code}: ${issue.message}`,\n }));\n\n console.log(\n renderSummaryBox({\n expression,\n title,\n items,\n footer: 'workos doctor --copy | https://workos.com/docs',\n }),\n );\n console.log('');\n}\n\nfunction formatIssue(issue: Issue): void {\n const icon = issue.severity === 'error' ? Chalk.red('✗') : Chalk.yellow('!');\n const color = issue.severity === 'error' ? Chalk.red : Chalk.yellow;\n\n console.log(`${icon} ${color(issue.code)}: ${issue.message}`);\n if (issue.remediation) {\n console.log(` ${Chalk.dim('→')} ${issue.remediation}`);\n }\n if (issue.docsUrl) {\n console.log(` ${Chalk.dim('Docs:')} ${issue.docsUrl}`);\n }\n console.log('');\n}\n\nfunction formatMfa(mfa: string | null): string {\n switch (mfa) {\n case 'required':\n return 'Required';\n case 'optional':\n return 'Optional';\n case 'disabled':\n return 'Disabled';\n default:\n return 'Not configured';\n }\n}\n"]}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/doctor/output.ts"],"names":[],"mappings":"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","sourcesContent":["import Chalk from 'chalk';\nimport { homedir } from 'os';\nimport { createAgents } from '../commands/install-skill.js';\nimport type { DoctorReport, Issue } from './types.js';\nimport { renderSummaryBox, type SummaryBoxItem } from '../utils/summary-box.js';\nimport type { LockExpression } from '../utils/lock-art.js';\n\nexport interface FormatOptions {\n verbose?: boolean;\n}\n\nexport function formatReport(report: DoctorReport, options?: FormatOptions): void {\n console.log('');\n console.log(Chalk.cyan('WorkOS Doctor'));\n console.log(Chalk.dim('━'.repeat(70)));\n\n // SDK & Project\n console.log('');\n console.log('SDK & Project Information');\n if (report.sdk.name) {\n console.log(` SDK: ${report.sdk.name}${report.sdk.version ? ` v${report.sdk.version}` : ''}`);\n } else {\n console.log(` SDK: ${Chalk.red('Not found')}`);\n }\n if (report.language.name !== 'Unknown') {\n console.log(` Language: ${report.language.name}`);\n }\n if (report.language.name === 'JavaScript/TypeScript' || report.language.name === 'Unknown') {\n console.log(` Runtime: Node.js ${report.runtime.nodeVersion}`);\n }\n if (report.framework.name) {\n const variant = report.framework.variant ? ` (${report.framework.variant})` : '';\n console.log(` Framework: ${report.framework.name} ${report.framework.version ?? ''}${variant}`);\n }\n if (report.language.packageManager) {\n console.log(` Package Manager: ${report.language.packageManager}`);\n } else if (report.runtime.packageManager) {\n console.log(` Package Manager: ${report.runtime.packageManager} ${report.runtime.packageManagerVersion ?? ''}`);\n }\n\n // Environment\n console.log('');\n console.log('Environment Configuration');\n const envType = report.environment.apiKeyType\n ? report.environment.apiKeyType.charAt(0).toUpperCase() + report.environment.apiKeyType.slice(1)\n : 'Unable to determine';\n console.log(` Environment: ${envType}`);\n console.log(` Client ID: ${report.environment.clientId ?? Chalk.red('Not set')}`);\n console.log(\n ` API Key: ${report.environment.apiKeyConfigured ? Chalk.green('configured') : Chalk.red('not set')}`,\n );\n console.log(` Base URL: ${report.environment.baseUrl} ${Chalk.green('✓')}`);\n\n // Connectivity & Credential Validation\n console.log('');\n console.log('Connectivity');\n if (report.connectivity.apiReachable) {\n console.log(` API: ${Chalk.green('✓')} Reachable (${report.connectivity.latencyMs}ms)`);\n } else if (report.connectivity.error?.includes('Skipped')) {\n console.log(` API: ${Chalk.dim('Skipped (--skip-api)')}`);\n } else {\n console.log(` API: ${Chalk.red('✗')} ${report.connectivity.error}`);\n }\n\n // Credential validation\n if (report.credentialValidation) {\n if (report.credentialValidation.valid && report.credentialValidation.clientIdMatch) {\n console.log(` Credentials: ${Chalk.green('✓')} Valid and matching`);\n } else if (!report.credentialValidation.valid) {\n console.log(` Credentials: ${Chalk.red('✗')} ${report.credentialValidation.error ?? 'Invalid'}`);\n } else if (!report.credentialValidation.clientIdMatch) {\n console.log(` Credentials: ${Chalk.red('✗')} Client ID mismatch`);\n }\n }\n\n // Dashboard Settings (if available)\n if (report.dashboardSettings) {\n console.log('');\n console.log('Dashboard Settings (Staging)');\n console.log(\n ` Auth Methods: ${report.dashboardSettings.authMethods.length > 0 ? report.dashboardSettings.authMethods.join(', ') : 'None configured'}`,\n );\n console.log(` Session Timeout: ${report.dashboardSettings.sessionTimeout ?? 'Default'}`);\n console.log(` MFA: ${formatMfa(report.dashboardSettings.mfa)}`);\n console.log(` Organizations: ${report.dashboardSettings.organizationCount} configured`);\n } else if (report.dashboardError) {\n console.log('');\n console.log('Dashboard Settings');\n console.log(` Status: ${Chalk.dim(report.dashboardError)}`);\n }\n\n // Redirect URI (can't verify against dashboard - no list API)\n if (report.redirectUris?.codeUri) {\n console.log('');\n const source = report.redirectUris.source === 'inferred' ? 'Inferred' : 'Configured';\n console.log(`Redirect URI (${source})`);\n console.log(` ${report.redirectUris.codeUri}`);\n }\n\n // Auth Patterns\n if (report.authPatterns) {\n console.log('');\n console.log('Auth Patterns');\n if (report.authPatterns.findings.length === 0) {\n console.log(` ${Chalk.green('✓')} ${report.authPatterns.checksRun} checks passed`);\n } else {\n console.log(\n ` ${report.authPatterns.checksRun} checked, ${Chalk.yellow(`${report.authPatterns.findings.length} finding(s)`)}`,\n );\n for (const finding of report.authPatterns.findings) {\n const icon = finding.severity === 'error' ? Chalk.red('✗') : Chalk.yellow('!');\n console.log(` ${icon} ${finding.message}`);\n if (finding.filePath) {\n console.log(` ${Chalk.dim('File:')} ${finding.filePath}`);\n }\n }\n }\n }\n\n // AI Analysis\n if (report.aiAnalysis) {\n console.log('');\n if (report.aiAnalysis.skipped) {\n console.log('AI Analysis');\n console.log(` ${Chalk.dim(report.aiAnalysis.skipReason ?? 'Skipped')}`);\n } else {\n const duration = (report.aiAnalysis.durationMs / 1000).toFixed(1);\n console.log(`AI Analysis ${Chalk.dim(`(${duration}s)`)}`);\n if (report.aiAnalysis.summary) {\n console.log(` ${report.aiAnalysis.summary}`);\n }\n console.log('');\n for (const finding of report.aiAnalysis.findings) {\n const icon =\n finding.severity === 'error'\n ? Chalk.red('✗')\n : finding.severity === 'warning'\n ? Chalk.yellow('!')\n : Chalk.dim('ℹ');\n const color =\n finding.severity === 'error' ? Chalk.red : finding.severity === 'warning' ? Chalk.yellow : Chalk.dim;\n console.log(` ${icon} ${color(finding.title)}`);\n console.log(` ${finding.detail}`);\n if (finding.remediation) {\n console.log(` ${Chalk.dim('→')} ${finding.remediation}`);\n }\n if (finding.filePath) {\n console.log(` ${Chalk.dim('File:')} ${finding.filePath}`);\n }\n console.log('');\n }\n }\n }\n\n // Skills refresh (--fix path)\n if (report.skillsRefresh) {\n const agents = createAgents(homedir());\n const displayName = (slug: string): string => agents[slug]?.displayName ?? slug;\n const formatVersion = (v: string | null): string => v ?? '(none)';\n\n console.log('');\n console.log('Skills');\n const slugs = Object.keys(report.skillsRefresh.before);\n for (const slug of slugs) {\n const before = formatVersion(report.skillsRefresh.before[slug] ?? null);\n const after = formatVersion(report.skillsRefresh.after[slug] ?? null);\n console.log(` ${Chalk.green('✓')} Updated WorkOS skills for ${displayName(slug)}: ${before} → ${after}`);\n }\n }\n\n // Verbose mode additions\n if (options?.verbose) {\n console.log('');\n console.log(Chalk.dim('Verbose Details'));\n console.log(` ${Chalk.dim('Project path:')} ${report.project.path}`);\n console.log(` ${Chalk.dim('Timestamp:')} ${report.timestamp}`);\n console.log(` ${Chalk.dim('Doctor version:')} ${report.version}`);\n }\n\n console.log('');\n console.log(Chalk.dim('━'.repeat(70)));\n\n // Issues\n if (report.issues.length > 0) {\n const errors = report.issues.filter((i) => i.severity === 'error');\n const warnings = report.issues.filter((i) => i.severity === 'warning');\n\n console.log('');\n if (errors.length > 0) {\n console.log(Chalk.red(`Critical Issues Found (${errors.length} errors)`));\n console.log('');\n for (const issue of errors) {\n formatIssue(issue);\n }\n }\n\n if (warnings.length > 0) {\n console.log(Chalk.yellow(`Warnings (${warnings.length})`));\n console.log('');\n for (const issue of warnings) {\n formatIssue(issue);\n }\n }\n }\n\n console.log('');\n\n // Summary box with lock character\n const expression: LockExpression = report.summary.healthy\n ? 'success'\n : report.summary.errors > 0\n ? 'error'\n : 'warning';\n\n const title = report.summary.healthy\n ? 'WorkOS Integration Healthy'\n : report.summary.errors > 0\n ? `${report.summary.errors} Issue(s) Found`\n : `${report.summary.warnings} Warning(s) to Review`;\n\n const items: SummaryBoxItem[] = report.issues.map((issue) => ({\n type: issue.severity === 'error' ? ('error' as const) : ('pending' as const),\n text: `${issue.code}: ${issue.message}`,\n }));\n\n console.log(\n renderSummaryBox({\n expression,\n title,\n items,\n footer: 'workos doctor --copy | https://workos.com/docs',\n }),\n );\n console.log('');\n}\n\nfunction formatIssue(issue: Issue): void {\n const icon = issue.severity === 'error' ? Chalk.red('✗') : Chalk.yellow('!');\n const color = issue.severity === 'error' ? Chalk.red : Chalk.yellow;\n\n console.log(`${icon} ${color(issue.code)}: ${issue.message}`);\n if (issue.remediation) {\n console.log(` ${Chalk.dim('→')} ${issue.remediation}`);\n }\n if (issue.docsUrl) {\n console.log(` ${Chalk.dim('Docs:')} ${issue.docsUrl}`);\n }\n console.log('');\n}\n\nfunction formatMfa(mfa: string | null): string {\n switch (mfa) {\n case 'required':\n return 'Required';\n case 'optional':\n return 'Optional';\n case 'disabled':\n return 'Disabled';\n default:\n return 'Not configured';\n }\n}\n"]}
@@ -92,6 +92,28 @@ export interface AuthPatternInfo {
92
92
  checksRun: number;
93
93
  findings: AuthPatternFinding[];
94
94
  }
95
+ export interface SkillAgentStatus {
96
+ agent: string;
97
+ installedVersion: string | null;
98
+ stale: boolean;
99
+ }
100
+ export interface SkillsInfo {
101
+ bundledVersion: string | null;
102
+ agents: SkillAgentStatus[];
103
+ }
104
+ /**
105
+ * Result of `workos doctor --fix` refreshing WorkOS skills. Captured per agent
106
+ * so the human-mode renderer can show a before/after line and the JSON consumer
107
+ * can reason about which agents changed.
108
+ */
109
+ export interface SkillsRefreshResult {
110
+ /** Marker version per agent.name BEFORE refresh (null = no marker). */
111
+ before: Record<string, string | null>;
112
+ /** Marker version per agent.name AFTER refresh. */
113
+ after: Record<string, string | null>;
114
+ /** Skills the refresh was scoped to (the FIXABLE_SKILLS allowlist). */
115
+ skillsInstalled: string[];
116
+ }
95
117
  export interface DoctorReport {
96
118
  version: string;
97
119
  timestamp: string;
@@ -111,6 +133,9 @@ export interface DoctorReport {
111
133
  credentialValidation?: CredentialValidation;
112
134
  authPatterns?: AuthPatternInfo;
113
135
  aiAnalysis?: AiAnalysis;
136
+ skills?: SkillsInfo;
137
+ /** Present only when `--fix` actually performed a refresh. */
138
+ skillsRefresh?: SkillsRefreshResult;
114
139
  issues: Issue[];
115
140
  summary: {
116
141
  errors: number;
@@ -140,4 +165,6 @@ export interface DoctorOptions {
140
165
  skipAi?: boolean;
141
166
  json?: boolean;
142
167
  copy?: boolean;
168
+ /** When true, refresh stale WorkOS skills (constrained to workos/ + workos-widgets/). */
169
+ fix?: boolean;
143
170
  }