@posthog/wizard 2.29.0 → 2.30.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 (53) hide show
  1. package/dist/{add-mcp-server-to-clients-B6Pj4IKt.js → add-mcp-server-to-clients-D0G4cmPf.js} +4 -4
  2. package/dist/{add-mcp-server-to-clients-B6Pj4IKt.js.map → add-mcp-server-to-clients-D0G4cmPf.js.map} +1 -1
  3. package/dist/{agent-interface-CVW8H9eF.js → agent-interface-CYFyWCMj.js} +26 -14
  4. package/dist/{agent-interface-CVW8H9eF.js.map → agent-interface-CYFyWCMj.js.map} +1 -1
  5. package/dist/{agent-runner-VzTpPaVT.js → agent-runner-HTfFCUrR.js} +11 -10
  6. package/dist/{agent-runner-VzTpPaVT.js.map → agent-runner-HTfFCUrR.js.map} +1 -1
  7. package/dist/{analytics-DvDjbNmK.js → analytics-CdT0VV8s.js} +2 -2
  8. package/dist/{analytics-DvDjbNmK.js.map → analytics-CdT0VV8s.js.map} +1 -1
  9. package/dist/{api-DfpSG5xU.js → api-D9CerM6x.js} +3 -3
  10. package/dist/{api-DfpSG5xU.js.map → api-D9CerM6x.js.map} +1 -1
  11. package/dist/bin.js +33 -32
  12. package/dist/bin.js.map +1 -1
  13. package/dist/{ci-install-Bzfo3nON.js → ci-install-CTydrjHu.js} +4 -4
  14. package/dist/{ci-install-Bzfo3nON.js.map → ci-install-CTydrjHu.js.map} +1 -1
  15. package/dist/{debug-HQ0NrBA2.js → debug-Bmq9KH4W.js} +1 -1
  16. package/dist/{debug-CMZ7kqW1.js → debug-D9giWww2.js} +2 -2
  17. package/dist/{debug-CMZ7kqW1.js.map → debug-D9giWww2.js.map} +1 -1
  18. package/dist/{environment-cVP7bGnh.js → environment-C6j-a4Gz.js} +3 -3
  19. package/dist/{environment-cVP7bGnh.js.map → environment-C6j-a4Gz.js.map} +1 -1
  20. package/dist/{file-utils-D1632P4x.js → file-utils-BiElGS_N.js} +2 -2
  21. package/dist/{file-utils-D1632P4x.js.map → file-utils-BiElGS_N.js.map} +1 -1
  22. package/dist/{interactive-DCIL3NcQ.js → interactive-C0Vssetd.js} +2 -2
  23. package/dist/{interactive-DCIL3NcQ.js.map → interactive-C0Vssetd.js.map} +1 -1
  24. package/dist/{mcp-prompt-streaming-BRoVSf3N.js → mcp-prompt-streaming-DQXxG2Pg.js} +4 -4
  25. package/dist/{mcp-prompt-streaming-BRoVSf3N.js.map → mcp-prompt-streaming-DQXxG2Pg.js.map} +1 -1
  26. package/dist/{non-interactive-u4VG76Vi.js → non-interactive-DX-N3ZEb.js} +2 -2
  27. package/dist/{non-interactive-u4VG76Vi.js.map → non-interactive-DX-N3ZEb.js.map} +1 -1
  28. package/dist/{package-manager-0M_uIOP0.js → package-manager-cIPAT7g3.js} +2 -2
  29. package/dist/{package-manager-0M_uIOP0.js.map → package-manager-cIPAT7g3.js.map} +1 -1
  30. package/dist/{playground-B6wgUvH-.js → playground-DQI2vpr0.js} +4 -4
  31. package/dist/{playground-B6wgUvH-.js.map → playground-DQI2vpr0.js.map} +1 -1
  32. package/dist/{posthog-integration-C_9G_kTS.js → posthog-integration-EUokB9U1.js} +12 -12
  33. package/dist/{posthog-integration-C_9G_kTS.js.map → posthog-integration-EUokB9U1.js.map} +1 -1
  34. package/dist/{provisioning-CgCxuoe6.js → provisioning-BCCeBATw.js} +3 -3
  35. package/dist/{provisioning-CgCxuoe6.js.map → provisioning-BCCeBATw.js.map} +1 -1
  36. package/dist/{registry-BgsYtCkS.js → registry-DCxIW2G5.js} +4 -4
  37. package/dist/{registry-BgsYtCkS.js.map → registry-DCxIW2G5.js.map} +1 -1
  38. package/dist/{setup-utils-DF6EKEeA.js → setup-utils-DmX3o2bT.js} +8 -8
  39. package/dist/{setup-utils-DF6EKEeA.js.map → setup-utils-DmX3o2bT.js.map} +1 -1
  40. package/dist/{start-tui-Deaj99It.js → start-tui-B9dCp0hW.js} +13 -13
  41. package/dist/{start-tui-Deaj99It.js.map → start-tui-B9dCp0hW.js.map} +1 -1
  42. package/dist/{steps-AF3ulYYe.js → steps-3XbXMf0T.js} +7 -7
  43. package/dist/{steps-AF3ulYYe.js.map → steps-3XbXMf0T.js.map} +1 -1
  44. package/dist/{telemetry-DPVvKu5X.js → telemetry-GFq8wmz0.js} +3 -3
  45. package/dist/{telemetry-DPVvKu5X.js.map → telemetry-GFq8wmz0.js.map} +1 -1
  46. package/dist/{terminal-BVKeWPb3.js → terminal-oI1dOWQI.js} +9 -9
  47. package/dist/{terminal-BVKeWPb3.js.map → terminal-oI1dOWQI.js.map} +1 -1
  48. package/dist/{urls-Bur7Zb7A.js → urls-93eQ-Rd0.js} +2 -2
  49. package/dist/{urls-Bur7Zb7A.js.map → urls-93eQ-Rd0.js.map} +1 -1
  50. package/dist/{wizard-abort-D0UMhCP5.js → wizard-abort-BehJBPpy.js} +3 -3
  51. package/dist/{wizard-abort-D0UMhCP5.js.map → wizard-abort-BehJBPpy.js.map} +1 -1
  52. package/dist/{wizard-abort-D3vY7K9a.js → wizard-abort-dmkJqxAb.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-CMZ7kqW1.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-D9giWww2.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-DvDjbNmK.js.map
223
+ //# sourceMappingURL=analytics-CdT0VV8s.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-DvDjbNmK.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-CdT0VV8s.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,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { Q as WIZARD_USER_AGENT } from "./debug-CMZ7kqW1.js";
3
- import { t as analytics } from "./analytics-DvDjbNmK.js";
2
+ import { Q as WIZARD_USER_AGENT } from "./debug-D9giWww2.js";
3
+ import { t as analytics } from "./analytics-CdT0VV8s.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-DfpSG5xU.js.map
173
+ //# sourceMappingURL=api-D9CerM6x.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-DfpSG5xU.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-D9CerM6x.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 { I as POSTHOG_DOCS_URL, Q as WIZARD_USER_AGENT, a as getLogFilePath, h as LoggingUI, m as setUI, nt as VERSION, p as getUI, r as debug, s as logToFile, tt as getSkillsBaseUrl } from "./debug-CMZ7kqW1.js";
3
- import { t as analytics } from "./analytics-DvDjbNmK.js";
4
- import { r as setEntryCommand } from "./telemetry-DPVvKu5X.js";
5
- import { n as isUsingTypeScript } from "./setup-utils-DF6EKEeA.js";
6
- import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-Bur7Zb7A.js";
7
- import { o as handleApiError } from "./api-DfpSG5xU.js";
2
+ import { I as POSTHOG_DOCS_URL, Q as WIZARD_USER_AGENT, a as getLogFilePath, h as LoggingUI, m as setUI, nt as VERSION, p as getUI, r as debug, s as logToFile, tt as getSkillsBaseUrl } from "./debug-D9giWww2.js";
3
+ import { t as analytics } from "./analytics-CdT0VV8s.js";
4
+ import { r as setEntryCommand } from "./telemetry-GFq8wmz0.js";
5
+ import { n as isUsingTypeScript } from "./setup-utils-DmX3o2bT.js";
6
+ import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-93eQ-Rd0.js";
7
+ import { o as handleApiError } from "./api-D9CerM6x.js";
8
8
  import "./wizard-session-G3VWD6hv.js";
9
- import { r as runCleanups } from "./wizard-abort-D0UMhCP5.js";
10
- import { n as isNonInteractiveEnvironment } from "./environment-cVP7bGnh.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-CVW8H9eF.js";
12
- import { i as SPINNER_MESSAGE } from "./registry-BgsYtCkS.js";
13
- import { _ as parsePyprojectToml, a as PRODUCT_SUITE_BLOCK, f as Colors, g 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, v as parseRequirementsTxt } from "./posthog-integration-C_9G_kTS.js";
14
- import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-D1632P4x.js";
9
+ import { r as runCleanups } from "./wizard-abort-BehJBPpy.js";
10
+ import { n as isNonInteractiveEnvironment } from "./environment-C6j-a4Gz.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-CYFyWCMj.js";
12
+ import { i as SPINNER_MESSAGE } from "./registry-DCxIW2G5.js";
13
+ import { _ as parsePyprojectToml, a as PRODUCT_SUITE_BLOCK, f as Colors, g 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, v as parseRequirementsTxt } from "./posthog-integration-EUokB9U1.js";
14
+ import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-BiElGS_N.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-CgCxuoe6.js").then((n) => n.n);
193
+ const { provisionNewAccount } = await import("./provisioning-BCCeBATw.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-Bzfo3nON.js");
258
+ const { runCIInstall } = await import("./ci-install-CTydrjHu.js");
259
259
  return runCIInstall(argv);
260
260
  }
261
261
  if (isNonInteractiveEnvironment()) {
262
- const { failNonInteractive } = await import("./non-interactive-u4VG76Vi.js");
262
+ const { failNonInteractive } = await import("./non-interactive-DX-N3ZEb.js");
263
263
  return failNonInteractive();
264
264
  }
265
265
  if (argv.playground) {
266
- const { runPlayground } = await import("./playground-B6wgUvH-.js");
266
+ const { runPlayground } = await import("./playground-DQI2vpr0.js");
267
267
  return runPlayground();
268
268
  }
269
- const { runInteractive } = await import("./interactive-DCIL3NcQ.js");
269
+ const { runInteractive } = await import("./interactive-C0Vssetd.js");
270
270
  runInteractive(argv);
271
271
  })();
272
272
  }
@@ -3510,6 +3510,7 @@ const run = {
3510
3510
  maxQuestions: 13,
3511
3511
  richLinks: true,
3512
3512
  askTimeoutMs: 1800 * 1e3,
3513
+ trackStepProgress: true,
3513
3514
  postRun: async (session) => {
3514
3515
  await removeInstalledSkill(session.installDir);
3515
3516
  },
@@ -3749,7 +3750,7 @@ function runMcpAdd(argv) {
3749
3750
  const debug = argv.debug;
3750
3751
  const localMcp = argv.local;
3751
3752
  try {
3752
- const { startTUI } = await import("./start-tui-Deaj99It.js");
3753
+ const { startTUI } = await import("./start-tui-B9dCp0hW.js");
3753
3754
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3754
3755
  const tui = startTUI(VERSION, Program.McpAdd);
3755
3756
  tui.store.session = buildSession({
@@ -3761,7 +3762,7 @@ function runMcpAdd(argv) {
3761
3762
  } catch (error) {
3762
3763
  if (!isTUIUnavailable(error)) throw error;
3763
3764
  setUI(new LoggingUI());
3764
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-B6Pj4IKt.js").then((n) => n.r);
3765
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-D0G4cmPf.js").then((n) => n.r);
3765
3766
  await addMCPServerToClientsStep({
3766
3767
  local: localMcp,
3767
3768
  features,
@@ -3800,7 +3801,7 @@ function runMcpRemove(argv) {
3800
3801
  const debug = argv.debug;
3801
3802
  const localMcp = argv.local;
3802
3803
  try {
3803
- const { startTUI } = await import("./start-tui-Deaj99It.js");
3804
+ const { startTUI } = await import("./start-tui-B9dCp0hW.js");
3804
3805
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3805
3806
  const tui = startTUI(VERSION, Program.McpRemove);
3806
3807
  tui.store.session = buildSession({
@@ -3809,7 +3810,7 @@ function runMcpRemove(argv) {
3809
3810
  });
3810
3811
  } catch {
3811
3812
  setUI(new LoggingUI());
3812
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-B6Pj4IKt.js").then((n) => n.r);
3813
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-D0G4cmPf.js").then((n) => n.r);
3813
3814
  await removeMCPServerFromClientsStep({ local: localMcp });
3814
3815
  }
3815
3816
  })();
@@ -3831,7 +3832,7 @@ function runMcpTutorial(argv) {
3831
3832
  const debug = argv.debug;
3832
3833
  const localMcp = argv.local;
3833
3834
  try {
3834
- const { startTUI } = await import("./start-tui-Deaj99It.js");
3835
+ const { startTUI } = await import("./start-tui-B9dCp0hW.js");
3835
3836
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
3836
3837
  const tui = startTUI(VERSION, Program.McpTutorial);
3837
3838
  tui.store.session = buildSession({
@@ -3886,7 +3887,7 @@ function runWizard(config, options) {
3886
3887
  (async () => {
3887
3888
  try {
3888
3889
  const installDir = options.installDir || process.cwd();
3889
- const { startTUI } = await import("./start-tui-Deaj99It.js");
3890
+ const { startTUI } = await import("./start-tui-B9dCp0hW.js");
3890
3891
  const { buildSession, RunPhase } = await import("./wizard-session-wPJtNl4c.js");
3891
3892
  const { TaskStreamPush } = await import("./task-stream-BQNSp0qR.js");
3892
3893
  const { PostHogDestination } = await import("./posthog-Cr37rnla.js");
@@ -3942,7 +3943,7 @@ function runWizard(config, options) {
3942
3943
  await activeTui.store.getGate("health-check");
3943
3944
  const skipAgent = config.run == null;
3944
3945
  if (skipAgent) {
3945
- const { getOrAskForProjectData } = await import("./setup-utils-DF6EKEeA.js").then((n) => n.r);
3946
+ const { getOrAskForProjectData } = await import("./setup-utils-DmX3o2bT.js").then((n) => n.r);
3946
3947
  const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
3947
3948
  signup: session.signup,
3948
3949
  ci: session.ci,
@@ -3957,7 +3958,7 @@ function runWizard(config, options) {
3957
3958
  projectId
3958
3959
  });
3959
3960
  } else {
3960
- const { runAgent } = await import("./agent-runner-VzTpPaVT.js");
3961
+ const { runAgent } = await import("./agent-runner-HTfFCUrR.js");
3961
3962
  await runAgent(config, activeTui.store.session);
3962
3963
  }
3963
3964
  const isDone = () => skipAgent ? activeTui.store.session.outroDismissed : activeTui.store.session.skillsComplete;
@@ -4034,10 +4035,10 @@ function runWizardCI(config, options) {
4034
4035
  (async () => {
4035
4036
  const path = await import("path");
4036
4037
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
4037
- const { readEnvironment } = await import("./environment-cVP7bGnh.js").then((n) => n.t);
4038
+ const { readEnvironment } = await import("./environment-C6j-a4Gz.js").then((n) => n.t);
4038
4039
  const { readApiKeyFromEnv } = await import("./env-api-key-MlzJYAvt.js").then((n) => n.t);
4039
- const { configureLogFileFromEnvironment, logToFile } = await import("./debug-HQ0NrBA2.js");
4040
- const { wizardAbort, WizardError } = await import("./wizard-abort-D3vY7K9a.js");
4040
+ const { configureLogFileFromEnvironment, logToFile } = await import("./debug-Bmq9KH4W.js");
4041
+ const { wizardAbort, WizardError } = await import("./wizard-abort-dmkJqxAb.js");
4041
4042
  configureLogFileFromEnvironment();
4042
4043
  const env = readEnvironment();
4043
4044
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -4088,7 +4089,7 @@ function runWizardCI(config, options) {
4088
4089
  })
4089
4090
  });
4090
4091
  }
4091
- const { runAgent } = await import("./agent-runner-VzTpPaVT.js");
4092
+ const { runAgent } = await import("./agent-runner-HTfFCUrR.js");
4092
4093
  await runAgent(config, session);
4093
4094
  } catch (error) {
4094
4095
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -4955,7 +4956,7 @@ async function runDoctorCI(options) {
4955
4956
  getUI().intro("Welcome to the PostHog setup wizard");
4956
4957
  getUI().log.info("Running posthog-doctor in CI mode");
4957
4958
  try {
4958
- const { getOrAskForProjectData } = await import("./setup-utils-DF6EKEeA.js").then((n) => n.r);
4959
+ const { getOrAskForProjectData } = await import("./setup-utils-DmX3o2bT.js").then((n) => n.r);
4959
4960
  const { host, accessToken, projectId } = await getOrAskForProjectData({
4960
4961
  signup: false,
4961
4962
  ci: true,
@@ -4972,7 +4973,7 @@ async function runDoctorCI(options) {
4972
4973
  for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
4973
4974
  process.exit(1);
4974
4975
  } catch (error) {
4975
- const { ApiError } = await import("./api-DfpSG5xU.js").then((n) => n.n);
4976
+ const { ApiError } = await import("./api-D9CerM6x.js").then((n) => n.n);
4976
4977
  const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
4977
4978
  getUI().log.error(`Doctor failed: ${message}`);
4978
4979
  process.exit(1);
@@ -5068,7 +5069,7 @@ function runSlackConnect(argv) {
5068
5069
  (async () => {
5069
5070
  const debug = argv.debug;
5070
5071
  try {
5071
- const { startTUI } = await import("./start-tui-Deaj99It.js");
5072
+ const { startTUI } = await import("./start-tui-B9dCp0hW.js");
5072
5073
  const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
5073
5074
  const tui = startTUI(VERSION, Program.SlackConnect);
5074
5075
  tui.store.session = buildSession({ debug });