workos 0.17.1 → 0.19.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.
- package/README.md +11 -149
- package/dist/bin.js +155 -23
- package/dist/bin.js.map +1 -1
- package/dist/cli.config.d.ts +0 -2
- package/dist/cli.config.js +3 -3
- package/dist/cli.config.js.map +1 -1
- package/dist/commands/api/index.js +18 -10
- package/dist/commands/api/index.js.map +1 -1
- package/dist/commands/api/interactive.js +11 -11
- package/dist/commands/api/interactive.js.map +1 -1
- package/dist/commands/claim.js +28 -16
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/connection.js +3 -3
- package/dist/commands/connection.js.map +1 -1
- package/dist/commands/debug.d.ts +11 -0
- package/dist/commands/debug.js +30 -14
- package/dist/commands/debug.js.map +1 -1
- package/dist/commands/dev.d.ts +7 -8
- package/dist/commands/dev.js +14 -14
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/directory.js +3 -3
- package/dist/commands/directory.js.map +1 -1
- package/dist/commands/doctor.js +2 -2
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/emulate.d.ts +1 -0
- package/dist/commands/emulate.js +3 -2
- package/dist/commands/emulate.js.map +1 -1
- package/dist/commands/env.d.ts +10 -0
- package/dist/commands/env.js +94 -18
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/install.js +9 -10
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts +25 -15
- package/dist/commands/login.js +126 -71
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.js +4 -4
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/mcp.d.ts +14 -0
- package/dist/commands/mcp.js +99 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/migrations.js +2 -1
- package/dist/commands/migrations.js.map +1 -1
- package/dist/commands/seed.js +5 -4
- package/dist/commands/seed.js.map +1 -1
- package/dist/commands/setup.d.ts +50 -0
- package/dist/commands/setup.js +237 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/vault-run.js +3 -2
- package/dist/commands/vault-run.js.map +1 -1
- package/dist/commands/verify-login.d.ts +25 -0
- package/dist/commands/verify-login.js +158 -0
- package/dist/commands/verify-login.js.map +1 -0
- package/dist/doctor/checks/ai-analysis.js +2 -1
- package/dist/doctor/checks/ai-analysis.js.map +1 -1
- package/dist/doctor/checks/mcp.d.ts +15 -0
- package/dist/doctor/checks/mcp.js +34 -0
- package/dist/doctor/checks/mcp.js.map +1 -0
- package/dist/doctor/index.js +7 -1
- package/dist/doctor/index.js.map +1 -1
- package/dist/doctor/issues.js +18 -1
- package/dist/doctor/issues.js.map +1 -1
- package/dist/doctor/output.js +18 -3
- package/dist/doctor/output.js.map +1 -1
- package/dist/doctor/types.d.ts +17 -0
- package/dist/doctor/types.js.map +1 -1
- package/dist/integrations/dotnet/index.js +1 -1
- package/dist/integrations/dotnet/index.js.map +1 -1
- package/dist/integrations/elixir/index.js +1 -1
- package/dist/integrations/elixir/index.js.map +1 -1
- package/dist/integrations/go/index.js +1 -1
- package/dist/integrations/go/index.js.map +1 -1
- package/dist/integrations/nextjs/index.js +8 -5
- package/dist/integrations/nextjs/index.js.map +1 -1
- package/dist/integrations/nextjs/utils.d.ts +1 -1
- package/dist/integrations/nextjs/utils.js +21 -6
- package/dist/integrations/nextjs/utils.js.map +1 -1
- package/dist/integrations/react-router/index.js +5 -5
- package/dist/integrations/react-router/index.js.map +1 -1
- package/dist/integrations/react-router/utils.js +28 -12
- package/dist/integrations/react-router/utils.js.map +1 -1
- package/dist/integrations/ruby/index.js +1 -1
- package/dist/integrations/ruby/index.js.map +1 -1
- package/dist/lib/adapters/cli-adapter.d.ts +33 -4
- package/dist/lib/adapters/cli-adapter.js +251 -135
- package/dist/lib/adapters/cli-adapter.js.map +1 -1
- package/dist/lib/adapters/dashboard-adapter.js +3 -3
- package/dist/lib/adapters/dashboard-adapter.js.map +1 -1
- package/dist/lib/adapters/headless-adapter.d.ts +7 -0
- package/dist/lib/adapters/headless-adapter.js +42 -5
- package/dist/lib/adapters/headless-adapter.js.map +1 -1
- package/dist/lib/agent-interface.js +19 -5
- package/dist/lib/agent-interface.js.map +1 -1
- package/dist/lib/agent-runner.js +1 -1
- package/dist/lib/agent-runner.js.map +1 -1
- package/dist/lib/ai-content.js +2 -1
- package/dist/lib/ai-content.js.map +1 -1
- package/dist/lib/api-key.js +2 -1
- package/dist/lib/api-key.js.map +1 -1
- package/dist/lib/completion-data.d.ts +33 -0
- package/dist/lib/completion-data.js +33 -0
- package/dist/lib/completion-data.js.map +1 -0
- package/dist/lib/config-store.d.ts +13 -0
- package/dist/lib/config-store.js +24 -0
- package/dist/lib/config-store.js.map +1 -1
- package/dist/lib/config.d.ts +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/constants.d.ts +17 -0
- package/dist/lib/constants.js +17 -0
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/events.d.ts +34 -1
- package/dist/lib/events.js.map +1 -1
- package/dist/lib/framework-config.d.ts +6 -0
- package/dist/lib/framework-config.js.map +1 -1
- package/dist/lib/installer-core.d.ts +34 -21
- package/dist/lib/installer-core.js +24 -5
- package/dist/lib/installer-core.js.map +1 -1
- package/dist/lib/installer-core.types.d.ts +3 -1
- package/dist/lib/installer-core.types.js.map +1 -1
- package/dist/lib/mcp-clients.d.ts +45 -0
- package/dist/lib/mcp-clients.js +297 -0
- package/dist/lib/mcp-clients.js.map +1 -0
- package/dist/lib/port-detection.js +19 -13
- package/dist/lib/port-detection.js.map +1 -1
- package/dist/lib/preferences.d.ts +42 -0
- package/dist/lib/preferences.js +34 -5
- package/dist/lib/preferences.js.map +1 -1
- package/dist/lib/run-with-core.js +42 -4
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/lib/settings.d.ts +5 -14
- package/dist/lib/settings.js +5 -16
- package/dist/lib/settings.js.map +1 -1
- package/dist/lib/startup-notice-gate.d.ts +21 -0
- package/dist/lib/startup-notice-gate.js +29 -0
- package/dist/lib/startup-notice-gate.js.map +1 -0
- package/dist/lib/telemetry-notice.d.ts +5 -5
- package/dist/lib/telemetry-notice.js +10 -8
- package/dist/lib/telemetry-notice.js.map +1 -1
- package/dist/lib/unclaimed-env-provision.js +15 -12
- package/dist/lib/unclaimed-env-provision.js.map +1 -1
- package/dist/lib/unclaimed-warning.js +7 -3
- package/dist/lib/unclaimed-warning.js.map +1 -1
- package/dist/lib/validation/security-checks.js +2 -1
- package/dist/lib/validation/security-checks.js.map +1 -1
- package/dist/lib/validation/validator.js +30 -3
- package/dist/lib/validation/validator.js.map +1 -1
- package/dist/lib/workos-management.js +26 -19
- package/dist/lib/workos-management.js.map +1 -1
- package/dist/run.d.ts +1 -0
- package/dist/run.js +5 -1
- package/dist/run.js.map +1 -1
- package/dist/steps/add-or-update-environment-variables.js +10 -10
- package/dist/steps/add-or-update-environment-variables.js.map +1 -1
- package/dist/steps/run-prettier.js +3 -3
- package/dist/steps/run-prettier.js.map +1 -1
- package/dist/steps/upload-environment-variables/index.js +15 -3
- package/dist/steps/upload-environment-variables/index.js.map +1 -1
- package/dist/steps/upload-environment-variables/providers/vercel.js +2 -2
- package/dist/steps/upload-environment-variables/providers/vercel.js.map +1 -1
- package/dist/utils/analytics.d.ts +1 -0
- package/dist/utils/analytics.js +5 -1
- package/dist/utils/analytics.js.map +1 -1
- package/dist/utils/box.d.ts +6 -30
- package/dist/utils/box.js +8 -95
- package/dist/utils/box.js.map +1 -1
- package/dist/utils/cli-symbols.d.ts +14 -2
- package/dist/utils/cli-symbols.js +12 -0
- package/dist/utils/cli-symbols.js.map +1 -1
- package/dist/utils/debug.js +3 -3
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/environment.js +1 -1
- package/dist/utils/environment.js.map +1 -1
- package/dist/utils/help-json.js +153 -4
- package/dist/utils/help-json.js.map +1 -1
- package/dist/utils/interaction-mode.d.ts +1 -1
- package/dist/utils/interaction-mode.js +0 -3
- package/dist/utils/interaction-mode.js.map +1 -1
- package/dist/utils/output.d.ts +5 -3
- package/dist/utils/output.js +5 -5
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/package-manager.js +1 -1
- package/dist/utils/package-manager.js.map +1 -1
- package/dist/utils/recovery-hints.d.ts +5 -0
- package/dist/utils/recovery-hints.js +12 -0
- package/dist/utils/recovery-hints.js.map +1 -1
- package/dist/utils/summary-box.d.ts +8 -1
- package/dist/utils/summary-box.js +67 -4
- package/dist/utils/summary-box.js.map +1 -1
- package/dist/utils/telemetry-types.d.ts +1 -1
- package/dist/utils/telemetry-types.js.map +1 -1
- package/dist/utils/types.d.ts +10 -0
- package/dist/utils/types.js.map +1 -1
- package/dist/utils/{clack-utils.d.ts → ui-utils.d.ts} +1 -1
- package/dist/utils/{clack-utils.js → ui-utils.js} +64 -37
- package/dist/utils/ui-utils.js.map +1 -0
- package/dist/utils/ui.d.ts +148 -0
- package/dist/utils/ui.js +368 -0
- package/dist/utils/ui.js.map +1 -0
- package/dist/utils/urls.d.ts +9 -3
- package/dist/utils/urls.js +10 -4
- package/dist/utils/urls.js.map +1 -1
- package/package.json +13 -20
- package/dist/check-coverage.ts +0 -237
- package/dist/emulate/core/id.d.ts +0 -48
- package/dist/emulate/core/id.js +0 -73
- package/dist/emulate/core/id.js.map +0 -1
- package/dist/emulate/core/index.d.ts +0 -8
- package/dist/emulate/core/index.js +0 -8
- package/dist/emulate/core/index.js.map +0 -1
- package/dist/emulate/core/jwt.d.ts +0 -28
- package/dist/emulate/core/jwt.js +0 -78
- package/dist/emulate/core/jwt.js.map +0 -1
- package/dist/emulate/core/middleware/auth.d.ts +0 -15
- package/dist/emulate/core/middleware/auth.js +0 -17
- package/dist/emulate/core/middleware/auth.js.map +0 -1
- package/dist/emulate/core/middleware/error-handler.d.ts +0 -22
- package/dist/emulate/core/middleware/error-handler.js +0 -72
- package/dist/emulate/core/middleware/error-handler.js.map +0 -1
- package/dist/emulate/core/pagination.d.ts +0 -27
- package/dist/emulate/core/pagination.js +0 -43
- package/dist/emulate/core/pagination.js.map +0 -1
- package/dist/emulate/core/plugin.d.ts +0 -15
- package/dist/emulate/core/plugin.js +0 -2
- package/dist/emulate/core/plugin.js.map +0 -1
- package/dist/emulate/core/server.d.ts +0 -17
- package/dist/emulate/core/server.js +0 -90
- package/dist/emulate/core/server.js.map +0 -1
- package/dist/emulate/core/store.d.ts +0 -44
- package/dist/emulate/core/store.js +0 -169
- package/dist/emulate/core/store.js.map +0 -1
- package/dist/emulate/index.d.ts +0 -25
- package/dist/emulate/index.js +0 -47
- package/dist/emulate/index.js.map +0 -1
- package/dist/emulate/workos/constants.d.ts +0 -56
- package/dist/emulate/workos/constants.js +0 -56
- package/dist/emulate/workos/constants.js.map +0 -1
- package/dist/emulate/workos/entities.d.ts +0 -360
- package/dist/emulate/workos/entities.js +0 -2
- package/dist/emulate/workos/entities.js.map +0 -1
- package/dist/emulate/workos/event-bus.d.ts +0 -17
- package/dist/emulate/workos/event-bus.js +0 -70
- package/dist/emulate/workos/event-bus.js.map +0 -1
- package/dist/emulate/workos/helpers.d.ts +0 -72
- package/dist/emulate/workos/helpers.js +0 -211
- package/dist/emulate/workos/helpers.js.map +0 -1
- package/dist/emulate/workos/index.d.ts +0 -93
- package/dist/emulate/workos/index.js +0 -326
- package/dist/emulate/workos/index.js.map +0 -1
- package/dist/emulate/workos/role-helpers.d.ts +0 -21
- package/dist/emulate/workos/role-helpers.js +0 -130
- package/dist/emulate/workos/role-helpers.js.map +0 -1
- package/dist/emulate/workos/routes/api-keys.d.ts +0 -2
- package/dist/emulate/workos/routes/api-keys.js +0 -32
- package/dist/emulate/workos/routes/api-keys.js.map +0 -1
- package/dist/emulate/workos/routes/audit-logs.d.ts +0 -2
- package/dist/emulate/workos/routes/audit-logs.js +0 -104
- package/dist/emulate/workos/routes/audit-logs.js.map +0 -1
- package/dist/emulate/workos/routes/auth-challenges.d.ts +0 -2
- package/dist/emulate/workos/routes/auth-challenges.js +0 -51
- package/dist/emulate/workos/routes/auth-challenges.js.map +0 -1
- package/dist/emulate/workos/routes/auth-factors.d.ts +0 -2
- package/dist/emulate/workos/routes/auth-factors.js +0 -51
- package/dist/emulate/workos/routes/auth-factors.js.map +0 -1
- package/dist/emulate/workos/routes/auth.d.ts +0 -2
- package/dist/emulate/workos/routes/auth.js +0 -350
- package/dist/emulate/workos/routes/auth.js.map +0 -1
- package/dist/emulate/workos/routes/authorization-checks.d.ts +0 -10
- package/dist/emulate/workos/routes/authorization-checks.js +0 -123
- package/dist/emulate/workos/routes/authorization-checks.js.map +0 -1
- package/dist/emulate/workos/routes/authorization-org-roles.d.ts +0 -2
- package/dist/emulate/workos/routes/authorization-org-roles.js +0 -64
- package/dist/emulate/workos/routes/authorization-org-roles.js.map +0 -1
- package/dist/emulate/workos/routes/authorization-permissions.d.ts +0 -2
- package/dist/emulate/workos/routes/authorization-permissions.js +0 -67
- package/dist/emulate/workos/routes/authorization-permissions.js.map +0 -1
- package/dist/emulate/workos/routes/authorization-resources.d.ts +0 -2
- package/dist/emulate/workos/routes/authorization-resources.js +0 -117
- package/dist/emulate/workos/routes/authorization-resources.js.map +0 -1
- package/dist/emulate/workos/routes/authorization-roles.d.ts +0 -2
- package/dist/emulate/workos/routes/authorization-roles.js +0 -13
- package/dist/emulate/workos/routes/authorization-roles.js.map +0 -1
- package/dist/emulate/workos/routes/config.d.ts +0 -2
- package/dist/emulate/workos/routes/config.js +0 -57
- package/dist/emulate/workos/routes/config.js.map +0 -1
- package/dist/emulate/workos/routes/connect.d.ts +0 -2
- package/dist/emulate/workos/routes/connect.js +0 -65
- package/dist/emulate/workos/routes/connect.js.map +0 -1
- package/dist/emulate/workos/routes/connections.d.ts +0 -2
- package/dist/emulate/workos/routes/connections.js +0 -73
- package/dist/emulate/workos/routes/connections.js.map +0 -1
- package/dist/emulate/workos/routes/data-integrations.d.ts +0 -2
- package/dist/emulate/workos/routes/data-integrations.js +0 -55
- package/dist/emulate/workos/routes/data-integrations.js.map +0 -1
- package/dist/emulate/workos/routes/directories.d.ts +0 -2
- package/dist/emulate/workos/routes/directories.js +0 -90
- package/dist/emulate/workos/routes/directories.js.map +0 -1
- package/dist/emulate/workos/routes/email-verification.d.ts +0 -2
- package/dist/emulate/workos/routes/email-verification.js +0 -49
- package/dist/emulate/workos/routes/email-verification.js.map +0 -1
- package/dist/emulate/workos/routes/events.d.ts +0 -2
- package/dist/emulate/workos/routes/events.js +0 -18
- package/dist/emulate/workos/routes/events.js.map +0 -1
- package/dist/emulate/workos/routes/feature-flags.d.ts +0 -2
- package/dist/emulate/workos/routes/feature-flags.js +0 -103
- package/dist/emulate/workos/routes/feature-flags.js.map +0 -1
- package/dist/emulate/workos/routes/invitations.d.ts +0 -2
- package/dist/emulate/workos/routes/invitations.js +0 -122
- package/dist/emulate/workos/routes/invitations.js.map +0 -1
- package/dist/emulate/workos/routes/legacy-mfa.d.ts +0 -2
- package/dist/emulate/workos/routes/legacy-mfa.js +0 -75
- package/dist/emulate/workos/routes/legacy-mfa.js.map +0 -1
- package/dist/emulate/workos/routes/magic-auth.d.ts +0 -2
- package/dist/emulate/workos/routes/magic-auth.js +0 -32
- package/dist/emulate/workos/routes/magic-auth.js.map +0 -1
- package/dist/emulate/workos/routes/memberships.d.ts +0 -2
- package/dist/emulate/workos/routes/memberships.js +0 -114
- package/dist/emulate/workos/routes/memberships.js.map +0 -1
- package/dist/emulate/workos/routes/organization-domains.d.ts +0 -2
- package/dist/emulate/workos/routes/organization-domains.js +0 -58
- package/dist/emulate/workos/routes/organization-domains.js.map +0 -1
- package/dist/emulate/workos/routes/organizations.d.ts +0 -2
- package/dist/emulate/workos/routes/organizations.js +0 -131
- package/dist/emulate/workos/routes/organizations.js.map +0 -1
- package/dist/emulate/workos/routes/password-reset.d.ts +0 -2
- package/dist/emulate/workos/routes/password-reset.js +0 -61
- package/dist/emulate/workos/routes/password-reset.js.map +0 -1
- package/dist/emulate/workos/routes/pipes.d.ts +0 -2
- package/dist/emulate/workos/routes/pipes.js +0 -82
- package/dist/emulate/workos/routes/pipes.js.map +0 -1
- package/dist/emulate/workos/routes/portal.d.ts +0 -2
- package/dist/emulate/workos/routes/portal.js +0 -18
- package/dist/emulate/workos/routes/portal.js.map +0 -1
- package/dist/emulate/workos/routes/radar.d.ts +0 -2
- package/dist/emulate/workos/routes/radar.js +0 -41
- package/dist/emulate/workos/routes/radar.js.map +0 -1
- package/dist/emulate/workos/routes/sessions.d.ts +0 -2
- package/dist/emulate/workos/routes/sessions.js +0 -51
- package/dist/emulate/workos/routes/sessions.js.map +0 -1
- package/dist/emulate/workos/routes/sso.d.ts +0 -2
- package/dist/emulate/workos/routes/sso.js +0 -161
- package/dist/emulate/workos/routes/sso.js.map +0 -1
- package/dist/emulate/workos/routes/user-features.d.ts +0 -2
- package/dist/emulate/workos/routes/user-features.js +0 -50
- package/dist/emulate/workos/routes/user-features.js.map +0 -1
- package/dist/emulate/workos/routes/users.d.ts +0 -2
- package/dist/emulate/workos/routes/users.js +0 -129
- package/dist/emulate/workos/routes/users.js.map +0 -1
- package/dist/emulate/workos/routes/webhook-endpoints.d.ts +0 -2
- package/dist/emulate/workos/routes/webhook-endpoints.js +0 -67
- package/dist/emulate/workos/routes/webhook-endpoints.js.map +0 -1
- package/dist/emulate/workos/routes/widgets.d.ts +0 -2
- package/dist/emulate/workos/routes/widgets.js +0 -27
- package/dist/emulate/workos/routes/widgets.js.map +0 -1
- package/dist/emulate/workos/store.d.ts +0 -48
- package/dist/emulate/workos/store.js +0 -102
- package/dist/emulate/workos/store.js.map +0 -1
- package/dist/emulate/workos/webhook-signer.d.ts +0 -1
- package/dist/emulate/workos/webhook-signer.js +0 -8
- package/dist/emulate/workos/webhook-signer.js.map +0 -1
- package/dist/gen-routes-lib.spec.ts +0 -659
- package/dist/gen-routes-lib.ts +0 -647
- package/dist/gen-routes.ts +0 -96
- package/dist/utils/clack-utils.js.map +0 -1
- package/dist/utils/clack.d.ts +0 -5
- package/dist/utils/clack.js +0 -34
- package/dist/utils/clack.js.map +0 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verify-login: prove the AuthKit login loop end-to-end against the active
|
|
3
|
+
* environment, headlessly (no browser, no email/OTP retrieval).
|
|
4
|
+
*
|
|
5
|
+
* The command creates a throwaway user, authenticates it with the password
|
|
6
|
+
* grant, asserts access + refresh tokens come back, and deletes the user in a
|
|
7
|
+
* `finally` block so cleanup always runs. It refuses to touch a production
|
|
8
|
+
* environment (unconditional, no override) because it mutates real users.
|
|
9
|
+
*/
|
|
10
|
+
import chalk from 'chalk';
|
|
11
|
+
import { createWorkOSClient } from '../lib/workos-client.js';
|
|
12
|
+
import { outputJson, isJsonMode, exitWithError } from '../utils/output.js';
|
|
13
|
+
import { exitWithCode, ExitCode } from '../utils/exit-codes.js';
|
|
14
|
+
import { formatWorkOSCommand } from '../utils/command-invocation.js';
|
|
15
|
+
/**
|
|
16
|
+
* A clearly-labeled, non-routable throwaway email so the user is obvious in the
|
|
17
|
+
* dashboard if cleanup ever fails.
|
|
18
|
+
*/
|
|
19
|
+
function generateEmail() {
|
|
20
|
+
return `verify-login+${crypto.randomUUID()}@example.workos.dev`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A strong random password (>= 24 chars) mixing character classes so it
|
|
24
|
+
* satisfies the API password policy regardless of the specific rules. The
|
|
25
|
+
* fixed `Aa1!` suffix guarantees upper/lower/digit/symbol coverage on top of
|
|
26
|
+
* the random base64url body.
|
|
27
|
+
*/
|
|
28
|
+
function generatePassword() {
|
|
29
|
+
const bytes = new Uint8Array(24);
|
|
30
|
+
crypto.getRandomValues(bytes);
|
|
31
|
+
const body = Buffer.from(bytes).toString('base64url');
|
|
32
|
+
return `${body}Aa1!`;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Translate an authenticate error into a human-readable check detail. When the
|
|
36
|
+
* failure looks like "password authentication not enabled" (a config gap, not a
|
|
37
|
+
* broken login) surface an actionable message instead of a bare error so agents
|
|
38
|
+
* do not misread it as "login is broken".
|
|
39
|
+
*
|
|
40
|
+
* NOTE: the exact code/message returned when password auth is disabled is
|
|
41
|
+
* UNCONFIRMED against a live environment; the heuristic below is best-effort and
|
|
42
|
+
* falls back to the raw error message.
|
|
43
|
+
*/
|
|
44
|
+
function describeAuthError(err) {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
if (/password/i.test(message) && /(not enabled|disabled|not available|unavailable)/i.test(message)) {
|
|
47
|
+
return ('Password authentication is not enabled for this environment. Enable it in the WorkOS ' +
|
|
48
|
+
'Dashboard (User Management → Authentication).');
|
|
49
|
+
}
|
|
50
|
+
return message;
|
|
51
|
+
}
|
|
52
|
+
function printHuman(result) {
|
|
53
|
+
for (const check of result.checks) {
|
|
54
|
+
const mark = check.passed ? chalk.green('✓') : chalk.red('✗');
|
|
55
|
+
console.log(`${mark} ${check.detail}`);
|
|
56
|
+
}
|
|
57
|
+
if (result.userId) {
|
|
58
|
+
if (result.userCleanedUp) {
|
|
59
|
+
console.log(`${chalk.green('✓')} Cleaned up test user`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log(chalk.yellow(`⚠ Could not delete test user ${result.orphanedUserId} — delete it manually in the dashboard.`));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const envLabel = result.environment ?? 'the active environment';
|
|
66
|
+
if (result.success) {
|
|
67
|
+
console.log(chalk.green(`Login verification passed for ${envLabel}.`));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log(chalk.red(`Login verification FAILED for ${envLabel}.`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export async function runVerifyLogin(options) {
|
|
74
|
+
const method = options.method ?? 'password';
|
|
75
|
+
const environment = options.envName ?? null;
|
|
76
|
+
// 1. Production refusal — before any SDK call. verify-login mutates real
|
|
77
|
+
// users, so it must never touch production. Refuse on either the stored env
|
|
78
|
+
// type OR a production-format key (belt-and-suspenders for keys passed via
|
|
79
|
+
// --api-key / WORKOS_API_KEY with no matching stored env).
|
|
80
|
+
if (options.envType === 'production' || options.apiKey.startsWith('sk_live_')) {
|
|
81
|
+
exitWithError({
|
|
82
|
+
code: 'production_env_refused',
|
|
83
|
+
message: 'verify-login creates and deletes real users and will not run against a production ' +
|
|
84
|
+
'environment. Switch to a staging/sandbox environment first.',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
// 2. clientId check — required for the password grant.
|
|
88
|
+
const clientId = options.clientId;
|
|
89
|
+
if (!clientId) {
|
|
90
|
+
exitWithError({
|
|
91
|
+
code: 'missing_client_id',
|
|
92
|
+
message: `No client ID for the active environment. Pass --client-id, or configure one via ` +
|
|
93
|
+
`\`${formatWorkOSCommand('env add --client-id <id>')}\`.`,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// 3. Construct the client.
|
|
97
|
+
const { sdk } = createWorkOSClient(options.apiKey, options.baseUrl);
|
|
98
|
+
// 4. Generate throwaway credentials.
|
|
99
|
+
const email = generateEmail();
|
|
100
|
+
const password = generatePassword();
|
|
101
|
+
// 5. Run the round-trip. Cleanup runs in `finally` so no orphaned user
|
|
102
|
+
// remains on the happy path or on an authentication failure.
|
|
103
|
+
const checks = [];
|
|
104
|
+
let userId = null;
|
|
105
|
+
let userCleanedUp = true;
|
|
106
|
+
let orphanedUserId = null;
|
|
107
|
+
try {
|
|
108
|
+
const user = await sdk.userManagement.createUser({ email, password, emailVerified: true });
|
|
109
|
+
userId = user.id;
|
|
110
|
+
checks.push({ name: 'create_user', passed: true, detail: `Created test user ${user.id}` });
|
|
111
|
+
const auth = await sdk.userManagement.authenticateWithPassword({ clientId, email, password });
|
|
112
|
+
checks.push({ name: 'authenticate', passed: true, detail: 'password grant succeeded' });
|
|
113
|
+
const hasTokens = Boolean(auth.accessToken && auth.refreshToken);
|
|
114
|
+
checks.push({
|
|
115
|
+
name: 'tokens',
|
|
116
|
+
passed: hasTokens,
|
|
117
|
+
detail: hasTokens ? 'access + refresh tokens present' : 'tokens missing from response',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
const failedStep = userId ? 'authenticate' : 'create_user';
|
|
122
|
+
checks.push({ name: failedStep, passed: false, detail: describeAuthError(err) });
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
if (userId) {
|
|
126
|
+
try {
|
|
127
|
+
await sdk.userManagement.deleteUser(userId);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
userCleanedUp = false;
|
|
131
|
+
orphanedUserId = userId;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const success = checks.length > 0 && checks.every((c) => c.passed);
|
|
136
|
+
const result = {
|
|
137
|
+
success,
|
|
138
|
+
method,
|
|
139
|
+
environment,
|
|
140
|
+
checks,
|
|
141
|
+
userId,
|
|
142
|
+
userCleanedUp,
|
|
143
|
+
orphanedUserId,
|
|
144
|
+
};
|
|
145
|
+
if (isJsonMode()) {
|
|
146
|
+
outputJson(result);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
printHuman(result);
|
|
150
|
+
}
|
|
151
|
+
// Exit follows the login verdict, not cleanup: a leaked user is surfaced
|
|
152
|
+
// machine-readably but does not fail the verification. No error arg here — the
|
|
153
|
+
// verdict was already emitted, so a second envelope would confuse parsers.
|
|
154
|
+
if (!success) {
|
|
155
|
+
exitWithCode(ExitCode.GENERAL_ERROR);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=verify-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-login.js","sourceRoot":"","sources":["../../src/commands/verify-login.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * verify-login: prove the AuthKit login loop end-to-end against the active\n * environment, headlessly (no browser, no email/OTP retrieval).\n *\n * The command creates a throwaway user, authenticates it with the password\n * grant, asserts access + refresh tokens come back, and deletes the user in a\n * `finally` block so cleanup always runs. It refuses to touch a production\n * environment (unconditional, no override) because it mutates real users.\n */\n\nimport chalk from 'chalk';\nimport { createWorkOSClient } from '../lib/workos-client.js';\nimport { outputJson, isJsonMode, exitWithError } from '../utils/output.js';\nimport { exitWithCode, ExitCode } from '../utils/exit-codes.js';\nimport { formatWorkOSCommand } from '../utils/command-invocation.js';\n\n// Widen this union (e.g. 'magic-auth') only alongside the code path that verifies it.\nexport type VerifyLoginMethod = 'password';\n\nexport interface VerifyLoginOptions {\n /** Already resolved by bin.ts via resolveApiKey (exits 4 if none). */\n apiKey: string;\n /** --client-id ?? activeEnv.clientId. */\n clientId?: string;\n /** resolveApiBaseUrl(). */\n baseUrl?: string;\n /** activeEnv.type — drives the production refusal. */\n envType?: 'production' | 'sandbox' | 'unclaimed' | null;\n /** activeEnv.name — display only. */\n envName?: string;\n /** Authentication method to verify (default 'password'). */\n method?: VerifyLoginMethod;\n}\n\ninterface Check {\n name: 'create_user' | 'authenticate' | 'tokens';\n passed: boolean;\n detail: string;\n}\n\ninterface VerifyLoginResult {\n success: boolean;\n method: VerifyLoginMethod;\n environment: string | null;\n checks: Check[];\n userId: string | null;\n userCleanedUp: boolean;\n orphanedUserId: string | null;\n}\n\n/**\n * A clearly-labeled, non-routable throwaway email so the user is obvious in the\n * dashboard if cleanup ever fails.\n */\nfunction generateEmail(): string {\n return `verify-login+${crypto.randomUUID()}@example.workos.dev`;\n}\n\n/**\n * A strong random password (>= 24 chars) mixing character classes so it\n * satisfies the API password policy regardless of the specific rules. The\n * fixed `Aa1!` suffix guarantees upper/lower/digit/symbol coverage on top of\n * the random base64url body.\n */\nfunction generatePassword(): string {\n const bytes = new Uint8Array(24);\n crypto.getRandomValues(bytes);\n const body = Buffer.from(bytes).toString('base64url');\n return `${body}Aa1!`;\n}\n\n/**\n * Translate an authenticate error into a human-readable check detail. When the\n * failure looks like \"password authentication not enabled\" (a config gap, not a\n * broken login) surface an actionable message instead of a bare error so agents\n * do not misread it as \"login is broken\".\n *\n * NOTE: the exact code/message returned when password auth is disabled is\n * UNCONFIRMED against a live environment; the heuristic below is best-effort and\n * falls back to the raw error message.\n */\nfunction describeAuthError(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n if (/password/i.test(message) && /(not enabled|disabled|not available|unavailable)/i.test(message)) {\n return (\n 'Password authentication is not enabled for this environment. Enable it in the WorkOS ' +\n 'Dashboard (User Management → Authentication).'\n );\n }\n return message;\n}\n\nfunction printHuman(result: VerifyLoginResult): void {\n for (const check of result.checks) {\n const mark = check.passed ? chalk.green('✓') : chalk.red('✗');\n console.log(`${mark} ${check.detail}`);\n }\n\n if (result.userId) {\n if (result.userCleanedUp) {\n console.log(`${chalk.green('✓')} Cleaned up test user`);\n } else {\n console.log(\n chalk.yellow(`⚠ Could not delete test user ${result.orphanedUserId} — delete it manually in the dashboard.`),\n );\n }\n }\n\n const envLabel = result.environment ?? 'the active environment';\n if (result.success) {\n console.log(chalk.green(`Login verification passed for ${envLabel}.`));\n } else {\n console.log(chalk.red(`Login verification FAILED for ${envLabel}.`));\n }\n}\n\nexport async function runVerifyLogin(options: VerifyLoginOptions): Promise<void> {\n const method: VerifyLoginMethod = options.method ?? 'password';\n const environment = options.envName ?? null;\n\n // 1. Production refusal — before any SDK call. verify-login mutates real\n // users, so it must never touch production. Refuse on either the stored env\n // type OR a production-format key (belt-and-suspenders for keys passed via\n // --api-key / WORKOS_API_KEY with no matching stored env).\n if (options.envType === 'production' || options.apiKey.startsWith('sk_live_')) {\n exitWithError({\n code: 'production_env_refused',\n message:\n 'verify-login creates and deletes real users and will not run against a production ' +\n 'environment. Switch to a staging/sandbox environment first.',\n });\n }\n\n // 2. clientId check — required for the password grant.\n const clientId = options.clientId;\n if (!clientId) {\n exitWithError({\n code: 'missing_client_id',\n message:\n `No client ID for the active environment. Pass --client-id, or configure one via ` +\n `\\`${formatWorkOSCommand('env add --client-id <id>')}\\`.`,\n });\n }\n\n // 3. Construct the client.\n const { sdk } = createWorkOSClient(options.apiKey, options.baseUrl);\n\n // 4. Generate throwaway credentials.\n const email = generateEmail();\n const password = generatePassword();\n\n // 5. Run the round-trip. Cleanup runs in `finally` so no orphaned user\n // remains on the happy path or on an authentication failure.\n const checks: Check[] = [];\n let userId: string | null = null;\n let userCleanedUp = true;\n let orphanedUserId: string | null = null;\n\n try {\n const user = await sdk.userManagement.createUser({ email, password, emailVerified: true });\n userId = user.id;\n checks.push({ name: 'create_user', passed: true, detail: `Created test user ${user.id}` });\n\n const auth = await sdk.userManagement.authenticateWithPassword({ clientId, email, password });\n checks.push({ name: 'authenticate', passed: true, detail: 'password grant succeeded' });\n\n const hasTokens = Boolean(auth.accessToken && auth.refreshToken);\n checks.push({\n name: 'tokens',\n passed: hasTokens,\n detail: hasTokens ? 'access + refresh tokens present' : 'tokens missing from response',\n });\n } catch (err) {\n const failedStep: Check['name'] = userId ? 'authenticate' : 'create_user';\n checks.push({ name: failedStep, passed: false, detail: describeAuthError(err) });\n } finally {\n if (userId) {\n try {\n await sdk.userManagement.deleteUser(userId);\n } catch {\n userCleanedUp = false;\n orphanedUserId = userId;\n }\n }\n }\n\n const success = checks.length > 0 && checks.every((c) => c.passed);\n\n const result: VerifyLoginResult = {\n success,\n method,\n environment,\n checks,\n userId,\n userCleanedUp,\n orphanedUserId,\n };\n\n if (isJsonMode()) {\n outputJson(result);\n } else {\n printHuman(result);\n }\n\n // Exit follows the login verdict, not cleanup: a leaked user is surfaced\n // machine-readably but does not fail the verification. No error arg here — the\n // verdict was already emitted, so a second envelope would confuse parsers.\n if (!success) {\n exitWithCode(ExitCode.GENERAL_ERROR);\n }\n}\n"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
-
import {
|
|
2
|
+
import { getAuthkitDomain, getCliAuthClientId, getConfig } from '../../lib/settings.js';
|
|
3
|
+
import { getLlmGatewayUrl } from '../../utils/urls.js';
|
|
3
4
|
import { getCredentials, isTokenExpired, updateTokens, diagnoseCredentials } from '../../lib/credentials.js';
|
|
4
5
|
import { refreshAccessToken } from '../../lib/token-refresh-client.js';
|
|
5
6
|
import { buildDoctorPrompt } from '../agent-prompt.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-analysis.js","sourceRoot":"","sources":["../../../src/doctor/checks/ai-analysis.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAC1G,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC7G,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAwB,MAAM,oBAAoB,CAAC;AAE7E,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE1E,SAAS,YAAY,CAAC,OAAe;IACnC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IACxF,CAAC,EAAE,EAAE,CAAC,CAAC;IACP,OAAO;QACL,IAAI,EAAE,GAAG,EAAE;YACT,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;QAChE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3E,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE1D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC;YAC7C,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAA0B,EAAE,EAAE,CAAC,CAAC;gBACnD,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAGlF;gBACV,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC;gBAC9B,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;gBACxC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;aACtD,CAAC,CAAC;YACL,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;IAC7D,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC7D,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;gBACxC,OAAO;oBACL,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;oBAC/D,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;iBACtC,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU;YACZ,CAAC;QACH,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IACvD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAAc,EAAE,KAAa;IACpD,IAAI,KAAK,GAAG,cAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IAEjD,IAAI,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,YAAY;YACrB,MAAM,IAAI,KAAK,CAAC,2BAA2B,mBAAmB,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;QACvG,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,gBAAgB,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAChE,MAAM,IAAI,KAAK,CAAC,2BAA2B,mBAAmB,CAAC,YAAY,CAAC,uBAAuB,CAAC,CAAC;QACvG,CAAC;QACD,YAAY,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;QACxE,KAAK,GAAG,cAAc,EAAG,CAAC;IAC5B,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,OAAO,EAAE,gBAAgB,EAAE;QAC3B,MAAM,EAAE,SAAS;QACjB,cAAc,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,CAAC,WAAW,EAAE,EAAE;KACjE,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;QAC5C,KAAK;QACL,UAAU,EAAE,IAAI;QAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;KAC9C,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IAC3C,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAwB,EAAE,OAA6B;IAC3F,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC,WAAW,CAAC;IAEtC,MAAM,aAAa,GAAG,CAAC,MAAc,EAAc,EAAE,CAAC,CAAC;QACrD,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,EAAE;QACX,KAAK;QACL,UAAU,EAAE,CAAC;QACb,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,MAAM;KACnB,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACnB,OAAO,aAAa,CAAC,0BAA0B,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,KAAK,GAAG,cAAc,EAAE,CAAC;IAC/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;QACnC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QACjD,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,aAAa,CAAC,6BAA6B,mBAAmB,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC;IACnH,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,YAAY,CAAC,8BAA8B,CAAC,CAAC;IAE7D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAC1C,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,eAAe,CAAC,YAAY,CAAC,CAAC;QAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAClD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAC1C,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;QACxE,OAAO,EAAE,GAAG,aAAa,CAAC,oBAAoB,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC;IACxE,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,IAAI,EAAE,CAAC;IACjB,CAAC;AACH,CAAC","sourcesContent":["import Anthropic from '@anthropic-ai/sdk';\nimport { getLlmGatewayUrl, getAuthkitDomain, getCliAuthClientId, getConfig } from '../../lib/settings.js';\nimport { getCredentials, isTokenExpired, updateTokens, diagnoseCredentials } from '../../lib/credentials.js';\nimport { refreshAccessToken } from '../../lib/token-refresh-client.js';\nimport { buildDoctorPrompt, type AnalysisContext } from '../agent-prompt.js';\nimport type { AiAnalysis, AiFinding } from '../types.js';\nimport { formatWorkOSCommand } from '../../utils/command-invocation.js';\n\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nfunction startSpinner(message: string): { stop: () => void } {\n let i = 0;\n const interval = setInterval(() => {\n process.stderr.write(`\\r ${SPINNER_FRAMES[i++ % SPINNER_FRAMES.length]} ${message}`);\n }, 80);\n return {\n stop: () => {\n clearInterval(interval);\n process.stderr.write(`\\r${' '.repeat(message.length + 6)}\\r`);\n },\n };\n}\n\nexport function parseAiResponse(text: string): { findings: AiFinding[]; summary: string } {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1] : text;\n\n try {\n const parsed = JSON.parse(jsonStr.trim());\n const findings = Array.isArray(parsed.findings)\n ? parsed.findings.map((f: Record<string, unknown>) => ({\n severity: (['error', 'warning', 'info'].includes(f.severity as string) ? f.severity : 'info') as\n | 'error'\n | 'warning'\n | 'info',\n title: String(f.title ?? ''),\n detail: String(f.detail ?? ''),\n remediation: String(f.remediation ?? ''),\n filePath: f.filePath ? String(f.filePath) : undefined,\n }))\n : [];\n return { findings, summary: String(parsed.summary ?? '') };\n } catch {\n const jsonMatch = text.match(/\\{[\\s\\S]*\"findings\"[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n findings: Array.isArray(parsed.findings) ? parsed.findings : [],\n summary: String(parsed.summary ?? ''),\n };\n } catch {\n // give up\n }\n }\n return { findings: [], summary: text.slice(0, 500) };\n }\n}\n\nasync function callModel(prompt: string, model: string): Promise<string> {\n let creds = getCredentials();\n if (!creds) throw new Error('Not authenticated');\n\n if (isTokenExpired(creds)) {\n if (!creds.refreshToken)\n throw new Error(`Session expired — run \\`${formatWorkOSCommand('auth login')}\\` to re-authenticate`);\n const result = await refreshAccessToken(getAuthkitDomain(), getCliAuthClientId());\n if (!result.success || !result.accessToken || !result.expiresAt) {\n throw new Error(`Session expired — run \\`${formatWorkOSCommand('auth login')}\\` to re-authenticate`);\n }\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n creds = getCredentials()!;\n }\n\n const client = new Anthropic({\n baseURL: getLlmGatewayUrl(),\n apiKey: 'gateway',\n defaultHeaders: { Authorization: `Bearer ${creds.accessToken}` },\n });\n\n const response = await client.messages.create({\n model,\n max_tokens: 2048,\n messages: [{ role: 'user', content: prompt }],\n });\n\n const text = response.content[0];\n if (text.type === 'text') return text.text;\n throw new Error('Unexpected response format');\n}\n\nexport async function checkAiAnalysis(context: AnalysisContext, options: { skipAi?: boolean }): Promise<AiAnalysis> {\n const model = getConfig().doctorModel;\n\n const skippedResult = (reason: string): AiAnalysis => ({\n findings: [],\n summary: '',\n model,\n durationMs: 0,\n skipped: true,\n skipReason: reason,\n });\n\n if (options.skipAi) {\n return skippedResult('Skipped (--skip-ai flag)');\n }\n\n const creds = getCredentials();\n if (!creds) {\n const diag = diagnoseCredentials();\n process.stderr.write('\\n [credential-debug]\\n');\n for (const line of diag) {\n process.stderr.write(` ${line}\\n`);\n }\n process.stderr.write('\\n');\n return skippedResult(`Not authenticated — run \\`${formatWorkOSCommand('auth login')}\\` for AI-powered analysis`);\n }\n\n const startTime = Date.now();\n const spinner = startSpinner('Analyzing project with AI...');\n\n try {\n const prompt = await buildDoctorPrompt(context);\n const responseText = await callModel(prompt, model);\n const durationMs = Date.now() - startTime;\n const { findings, summary } = parseAiResponse(responseText);\n return { findings, summary, model, durationMs };\n } catch (error) {\n const durationMs = Date.now() - startTime;\n const errMsg = error instanceof Error ? error.message : 'Unknown error';\n return { ...skippedResult(`Analysis failed: ${errMsg}`), durationMs };\n } finally {\n spinner.stop();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ai-analysis.js","sourceRoot":"","sources":["../../../src/doctor/checks/ai-analysis.ts"],"names":[],"mappings":"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","sourcesContent":["import Anthropic from '@anthropic-ai/sdk';\nimport { getAuthkitDomain, getCliAuthClientId, getConfig } from '../../lib/settings.js';\nimport { getLlmGatewayUrl } from '../../utils/urls.js';\nimport { getCredentials, isTokenExpired, updateTokens, diagnoseCredentials } from '../../lib/credentials.js';\nimport { refreshAccessToken } from '../../lib/token-refresh-client.js';\nimport { buildDoctorPrompt, type AnalysisContext } from '../agent-prompt.js';\nimport type { AiAnalysis, AiFinding } from '../types.js';\nimport { formatWorkOSCommand } from '../../utils/command-invocation.js';\n\nconst SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n\nfunction startSpinner(message: string): { stop: () => void } {\n let i = 0;\n const interval = setInterval(() => {\n process.stderr.write(`\\r ${SPINNER_FRAMES[i++ % SPINNER_FRAMES.length]} ${message}`);\n }, 80);\n return {\n stop: () => {\n clearInterval(interval);\n process.stderr.write(`\\r${' '.repeat(message.length + 6)}\\r`);\n },\n };\n}\n\nexport function parseAiResponse(text: string): { findings: AiFinding[]; summary: string } {\n const codeBlockMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)\\n?\\s*```/);\n const jsonStr = codeBlockMatch ? codeBlockMatch[1] : text;\n\n try {\n const parsed = JSON.parse(jsonStr.trim());\n const findings = Array.isArray(parsed.findings)\n ? parsed.findings.map((f: Record<string, unknown>) => ({\n severity: (['error', 'warning', 'info'].includes(f.severity as string) ? f.severity : 'info') as\n | 'error'\n | 'warning'\n | 'info',\n title: String(f.title ?? ''),\n detail: String(f.detail ?? ''),\n remediation: String(f.remediation ?? ''),\n filePath: f.filePath ? String(f.filePath) : undefined,\n }))\n : [];\n return { findings, summary: String(parsed.summary ?? '') };\n } catch {\n const jsonMatch = text.match(/\\{[\\s\\S]*\"findings\"[\\s\\S]*\\}/);\n if (jsonMatch) {\n try {\n const parsed = JSON.parse(jsonMatch[0]);\n return {\n findings: Array.isArray(parsed.findings) ? parsed.findings : [],\n summary: String(parsed.summary ?? ''),\n };\n } catch {\n // give up\n }\n }\n return { findings: [], summary: text.slice(0, 500) };\n }\n}\n\nasync function callModel(prompt: string, model: string): Promise<string> {\n let creds = getCredentials();\n if (!creds) throw new Error('Not authenticated');\n\n if (isTokenExpired(creds)) {\n if (!creds.refreshToken)\n throw new Error(`Session expired — run \\`${formatWorkOSCommand('auth login')}\\` to re-authenticate`);\n const result = await refreshAccessToken(getAuthkitDomain(), getCliAuthClientId());\n if (!result.success || !result.accessToken || !result.expiresAt) {\n throw new Error(`Session expired — run \\`${formatWorkOSCommand('auth login')}\\` to re-authenticate`);\n }\n updateTokens(result.accessToken, result.expiresAt, result.refreshToken);\n creds = getCredentials()!;\n }\n\n const client = new Anthropic({\n baseURL: getLlmGatewayUrl(),\n apiKey: 'gateway',\n defaultHeaders: { Authorization: `Bearer ${creds.accessToken}` },\n });\n\n const response = await client.messages.create({\n model,\n max_tokens: 2048,\n messages: [{ role: 'user', content: prompt }],\n });\n\n const text = response.content[0];\n if (text.type === 'text') return text.text;\n throw new Error('Unexpected response format');\n}\n\nexport async function checkAiAnalysis(context: AnalysisContext, options: { skipAi?: boolean }): Promise<AiAnalysis> {\n const model = getConfig().doctorModel;\n\n const skippedResult = (reason: string): AiAnalysis => ({\n findings: [],\n summary: '',\n model,\n durationMs: 0,\n skipped: true,\n skipReason: reason,\n });\n\n if (options.skipAi) {\n return skippedResult('Skipped (--skip-ai flag)');\n }\n\n const creds = getCredentials();\n if (!creds) {\n const diag = diagnoseCredentials();\n process.stderr.write('\\n [credential-debug]\\n');\n for (const line of diag) {\n process.stderr.write(` ${line}\\n`);\n }\n process.stderr.write('\\n');\n return skippedResult(`Not authenticated — run \\`${formatWorkOSCommand('auth login')}\\` for AI-powered analysis`);\n }\n\n const startTime = Date.now();\n const spinner = startSpinner('Analyzing project with AI...');\n\n try {\n const prompt = await buildDoctorPrompt(context);\n const responseText = await callModel(prompt, model);\n const durationMs = Date.now() - startTime;\n const { findings, summary } = parseAiResponse(responseText);\n return { findings, summary, model, durationMs };\n } catch (error) {\n const durationMs = Date.now() - startTime;\n const errMsg = error instanceof Error ? error.message : 'Unknown error';\n return { ...skippedResult(`Analysis failed: ${errMsg}`), durationMs };\n } finally {\n spinner.stop();\n }\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { McpInfo } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Report the WorkOS MCP server status across detected coding agents.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors checkSkills: per-detected-agent loop, typed `*Info` return, null when
|
|
6
|
+
* no agents are detected (so doctor renders no MCP section for users with no
|
|
7
|
+
* coding agent installed). Report-only — never mutates config (`--fix` does not
|
|
8
|
+
* touch MCP in this phase).
|
|
9
|
+
*
|
|
10
|
+
* Absent MCP is deliberately NOT an issue: the user may have declined the
|
|
11
|
+
* offer. Only Cursor exposes a readable config, so URL drift ("misconfigured")
|
|
12
|
+
* is detected for Cursor alone; issues.ts derives a warning from it. Per-agent
|
|
13
|
+
* shell-outs carry the 10s timeout from the client library, keeping doctor fast.
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkMcp(): Promise<McpInfo | null>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { detectMcpClients, getCursorConfiguredUrl } from '../../lib/mcp-clients.js';
|
|
2
|
+
import { MCP_SERVER_URL } from '../../lib/constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Report the WorkOS MCP server status across detected coding agents.
|
|
5
|
+
*
|
|
6
|
+
* Mirrors checkSkills: per-detected-agent loop, typed `*Info` return, null when
|
|
7
|
+
* no agents are detected (so doctor renders no MCP section for users with no
|
|
8
|
+
* coding agent installed). Report-only — never mutates config (`--fix` does not
|
|
9
|
+
* touch MCP in this phase).
|
|
10
|
+
*
|
|
11
|
+
* Absent MCP is deliberately NOT an issue: the user may have declined the
|
|
12
|
+
* offer. Only Cursor exposes a readable config, so URL drift ("misconfigured")
|
|
13
|
+
* is detected for Cursor alone; issues.ts derives a warning from it. Per-agent
|
|
14
|
+
* shell-outs carry the 10s timeout from the client library, keeping doctor fast.
|
|
15
|
+
*/
|
|
16
|
+
export async function checkMcp() {
|
|
17
|
+
const clients = await detectMcpClients();
|
|
18
|
+
if (clients.length === 0)
|
|
19
|
+
return null;
|
|
20
|
+
const agents = await Promise.all(clients.map(async (client) => {
|
|
21
|
+
const installed = await client.isInstalled();
|
|
22
|
+
const status = { agent: client.displayName, available: true, installed };
|
|
23
|
+
// Cursor is the only client whose config we can read, so it's the only
|
|
24
|
+
// one we can flag for URL drift. A missing/unreadable URL (null) is not
|
|
25
|
+
// "unexpected" — only a present-but-different URL counts.
|
|
26
|
+
if (client.key === 'cursor' && installed) {
|
|
27
|
+
const url = await getCursorConfiguredUrl();
|
|
28
|
+
status.misconfigured = url !== null && url !== MCP_SERVER_URL;
|
|
29
|
+
}
|
|
30
|
+
return status;
|
|
31
|
+
}));
|
|
32
|
+
return { serverUrl: MCP_SERVER_URL, agents };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/doctor/checks/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACpF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,OAAO,GAAG,MAAM,gBAAgB,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAA8B,EAAE;QACvD,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAsB,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC5F,uEAAuE;QACvE,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,SAAS,EAAE,CAAC;YACzC,MAAM,GAAG,GAAG,MAAM,sBAAsB,EAAE,CAAC;YAC3C,MAAM,CAAC,aAAa,GAAG,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,cAAc,CAAC;QAChE,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;AAC/C,CAAC","sourcesContent":["import { detectMcpClients, getCursorConfiguredUrl } from '../../lib/mcp-clients.js';\nimport { MCP_SERVER_URL } from '../../lib/constants.js';\nimport type { McpInfo, McpAgentMcpStatus } from '../types.js';\n\n/**\n * Report the WorkOS MCP server status across detected coding agents.\n *\n * Mirrors checkSkills: per-detected-agent loop, typed `*Info` return, null when\n * no agents are detected (so doctor renders no MCP section for users with no\n * coding agent installed). Report-only — never mutates config (`--fix` does not\n * touch MCP in this phase).\n *\n * Absent MCP is deliberately NOT an issue: the user may have declined the\n * offer. Only Cursor exposes a readable config, so URL drift (\"misconfigured\")\n * is detected for Cursor alone; issues.ts derives a warning from it. Per-agent\n * shell-outs carry the 10s timeout from the client library, keeping doctor fast.\n */\nexport async function checkMcp(): Promise<McpInfo | null> {\n const clients = await detectMcpClients();\n if (clients.length === 0) return null;\n\n const agents = await Promise.all(\n clients.map(async (client): Promise<McpAgentMcpStatus> => {\n const installed = await client.isInstalled();\n const status: McpAgentMcpStatus = { agent: client.displayName, available: true, installed };\n // Cursor is the only client whose config we can read, so it's the only\n // one we can flag for URL drift. A missing/unreadable URL (null) is not\n // \"unexpected\" — only a present-but-different URL counts.\n if (client.key === 'cursor' && installed) {\n const url = await getCursorConfiguredUrl();\n status.misconfigured = url !== null && url !== MCP_SERVER_URL;\n }\n return status;\n }),\n );\n\n return { serverUrl: MCP_SERVER_URL, agents };\n}\n"]}
|
package/dist/doctor/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { checkDashboardSettings, compareRedirectUris } from './checks/dashboard.
|
|
|
9
9
|
import { checkAuthPatterns } from './checks/auth-patterns.js';
|
|
10
10
|
import { checkAiAnalysis } from './checks/ai-analysis.js';
|
|
11
11
|
import { checkSkills } from './checks/skills.js';
|
|
12
|
+
import { checkMcp } from './checks/mcp.js';
|
|
12
13
|
import { refreshWorkOSSkills } from '../commands/install-skill.js';
|
|
13
14
|
import { detectIssues } from './issues.js';
|
|
14
15
|
import { formatReport } from './output.js';
|
|
@@ -61,14 +62,17 @@ export async function runDoctor(options) {
|
|
|
61
62
|
// Must run before connectivity so the resolved base URL is available
|
|
62
63
|
const { info: environment, raw: envRaw } = checkEnvironment(options);
|
|
63
64
|
// Run remaining checks concurrently
|
|
64
|
-
const [sdk, framework, runtime, connectivity, language, hostExecution] = await Promise.all([
|
|
65
|
+
const [sdk, framework, runtime, connectivity, language, hostExecution, mcpResult] = await Promise.all([
|
|
65
66
|
checkSdk(options),
|
|
66
67
|
checkFramework(options),
|
|
67
68
|
checkRuntime(options),
|
|
68
69
|
checkConnectivity(options, environment.baseUrl ?? 'https://api.workos.com'),
|
|
69
70
|
checkLanguage(options.installDir),
|
|
70
71
|
checkHostExecution(),
|
|
72
|
+
checkMcp(),
|
|
71
73
|
]);
|
|
74
|
+
// Normalize the check's null (no agents detected) to undefined for the report.
|
|
75
|
+
const mcp = mcpResult ?? undefined;
|
|
72
76
|
let skills = (await checkSkills()) ?? undefined;
|
|
73
77
|
// `--fix`: refresh stale WorkOS skills BEFORE earlyIssues + AI analysis so
|
|
74
78
|
// every downstream consumer (issue detection, AI prompt context) sees the
|
|
@@ -92,6 +96,7 @@ export async function runDoctor(options) {
|
|
|
92
96
|
hostExecution,
|
|
93
97
|
connectivity,
|
|
94
98
|
skills,
|
|
99
|
+
mcp,
|
|
95
100
|
});
|
|
96
101
|
const [dashboardResult, authPatterns, aiAnalysis] = await Promise.all([
|
|
97
102
|
checkDashboardSettings(options, environment.apiKeyType, envRaw),
|
|
@@ -132,6 +137,7 @@ export async function runDoctor(options) {
|
|
|
132
137
|
aiAnalysis,
|
|
133
138
|
skills,
|
|
134
139
|
skillsRefresh,
|
|
140
|
+
mcp,
|
|
135
141
|
};
|
|
136
142
|
// Detect issues based on (post-refresh) data.
|
|
137
143
|
const issues = detectIssues(partialReport);
|
package/dist/doctor/index.js.map
CHANGED
|
@@ -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 { checkHostExecution } from './checks/host-execution.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 { getInteractionMode } from '../utils/interaction-mode.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 const interactionMode = getInteractionMode();\n\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, hostExecution] = 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 checkHostExecution(),\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 interactionMode,\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\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 interactionMode,\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\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"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doctor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,cAAc,GAAG,OAAO,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,QAAQ,EAAE,gBAAgB,CAAU,CAAC;AAEpE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAmC,EACnC,MAA8B;IAK9B,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAE/C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,KAAK,IAAI,CAAC,CAAC;IACvF,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAErC,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC;QACxC,8DAA8D;QAC9D,sDAAsD;QACtD,MAAM,EAAE,CAAC,GAAG,cAAc,CAAC;KAC5B,CAAC,CAAC;IACH,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAEhC,OAAO;QACL,aAAa,EAAE;YACb,MAAM,EAAE,OAAO,CAAC,cAAc;YAC9B,KAAK,EAAE,OAAO,CAAC,aAAa;YAC5B,eAAe,EAAE,OAAO,CAAC,MAAM;SAChC;QACD,MAAM,EAAE,CAAC,MAAM,WAAW,EAAE,CAAC,IAAI,SAAS;KAC3C,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAsB;IACpD,MAAM,eAAe,GAAG,kBAAkB,EAAE,CAAC;IAE7C,kEAAkE;IAClE,qEAAqE;IACrE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAErE,oCAAoC;IACpC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpG,QAAQ,CAAC,OAAO,CAAC;QACjB,cAAc,CAAC,OAAO,CAAC;QACvB,YAAY,CAAC,OAAO,CAAC;QACrB,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,wBAAwB,CAAC;QAC3E,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC;QACjC,kBAAkB,EAAE;QACpB,QAAQ,EAAE;KACX,CAAC,CAAC;IACH,+EAA+E;IAC/E,MAAM,GAAG,GAAG,SAAS,IAAI,SAAS,CAAC;IAEnC,IAAI,MAAM,GAAG,CAAC,MAAM,WAAW,EAAE,CAAC,IAAI,SAAS,CAAC;IAEhD,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,0BAA0B;IAC1B,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,cAAc,CAAC,aAAa,CAAC;IACnD,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC;IAE/B,8FAA8F;IAC9F,yEAAyE;IACzE,MAAM,WAAW,GAAG,YAAY,CAAC;QAC/B,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,EAAE;QACb,eAAe;QACf,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,UAAU,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE;QAC7E,GAAG;QACH,QAAQ;QACR,OAAO;QACP,SAAS;QACT,WAAW;QACX,aAAa;QACb,YAAY;QACZ,MAAM;QACN,GAAG;KACJ,CAAC,CAAC;IAEH,MAAM,CAAC,eAAe,EAAE,YAAY,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QACpE,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,UAAU,EAAE,MAAM,CAAC;QAC/D,iBAAiB,CAAC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,CAAC;QACvD,eAAe,CACb,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,EACtG,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAC3B;KACF,CAAC,CAAC;IAEH,2EAA2E;IAC3E,MAAM,iBAAiB,GAAuB,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC3F,MAAM,mBAAmB,GACvB,WAAW,CAAC,WAAW;QACvB,CAAC,SAAS,CAAC,oBAAoB,IAAI,SAAS,CAAC,YAAY;YACvD,CAAC,CAAC,oBAAoB,SAAS,CAAC,YAAY,GAAG,SAAS,CAAC,oBAAoB,EAAE;YAC/E,CAAC,CAAC,IAAI,CAAC,CAAC;IAEZ,kDAAkD;IAClD,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ;QAC3C,CAAC,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,eAAe,CAAC,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;QACpG,CAAC,CAAC,SAAS,CAAC;IAEd,uBAAuB;IACvB,MAAM,aAAa,GAAG;QACpB,OAAO,EAAE,cAAc;QACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,eAAe;QACf,OAAO,EAAE;YACP,IAAI,EAAE,OAAO,CAAC,UAAU;YACxB,cAAc,EAAE,OAAO,CAAC,cAAc;SACvC;QACD,GAAG;QACH,QAAQ;QACR,OAAO;QACP,SAAS;QACT,WAAW;QACX,aAAa;QACb,YAAY;QACZ,oBAAoB,EAAE,eAAe,CAAC,oBAAoB;QAC1D,iBAAiB,EAAE,eAAe,CAAC,QAAQ,IAAI,SAAS;QACxD,cAAc,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK;QAC5E,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,MAAM;QACN,aAAa;QACb,GAAG;KACJ,CAAC;IAEF,8CAA8C;IAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;IAE3C,oBAAoB;IACpB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IAEvE,MAAM,MAAM,GAAiB;QAC3B,GAAG,aAAa;QAChB,MAAM;QACN,OAAO,EAAE;YACP,MAAM;YACN,QAAQ;YACR,OAAO,EAAE,MAAM,KAAK,CAAC;SACtB;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAoB,EAAE,OAAsB;IAC7E,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAElB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;IACH,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAEnD,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;YACxC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC","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 { checkHostExecution } from './checks/host-execution.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 { checkMcp } from './checks/mcp.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 { getInteractionMode } from '../utils/interaction-mode.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 const interactionMode = getInteractionMode();\n\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, hostExecution, mcpResult] = 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 checkHostExecution(),\n checkMcp(),\n ]);\n // Normalize the check's null (no agents detected) to undefined for the report.\n const mcp = mcpResult ?? undefined;\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 interactionMode,\n project: { path: options.installDir, packageManager: runtime.packageManager },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\n connectivity,\n skills,\n mcp,\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 interactionMode,\n project: {\n path: options.installDir,\n packageManager: runtime.packageManager,\n },\n sdk,\n language,\n runtime,\n framework,\n environment,\n hostExecution,\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 mcp,\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"]}
|
package/dist/doctor/issues.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getInstallHint, languageToSdkLanguage } from './checks/language.js';
|
|
2
|
+
import { formatWorkOSCommand } from '../utils/command-invocation.js';
|
|
2
3
|
export const ISSUE_DEFINITIONS = {
|
|
3
4
|
MISSING_API_KEY: {
|
|
4
5
|
severity: 'error',
|
|
@@ -159,11 +160,27 @@ export function detectIssues(report) {
|
|
|
159
160
|
code: 'SKILLS_OUTDATED',
|
|
160
161
|
severity: 'warning',
|
|
161
162
|
message: `WorkOS skills outdated for ${agentList} — bundled: ${report.skills.bundledVersion}`,
|
|
162
|
-
remediation:
|
|
163
|
+
remediation: `Run: ${formatWorkOSCommand('skills install')}`,
|
|
163
164
|
details: { bundledVersion: report.skills.bundledVersion, stale: stale.map((a) => a.agent) },
|
|
164
165
|
});
|
|
165
166
|
}
|
|
166
167
|
}
|
|
168
|
+
// MCP server URL drift — warn ONLY when a configured entry points at an
|
|
169
|
+
// unexpected URL. Absent MCP is never an issue: the user may have declined
|
|
170
|
+
// the offer, and doctor reports state without judging.
|
|
171
|
+
if (report.mcp) {
|
|
172
|
+
const misconfigured = report.mcp.agents.filter((a) => a.misconfigured);
|
|
173
|
+
if (misconfigured.length > 0) {
|
|
174
|
+
const agentList = misconfigured.map((a) => a.agent).join(', ');
|
|
175
|
+
issues.push({
|
|
176
|
+
code: 'MCP_MISCONFIGURED',
|
|
177
|
+
severity: 'warning',
|
|
178
|
+
message: `WorkOS MCP server configured with an unexpected URL for ${agentList} — expected ${report.mcp.serverUrl}`,
|
|
179
|
+
remediation: `Run: ${formatWorkOSCommand('mcp install')}`,
|
|
180
|
+
details: { agents: misconfigured.map((a) => a.agent), expectedUrl: report.mcp.serverUrl },
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
167
184
|
return issues;
|
|
168
185
|
}
|
|
169
186
|
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 HOST_EXECUTION_UNTRUSTED: {\n severity: 'warning' as const,\n message: 'Host-only WorkOS state may be unavailable in this shell',\n remediation:\n 'Agent/CI host execution is untrusted. Re-run this command on the host shell before trusting auth, config, or API failures.',\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 if (!report.hostExecution.ok) {\n issues.push({\n code: 'HOST_EXECUTION_UNTRUSTED',\n ...ISSUE_DEFINITIONS.HOST_EXECUTION_UNTRUSTED,\n details: { failures: report.hostExecution.failures },\n });\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
|
+
{"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';\nimport { formatWorkOSCommand } from '../utils/command-invocation.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 HOST_EXECUTION_UNTRUSTED: {\n severity: 'warning' as const,\n message: 'Host-only WorkOS state may be unavailable in this shell',\n remediation:\n 'Agent/CI host execution is untrusted. Re-run this command on the host shell before trusting auth, config, or API failures.',\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 if (!report.hostExecution.ok) {\n issues.push({\n code: 'HOST_EXECUTION_UNTRUSTED',\n ...ISSUE_DEFINITIONS.HOST_EXECUTION_UNTRUSTED,\n details: { failures: report.hostExecution.failures },\n });\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: ${formatWorkOSCommand('skills install')}`,\n details: { bundledVersion: report.skills.bundledVersion, stale: stale.map((a) => a.agent) },\n });\n }\n }\n\n // MCP server URL drift — warn ONLY when a configured entry points at an\n // unexpected URL. Absent MCP is never an issue: the user may have declined\n // the offer, and doctor reports state without judging.\n if (report.mcp) {\n const misconfigured = report.mcp.agents.filter((a) => a.misconfigured);\n if (misconfigured.length > 0) {\n const agentList = misconfigured.map((a) => a.agent).join(', ');\n issues.push({\n code: 'MCP_MISCONFIGURED',\n severity: 'warning',\n message: `WorkOS MCP server configured with an unexpected URL for ${agentList} — expected ${report.mcp.serverUrl}`,\n remediation: `Run: ${formatWorkOSCommand('mcp install')}`,\n details: { agents: misconfigured.map((a) => a.agent), expectedUrl: report.mcp.serverUrl },\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"]}
|
package/dist/doctor/output.js
CHANGED
|
@@ -2,6 +2,7 @@ import Chalk from 'chalk';
|
|
|
2
2
|
import { homedir } from 'os';
|
|
3
3
|
import { createAgents } from '../commands/install-skill.js';
|
|
4
4
|
import { renderSummaryBox } from '../utils/summary-box.js';
|
|
5
|
+
import { formatWorkOSCommand } from '../utils/command-invocation.js';
|
|
5
6
|
export function formatReport(report, options) {
|
|
6
7
|
console.log('');
|
|
7
8
|
console.log(Chalk.cyan('WorkOS Doctor'));
|
|
@@ -175,6 +176,22 @@ export function formatReport(report, options) {
|
|
|
175
176
|
console.log(` ${Chalk.green('✓')} Updated WorkOS skills for ${displayName(slug)}: ${before} → ${after}`);
|
|
176
177
|
}
|
|
177
178
|
}
|
|
179
|
+
// MCP Server (per detected coding agent)
|
|
180
|
+
if (report.mcp) {
|
|
181
|
+
console.log('');
|
|
182
|
+
console.log('MCP Server');
|
|
183
|
+
for (const agent of report.mcp.agents) {
|
|
184
|
+
if (agent.misconfigured) {
|
|
185
|
+
console.log(` ${Chalk.yellow('!')} ${agent.agent}: configured with an unexpected URL`);
|
|
186
|
+
}
|
|
187
|
+
else if (agent.installed) {
|
|
188
|
+
console.log(` ${Chalk.green('✓')} ${agent.agent}: installed`);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
console.log(` ${agent.agent}: ${Chalk.dim('not installed')}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
178
195
|
// Verbose mode additions
|
|
179
196
|
if (options?.verbose) {
|
|
180
197
|
console.log('');
|
|
@@ -225,7 +242,7 @@ export function formatReport(report, options) {
|
|
|
225
242
|
expression,
|
|
226
243
|
title,
|
|
227
244
|
items,
|
|
228
|
-
footer: '
|
|
245
|
+
footer: `${formatWorkOSCommand('doctor --copy')} | https://workos.com/docs`,
|
|
229
246
|
}));
|
|
230
247
|
console.log('');
|
|
231
248
|
}
|
|
@@ -235,8 +252,6 @@ export function formatInteractionModeSource(source) {
|
|
|
235
252
|
return '--mode';
|
|
236
253
|
case 'env':
|
|
237
254
|
return 'WORKOS_MODE';
|
|
238
|
-
case 'workos_no_prompt':
|
|
239
|
-
return 'WORKOS_NO_PROMPT';
|
|
240
255
|
case 'ci_env':
|
|
241
256
|
return 'CI environment';
|
|
242
257
|
case 'agent_env':
|