@posthog/wizard 2.27.0 → 2.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{add-mcp-server-to-clients-D2XNlVgw.js → add-mcp-server-to-clients-pXmZQkpk.js} +4 -4
  2. package/dist/{add-mcp-server-to-clients-D2XNlVgw.js.map → add-mcp-server-to-clients-pXmZQkpk.js.map} +1 -1
  3. package/dist/{agent-interface-DpkR1mbC.js → agent-interface-Bw1w0ePT.js} +5 -5
  4. package/dist/{agent-interface-DpkR1mbC.js.map → agent-interface-Bw1w0ePT.js.map} +1 -1
  5. package/dist/{agent-runner-D7hIITUf.js → agent-runner-djkxwCd9.js} +9 -9
  6. package/dist/{agent-runner-D7hIITUf.js.map → agent-runner-djkxwCd9.js.map} +1 -1
  7. package/dist/{analytics-B7-uRKIJ.js → analytics-AnN3M677.js} +2 -2
  8. package/dist/{analytics-B7-uRKIJ.js.map → analytics-AnN3M677.js.map} +1 -1
  9. package/dist/{api-2zPZQONC.js → api-CeVi1ZfZ.js} +3 -3
  10. package/dist/{api-2zPZQONC.js.map → api-CeVi1ZfZ.js.map} +1 -1
  11. package/dist/bin.js +46 -44
  12. package/dist/bin.js.map +1 -1
  13. package/dist/{ci-install-CpGSFNDi.js → ci-install-DPnE1HL3.js} +4 -4
  14. package/dist/{ci-install-CpGSFNDi.js.map → ci-install-DPnE1HL3.js.map} +1 -1
  15. package/dist/{debug-CDLYQOQh.js → debug-CyadC-pR.js} +1 -1
  16. package/dist/{debug-Br_xCc9s.js → debug-i9wAxF8s.js} +2 -2
  17. package/dist/{debug-Br_xCc9s.js.map → debug-i9wAxF8s.js.map} +1 -1
  18. package/dist/{environment-CFXsie0G.js → environment-CxkKJEfj.js} +3 -3
  19. package/dist/{environment-CFXsie0G.js.map → environment-CxkKJEfj.js.map} +1 -1
  20. package/dist/{file-utils-CHAj73KM.js → file-utils-D8H35Gk0.js} +2 -2
  21. package/dist/{file-utils-CHAj73KM.js.map → file-utils-D8H35Gk0.js.map} +1 -1
  22. package/dist/{interactive-lfAs6vF7.js → interactive-DwLH5ADP.js} +2 -2
  23. package/dist/{interactive-lfAs6vF7.js.map → interactive-DwLH5ADP.js.map} +1 -1
  24. package/dist/{mcp-prompt-streaming-BHdAwwob.js → mcp-prompt-streaming-Cxy0XPv4.js} +4 -4
  25. package/dist/{mcp-prompt-streaming-BHdAwwob.js.map → mcp-prompt-streaming-Cxy0XPv4.js.map} +1 -1
  26. package/dist/{non-interactive--4CK1bkn.js → non-interactive-LHbUCRuo.js} +2 -2
  27. package/dist/{non-interactive--4CK1bkn.js.map → non-interactive-LHbUCRuo.js.map} +1 -1
  28. package/dist/{package-manager-BlogZvIK.js → package-manager-BabzIzcR.js} +2 -2
  29. package/dist/{package-manager-BlogZvIK.js.map → package-manager-BabzIzcR.js.map} +1 -1
  30. package/dist/{playground-De_BxaCh.js → playground-BphF8gEy.js} +4 -4
  31. package/dist/{playground-De_BxaCh.js.map → playground-BphF8gEy.js.map} +1 -1
  32. package/dist/{posthog-integration-DWs8JM8J.js → posthog-integration-vJHebMhn.js} +11 -11
  33. package/dist/{posthog-integration-DWs8JM8J.js.map → posthog-integration-vJHebMhn.js.map} +1 -1
  34. package/dist/{provisioning-CUwxxByi.js → provisioning-BYJOD26-.js} +3 -3
  35. package/dist/{provisioning-CUwxxByi.js.map → provisioning-BYJOD26-.js.map} +1 -1
  36. package/dist/{registry-CIjJsxDE.js → registry-BGXvbfI-.js} +4 -4
  37. package/dist/{registry-CIjJsxDE.js.map → registry-BGXvbfI-.js.map} +1 -1
  38. package/dist/{setup-utils-CjKjaKcG.js → setup-utils-DGnWKE9t.js} +9 -9
  39. package/dist/{setup-utils-CjKjaKcG.js.map → setup-utils-DGnWKE9t.js.map} +1 -1
  40. package/dist/{start-tui-Cbw0kVr3.js → start-tui-DetsuXHe.js} +13 -13
  41. package/dist/{start-tui-Cbw0kVr3.js.map → start-tui-DetsuXHe.js.map} +1 -1
  42. package/dist/{steps-DUz5lHWu.js → steps-DgYfPftk.js} +7 -7
  43. package/dist/{steps-DUz5lHWu.js.map → steps-DgYfPftk.js.map} +1 -1
  44. package/dist/{telemetry-D3CnLknq.js → telemetry-WZu-ePKr.js} +3 -3
  45. package/dist/{telemetry-D3CnLknq.js.map → telemetry-WZu-ePKr.js.map} +1 -1
  46. package/dist/{terminal-DwAdsRPX.js → terminal-CfJ-haHU.js} +9 -9
  47. package/dist/{terminal-DwAdsRPX.js.map → terminal-CfJ-haHU.js.map} +1 -1
  48. package/dist/{urls-JN8mo6lU.js → urls-yVHBHA-b.js} +2 -2
  49. package/dist/{urls-JN8mo6lU.js.map → urls-yVHBHA-b.js.map} +1 -1
  50. package/dist/{wizard-abort-gHZ7kHYo.js → wizard-abort-Ba5HDRGB.js} +3 -3
  51. package/dist/{wizard-abort-gHZ7kHYo.js.map → wizard-abort-Ba5HDRGB.js.map} +1 -1
  52. package/dist/{wizard-abort-BPr0xo7i.js → wizard-abort-ChmzV0wB.js} +1 -1
  53. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { S as ANALYTICS_TEAM_TAG, b as ANALYTICS_HOST_URL, r as debug, s as logToFile, x as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY } from "./debug-Br_xCc9s.js";
1
+ import { S as ANALYTICS_TEAM_TAG, b as ANALYTICS_HOST_URL, r as debug, s as logToFile, x as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY } from "./debug-i9wAxF8s.js";
2
2
  import { PostHog } from "posthog-node";
3
3
  import { v4 } from "uuid";
4
4
  //#region src/utils/ci-flag-overrides.ts
@@ -220,4 +220,4 @@ const analytics = new Analytics();
220
220
  //#endregion
221
221
  export { ciExcludedTaskTypes as i, groupsFromUser as n, sessionProperties as r, analytics as t };
222
222
 
223
- //# sourceMappingURL=analytics-B7-uRKIJ.js.map
223
+ //# sourceMappingURL=analytics-AnN3M677.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-B7-uRKIJ.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n): Record<string, string> {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return flags;\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return flags;\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const merged = { ...flags };\n for (const [key, value] of Object.entries(overrides)) {\n merged[key] = String(value);\n }\n logToFile('[flags] CI overrides applied', overrides);\n return merged;\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n discovered_features: session.discoveredFeatures,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci segment cleanly\n // in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in published\n // builds and `false` for dev/tsx/test runs. CI runs (always non-prod\n // builds) upgrade this to 'ci' in runWizardCI.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this.runId = uuidv4();\n this.tags.run_id = this.runId;\n\n this.distinctId = undefined;\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n return { $app_name: this.appName, ...this.personProperties };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: this.flagPersonProperties(),\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n const flags = result.featureFlags ?? {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n this.activeFlags = applyCiFlagOverrides(out);\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Hoisted out of `tags` so the run's terminal event is filterable by\n // run, and joins the session when one was opened (post-OAuth runs).\n run_id: this.runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
1
+ {"version":3,"file":"analytics-AnN3M677.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n): Record<string, string> {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return flags;\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return flags;\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const merged = { ...flags };\n for (const [key, value] of Object.entries(overrides)) {\n merged[key] = String(value);\n }\n logToFile('[flags] CI overrides applied', overrides);\n return merged;\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n discovered_features: session.discoveredFeatures,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci segment cleanly\n // in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in published\n // builds and `false` for dev/tsx/test runs. CI runs (always non-prod\n // builds) upgrade this to 'ci' in runWizardCI.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this.runId = uuidv4();\n this.tags.run_id = this.runId;\n\n this.distinctId = undefined;\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n return { $app_name: this.appName, ...this.personProperties };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: this.flagPersonProperties(),\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n const flags = result.featureFlags ?? {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n this.activeFlags = applyCiFlagOverrides(out);\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Hoisted out of `tags` so the run's terminal event is filterable by\n // run, and joins the session when one was opened (post-OAuth runs).\n run_id: this.runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":";;;;AAkBA,SAAgB,qBACd,OACwB;AAImB,QAAO;;;;;;;;;AA+BpD,SAAgB,sBAAyC;AACZ,QAAO,EAAE;;;;;;;;ACvCtD,SAAgB,kBACd,SACyB;AACzB,QAAO;EACL,aAAa,QAAQ;EACrB,oBAAoB,QAAQ;EAC5B,YAAY,QAAQ;EACpB,YAAY,QAAQ,aAAa;EACjC,qBAAqB,QAAQ;EAC7B,qBAAqB,QAAQ;EAC7B,WAAW,QAAQ;EACpB;;AAGH,SAAgB,eACd,MACA,MACwB;CACxB,MAAM,SAAiC,EAAE,UAAU,MAAM;AACzD,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,iBAAiB,KAAK,cAAc;AAC1C,KAAI,eAAgB,QAAO,eAAe;CAE1C,MAAM,aAAa,KAAK,cAAc;AACtC,KAAI,WAAY,QAAO,WAAW;CAElC,MAAM,cAAc,KAAK,MAAM;AAC/B,KAAI,YAAa,QAAO,UAAU;AAElC,QAAO;;AAGT,IAAa,YAAb,MAAuB;CACrB;CACA,OACE,EAAE;CACJ;CACA;CACA;CACA,YAAmC;CACnC,UAAkB;CAClB,cAAqD;CACrD,SAAyC,EAAE;CAC3C,mBAAmD,EAAE;CAErD,cAAc;AACZ,OAAK,SAAS,IAAI,QAAQ,4CAA4C;GACpE,MAAM;GACN,SAAS;GACT,eAAe;GACf,4BAA4B;GAC5B,cAAc,UAAU;AACtB,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,OAAO,KAAK,KAAK,OAAO,CAAC,SAAS,EACpC,OAAM,SAAS;KAAE,GAAG,KAAK;KAAQ,GAAG,MAAM;KAAQ;AAKpD,QAAI,MAAM,UAAU,cAAc;AAChC,WAAM,aAAa,KAAK,cAAc,KAAK;KAC3C,MAAM,EAAE,yBAAyB,GAAG,eAClC,MAAM,cAAc,EAAE;AAExB,WAAM,aAAa;MAAE,GAAG,KAAK;MAAM,GAAG;MAAY;;AAEpD,WAAO;;GAEV,CAAC;AAEF,OAAK,OAAO,EAAE,WAAW,KAAK,SAAS;AAKvC,OAAK,KAAK,QAA8B;AAExC,OAAK,cAAcA,IAAQ;AAS3B,OAAK,QAAQA,IAAQ;AACrB,OAAK,KAAK,SAAS,KAAK;AAExB,OAAK,aAAa,KAAA;;;;;;;;;;CAWpB,aAAa,MAAe;EAC1B,MAAM,aAAa,KAAK;AACxB,MAAI,KAAK,eAAe,cAAc,eAAe,KAAK,YACxD;AAEF,OAAK,aAAa;AAMlB,MAAI,CAAC,KAAK,WAAW;AACnB,QAAK,YAAYA,IAAQ;AACzB,QAAK,KAAK,cAAc,KAAK;;EAE/B,MAAM,QAAgC,EAAE;AACxC,MAAI,KAAK,MAAO,OAAM,QAAQ,KAAK;EACnC,MAAM,OAAO,CAAC,KAAK,YAAY,KAAK,UAAU,CAC3C,OAAO,QAAQ,CACf,KAAK,IAAI,CACT,MAAM;AACT,MAAI,KAAM,OAAM,OAAO;AACvB,OAAK,mBAAmB;AACxB,OAAK,OAAO,SAAS;GAAE;GAAY,YAAY,EAAE,MAAM,OAAO;GAAE,CAAC;AACjE,OAAK,OAAO,MAAM;GAChB;GACA,OAAO,KAAK;GACb,CAAC;AAIF,OAAK,cAAc;;;CAIrB,uBAAuD;AACrD,SAAO;GAAE,WAAW,KAAK;GAAS,GAAG,KAAK;GAAkB;;CAG9D,OAAO,KAAa,OAAqD;AACvE,OAAK,KAAK,OAAO;;CAGnB,UAAU,QAAgC;AACxC,OAAK,SAAS;;CAGhB,iBAAiB,OAAc,aAAsC,EAAE,EAAE;AACvE,OAAK,OAAO,iBAAiB,OAAO,KAAK,cAAc,KAAK,aAAa;GACvE,MAAM;GACN,GAAG,KAAK;GACR,GAAG;GACJ,CAAC;;CAGJ,QAAQ,WAAmB,YAAsC;AAC/D,OAAK,OAAO,QAAQ;GAClB,YAAY,KAAK,cAAc,KAAK;GACpC,OAAO;GACP,YAAY;IACV,GAAG,KAAK;IACR,GAAG;IACJ;GACF,CAAC;;;;;;CAOJ,cAAc,WAAmB,YAA4C;AAC3E,OAAK,QAAQ,WAAW,aAAa,WAAW;;;;;;;;CASlD,MAAM,QAAuB;AAC3B,QAAM,KAAK,OAAO,UAAU;;CAG9B,MAAM,eAAe,SAAwD;AAC3E,MAAI;GACF,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,UAAO,MAAM,KAAK,OAAO,eAAe,SAAS,YAAY;IAC3D,uBAAuB;IACvB,kBAAkB,KAAK,sBAAsB;IAC9C,CAAC;WACK,OAAO;AACd,SAAM,+BAA+B,SAAS,MAAM;AACpD;;;;;;;;CASJ,MAAM,uBAAwD;AAC5D,MAAI,KAAK,gBAAgB,KACvB,QAAO,KAAK;EAEd,MAAM,MAA8B,EAAE;AACtC,MAAI;GACF,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,aAAU,yBAAyB;IACjC;IACA,YAAY,KAAK,eAAe,KAAA;IAChC,kBAAkB,KAAK,sBAAsB;IAC9C,CAAC;GAIF,MAAM,SAHS,MAAM,KAAK,OAAO,uBAAuB,YAAY,EAClE,kBAAkB,KAAK,sBAAsB,EAC9C,CAAC,EACmB,gBAAgB,EAAE;AACvC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;AAChD,QAAI,UAAU,KAAA,EAAW;AACzB,QAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,GAAG,OAAO,MAAM;;WAEhE,OAAO;AACd,SAAM,oCAAoC,MAAM;AAChD,QAAK,iBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,EAAE,MAAM,iBAAiB,CAC1B;;AAKH,OAAK,cAAc,qBAAqB,IAAI;AAC5C,YAAU,qBAAqB,KAAK,YAAY;AAChD,SAAO,KAAK;;CAGd,MAAM,SAAS,QAA2C;AACxD,MAAI,OAAO,KAAK,KAAK,KAAK,CAAC,WAAW,EACpC;AAGF,OAAK,OAAO,QAAQ;GAClB,YAAY,KAAK,cAAc,KAAK;GACpC,OAAO;GACP,YAAY;IAGV,QAAQ,KAAK;IACb,GAAI,KAAK,YAAY,EAAE,aAAa,KAAK,WAAW,GAAG,EAAE;IACzD;IACA,MAAM,KAAK;IACZ;GACF,CAAC;AAEF,QAAM,KAAK,OAAO,UAAU;;;AAIhC,MAAa,YAAY,IAAI,WAAW"}
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { X as WIZARD_USER_AGENT } from "./debug-Br_xCc9s.js";
3
- import { t as analytics } from "./analytics-B7-uRKIJ.js";
2
+ import { X as WIZARD_USER_AGENT } from "./debug-i9wAxF8s.js";
3
+ import { t as analytics } from "./analytics-AnN3M677.js";
4
4
  import axios from "axios";
5
5
  import { z } from "zod";
6
6
  //#region src/lib/api.ts
@@ -170,4 +170,4 @@ function handleApiError(error, operation) {
170
170
  //#endregion
171
171
  export { fetchUserData as a, fetchSlackConnected as i, api_exports as n, handleApiError as o, fetchProjectData as r, ApiError as t };
172
172
 
173
- //# sourceMappingURL=api-2zPZQONC.js.map
173
+ //# sourceMappingURL=api-CeVi1ZfZ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-2zPZQONC.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-CeVi1ZfZ.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
package/dist/bin.js CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { $ as getSkillsBaseUrl, P as POSTHOG_DOCS_URL, X as WIZARD_USER_AGENT, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, et as VERSION, h as LoggingUI, m as setUI, p as getUI, r as debug, s as logToFile, v as evaluateWizardReadiness, y as getBlockingServiceKeys } from "./debug-Br_xCc9s.js";
3
- import { t as analytics } from "./analytics-B7-uRKIJ.js";
4
- import { r as setEntryCommand } from "./telemetry-D3CnLknq.js";
5
- import { n as isUsingTypeScript } from "./setup-utils-CjKjaKcG.js";
6
- import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-JN8mo6lU.js";
7
- import { o as handleApiError } from "./api-2zPZQONC.js";
2
+ import { $ as getSkillsBaseUrl, P as POSTHOG_DOCS_URL, X as WIZARD_USER_AGENT, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, et as VERSION, h as LoggingUI, m as setUI, p as getUI, r as debug, s as logToFile, v as evaluateWizardReadiness, y as getBlockingServiceKeys } from "./debug-i9wAxF8s.js";
3
+ import { t as analytics } from "./analytics-AnN3M677.js";
4
+ import { r as setEntryCommand } from "./telemetry-WZu-ePKr.js";
5
+ import { n as isUsingTypeScript } from "./setup-utils-DGnWKE9t.js";
6
+ import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-yVHBHA-b.js";
7
+ import { o as handleApiError } from "./api-CeVi1ZfZ.js";
8
8
  import "./wizard-session-G3VWD6hv.js";
9
- import { r as runCleanups } from "./wizard-abort-gHZ7kHYo.js";
10
- import { n as isNonInteractiveEnvironment } from "./environment-CFXsie0G.js";
11
- import { S as AUDIT_REPORT_FILE, b as AUDIT_CHECKS_FILE, c as recoverOrphanedSettingsBackups, h as fetchSkillMenu, p as WIZARD_TOOL_NAMES, u as AgentSignals, x as AUDIT_CHECKS_KEY } from "./agent-interface-DpkR1mbC.js";
12
- import { i as SPINNER_MESSAGE } from "./registry-CIjJsxDE.js";
13
- import { _ as parseRequirementsTxt, a as PRODUCT_SUITE_BLOCK, f as Colors, g as parsePyprojectToml, h as parsePipfile, i as LINE_CHART_BLOCK, l as isClearBlock, m as HEALTH_CHECK_STEP, n as posthogIntegrationConfig, o as StatusPeekTrigger, p as Icons, r as FUNNEL_BLOCK } from "./posthog-integration-DWs8JM8J.js";
14
- import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-CHAj73KM.js";
9
+ import { r as runCleanups } from "./wizard-abort-Ba5HDRGB.js";
10
+ import { n as isNonInteractiveEnvironment } from "./environment-CxkKJEfj.js";
11
+ import { S as AUDIT_REPORT_FILE, b as AUDIT_CHECKS_FILE, c as recoverOrphanedSettingsBackups, h as fetchSkillMenu, p as WIZARD_TOOL_NAMES, u as AgentSignals, x as AUDIT_CHECKS_KEY } from "./agent-interface-Bw1w0ePT.js";
12
+ import { i as SPINNER_MESSAGE } from "./registry-BGXvbfI-.js";
13
+ import { _ as parseRequirementsTxt, a as PRODUCT_SUITE_BLOCK, f as Colors, g as parsePyprojectToml, h as parsePipfile, i as LINE_CHART_BLOCK, l as isClearBlock, m as HEALTH_CHECK_STEP, n as posthogIntegrationConfig, o as StatusPeekTrigger, p as Icons, r as FUNNEL_BLOCK } from "./posthog-integration-vJHebMhn.js";
14
+ import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-D8H35Gk0.js";
15
15
  import { n as readApiKeyFromEnv } from "./env-api-key-MlzJYAvt.js";
16
16
  import { satisfies } from "semver";
17
17
  import yargs from "yargs";
@@ -190,7 +190,7 @@ function runProvision(argv) {
190
190
  }
191
191
  async function provision({ email, region, name, jsonMode }) {
192
192
  try {
193
- const { provisionNewAccount } = await import("./provisioning-CUwxxByi.js").then((n) => n.n);
193
+ const { provisionNewAccount } = await import("./provisioning-BYJOD26-.js").then((n) => n.n);
194
194
  if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
195
195
  emitResult(await provisionNewAccount(email, name, region), jsonMode);
196
196
  process.exit(0);
@@ -255,18 +255,18 @@ const basicIntegrationCommand = {
255
255
  setEntryCommand("integrate");
256
256
  (async () => {
257
257
  if (argv.ci) {
258
- const { runCIInstall } = await import("./ci-install-CpGSFNDi.js");
258
+ const { runCIInstall } = await import("./ci-install-DPnE1HL3.js");
259
259
  return runCIInstall(argv);
260
260
  }
261
261
  if (isNonInteractiveEnvironment()) {
262
- const { failNonInteractive } = await import("./non-interactive--4CK1bkn.js");
262
+ const { failNonInteractive } = await import("./non-interactive-LHbUCRuo.js");
263
263
  return failNonInteractive();
264
264
  }
265
265
  if (argv.playground) {
266
- const { runPlayground } = await import("./playground-De_BxaCh.js");
266
+ const { runPlayground } = await import("./playground-BphF8gEy.js");
267
267
  return runPlayground();
268
268
  }
269
- const { runInteractive } = await import("./interactive-lfAs6vF7.js");
269
+ const { runInteractive } = await import("./interactive-DwLH5ADP.js");
270
270
  runInteractive(argv);
271
271
  })();
272
272
  }
@@ -3163,10 +3163,10 @@ function buildSelfDrivingPrompt(ctx) {
3163
3163
  const inboxUrl = `${projectBase}/inbox`;
3164
3164
  const optIn = (value) => value === true ? "ON" : value === false ? "OFF" : "unknown";
3165
3165
  const optIns = ctx.teamProductOptIns;
3166
- return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout fleet, design custom scouts for what this product uniquely needs, and hand the user a configured inbox.
3166
+ return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout troop, design custom scouts for what this product uniquely needs, and hand the user a configured inbox.
3167
3167
 
3168
3168
  Project URLs:
3169
- - Integrations settings (GitHub App install): ${integrationsSettingsUrl}
3169
+ - Integrations settings: ${integrationsSettingsUrl}
3170
3170
  - Organization AI settings: ${orgAiSettingsUrl}
3171
3171
  - New data warehouse source (Linear / Zendesk / GitHub issues / pganalyze): ${newWarehouseSourceUrl}
3172
3172
  - Self-driving inbox: ${inboxUrl}
@@ -3193,7 +3193,7 @@ tasks, in this order:
3193
3193
  3. Connect GitHub (required)
3194
3194
  4. Enable signal sources
3195
3195
  5. Offer issue-tracker integrations
3196
- 6. Configure the scout fleet
3196
+ 6. Configure the scout troop
3197
3197
  7. Design custom scouts
3198
3198
  8. Write report and hand off
3199
3199
  Drive the list with TaskUpdate — mark a task in_progress when you start
@@ -3231,9 +3231,10 @@ STEP 2 — Read project and current Signals state. (skill: "Read context")
3231
3231
 
3232
3232
  STEP 3 — Connect GitHub. REQUIRED. (skill: "Connect GitHub")
3233
3233
  Signals cannot research or fix issues without code access. Check for
3234
- an existing GitHub integration first; if absent, send the user to
3235
- ${integrationsSettingsUrl} via wizard_ask and verify the connection
3236
- after they confirm. If the user cannot connect now, emit
3234
+ an existing GitHub integration first; if absent, send the user
3235
+ through the GitHub App connection via wizard_ask exactly as the skill
3236
+ describes (it builds the one-click authorize link), and verify the
3237
+ connection after they confirm. If the user cannot connect now, emit
3237
3238
  ${AgentSignals.ABORT} github connection declined
3238
3239
  and halt — never finish setup without GitHub.
3239
3240
 
@@ -3251,14 +3252,15 @@ STEP 5 — Offer issue-tracker integrations. (skill: "Connected tools")
3251
3252
  never sends the user to paste credentials and never re-prompts. Enable
3252
3253
  a source only for a tool the user picked.
3253
3254
 
3254
- STEP 6 — Configure the scout fleet. (skill: "Scouts")
3255
- Materialize the fleet and disable the scouts whose product surface
3256
- this project lacks, per the skill.
3255
+ STEP 6 — Configure the scout troop. (skill: "Scouts")
3256
+ Materialize the troop, then enable only a small set — the "general"
3257
+ scout plus the one or two specialists for the products this project
3258
+ uses most — and disable the rest, per the skill.
3257
3259
 
3258
3260
  STEP 7 — Design custom scouts for this product. (skill: "Custom scouts")
3259
3261
  You are the only actor that has read this repo — turn that into
3260
3262
  coverage per the skill: a real gap analysis of the project's
3261
- watchable surfaces against what the canonical fleet already covers,
3263
+ watchable surfaces against what the canonical troop already covers,
3262
3264
  then custom scouts for the uncovered ones. Keep scout bodies
3263
3265
  high-level: describe the behavior and signal conditions to watch,
3264
3266
  referencing repo evidence by file/function name — never paste raw
@@ -3280,12 +3282,12 @@ const SELF_DRIVING_TIPS = [
3280
3282
  {
3281
3283
  id: "what-is-a-signal-source",
3282
3284
  title: "What's a signal source?",
3283
- description: "A signal source is a PostHog product or connected tool — errors, session replays, support, GitHub or Linear issues that feeds findings into your Self-driving inbox."
3285
+ description: "A signal source is one of the streams PostHog plugs straight intoyour errors, session replays, support, GitHub or Linear issues. Each one watches its own stream and speaks up the moment something specific goes wrong there."
3284
3286
  },
3285
3287
  {
3286
3288
  id: "what-is-a-scout",
3287
3289
  title: "What's a scout?",
3288
- description: "Scouts are scheduled checks that scan your data and flag issues — a spike in errors, a dropping funnel straight to your inbox."
3290
+ description: "A scout is like an analyst PostHog runs for you on a schedule: rather than watching one stream, it ranges freely across your product data, looking for the bigger trends and surprises — a spike in errors, a funnel quietly dropping — that no single stream would catch."
3289
3291
  },
3290
3292
  {
3291
3293
  id: "findings-in-inbox",
@@ -3572,7 +3574,7 @@ function runMcpAdd(argv) {
3572
3574
  const debug = argv.debug;
3573
3575
  const localMcp = argv.local;
3574
3576
  try {
3575
- const { startTUI } = await import("./start-tui-Cbw0kVr3.js");
3577
+ const { startTUI } = await import("./start-tui-DetsuXHe.js");
3576
3578
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3577
3579
  const tui = startTUI(VERSION, Program.McpAdd);
3578
3580
  tui.store.session = buildSession({
@@ -3584,7 +3586,7 @@ function runMcpAdd(argv) {
3584
3586
  } catch (error) {
3585
3587
  if (!isTUIUnavailable(error)) throw error;
3586
3588
  setUI(new LoggingUI());
3587
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-D2XNlVgw.js").then((n) => n.r);
3589
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-pXmZQkpk.js").then((n) => n.r);
3588
3590
  await addMCPServerToClientsStep({
3589
3591
  local: localMcp,
3590
3592
  features,
@@ -3623,7 +3625,7 @@ function runMcpRemove(argv) {
3623
3625
  const debug = argv.debug;
3624
3626
  const localMcp = argv.local;
3625
3627
  try {
3626
- const { startTUI } = await import("./start-tui-Cbw0kVr3.js");
3628
+ const { startTUI } = await import("./start-tui-DetsuXHe.js");
3627
3629
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3628
3630
  const tui = startTUI(VERSION, Program.McpRemove);
3629
3631
  tui.store.session = buildSession({
@@ -3632,7 +3634,7 @@ function runMcpRemove(argv) {
3632
3634
  });
3633
3635
  } catch {
3634
3636
  setUI(new LoggingUI());
3635
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-D2XNlVgw.js").then((n) => n.r);
3637
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-pXmZQkpk.js").then((n) => n.r);
3636
3638
  await removeMCPServerFromClientsStep({ local: localMcp });
3637
3639
  }
3638
3640
  })();
@@ -3654,7 +3656,7 @@ function runMcpTutorial(argv) {
3654
3656
  const debug = argv.debug;
3655
3657
  const localMcp = argv.local;
3656
3658
  try {
3657
- const { startTUI } = await import("./start-tui-Cbw0kVr3.js");
3659
+ const { startTUI } = await import("./start-tui-DetsuXHe.js");
3658
3660
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3659
3661
  const tui = startTUI(VERSION, Program.McpTutorial);
3660
3662
  tui.store.session = buildSession({
@@ -3709,7 +3711,7 @@ function runWizard(config, options) {
3709
3711
  (async () => {
3710
3712
  try {
3711
3713
  const installDir = options.installDir || process.cwd();
3712
- const { startTUI } = await import("./start-tui-Cbw0kVr3.js");
3714
+ const { startTUI } = await import("./start-tui-DetsuXHe.js");
3713
3715
  const { buildSession, RunPhase } = await import("./wizard-session-wPJtNl4c.js");
3714
3716
  const { TaskStreamPush } = await import("./task-stream-BQNSp0qR.js");
3715
3717
  const { PostHogDestination } = await import("./posthog-Cr37rnla.js");
@@ -3765,7 +3767,7 @@ function runWizard(config, options) {
3765
3767
  await activeTui.store.getGate("health-check");
3766
3768
  const skipAgent = config.run == null;
3767
3769
  if (skipAgent) {
3768
- const { getOrAskForProjectData } = await import("./setup-utils-CjKjaKcG.js").then((n) => n.r);
3770
+ const { getOrAskForProjectData } = await import("./setup-utils-DGnWKE9t.js").then((n) => n.r);
3769
3771
  const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
3770
3772
  signup: session.signup,
3771
3773
  ci: session.ci,
@@ -3780,7 +3782,7 @@ function runWizard(config, options) {
3780
3782
  projectId
3781
3783
  });
3782
3784
  } else {
3783
- const { runAgent } = await import("./agent-runner-D7hIITUf.js");
3785
+ const { runAgent } = await import("./agent-runner-djkxwCd9.js");
3784
3786
  await runAgent(config, activeTui.store.session);
3785
3787
  }
3786
3788
  const isDone = () => skipAgent ? activeTui.store.session.outroDismissed : activeTui.store.session.skillsComplete;
@@ -3857,10 +3859,10 @@ function runWizardCI(config, options) {
3857
3859
  (async () => {
3858
3860
  const path = await import("path");
3859
3861
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3860
- const { readEnvironment } = await import("./environment-CFXsie0G.js").then((n) => n.t);
3862
+ const { readEnvironment } = await import("./environment-CxkKJEfj.js").then((n) => n.t);
3861
3863
  const { readApiKeyFromEnv } = await import("./env-api-key-MlzJYAvt.js").then((n) => n.t);
3862
- const { configureLogFileFromEnvironment, logToFile } = await import("./debug-CDLYQOQh.js");
3863
- const { wizardAbort, WizardError } = await import("./wizard-abort-BPr0xo7i.js");
3864
+ const { configureLogFileFromEnvironment, logToFile } = await import("./debug-CyadC-pR.js");
3865
+ const { wizardAbort, WizardError } = await import("./wizard-abort-ChmzV0wB.js");
3864
3866
  configureLogFileFromEnvironment();
3865
3867
  const env = readEnvironment();
3866
3868
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -3911,7 +3913,7 @@ function runWizardCI(config, options) {
3911
3913
  })
3912
3914
  });
3913
3915
  }
3914
- const { runAgent } = await import("./agent-runner-D7hIITUf.js");
3916
+ const { runAgent } = await import("./agent-runner-djkxwCd9.js");
3915
3917
  await runAgent(config, session);
3916
3918
  } catch (error) {
3917
3919
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -4778,7 +4780,7 @@ async function runDoctorCI(options) {
4778
4780
  getUI().intro("Welcome to the PostHog setup wizard");
4779
4781
  getUI().log.info("Running posthog-doctor in CI mode");
4780
4782
  try {
4781
- const { getOrAskForProjectData } = await import("./setup-utils-CjKjaKcG.js").then((n) => n.r);
4783
+ const { getOrAskForProjectData } = await import("./setup-utils-DGnWKE9t.js").then((n) => n.r);
4782
4784
  const { host, accessToken, projectId } = await getOrAskForProjectData({
4783
4785
  signup: false,
4784
4786
  ci: true,
@@ -4795,7 +4797,7 @@ async function runDoctorCI(options) {
4795
4797
  for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
4796
4798
  process.exit(1);
4797
4799
  } catch (error) {
4798
- const { ApiError } = await import("./api-2zPZQONC.js").then((n) => n.n);
4800
+ const { ApiError } = await import("./api-CeVi1ZfZ.js").then((n) => n.n);
4799
4801
  const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
4800
4802
  getUI().log.error(`Doctor failed: ${message}`);
4801
4803
  process.exit(1);
@@ -4891,7 +4893,7 @@ function runSlackConnect(argv) {
4891
4893
  (async () => {
4892
4894
  const debug = argv.debug;
4893
4895
  try {
4894
- const { startTUI } = await import("./start-tui-Cbw0kVr3.js");
4896
+ const { startTUI } = await import("./start-tui-DetsuXHe.js");
4895
4897
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
4896
4898
  const tui = startTUI(VERSION, Program.SlackConnect);
4897
4899
  tui.store.session = buildSession({ debug });