@posthog/wizard 2.50.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/{add-mcp-server-to-clients-Bd8XRxzi.js → add-mcp-server-to-clients-DJyWMMGj.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-Bd8XRxzi.js.map → add-mcp-server-to-clients-DJyWMMGj.js.map} +1 -1
  3. package/dist/{agent-interface-C_aRBziP.js → agent-interface-DoFVHRFh.js} +30 -69
  4. package/dist/agent-interface-DoFVHRFh.js.map +1 -0
  5. package/dist/agent-prompt-loader-D-cPVoL5.js +275 -0
  6. package/dist/agent-prompt-loader-D-cPVoL5.js.map +1 -0
  7. package/dist/{agent-runner-NzzrOB02.js → agent-runner-B1qCtjid.js} +100 -318
  8. package/dist/agent-runner-B1qCtjid.js.map +1 -0
  9. package/dist/{analytics-CArgq7XO.js → analytics-BXz4SIuS.js} +33 -20
  10. package/dist/analytics-BXz4SIuS.js.map +1 -0
  11. package/dist/analytics-D2xds3nw.js +2 -0
  12. package/dist/{api-CX1g-14-.js → api-BaacjH-Y.js} +3 -3
  13. package/dist/{api-CX1g-14-.js.map → api-BaacjH-Y.js.map} +1 -1
  14. package/dist/bin.js +97 -91
  15. package/dist/bin.js.map +1 -1
  16. package/dist/bounded-fs-Cx-8nk-1.js +242 -0
  17. package/dist/bounded-fs-Cx-8nk-1.js.map +1 -0
  18. package/dist/{ci-install-BYThh_Gl.js → ci-install-D1Mum8Ah.js} +4 -4
  19. package/dist/{ci-install-BYThh_Gl.js.map → ci-install-D1Mum8Ah.js.map} +1 -1
  20. package/dist/commandments-BagyrYRW.js +2 -0
  21. package/dist/{commandments-DSNrOeOC.js → commandments-DiMtIz1o.js} +1 -1
  22. package/dist/{commandments-DSNrOeOC.js.map → commandments-DiMtIz1o.js.map} +1 -1
  23. package/dist/{debug-dX5JKcxf.js → debug-C3ZR1TVF.js} +14 -29
  24. package/dist/debug-C3ZR1TVF.js.map +1 -0
  25. package/dist/{debug-CdScMjI7.js → debug-DsSCOPe8.js} +1 -1
  26. package/dist/{defaults-CtWMmC8s.js → defaults-DAE9_QMn.js} +1 -1
  27. package/dist/{defaults-CtWMmC8s.js.map → defaults-DAE9_QMn.js.map} +1 -1
  28. package/dist/{env-api-key-C3LzH8Lr.js → env-api-key-DDVkPQmo.js} +1 -1
  29. package/dist/{env-api-key-C3LzH8Lr.js.map → env-api-key-DDVkPQmo.js.map} +1 -1
  30. package/dist/{environment-D-xSv8Xv.js → environment-Bi-zynk6.js} +4 -4
  31. package/dist/environment-Bi-zynk6.js.map +1 -0
  32. package/dist/{file-watcher-Z28w46F3.js → file-watcher-PmRIDAfM.js} +2 -2
  33. package/dist/{file-watcher-Z28w46F3.js.map → file-watcher-PmRIDAfM.js.map} +1 -1
  34. package/dist/{headless-ui-T-cv04Ne.js → headless-ui-C4X9lAOY.js} +2 -2
  35. package/dist/{headless-ui-T-cv04Ne.js.map → headless-ui-C4X9lAOY.js.map} +1 -1
  36. package/dist/{interactive-uhGISvkt.js → interactive-HM71vLQe.js} +2 -2
  37. package/dist/{interactive-uhGISvkt.js.map → interactive-HM71vLQe.js.map} +1 -1
  38. package/dist/mcp-D0Hpb_nk.js +64 -0
  39. package/dist/mcp-D0Hpb_nk.js.map +1 -0
  40. package/dist/{mcp-prompt-streaming-ByofAot4.js → mcp-prompt-streaming-Crk8qFlQ.js} +3 -3
  41. package/dist/{mcp-prompt-streaming-ByofAot4.js.map → mcp-prompt-streaming-Crk8qFlQ.js.map} +1 -1
  42. package/dist/{non-interactive-dGAp1rES.js → non-interactive-DdUe8lqX.js} +2 -2
  43. package/dist/{non-interactive-dGAp1rES.js.map → non-interactive-DdUe8lqX.js.map} +1 -1
  44. package/dist/{orchestrator-tools-9D5vTenD.js → orchestrator-tools-CpRruqZl.js} +3 -3
  45. package/dist/{orchestrator-tools-9D5vTenD.js.map → orchestrator-tools-CpRruqZl.js.map} +1 -1
  46. package/dist/{package-json-DCuoye-H.js → package-json-CDs1ZVKu.js} +1 -1
  47. package/dist/{package-json-DCuoye-H.js.map → package-json-CDs1ZVKu.js.map} +1 -1
  48. package/dist/{package-manager-D3M_H5Pk.js → package-manager-wkSzPJqW.js} +2 -2
  49. package/dist/{package-manager-D3M_H5Pk.js.map → package-manager-wkSzPJqW.js.map} +1 -1
  50. package/dist/{pi--w-M8eD-.js → pi-CGPjm4oE.js} +91 -140
  51. package/dist/pi-CGPjm4oE.js.map +1 -0
  52. package/dist/{playground-GURThvy5.js → playground-lg7h9GHG.js} +7 -7
  53. package/dist/{playground-GURThvy5.js.map → playground-lg7h9GHG.js.map} +1 -1
  54. package/dist/{posthog-integration-Dk1hbtRQ.js → posthog-integration-pnxhTbxw.js} +45 -38
  55. package/dist/posthog-integration-pnxhTbxw.js.map +1 -0
  56. package/dist/{posthog-DZZbziJ1.js → posthog-mgz-FQlS.js} +1 -1
  57. package/dist/{posthog-DZZbziJ1.js.map → posthog-mgz-FQlS.js.map} +1 -1
  58. package/dist/{provisioning-CJQwMFVo.js → provisioning-T4jtJqBa.js} +3 -3
  59. package/dist/{provisioning-CJQwMFVo.js.map → provisioning-T4jtJqBa.js.map} +1 -1
  60. package/dist/{queue-tools-DW-pUVKK.js → queue-tools-D7ctuzyo.js} +97 -10
  61. package/dist/queue-tools-D7ctuzyo.js.map +1 -0
  62. package/dist/{registry-CYNjgbAh.js → registry-CsFuKtXn.js} +272 -429
  63. package/dist/registry-CsFuKtXn.js.map +1 -0
  64. package/dist/{security-D9TV_nIO.js → security-YAaZfmHs.js} +4 -4
  65. package/dist/{security-D9TV_nIO.js.map → security-YAaZfmHs.js.map} +1 -1
  66. package/dist/{setup-utils-D5RLhAEe.js → setup-utils-DDzEnDxJ.js} +14 -17
  67. package/dist/setup-utils-DDzEnDxJ.js.map +1 -0
  68. package/dist/smoke-test.sh +1 -1
  69. package/dist/{start-tui-Dvk-0lGv.js → start-tui-pCi7WVAK.js} +72 -87
  70. package/dist/start-tui-pCi7WVAK.js.map +1 -0
  71. package/dist/{steps-CcRX3kDT.js → steps-DmsrBqb9.js} +7 -7
  72. package/dist/{steps-CcRX3kDT.js.map → steps-DmsrBqb9.js.map} +1 -1
  73. package/dist/{store-DkQLlZF9.js → store-BCRdtfOH.js} +5 -5
  74. package/dist/{store-DkQLlZF9.js.map → store-BCRdtfOH.js.map} +1 -1
  75. package/dist/{subagent-Dxh0Pwgv.js → subagent-jNXS8IPU.js} +2 -2
  76. package/dist/{subagent-Dxh0Pwgv.js.map → subagent-jNXS8IPU.js.map} +1 -1
  77. package/dist/{task-C-r2xQvb.js → task-CSmrfyNf.js} +30 -46
  78. package/dist/task-CSmrfyNf.js.map +1 -0
  79. package/dist/{task-stream-_e6Mf24V.js → task-stream-BZOjOhKu.js} +5 -5
  80. package/dist/{task-stream-_e6Mf24V.js.map → task-stream-BZOjOhKu.js.map} +1 -1
  81. package/dist/{tasks-BqpaakPz.js → tasks-BMgQt251.js} +2 -2
  82. package/dist/{tasks-BqpaakPz.js.map → tasks-BMgQt251.js.map} +1 -1
  83. package/dist/{telemetry-CeQm0f0H.js → telemetry-qeKIGkte.js} +3 -3
  84. package/dist/{telemetry-CeQm0f0H.js.map → telemetry-qeKIGkte.js.map} +1 -1
  85. package/dist/{terminal-2gT6ezna.js → terminal-tbxhJGlI.js} +13 -13
  86. package/dist/{terminal-2gT6ezna.js.map → terminal-tbxhJGlI.js.map} +1 -1
  87. package/dist/{tools-C5Lsz2zR.js → tools-DVnBIYFn.js} +10 -8
  88. package/dist/tools-DVnBIYFn.js.map +1 -0
  89. package/dist/{wizard-abort-D_Xcbesm.js → wizard-abort-AEhoDJ4P.js} +4 -4
  90. package/dist/{wizard-abort-D_Xcbesm.js.map → wizard-abort-AEhoDJ4P.js.map} +1 -1
  91. package/dist/{wizard-abort-CaKAS9_Z.js → wizard-abort-DHC_XStW.js} +1 -1
  92. package/dist/{wizard-session-tp4Zdbwl.js → wizard-session-BAZql11N.js} +1 -1
  93. package/dist/{wizard-session-tp4Zdbwl.js.map → wizard-session-BAZql11N.js.map} +1 -1
  94. package/dist/{wizard-session-DWHe83uk.js → wizard-session-C5lZPPEc.js} +1 -1
  95. package/dist/{yara-hooks-CGzlyuQA.js → yara-hooks-CKsVxWiN.js} +139 -56
  96. package/dist/yara-hooks-CKsVxWiN.js.map +1 -0
  97. package/dist/yara-hooks-DWRdZQuG.js +2 -0
  98. package/package.json +7 -7
  99. package/dist/agent-interface-C_aRBziP.js.map +0 -1
  100. package/dist/agent-runner-NzzrOB02.js.map +0 -1
  101. package/dist/analytics-C7QE7PWl.js +0 -2
  102. package/dist/analytics-CArgq7XO.js.map +0 -1
  103. package/dist/commandments-qTW7pwaT.js +0 -2
  104. package/dist/debug-dX5JKcxf.js.map +0 -1
  105. package/dist/environment-D-xSv8Xv.js.map +0 -1
  106. package/dist/file-utils-BpTQ4NFR.js +0 -140
  107. package/dist/file-utils-BpTQ4NFR.js.map +0 -1
  108. package/dist/mcp-B9NosVx4.js +0 -104
  109. package/dist/mcp-B9NosVx4.js.map +0 -1
  110. package/dist/pi--w-M8eD-.js.map +0 -1
  111. package/dist/posthog-integration-Dk1hbtRQ.js.map +0 -1
  112. package/dist/queue-tools-DW-pUVKK.js.map +0 -1
  113. package/dist/registry-CYNjgbAh.js.map +0 -1
  114. package/dist/setup-utils-D5RLhAEe.js.map +0 -1
  115. package/dist/start-tui-Dvk-0lGv.js.map +0 -1
  116. package/dist/task-C-r2xQvb.js.map +0 -1
  117. package/dist/tools-C5Lsz2zR.js.map +0 -1
  118. package/dist/yara-hooks-CGzlyuQA.js.map +0 -1
  119. package/dist/yara-hooks-CQaKM0f4.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-BXz4SIuS.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 payloads: Record<string, unknown> = {},\n): { flags: Record<string, string>; payloads: Record<string, unknown> } {\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, payloads };\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return { flags, payloads };\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 mergedFlags = { ...flags };\n const mergedPayloads = { ...payloads };\n for (const [key, value] of Object.entries(overrides)) {\n // An object/array override is a flag payload: the flag reads 'true' and\n // the value rides the payload channel, matching a payload-carrying flag.\n if (typeof value === 'object' && value !== null) {\n mergedFlags[key] = 'true';\n mergedPayloads[key] = value;\n } else {\n mergedFlags[key] = String(value);\n }\n }\n logToFile('[flags] CI overrides applied', overrides);\n return { flags: mergedFlags, payloads: mergedPayloads };\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 WIZARD_FLAG_KEYS,\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, RUN_SURFACE } from '@env';\nimport { VERSION } from '@lib/version';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * The invocation, reduced to flag-safe strings: the command word (first\n * positional, 'default' for the bare flow) and the sorted option NAMES.\n * Option values never leave the machine — they carry paths, emails, keys.\n */\nfunction invocationProperties(): { command: string; cli_flags: string } {\n const args = process.argv.slice(2);\n const command = args.find((a) => !a.startsWith('-')) ?? 'default';\n const flags = [\n ...new Set(\n args\n .filter((a) => a.startsWith('--'))\n .map((a) => a.slice(2).split('=')[0]),\n ),\n ].sort();\n return { command, cli_flags: flags.join(',') };\n}\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\nconst WIZARD_FLAGS: ReadonlySet<string> = new Set(WIZARD_FLAG_KEYS);\n\n// Widen back to the SDK's shape — a filter on `true` never matches `'true'`.\nfunction flagResponseValue(value: string): string | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return value;\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 activeFlagPayloads: Record<string, unknown> = {};\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\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 // The SDK captures this one itself, bypassing capture(), so tags merge here.\n if (event.event === '$feature_flag_called') {\n event.properties = { ...this.tags, ...(event.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 / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\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 /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\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 this.activeFlagPayloads = {};\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n // Environment facts flag conditions can scope on — evaluation-time only,\n // never persisted onto the person. `version` gates an experiment to\n // releases that implement it (a condition on a property older builds\n // don't send silently never matches them); `run_surface`/`build` scope\n // by invocation surface; `command`/`cli_flags` by subcommand; `os`/\n // `node_major` by platform.\n return {\n $app_name: this.appName,\n version: VERSION,\n run_surface: RUN_SURFACE,\n build: String(this.tags.build ?? 'dev'),\n os: process.platform,\n node_major: process.versions.node.split('.')[0],\n ...invocationProperties(),\n ...this.personProperties,\n };\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 ...this.wizardFlagFeatureProperties(),\n ...properties,\n },\n });\n }\n\n // Built from the resolved map, not the SDK snapshot: a CI-forced variant must own its events.\n private wizardFlagFeatureProperties(): Record<string, unknown> {\n if (this.activeFlags === null) return {};\n const props: Record<string, unknown> = {};\n const active: string[] = [];\n for (const [key, value] of Object.entries(this.activeFlags)) {\n if (!WIZARD_FLAGS.has(key)) continue;\n const resolved = flagResponseValue(value);\n props[`$feature/${key}`] = resolved;\n if (resolved !== false) active.push(key);\n }\n if (active.length > 0) props.$active_feature_flags = active.sort();\n return props;\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 /**\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 // Only a getFlag read records an exposure; the bulk response records none.\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n const payloads: Record<string, unknown> = {};\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 evaluation = await this.client.evaluateFlags(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n for (const key of WIZARD_FLAG_KEYS) {\n const value = evaluation.getFlag(key);\n if (value === undefined) continue;\n out[key] = String(value);\n const payload = evaluation.getFlagPayload(key);\n if (payload !== undefined) payloads[key] = payload;\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 const merged = applyCiFlagOverrides(out, payloads);\n this.activeFlags = merged.flags;\n this.activeFlagPayloads = merged.payloads;\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n /** Flag payloads from the same snapshot; empty until the flags are fetched. */\n getWizardFlagPayloads(): Record<string, unknown> {\n return this.activeFlagPayloads;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\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,OACA,WAAoC,EAAE,EACgC;AAI3B,QAAO;EAAE;EAAO;EAAU;;;;;;;;;AAuCvE,SAAgB,sBAAyC;AACZ,QAAO,EAAE;;;;;;;;;AC7CtD,SAAS,uBAA+D;CACtE,MAAM,OAAO,QAAQ,KAAK,MAAM,EAAE;AASlC,QAAO;EAAE,SARO,KAAK,MAAM,MAAM,CAAC,EAAE,WAAW,IAAI,CAAC,IAAI;EAQtC,WAPJ,CACZ,GAAG,IAAI,IACL,KACG,QAAQ,MAAM,EAAE,WAAW,KAAK,CAAC,CACjC,KAAK,MAAM,EAAE,MAAM,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,CACxC,CACF,CAAC,MAAM,CAC2B,KAAK,IAAI;EAAE;;;;;;AAOhD,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,MAAM,eAAoC,IAAI,IAAI,iBAAiB;AAGnE,SAAS,kBAAkB,OAAiC;AAC1D,KAAI,UAAU,OAAQ,QAAO;AAC7B,KAAI,UAAU,QAAS,QAAO;AAC9B,QAAO;;AAGT,IAAa,YAAb,MAAuB;CACrB;CACA,OACE,EAAE;CACJ;CACA;CACA;CACA,YAAmC;CACnC,UAAkB;CAClB,cAAqD;CACrD,qBAAsD,EAAE;CACxD,SAAyC,EAAE;CAC3C,mBAAmD,EAAE;CACrD,oBAA4B;CAE5B,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;;AAGpD,QAAI,MAAM,UAAU,uBAClB,OAAM,aAAa;KAAE,GAAG,KAAK;KAAM,GAAI,MAAM,cAAc,EAAE;KAAG;AAElE,WAAO;;GAEV,CAAC;AAEF,OAAK,OAAO,EAAE,WAAW,KAAK,SAAS;AAMvC,OAAK,KAAK,QAA8B;AAExC,OAAK,KAAK,cAAc;AAExB,OAAK,cAAcA,IAAQ;AAS3B,OAAK,SAASA,IAAQ;AACtB,OAAK,KAAK,SAAS,KAAK;AAExB,OAAK,aAAa,KAAA;;;CAIpB,IAAI,QAAgB;AAClB,SAAO,KAAK;;;CAId,IAAI,QAAgB;AAClB,SAAO,OAAO,KAAK,KAAK,SAAS,MAAM;;;;;;;;;;CAWzC,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;AACnB,OAAK,qBAAqB,EAAE;;;CAI9B,uBAAuD;AAOrD,SAAO;GACL,WAAW,KAAK;GAChB,SAAS;GACT,aAAa;GACb,OAAO,OAAO,KAAK,KAAK,SAAS,MAAM;GACvC,IAAI,QAAQ;GACZ,YAAY,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;GAC7C,GAAG,sBAAsB;GACzB,GAAG,KAAK;GACT;;CAGH,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,KAAK,6BAA6B;IACrC,GAAG;IACJ;GACF,CAAC;;CAIJ,8BAA+D;AAC7D,MAAI,KAAK,gBAAgB,KAAM,QAAO,EAAE;EACxC,MAAM,QAAiC,EAAE;EACzC,MAAM,SAAmB,EAAE;AAC3B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,EAAE;AAC3D,OAAI,CAAC,aAAa,IAAI,IAAI,CAAE;GAC5B,MAAM,WAAW,kBAAkB,MAAM;AACzC,SAAM,YAAY,SAAS;AAC3B,OAAI,aAAa,MAAO,QAAO,KAAK,IAAI;;AAE1C,MAAI,OAAO,SAAS,EAAG,OAAM,wBAAwB,OAAO,MAAM;AAClE,SAAO;;;;;;CAOT,cAAc,WAAmB,YAA4C;AAC3E,OAAK,QAAQ,WAAW,aAAa,WAAW;;;;;;;;CASlD,MAAM,QAAuB;AAC3B,QAAM,KAAK,OAAO,UAAU;;;;;;;CAS9B,MAAM,uBAAwD;AAC5D,MAAI,KAAK,gBAAgB,KACvB,QAAO,KAAK;EAEd,MAAM,MAA8B,EAAE;EACtC,MAAM,WAAoC,EAAE;AAC5C,MAAI;GACF,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,aAAU,yBAAyB;IACjC;IACA,YAAY,KAAK,eAAe,KAAA;IAChC,kBAAkB,KAAK,sBAAsB;IAC9C,CAAC;GACF,MAAM,aAAa,MAAM,KAAK,OAAO,cAAc,YAAY,EAC7D,kBAAkB,KAAK,sBAAsB,EAC9C,CAAC;AACF,QAAK,MAAM,OAAO,kBAAkB;IAClC,MAAM,QAAQ,WAAW,QAAQ,IAAI;AACrC,QAAI,UAAU,KAAA,EAAW;AACzB,QAAI,OAAO,OAAO,MAAM;IACxB,MAAM,UAAU,WAAW,eAAe,IAAI;AAC9C,QAAI,YAAY,KAAA,EAAW,UAAS,OAAO;;WAEtC,OAAO;AACd,SAAM,oCAAoC,MAAM;AAChD,QAAK,iBACH,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,MAAM,CAAC,EACzD,EAAE,MAAM,iBAAiB,CAC1B;;EAKH,MAAM,SAAS,qBAAqB,KAAK,SAAS;AAClD,OAAK,cAAc,OAAO;AAC1B,OAAK,qBAAqB,OAAO;AACjC,YAAU,qBAAqB,KAAK,YAAY;AAChD,SAAO,KAAK;;;CAId,wBAAiD;AAC/C,SAAO,KAAK;;CAGd,MAAM,SAAS,QAA2C;AACxD,MAAI,OAAO,KAAK,KAAK,KAAK,CAAC,WAAW,EACpC;AAOF,MAAI,KAAK,kBACP;AAEF,OAAK,oBAAoB;AAEzB,OAAK,OAAO,QAAQ;GAClB,YAAY,KAAK,cAAc,KAAK;GACpC,OAAO;GACP,YAAY;IAEV,GAAG,KAAK;IACR,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"}
@@ -0,0 +1,2 @@
1
+ import { n as analytics } from "./analytics-BXz4SIuS.js";
2
+ export { analytics };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { gt as WIZARD_USER_AGENT } from "./debug-dX5JKcxf.js";
3
- import { n as analytics } from "./analytics-CArgq7XO.js";
2
+ import { dt as WIZARD_USER_AGENT } from "./debug-C3ZR1TVF.js";
3
+ import { n as analytics } from "./analytics-BXz4SIuS.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-CX1g-14-.js.map
173
+ //# sourceMappingURL=api-BaacjH-Y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-CX1g-14-.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-BaacjH-Y.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,19 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import { B as Integration, Et as regionOption, K as POSTHOG_DOCS_URL, Tt as isHeadless, a as getLogFilePath, bt as VERSION, f as getUI, gt as WIZARD_USER_AGENT, m as LoggingUI, p as setUI, r as debug, s as logToFile, vt as getSkillsBaseUrl, wt as headlessOption } from "./debug-dX5JKcxf.js";
3
- import { n as analytics } from "./analytics-CArgq7XO.js";
4
- import { r as setEntryCommand } from "./telemetry-CeQm0f0H.js";
5
- import { n as isUsingTypeScript } from "./setup-utils-D5RLhAEe.js";
6
- import { o as handleApiError } from "./api-CX1g-14-.js";
7
- import "./wizard-session-tp4Zdbwl.js";
8
- import { r as runCleanups } from "./wizard-abort-D_Xcbesm.js";
9
- import { n as isNonInteractiveEnvironment } from "./environment-D-xSv8Xv.js";
10
- import { n as runAgent, o as authenticate } from "./agent-runner-NzzrOB02.js";
11
- import { l as recoverOrphanedSettingsBackups, p as AgentSignals, v as WIZARD_TOOL_NAMES, x as fetchSkillMenu } from "./agent-interface-C_aRBziP.js";
12
- import { _ as AUDIT_CHECKS_FILE, h as SETUP_REPORT_FILE, v as AUDIT_CHECKS_KEY, y as AUDIT_REPORT_FILE } from "./yara-hooks-CGzlyuQA.js";
13
- import { i as SPINNER_MESSAGE } from "./registry-CYNjgbAh.js";
14
- import { S as gatherFrameworkContext, _ as detectWarehousePrerequisites, a as LINE_CHART_BLOCK, g as WAREHOUSE_ABORT_CASES, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as getDetectedWarehouseSources, x as resolveProjectDir, y as detectIntegrationProjects } from "./posthog-integration-Dk1hbtRQ.js";
15
- import { t as IGNORED_DIRS } from "./file-utils-BpTQ4NFR.js";
16
- import { n as readApiKeyFromEnv } from "./env-api-key-C3LzH8Lr.js";
2
+ import { H as POSTHOG_DOCS_URL, I as Integration, a as getLogFilePath, bt as regionOption, dt as WIZARD_USER_AGENT, f as getUI, ft as getSkillsBaseUrl, m as LoggingUI, mt as VERSION, p as setUI, r as debug, s as logToFile, vt as headlessOption, yt as isHeadless } from "./debug-C3ZR1TVF.js";
3
+ import { n as analytics } from "./analytics-BXz4SIuS.js";
4
+ import { r as setEntryCommand } from "./telemetry-qeKIGkte.js";
5
+ import { a as walkProjectFiles, i as safeReadFile } from "./bounded-fs-Cx-8nk-1.js";
6
+ import { n as isUsingTypeScript } from "./setup-utils-DDzEnDxJ.js";
7
+ import { o as handleApiError } from "./api-BaacjH-Y.js";
8
+ import "./wizard-session-BAZql11N.js";
9
+ import { r as runCleanups } from "./wizard-abort-AEhoDJ4P.js";
10
+ import { n as isNonInteractiveEnvironment } from "./environment-Bi-zynk6.js";
11
+ import { n as runAgent, o as authenticate } from "./agent-runner-B1qCtjid.js";
12
+ import { _ as WIZARD_TOOL_NAMES, b as fetchSkillMenu, l as recoverOrphanedSettingsBackups, p as AgentSignals } from "./agent-interface-DoFVHRFh.js";
13
+ import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-CKsVxWiN.js";
14
+ import { i as SPINNER_MESSAGE } from "./registry-CsFuKtXn.js";
15
+ import { S as gatherFrameworkContext, _ as detectWarehousePrerequisites, a as LINE_CHART_BLOCK, g as WAREHOUSE_ABORT_CASES, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as getDetectedWarehouseSources, x as resolveProjectDir, y as detectIntegrationProjects } from "./posthog-integration-pnxhTbxw.js";
16
+ import { n as readApiKeyFromEnv } from "./env-api-key-DDVkPQmo.js";
17
17
  import { satisfies } from "semver";
18
18
  import yargs from "yargs";
19
19
  import { hideBin } from "yargs/helpers";
@@ -200,7 +200,7 @@ function runProvision(argv) {
200
200
  }
201
201
  async function provision({ email, region, name, baseUrl, jsonMode }) {
202
202
  try {
203
- const { provisionNewAccount } = await import("./provisioning-CJQwMFVo.js").then((n) => n.n);
203
+ const { provisionNewAccount } = await import("./provisioning-T4jtJqBa.js").then((n) => n.n);
204
204
  if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
205
205
  emitResult(await provisionNewAccount(email, name, region, { baseUrl }), jsonMode);
206
206
  process.exit(0);
@@ -267,73 +267,64 @@ const basicIntegrationCommand = {
267
267
  setEntryCommand("integrate");
268
268
  (async () => {
269
269
  if (isHeadless(argv)) {
270
- const { runHeadlessInstall } = await import("./ci-install-BYThh_Gl.js");
270
+ const { runHeadlessInstall } = await import("./ci-install-D1Mum8Ah.js");
271
271
  return runHeadlessInstall(argv);
272
272
  }
273
273
  if (argv.ci) {
274
- const { runCIInstall } = await import("./ci-install-BYThh_Gl.js");
274
+ const { runCIInstall } = await import("./ci-install-D1Mum8Ah.js");
275
275
  return runCIInstall(argv);
276
276
  }
277
277
  if (isNonInteractiveEnvironment()) {
278
- const { failNonInteractive } = await import("./non-interactive-dGAp1rES.js");
278
+ const { failNonInteractive } = await import("./non-interactive-DdUe8lqX.js");
279
279
  return failNonInteractive();
280
280
  }
281
281
  if (argv.playground) {
282
- const { runPlayground } = await import("./playground-GURThvy5.js");
282
+ const { runPlayground } = await import("./playground-lg7h9GHG.js");
283
283
  return runPlayground();
284
284
  }
285
- const { runInteractive } = await import("./interactive-uhGISvkt.js");
285
+ const { runInteractive } = await import("./interactive-HM71vLQe.js");
286
286
  runInteractive(argv);
287
287
  })();
288
288
  }
289
289
  };
290
290
  //#endregion
291
291
  //#region src/lib/programs/shared/package-scanning.ts
292
- const POSTHOG_SDKS = [
292
+ const POSTHOG_SDKS = new Set([
293
293
  "posthog-js",
294
294
  "posthog-node",
295
295
  "posthog-react-native",
296
296
  "posthog-android",
297
297
  "posthog-ios"
298
- ];
299
- const STRIPE_SDKS = [
298
+ ]);
299
+ const STRIPE_SDKS = new Set([
300
300
  "stripe",
301
301
  "@stripe/stripe-js",
302
302
  "@stripe/react-stripe-js"
303
- ];
303
+ ]);
304
+ const MAX_PACKAGE_MATCHES = 500;
304
305
  /**
305
- * Recursively find all package.json files under installDir (max depth 3),
306
- * skipping common ignored directories. Returns matches with detected SDKs.
306
+ * Find all package.json files under installDir via the shared bounded walk
307
+ * (depth cap, ignored dirs, symlink-loop protection, per-dir entry cap).
308
+ * Returns matches with detected SDKs.
307
309
  */
308
310
  function findPackageJsons(installDir, maxDepth = 3) {
309
311
  const matches = [];
310
- function scan(dir, depth) {
311
- if (depth > maxDepth) return;
312
- let entries;
312
+ walkProjectFiles(installDir, (name, fullPath) => {
313
+ if (name !== "package.json" || matches.length >= MAX_PACKAGE_MATCHES) return;
314
+ const content = safeReadFile(fullPath);
315
+ if (content === null) return;
313
316
  try {
314
- entries = readdirSync(dir, { withFileTypes: true });
315
- } catch {
316
- return;
317
- }
318
- for (const entry of entries) {
319
- if (entry.name.startsWith(".") && entry.name !== ".") continue;
320
- if (IGNORED_DIRS.has(entry.name)) continue;
321
- const fullPath = join(dir, entry.name);
322
- if (entry.isFile() && entry.name === "package.json") try {
323
- const pkg = JSON.parse(readFileSync(fullPath, "utf-8"));
324
- const depNames = [...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})];
325
- const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.includes(d));
326
- const stripeSdks = depNames.filter((d) => STRIPE_SDKS.includes(d));
327
- matches.push({
328
- path: relative(installDir, fullPath) || "package.json",
329
- posthogSdks,
330
- stripeSdks
331
- });
332
- } catch {}
333
- else if (entry.isDirectory()) scan(fullPath, depth + 1);
334
- }
335
- }
336
- scan(installDir, 0);
317
+ const pkg = JSON.parse(content);
318
+ const depNames = [...Object.keys(pkg.dependencies ?? {}), ...Object.keys(pkg.devDependencies ?? {})];
319
+ const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.has(d));
320
+ const stripeSdks = depNames.filter((d) => STRIPE_SDKS.has(d));
321
+ matches.push({
322
+ path: relative(installDir, fullPath) || "package.json",
323
+ posthogSdks,
324
+ stripeSdks
325
+ });
326
+ } catch {}
327
+ }, maxDepth);
337
328
  return matches;
338
329
  }
339
330
  //#endregion
@@ -1797,13 +1788,14 @@ const DISPLAY_NAME = {
1797
1788
  rollup: "Rollup"
1798
1789
  };
1799
1790
  /**
1800
- * Variants the wizard can wire up source-map upload for automatically. The
1801
- * native variants (react-native, flutter) are recognised but not yet
1802
- * automatable, so the agentic picker treats them as non-instrumentable.
1791
+ * Variants the wizard can wire up source-map upload for automatically. React
1792
+ * Native is recognised but not yet automatable, so the agentic picker treats
1793
+ * it as non-instrumentable.
1803
1794
  */
1804
1795
  const AUTOMATABLE_VARIANTS = [
1805
1796
  "android",
1806
1797
  "ios",
1798
+ "flutter",
1807
1799
  "web",
1808
1800
  "nextjs",
1809
1801
  "node",
@@ -1816,9 +1808,16 @@ const AUTOMATABLE_VARIANTS = [
1816
1808
  ];
1817
1809
  /**
1818
1810
  * Variants the wizard pre-installs a machine-global `posthog-cli` for — their
1819
- * build shells out to it with no npx / local-dep fallback. JS variants stay out.
1811
+ * build shells out to it with no npx / local-dep fallback. JS variants stay
1812
+ * out. Flutter counts here despite emitting plain `.js.map` files: a Flutter
1813
+ * project has no `package.json`, so there is no npx or local dependency to
1814
+ * fall back to when the post-build step invokes the CLI.
1820
1815
  */
1821
- const VARIANTS_REQUIRING_POSTHOG_CLI = new Set(["ios", "android"]);
1816
+ const VARIANTS_REQUIRING_POSTHOG_CLI = new Set([
1817
+ "ios",
1818
+ "android",
1819
+ "flutter"
1820
+ ]);
1822
1821
  /** `[ABORT] <reason>` cases the source maps skill can emit. */
1823
1822
  const SOURCE_MAPS_ABORT_CASES = [{
1824
1823
  match: /^no posthog sdk detected$/i,
@@ -2663,23 +2662,30 @@ const WALK_MAX_DEPTH = 2;
2663
2662
  */
2664
2663
  function scanDirs(installDir) {
2665
2664
  const rels = new Set(POSTHOG_DIRS);
2666
- const walk = (rel, depth) => {
2665
+ const stack = [{
2666
+ rel: ".",
2667
+ depth: 0
2668
+ }];
2669
+ while (stack.length > 0) {
2670
+ const { rel, depth } = stack.pop();
2667
2671
  rels.add(rel);
2668
- if (depth >= WALK_MAX_DEPTH) return;
2672
+ if (depth >= WALK_MAX_DEPTH) continue;
2669
2673
  let entries;
2670
2674
  try {
2671
2675
  entries = readdirSync(join(installDir, rel), { withFileTypes: true });
2672
2676
  } catch {
2673
- return;
2677
+ continue;
2674
2678
  }
2675
2679
  for (const e of entries) {
2676
2680
  if (!e.isDirectory()) continue;
2677
2681
  if (e.name.startsWith(".") || WALK_SKIP_DIRS.has(e.name)) continue;
2678
2682
  if (e.name.endsWith(".xcodeproj") || e.name.endsWith(".xcworkspace")) continue;
2679
- walk(rel === "." ? e.name : `${rel}/${e.name}`, depth + 1);
2683
+ stack.push({
2684
+ rel: rel === "." ? e.name : `${rel}/${e.name}`,
2685
+ depth: depth + 1
2686
+ });
2680
2687
  }
2681
- };
2682
- walk(".", 0);
2688
+ }
2683
2689
  return [...rels];
2684
2690
  }
2685
2691
  /**
@@ -3787,13 +3793,13 @@ const mcpAddCommand = {
3787
3793
  function runMcpAdd(argv) {
3788
3794
  const features = parseFeatures(argv.features);
3789
3795
  (async () => {
3790
- const { readApiKeyFromEnv } = await import("./env-api-key-C3LzH8Lr.js").then((n) => n.t);
3796
+ const { readApiKeyFromEnv } = await import("./env-api-key-DDVkPQmo.js").then((n) => n.t);
3791
3797
  const apiKey = argv.apiKey || readApiKeyFromEnv();
3792
3798
  const debug = argv.debug;
3793
3799
  const localMcp = argv.local;
3794
3800
  try {
3795
- const { startTUI } = await import("./start-tui-Dvk-0lGv.js");
3796
- const { buildSession } = await import("./wizard-session-DWHe83uk.js");
3801
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3802
+ const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3797
3803
  const tui = startTUI(VERSION, Program.McpAdd);
3798
3804
  tui.store.session = buildSession({
3799
3805
  debug,
@@ -3805,7 +3811,7 @@ function runMcpAdd(argv) {
3805
3811
  } catch (error) {
3806
3812
  if (!isTUIUnavailable(error)) throw error;
3807
3813
  setUI(new LoggingUI());
3808
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-Bd8XRxzi.js").then((n) => n.r);
3814
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-DJyWMMGj.js").then((n) => n.r);
3809
3815
  await addMCPServerToClientsStep({
3810
3816
  local: localMcp,
3811
3817
  features,
@@ -3844,8 +3850,8 @@ function runMcpRemove(argv) {
3844
3850
  const debug = argv.debug;
3845
3851
  const localMcp = argv.local;
3846
3852
  try {
3847
- const { startTUI } = await import("./start-tui-Dvk-0lGv.js");
3848
- const { buildSession } = await import("./wizard-session-DWHe83uk.js");
3853
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3854
+ const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3849
3855
  const tui = startTUI(VERSION, Program.McpRemove);
3850
3856
  tui.store.session = buildSession({
3851
3857
  debug,
@@ -3854,7 +3860,7 @@ function runMcpRemove(argv) {
3854
3860
  });
3855
3861
  } catch {
3856
3862
  setUI(new LoggingUI());
3857
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-Bd8XRxzi.js").then((n) => n.r);
3863
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-DJyWMMGj.js").then((n) => n.r);
3858
3864
  await removeMCPServerFromClientsStep({ local: localMcp });
3859
3865
  }
3860
3866
  })();
@@ -3876,8 +3882,8 @@ function runMcpTutorial(argv) {
3876
3882
  const debug = argv.debug;
3877
3883
  const localMcp = argv.local;
3878
3884
  try {
3879
- const { startTUI } = await import("./start-tui-Dvk-0lGv.js");
3880
- const { buildSession } = await import("./wizard-session-DWHe83uk.js");
3885
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3886
+ const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3881
3887
  const tui = startTUI(VERSION, Program.McpTutorial);
3882
3888
  tui.store.session = buildSession({
3883
3889
  debug,
@@ -3957,10 +3963,10 @@ function runWizard(config, options) {
3957
3963
  (async () => {
3958
3964
  try {
3959
3965
  const installDir = options.installDir || process.cwd();
3960
- const { startTUI } = await import("./start-tui-Dvk-0lGv.js");
3961
- const { buildSession, RunPhase } = await import("./wizard-session-DWHe83uk.js");
3962
- const { TaskStreamPush } = await import("./task-stream-_e6Mf24V.js");
3963
- const { PostHogDestination } = await import("./posthog-DZZbziJ1.js");
3966
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3967
+ const { buildSession, RunPhase } = await import("./wizard-session-C5lZPPEc.js");
3968
+ const { TaskStreamPush } = await import("./task-stream-BZOjOhKu.js");
3969
+ const { PostHogDestination } = await import("./posthog-mgz-FQlS.js");
3964
3970
  tui = startTUI(WIZARD_VERSION, config.id);
3965
3971
  const activeTui = tui;
3966
3972
  const session = buildSession({
@@ -4025,7 +4031,7 @@ function runWizard(config, options) {
4025
4031
  if (shown(step)) await advanceStep(step, activeTui.store, config);
4026
4032
  }
4027
4033
  else if (skipAgent) {
4028
- const { getOrAskForProjectData } = await import("./setup-utils-D5RLhAEe.js").then((n) => n.r);
4034
+ const { getOrAskForProjectData } = await import("./setup-utils-DDzEnDxJ.js").then((n) => n.r);
4029
4035
  const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
4030
4036
  signup: session.signup,
4031
4037
  ci: session.ci,
@@ -4126,11 +4132,11 @@ function runNonInteractive(config, options, mode) {
4126
4132
  analytics.setTag("build", mode);
4127
4133
  (async () => {
4128
4134
  const path = await import("path");
4129
- const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-DWHe83uk.js");
4130
- const { readEnvironment } = await import("./environment-D-xSv8Xv.js").then((n) => n.t);
4131
- const { readApiKeyFromEnv } = await import("./env-api-key-C3LzH8Lr.js").then((n) => n.t);
4132
- const { configureLogFileFromEnvironment, logToFile } = await import("./debug-CdScMjI7.js");
4133
- const { wizardAbort, WizardError } = await import("./wizard-abort-CaKAS9_Z.js");
4135
+ const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-C5lZPPEc.js");
4136
+ const { readEnvironment } = await import("./environment-Bi-zynk6.js").then((n) => n.t);
4137
+ const { readApiKeyFromEnv } = await import("./env-api-key-DDVkPQmo.js").then((n) => n.t);
4138
+ const { configureLogFileFromEnvironment, logToFile } = await import("./debug-DsSCOPe8.js");
4139
+ const { wizardAbort, WizardError } = await import("./wizard-abort-DHC_XStW.js");
4134
4140
  configureLogFileFromEnvironment();
4135
4141
  const env = readEnvironment();
4136
4142
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -4162,9 +4168,9 @@ function runNonInteractive(config, options, mode) {
4162
4168
  let store = null;
4163
4169
  let taskStream = null;
4164
4170
  if (mode === "headless") {
4165
- const { WizardStore } = await import("./store-DkQLlZF9.js").then((n) => n.n);
4166
- const { HeadlessUI } = await import("./headless-ui-T-cv04Ne.js");
4167
- const { TaskStreamPush, PostHogDestination } = await import("./task-stream-_e6Mf24V.js");
4171
+ const { WizardStore } = await import("./store-BCRdtfOH.js").then((n) => n.n);
4172
+ const { HeadlessUI } = await import("./headless-ui-C4X9lAOY.js");
4173
+ const { TaskStreamPush, PostHogDestination } = await import("./task-stream-BZOjOhKu.js");
4168
4174
  store = new WizardStore(config.id);
4169
4175
  store.session = session;
4170
4176
  setUI(new HeadlessUI(store));
@@ -4220,7 +4226,7 @@ function runNonInteractive(config, options, mode) {
4220
4226
  });
4221
4227
  }
4222
4228
  }
4223
- const { runAgent } = await import("./agent-runner-NzzrOB02.js").then((n) => n.t);
4229
+ const { runAgent } = await import("./agent-runner-B1qCtjid.js").then((n) => n.t);
4224
4230
  await runAgent(config, session);
4225
4231
  await settleStream(RunPhase.Completed);
4226
4232
  } catch (error) {
@@ -5163,7 +5169,7 @@ async function runDoctorCI(options) {
5163
5169
  getUI().intro("Welcome to the PostHog setup wizard");
5164
5170
  getUI().log.info("Running posthog-doctor in CI mode");
5165
5171
  try {
5166
- const { getOrAskForProjectData } = await import("./setup-utils-D5RLhAEe.js").then((n) => n.r);
5172
+ const { getOrAskForProjectData } = await import("./setup-utils-DDzEnDxJ.js").then((n) => n.r);
5167
5173
  const { host, accessToken, projectId } = await getOrAskForProjectData({
5168
5174
  signup: false,
5169
5175
  ci: true,
@@ -5181,7 +5187,7 @@ async function runDoctorCI(options) {
5181
5187
  for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
5182
5188
  process.exit(1);
5183
5189
  } catch (error) {
5184
- const { ApiError } = await import("./api-CX1g-14-.js").then((n) => n.n);
5190
+ const { ApiError } = await import("./api-BaacjH-Y.js").then((n) => n.n);
5185
5191
  const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
5186
5192
  getUI().log.error(`Doctor failed: ${message}`);
5187
5193
  process.exit(1);
@@ -5263,8 +5269,8 @@ function runSlackConnect(argv) {
5263
5269
  (async () => {
5264
5270
  const debug = argv.debug;
5265
5271
  try {
5266
- const { startTUI } = await import("./start-tui-Dvk-0lGv.js");
5267
- const { buildSession } = await import("./wizard-session-DWHe83uk.js");
5272
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
5273
+ const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
5268
5274
  const tui = startTUI(VERSION, Program.SlackConnect);
5269
5275
  tui.store.session = buildSession({
5270
5276
  debug,