@posthog/wizard 2.70.1 → 2.71.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 (108) hide show
  1. package/dist/{add-mcp-server-to-clients-BCnjUqnW.js → add-mcp-server-to-clients-B6-ZL--P.js} +4 -4
  2. package/dist/{add-mcp-server-to-clients-BCnjUqnW.js.map → add-mcp-server-to-clients-B6-ZL--P.js.map} +1 -1
  3. package/dist/{agent-interface-Lu7tnLr0.js → agent-interface-DFm4jB4d.js} +108 -15
  4. package/dist/agent-interface-DFm4jB4d.js.map +1 -0
  5. package/dist/{agent-prompt-loader-y5GxgEkc.js → agent-prompt-loader-Bi3IzSBW.js} +5 -5
  6. package/dist/{agent-prompt-loader-y5GxgEkc.js.map → agent-prompt-loader-Bi3IzSBW.js.map} +1 -1
  7. package/dist/{agent-runner-vKtpgqVI.js → agent-runner-Cp6iLqDk.js} +49 -16
  8. package/dist/agent-runner-Cp6iLqDk.js.map +1 -0
  9. package/dist/{analytics-DTyJClPr.js → analytics-D54mLptm.js} +3 -3
  10. package/dist/{analytics-DTyJClPr.js.map → analytics-D54mLptm.js.map} +1 -1
  11. package/dist/analytics-Ge1LsCNg.js +2 -0
  12. package/dist/{api-j-OfJ8Dz.js → api-BNBVOguz.js} +23 -4
  13. package/dist/{api-j-OfJ8Dz.js.map → api-BNBVOguz.js.map} +1 -1
  14. package/dist/bin.js +79 -73
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{bounded-fs-BWX25ixc.js → bounded-fs-DHIaH3Sc.js} +3 -3
  17. package/dist/{bounded-fs-BWX25ixc.js.map → bounded-fs-DHIaH3Sc.js.map} +1 -1
  18. package/dist/{ci-install-zNWgp1TL.js → ci-install-Can8LRdJ.js} +5 -5
  19. package/dist/{ci-install-zNWgp1TL.js.map → ci-install-Can8LRdJ.js.map} +1 -1
  20. package/dist/{debug-xr2Pq5VA.js → debug-C4RPcEIX.js} +1 -1
  21. package/dist/{debug-BM0fZaGl.js → debug-YQdeZulR.js} +4 -3
  22. package/dist/debug-YQdeZulR.js.map +1 -0
  23. package/dist/{env-api-key-DlxCZWU0.js → env-api-key-9yogO8OI.js} +2 -2
  24. package/dist/{env-api-key-DlxCZWU0.js.map → env-api-key-9yogO8OI.js.map} +1 -1
  25. package/dist/{environment-o-bTOuzK.js → environment-6ZuAWRpQ.js} +4 -4
  26. package/dist/{environment-o-bTOuzK.js.map → environment-6ZuAWRpQ.js.map} +1 -1
  27. package/dist/{errors-BSdz2lsl.js → errors-u8z27V-x.js} +4 -2
  28. package/dist/errors-u8z27V-x.js.map +1 -0
  29. package/dist/{file-watcher-D7G4f5sP.js → file-watcher-CeWdvMVT.js} +2 -2
  30. package/dist/{file-watcher-D7G4f5sP.js.map → file-watcher-CeWdvMVT.js.map} +1 -1
  31. package/dist/{headless-ui-C46DctKG.js → headless-ui-BxSVgNoT.js} +2 -2
  32. package/dist/{headless-ui-C46DctKG.js.map → headless-ui-BxSVgNoT.js.map} +1 -1
  33. package/dist/{interactive-B5zy3Gxk.js → interactive-CRR9zPl4.js} +2 -2
  34. package/dist/{interactive-B5zy3Gxk.js.map → interactive-CRR9zPl4.js.map} +1 -1
  35. package/dist/{mcp-lJRwE-YW.js → mcp-D_rRzruj.js} +2 -2
  36. package/dist/{mcp-lJRwE-YW.js.map → mcp-D_rRzruj.js.map} +1 -1
  37. package/dist/{mcp-prompt-streaming-Dsos09hT.js → mcp-prompt-streaming-DRAK8CMP.js} +5 -4
  38. package/dist/mcp-prompt-streaming-DRAK8CMP.js.map +1 -0
  39. package/dist/{non-interactive-qcCCtiYQ.js → non-interactive-1EJRlN6u.js} +3 -3
  40. package/dist/{non-interactive-qcCCtiYQ.js.map → non-interactive-1EJRlN6u.js.map} +1 -1
  41. package/dist/{orchestrator-tools-ezFTbAIp.js → orchestrator-tools-DjZWqWmd.js} +3 -3
  42. package/dist/{orchestrator-tools-ezFTbAIp.js.map → orchestrator-tools-DjZWqWmd.js.map} +1 -1
  43. package/dist/{package-manager-CGfN9UhH.js → package-manager-DMbzbdkL.js} +2 -2
  44. package/dist/{package-manager-CGfN9UhH.js.map → package-manager-DMbzbdkL.js.map} +1 -1
  45. package/dist/{pi-DzQLHIcQ.js → pi-D4JQMC-7.js} +18 -15
  46. package/dist/pi-D4JQMC-7.js.map +1 -0
  47. package/dist/{playground-DLN31BPV.js → playground-Y1nSGXpn.js} +43 -8
  48. package/dist/playground-Y1nSGXpn.js.map +1 -0
  49. package/dist/{posthog-Dxr8XK4x.js → posthog-D9VwcWvJ.js} +2 -2
  50. package/dist/{posthog-Dxr8XK4x.js.map → posthog-D9VwcWvJ.js.map} +1 -1
  51. package/dist/{posthog-integration-MDfRO911.js → posthog-integration-B8f4xRBd.js} +18 -18
  52. package/dist/posthog-integration-B8f4xRBd.js.map +1 -0
  53. package/dist/{provisioning-Di5GNV9k.js → provisioning-f7lA29tW.js} +14 -5
  54. package/dist/provisioning-f7lA29tW.js.map +1 -0
  55. package/dist/{queue-tools-KosDptd6.js → queue-tools-DGaHf3n-.js} +3 -3
  56. package/dist/{queue-tools-KosDptd6.js.map → queue-tools-DGaHf3n-.js.map} +1 -1
  57. package/dist/{registry-BBdaIFWq.js → registry-D1By1SgH.js} +5 -5
  58. package/dist/{registry-BBdaIFWq.js.map → registry-D1By1SgH.js.map} +1 -1
  59. package/dist/{security-BwOvjMaq.js → security-C2c3_Ycy.js} +5 -5
  60. package/dist/{security-BwOvjMaq.js.map → security-C2c3_Ycy.js.map} +1 -1
  61. package/dist/{setup-utils-Bo3WZt3a.js → setup-utils-BRrCeajl.js} +42 -11
  62. package/dist/setup-utils-BRrCeajl.js.map +1 -0
  63. package/dist/{start-tui-B1LrB7k1.js → start-tui-r4Spgptv.js} +257 -23
  64. package/dist/start-tui-r4Spgptv.js.map +1 -0
  65. package/dist/{steps-BMrQJpQh.js → steps-BZd65XfI.js} +7 -7
  66. package/dist/{steps-BMrQJpQh.js.map → steps-BZd65XfI.js.map} +1 -1
  67. package/dist/{store-DhNTBWQR.js → store-DGVXu7xt.js} +25 -6
  68. package/dist/store-DGVXu7xt.js.map +1 -0
  69. package/dist/{subagent-q6M-mBHo.js → subagent-BaMxO7OT.js} +2 -2
  70. package/dist/{subagent-q6M-mBHo.js.map → subagent-BaMxO7OT.js.map} +1 -1
  71. package/dist/{task-CgAOxod7.js → task-DpKoEZ5I.js} +13 -13
  72. package/dist/{task-CgAOxod7.js.map → task-DpKoEZ5I.js.map} +1 -1
  73. package/dist/{task-stream-rxR1IsdJ.js → task-stream-CdrBraqP.js} +6 -6
  74. package/dist/{task-stream-rxR1IsdJ.js.map → task-stream-CdrBraqP.js.map} +1 -1
  75. package/dist/{tasks-lzvWF__k.js → tasks-KsP66Cis.js} +2 -2
  76. package/dist/{tasks-lzvWF__k.js.map → tasks-KsP66Cis.js.map} +1 -1
  77. package/dist/{telemetry-CickTk_7.js → telemetry-DedDTtSa.js} +3 -3
  78. package/dist/{telemetry-CickTk_7.js.map → telemetry-DedDTtSa.js.map} +1 -1
  79. package/dist/{terminal-BjUFxn_x.js → terminal-BH8yLclG.js} +107 -61
  80. package/dist/terminal-BH8yLclG.js.map +1 -0
  81. package/dist/{tools-MKXGXFSk.js → tools-CJw5vnZd.js} +6 -6
  82. package/dist/{tools-MKXGXFSk.js.map → tools-CJw5vnZd.js.map} +1 -1
  83. package/dist/{wizard-abort-CooWEh9N.js → wizard-abort-D54j2gmb.js} +5 -5
  84. package/dist/{wizard-abort-CooWEh9N.js.map → wizard-abort-D54j2gmb.js.map} +1 -1
  85. package/dist/{wizard-abort-CW_C2EXr.js → wizard-abort-Q1NiYELE.js} +1 -1
  86. package/dist/{wizard-session-Bki7dQhv.js → wizard-session-CwQPZN4y.js} +3 -1
  87. package/dist/wizard-session-CwQPZN4y.js.map +1 -0
  88. package/dist/{wizard-session-gbYCXdBf.js → wizard-session-Dwc1Rh_7.js} +1 -1
  89. package/dist/yara-hooks-BI6WY0Sl.js +2 -0
  90. package/dist/{yara-hooks-BpngckdZ.js → yara-hooks-CL2LVEgO.js} +4 -4
  91. package/dist/{yara-hooks-BpngckdZ.js.map → yara-hooks-CL2LVEgO.js.map} +1 -1
  92. package/package.json +1 -1
  93. package/dist/agent-interface-Lu7tnLr0.js.map +0 -1
  94. package/dist/agent-runner-vKtpgqVI.js.map +0 -1
  95. package/dist/analytics-D-bMEYjD.js +0 -2
  96. package/dist/debug-BM0fZaGl.js.map +0 -1
  97. package/dist/errors-BSdz2lsl.js.map +0 -1
  98. package/dist/mcp-prompt-streaming-Dsos09hT.js.map +0 -1
  99. package/dist/pi-DzQLHIcQ.js.map +0 -1
  100. package/dist/playground-DLN31BPV.js.map +0 -1
  101. package/dist/posthog-integration-MDfRO911.js.map +0 -1
  102. package/dist/provisioning-Di5GNV9k.js.map +0 -1
  103. package/dist/setup-utils-Bo3WZt3a.js.map +0 -1
  104. package/dist/start-tui-B1LrB7k1.js.map +0 -1
  105. package/dist/store-DhNTBWQR.js.map +0 -1
  106. package/dist/terminal-BjUFxn_x.js.map +0 -1
  107. package/dist/wizard-session-Bki7dQhv.js.map +0 -1
  108. package/dist/yara-hooks-C-qG6EJt.js +0 -2
@@ -1,5 +1,5 @@
1
- import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, bt as TASK_RUN_ID, gt as VERSION, it as WIZARD_FLAG_KEYS, r as debug, s as logToFile, vt as RUN_SURFACE, w as ANALYTICS_TEAM_TAG, yt as TASK_ID } from "./debug-BM0fZaGl.js";
2
- import { s as reportableDiscoveredFeatures } from "./wizard-session-Bki7dQhv.js";
1
+ import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, bt as TASK_RUN_ID, gt as VERSION, it as WIZARD_FLAG_KEYS, r as debug, s as logToFile, vt as RUN_SURFACE, w as ANALYTICS_TEAM_TAG, yt as TASK_ID } from "./debug-YQdeZulR.js";
2
+ import { s as reportableDiscoveredFeatures } from "./wizard-session-CwQPZN4y.js";
3
3
  import { PostHog } from "posthog-node";
4
4
  import { v4 } from "uuid";
5
5
  //#region src/utils/ci-flag-overrides.ts
@@ -291,4 +291,4 @@ const analytics = new Analytics();
291
291
  //#endregion
292
292
  export { ciExcludedTaskTypes as a, sessionProperties as i, analytics as n, groupsFromUser as r, Analytics as t };
293
293
 
294
- //# sourceMappingURL=analytics-DTyJClPr.js.map
294
+ //# sourceMappingURL=analytics-D54mLptm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-DTyJClPr.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 {\n reportableDiscoveredFeatures,\n type WizardSession,\n} from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } 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 // reportableDiscoveredFeatures() owns the consent decision; this file\n // never needs to know what `scanConsent` means, only that the result\n // might be absent. An absent key is unambiguous, while an empty array\n // would read as \"we looked and found nothing\" instead of \"not reported\".\n const discoveredFeatures = reportableDiscoveredFeatures(session);\n\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n ...(discoveredFeatures !== undefined\n ? { discovered_features: discoveredFeatures }\n : {}),\n scan_consent: session.scanConsent,\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 // The build this run came from. Already sent as a flag-evaluation person\n // property; tagging it makes every event attributable to a release, so a\n // regression can be bounded to the versions that carry it.\n this.tags.version = VERSION;\n\n // Cloud runs only: the task run that owns the sandbox. Without these the\n // wizard's events and the run that launched it are two unrelated streams,\n // since run_id above is minted per process and never leaves the wizard.\n // Left unset for local runs so the properties stay absent rather than null.\n if (TASK_RUN_ID) this.tags.task_run_id = TASK_RUN_ID;\n if (TASK_ID) this.tags.task_id = TASK_ID;\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 groupIdentify(\n groupType: string,\n groupKey: string,\n properties: Record<string, unknown>,\n ) {\n this.client.groupIdentify({ groupType, groupKey, properties });\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":"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"}
1
+ {"version":3,"file":"analytics-D54mLptm.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 {\n reportableDiscoveredFeatures,\n type WizardSession,\n} from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } 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 // reportableDiscoveredFeatures() owns the consent decision; this file\n // never needs to know what `scanConsent` means, only that the result\n // might be absent. An absent key is unambiguous, while an empty array\n // would read as \"we looked and found nothing\" instead of \"not reported\".\n const discoveredFeatures = reportableDiscoveredFeatures(session);\n\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n ...(discoveredFeatures !== undefined\n ? { discovered_features: discoveredFeatures }\n : {}),\n scan_consent: session.scanConsent,\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 // The build this run came from. Already sent as a flag-evaluation person\n // property; tagging it makes every event attributable to a release, so a\n // regression can be bounded to the versions that carry it.\n this.tags.version = VERSION;\n\n // Cloud runs only: the task run that owns the sandbox. Without these the\n // wizard's events and the run that launched it are two unrelated streams,\n // since run_id above is minted per process and never leaves the wizard.\n // Left unset for local runs so the properties stay absent rather than null.\n if (TASK_RUN_ID) this.tags.task_run_id = TASK_RUN_ID;\n if (TASK_ID) this.tags.task_id = TASK_ID;\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 groupIdentify(\n groupType: string,\n groupKey: string,\n properties: Record<string, unknown>,\n ) {\n this.client.groupIdentify({ groupType, groupKey, properties });\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":"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"}
@@ -0,0 +1,2 @@
1
+ import { n as analytics } from "./analytics-D54mLptm.js";
2
+ export { analytics };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { pt as WIZARD_USER_AGENT } from "./debug-BM0fZaGl.js";
3
- import { n as analytics } from "./analytics-DTyJClPr.js";
2
+ import { pt as WIZARD_USER_AGENT } from "./debug-YQdeZulR.js";
3
+ import { n as analytics } from "./analytics-D54mLptm.js";
4
4
  import axios from "axios";
5
5
  import { z } from "zod";
6
6
  //#region src/lib/api.ts
@@ -9,6 +9,7 @@ var api_exports = /* @__PURE__ */ __exportAll({
9
9
  ApiError: () => ApiError,
10
10
  ApiProjectSchema: () => ApiProjectSchema,
11
11
  ApiUserSchema: () => ApiUserSchema,
12
+ fetchGithubConnected: () => fetchGithubConnected,
12
13
  fetchProjectData: () => fetchProjectData,
13
14
  fetchSlackConnected: () => fetchSlackConnected,
14
15
  fetchUserData: () => fetchUserData,
@@ -153,6 +154,24 @@ async function fetchSlackConnected(accessToken, projectId, baseUrl, signal) {
153
154
  if (!parsed.success) return false;
154
155
  return parsed.data.results.some((i) => i.kind === "slack");
155
156
  }
157
+ /**
158
+ * Check whether the project already has a GitHub App integration connected.
159
+ * Requires the `integration:read` scope. Throws on failure — callers (the
160
+ * SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for
161
+ * capturing the error exactly once.
162
+ */
163
+ async function fetchGithubConnected(accessToken, projectId, baseUrl, signal) {
164
+ const response = await axios.get(`${baseUrl}/api/projects/${projectId}/integrations/`, {
165
+ headers: {
166
+ Authorization: `Bearer ${accessToken}`,
167
+ "User-Agent": WIZARD_USER_AGENT
168
+ },
169
+ signal
170
+ });
171
+ const parsed = IntegrationsResponseSchema.safeParse(response.data);
172
+ if (!parsed.success) return false;
173
+ return parsed.data.results.some((i) => i.kind === "github");
174
+ }
156
175
  function handleApiError(error, operation) {
157
176
  if (axios.isAxiosError(error)) {
158
177
  const axiosError = error;
@@ -168,6 +187,6 @@ function handleApiError(error, operation) {
168
187
  return new ApiError(`Unexpected error while trying to ${operation}: ${error instanceof Error ? error.message : "Unknown error"}`);
169
188
  }
170
189
  //#endregion
171
- export { fetchUserData as a, fetchSlackConnected as i, api_exports as n, handleApiError as o, fetchProjectData as r, ApiError as t };
190
+ export { fetchSlackConnected as a, fetchProjectData as i, api_exports as n, fetchUserData as o, fetchGithubConnected as r, handleApiError as s, ApiError as t };
172
191
 
173
- //# sourceMappingURL=api-j-OfJ8Dz.js.map
192
+ //# sourceMappingURL=api-BNBVOguz.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-j-OfJ8Dz.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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAa,gBAAgB,EAC1B,OAAO;CAEN,aAAa,EAAE,QAAQ;CACvB,MAAM,EAAE,QAAQ,CAAC,SAAS;CAC1B,IAAI,EAAE,QAAQ,CAAC,SAAS;CAGxB,OAAO,EAAE,QAAQ,CAAC,SAAS;CAC3B,YAAY,EAAE,QAAQ,CAAC,SAAS;CAChC,WAAW,EAAE,QAAQ,CAAC,SAAS;CAC/B,aAAa,EAAE,QAAQ,CAAC,SAAS;CACjC,mBAAmB,EAAE,SAAS,CAAC,SAAS;CACxC,gBAAgB,EAAE,SAAS,CAAC,SAAS;CACrC,UAAU,EAAE,SAAS,CAAC,SAAS;CAG/B,YAAY,EAAE,QAAQ,CAAC,SAAS;CAChC,cAAc,EAAE,QAAQ,CAAC,SAAS;CAClC,gBAAgB,EAAE,SAAS,CAAC,SAAS;CAKrC,sBAAsB,EAAE,QAAQ,CAAC,SAAS;CAI1C,MAAM,EACH,OAAO;EACN,IAAI,EAAE,QAAQ;EACd,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,cAAc,EAAE,QAAQ,CAAC,MAAM;EAC/B,WAAW,EAAE,QAAQ,CAAC,SAAS;EAC/B,YAAY,EAAE,QAAQ,CAAC,SAAS;EAChC,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,UAAU,EAAE,QAAQ,CAAC,SAAS;EAC/B,CAAC,CACD,aAAa;CAChB,cAAc,EACX,OAAO;EACN,IAAI,EAAE,QAAQ,CAAC,MAAM;EACrB,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,kBAAkB,EAAE,QAAQ,CAAC,SAAS;EACtC,aAAa,EAAE,QAAQ,CAAC,SAAS;EAIjC,gCAAgC,EAAE,SAAS,CAAC,SAAS;EACtD,CAAC,CACD,aAAa;CAChB,eAAe,EAAE,MACf,EACG,OAAO;EACN,IAAI,EAAE,QAAQ,CAAC,MAAM;EACrB,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,kBAAkB,EAAE,QAAQ,CAAC,SAAS;EACvC,CAAC,CACD,aAAa,CACjB;CACF,CAAC,CACD,aAAa;;;;;;;;;;;;AAahB,MAAa,yBAAyB,EACnC,OAAO;CACN,OAAO,EAAE,QAAQ,CAAC,SAAS;CAC3B,UAAU,EAAE,QAAQ,CAAC,SAAS;CAC9B,YAAY,EAAE,QAAQ,CAAC,SAAS;CACjC,CAAC,CACD,aAAa;AAGyB,EAAE,OAAO,EAChD,SAAS,EAAE,MAAM,uBAAuB,EACzC,CAAC;AAKF,MAAa,mBAAmB,EAAE,OAAO;CACvC,IAAI,EAAE,QAAQ;CACd,MAAM,EAAE,QAAQ,CAAC,MAAM;CACvB,cAAc,EAAE,QAAQ,CAAC,MAAM;CAC/B,WAAW,EAAE,QAAQ;CACrB,MAAM,EAAE,QAAQ;CAOhB,0BAA0B,EAAE,SAAS,CAAC,SAAS;CAC/C,+BAA+B,EAAE,SAAS,CAAC,SAAS;CACpD,gBAAgB,EAAE,SAAS,CAAC,SAAS;CACtC,CAAC;AAKF,IAAa,WAAb,cAA8B,MAAM;CAClC,YACE,SACA,YACA,UACA;AACA,QAAM,QAAQ;AAHE,OAAA,aAAA;AACA,OAAA,WAAA;AAGhB,OAAK,OAAO;;;AAIhB,eAAsB,cACpB,aACA,SACkB;AAClB,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,IAAI,GAAG,QAAQ,kBAAkB,EAC5D,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,CAAC;AAEF,SAAO,cAAc,MAAM,SAAS,KAAK;UAClC,OAAO;EACd,MAAM,WAAW,eAAe,OAAO,kBAAkB;AACzD,YAAU,iBAAiB,UAAU;GACnC,UAAU;GACV;GACD,CAAC;AACF,QAAM;;;AA+CV,eAAsB,iBACpB,aACA,WACA,SACqB;AACrB,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,IAAI,GAAG,QAAQ,gBAAgB,UAAU,IAAI,EACxE,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,CAAC;AAEF,SAAO,iBAAiB,MAAM,SAAS,KAAK;UACrC,OAAO;EACd,MAAM,WAAW,eAAe,OAAO,qBAAqB;AAC5D,YAAU,iBAAiB,UAAU;GACnC,UAAU,iBAAiB,UAAU;GACrC;GACA;GACD,CAAC;AACF,QAAM;;;;AAKV,MAAM,6BAA6B,EAAE,OAAO,EAC1C,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,aAAa,CAAC,EACzE,CAAC;;;;;;;AAQF,eAAsB,oBACpB,aACA,WACA,SACA,QACkB;CAClB,MAAM,WAAW,MAAM,MAAM,IAC3B,GAAG,QAAQ,gBAAgB,UAAU,iBACrC;EACE,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf;EACD;EACD,CACF;CACD,MAAM,SAAS,2BAA2B,UAAU,SAAS,KAAK;AAClE,KAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,QAAO,OAAO,KAAK,QAAQ,MAAM,MAAM,EAAE,SAAS,QAAQ;;AAG5D,SAAgB,eAAe,OAAgB,WAA6B;AAC1E,KAAI,MAAM,aAAa,MAAM,EAAE;EAC7B,MAAM,aAAa;EACnB,MAAM,SAAS,WAAW,UAAU;EACpC,MAAM,SAAS,WAAW,UAAU,MAAM;EAC1C,MAAM,WAAW,WAAW,QAAQ;AAEpC,MAAI,WAAW,IACb,QAAO,IAAI,SACT,yCAAyC,aACzC,QACA,SACD;AAGH,MAAI,WAAW,IACb,QAAO,IAAI,SACT,iCAAiC,aACjC,QACA,SACD;AAGH,MAAI,WAAW,IACb,QAAO,IAAI,SACT,sCAAsC,aACtC,QACA,SACD;AAIH,SAAO,IAAI,SADK,UAAU,aAAa,aACV,QAAQ,SAAS;;AAGhD,KAAI,iBAAiB,EAAE,SACrB,QAAO,IAAI,SAAS,2CAA2C,YAAY;AAG7E,QAAO,IAAI,SACT,oCAAoC,UAAU,IAC5C,iBAAiB,QAAQ,MAAM,UAAU,kBAE5C"}
1
+ {"version":3,"file":"api-BNBVOguz.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\n/**\n * Check whether the project already has a GitHub App integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers (the\n * SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for\n * capturing the error exactly once.\n */\nexport async function fetchGithubConnected(\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 === 'github');\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,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- import { a as AgentSignals, c as emitWizardError, l as ErrorCodes, r as detectErrorCode } from "./errors-BSdz2lsl.js";
3
- import { Ct as isHeadless, L as Integration, St as headlessOption, U as POSTHOG_DOCS_URL, a as getLogFilePath, f as getUI, gt as VERSION, m as LoggingUI, mt as getSkillsBaseUrl, p as setUI, pt as WIZARD_USER_AGENT, r as debug, s as logToFile, wt as regionOption } from "./debug-BM0fZaGl.js";
2
+ import { a as AgentSignals, c as emitWizardError, l as ErrorCodes, r as detectErrorCode } from "./errors-u8z27V-x.js";
3
+ import { Ct as isHeadless, L as Integration, St as headlessOption, U as POSTHOG_DOCS_URL, a as getLogFilePath, f as getUI, gt as VERSION, m as LoggingUI, mt as getSkillsBaseUrl, p as setUI, pt as WIZARD_USER_AGENT, r as debug, s as logToFile, wt as regionOption } from "./debug-YQdeZulR.js";
4
4
  import { a as getLocalDev, i as checkLocalServices, o as initLocalDev, r as POSTHOG_LOCAL_URL, s as localMcpSkillsNotice } from "./local-dev-DPZiIPCK.js";
5
- import "./wizard-session-Bki7dQhv.js";
6
- import { n as analytics } from "./analytics-DTyJClPr.js";
7
- import { r as setEntryCommand } from "./telemetry-CickTk_7.js";
8
- import { a as safeReadFile, o as walkProjectFiles } from "./bounded-fs-BWX25ixc.js";
9
- import { n as isUsingTypeScript } from "./setup-utils-Bo3WZt3a.js";
10
- import { o as handleApiError } from "./api-j-OfJ8Dz.js";
11
- import { i as wizardAbort, r as runCleanups } from "./wizard-abort-CooWEh9N.js";
12
- import { n as isNonInteractiveEnvironment } from "./environment-o-bTOuzK.js";
13
- import { n as runAgent, s as authenticate } from "./agent-runner-vKtpgqVI.js";
14
- import { T as WIZARD_TOOL_NAMES, k as fetchSkillMenu, l as recoverOrphanedSettingsBackups } from "./agent-interface-Lu7tnLr0.js";
15
- import { m as writeJsonAtomic } from "./queue-tools-KosDptd6.js";
16
- import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-BpngckdZ.js";
17
- import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-BBdaIFWq.js";
18
- import { C as detectIntegrationProjects, D as gatherFrameworkContext, E as resolveProjectDir, O as detectFramework, S as detectWarehouseSources, a as LINE_CHART_BLOCK, b as detectWarehousePrerequisites, d as isClearBlock, g as detectPostHogIntegration, h as Icons, i as FUNNEL_BLOCK, m as Colors, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as wordWrap, v as HEALTH_CHECK_STEP, w as scopeInstallDirToProject, x as getDetectedWarehouseSources, y as WAREHOUSE_ABORT_CASES } from "./posthog-integration-MDfRO911.js";
19
- import { n as readApiKeyFromEnv } from "./env-api-key-DlxCZWU0.js";
5
+ import "./wizard-session-CwQPZN4y.js";
6
+ import { n as analytics } from "./analytics-D54mLptm.js";
7
+ import { r as setEntryCommand } from "./telemetry-DedDTtSa.js";
8
+ import { a as safeReadFile, o as walkProjectFiles } from "./bounded-fs-DHIaH3Sc.js";
9
+ import { n as isUsingTypeScript } from "./setup-utils-BRrCeajl.js";
10
+ import { s as handleApiError } from "./api-BNBVOguz.js";
11
+ import { i as wizardAbort, r as runCleanups } from "./wizard-abort-D54j2gmb.js";
12
+ import { n as isNonInteractiveEnvironment } from "./environment-6ZuAWRpQ.js";
13
+ import { A as fetchSkillMenu, E as WIZARD_TOOL_NAMES, u as recoverOrphanedSettingsBackups } from "./agent-interface-DFm4jB4d.js";
14
+ import { n as runAgent, s as authenticate } from "./agent-runner-Cp6iLqDk.js";
15
+ import { m as writeJsonAtomic } from "./queue-tools-DGaHf3n-.js";
16
+ import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-CL2LVEgO.js";
17
+ import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-D1By1SgH.js";
18
+ import { C as detectIntegrationProjects, D as gatherFrameworkContext, E as resolveProjectDir, O as detectFramework, S as detectWarehouseSources, a as LINE_CHART_BLOCK, b as detectWarehousePrerequisites, d as isClearBlock, g as detectPostHogIntegration, h as Icons, i as FUNNEL_BLOCK, m as Colors, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as wordWrap, v as HEALTH_CHECK_STEP, w as scopeInstallDirToProject, x as getDetectedWarehouseSources, y as WAREHOUSE_ABORT_CASES } from "./posthog-integration-B8f4xRBd.js";
19
+ import { n as readApiKeyFromEnv } from "./env-api-key-9yogO8OI.js";
20
20
  import { satisfies } from "semver";
21
21
  import yargs from "yargs";
22
22
  import { hideBin } from "yargs/helpers";
@@ -242,7 +242,7 @@ function runProvision(argv) {
242
242
  }
243
243
  async function provision({ email, region, name, baseUrl, jsonMode }) {
244
244
  try {
245
- const { provisionNewAccount } = await import("./provisioning-Di5GNV9k.js").then((n) => n.r);
245
+ const { provisionNewAccount } = await import("./provisioning-f7lA29tW.js").then((n) => n.r);
246
246
  if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
247
247
  emitResult(await provisionNewAccount(email, name, region, { baseUrl }), jsonMode);
248
248
  process.exit(0);
@@ -309,22 +309,22 @@ const basicIntegrationCommand = {
309
309
  setEntryCommand("integrate");
310
310
  (async () => {
311
311
  if (isHeadless(argv)) {
312
- const { runHeadlessInstall } = await import("./ci-install-zNWgp1TL.js");
312
+ const { runHeadlessInstall } = await import("./ci-install-Can8LRdJ.js");
313
313
  return runHeadlessInstall(argv);
314
314
  }
315
315
  if (argv.ci) {
316
- const { runCIInstall } = await import("./ci-install-zNWgp1TL.js");
316
+ const { runCIInstall } = await import("./ci-install-Can8LRdJ.js");
317
317
  return runCIInstall(argv);
318
318
  }
319
319
  if (isNonInteractiveEnvironment()) {
320
- const { failNonInteractive } = await import("./non-interactive-qcCCtiYQ.js");
320
+ const { failNonInteractive } = await import("./non-interactive-1EJRlN6u.js");
321
321
  return failNonInteractive();
322
322
  }
323
323
  if (argv.playground) {
324
- const { runPlayground } = await import("./playground-DLN31BPV.js");
324
+ const { runPlayground } = await import("./playground-Y1nSGXpn.js");
325
325
  return runPlayground();
326
326
  }
327
- const { runInteractive } = await import("./interactive-B5zy3Gxk.js");
327
+ const { runInteractive } = await import("./interactive-CRR9zPl4.js");
328
328
  runInteractive(argv);
329
329
  })();
330
330
  }
@@ -2865,6 +2865,10 @@ function detectPostHogPresent(installDir) {
2865
2865
  * reason strings are part of the skill contract — the context-mill
2866
2866
  * `self-driving-setup` skill emits these exact strings.
2867
2867
  */
2868
+ /** Headline shown when the run ends because GitHub was not connected. */
2869
+ const GITHUB_REQUIRED_MESSAGE = "GitHub connection required";
2870
+ /** Body for {@link GITHUB_REQUIRED_MESSAGE}. Shared by the pre-run gate and the abort case. */
2871
+ const GITHUB_REQUIRED_BODY = "Self-driving needs GitHub access to research issues in your code and open fixes, so setup cannot finish without it. Nothing was changed. When you are ready to install the PostHog GitHub App, run the wizard again.";
2868
2872
  const SELF_DRIVING_ABORT_CASES = [
2869
2873
  {
2870
2874
  match: /^self-driving is not available for this project$/i,
@@ -2873,8 +2877,8 @@ const SELF_DRIVING_ABORT_CASES = [
2873
2877
  },
2874
2878
  {
2875
2879
  match: /^github connection declined$/i,
2876
- message: "GitHub connection required",
2877
- body: "Self-driving needs GitHub access to research issues in your code and open fixes, so setup cannot finish without it. Nothing was left half-configured. When you are ready to install the PostHog GitHub App, run the wizard again."
2880
+ message: GITHUB_REQUIRED_MESSAGE,
2881
+ body: GITHUB_REQUIRED_BODY
2878
2882
  },
2879
2883
  {
2880
2884
  match: /^requires-interactive-mode$/i,
@@ -3075,10 +3079,18 @@ const SELF_DRIVING_PROGRAM = [
3075
3079
  show: (session) => session.integrate === true,
3076
3080
  isComplete: (session) => session.selfDrivingHandoffConfirmed
3077
3081
  },
3082
+ {
3083
+ id: "self-driving-github",
3084
+ label: "GitHub",
3085
+ screenId: "self-driving-github",
3086
+ isComplete: (session) => session.githubConnected === true || session.githubDeclined,
3087
+ gate: (session) => session.githubConnected === true || session.githubDeclined
3088
+ },
3078
3089
  {
3079
3090
  id: "run",
3080
3091
  label: "Self-driving",
3081
3092
  screenId: "run",
3093
+ show: (session) => !session.githubDeclined,
3082
3094
  isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
3083
3095
  },
3084
3096
  {
@@ -3131,7 +3143,7 @@ function buildSelfDrivingPrompt(ctx, detectedSources = []) {
3131
3143
  const inboxUrl = `${projectBase}/inbox`;
3132
3144
  const optIn = (value) => value === true ? "ON" : value === false ? "OFF" : "unknown";
3133
3145
  const optIns = ctx.teamProductOptIns;
3134
- return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout troop, design custom scouts for what this product uniquely needs, put Replay Vision scanners on its key flows, and hand the user a configured inbox.
3146
+ return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, tune the scout troop, design custom scouts for what this product uniquely needs, put Replay Vision scanners on its key flows, and hand the user a configured inbox.
3135
3147
 
3136
3148
  Project URLs:
3137
3149
  - Integrations settings: ${integrationsSettingsUrl}
@@ -3160,8 +3172,7 @@ call so the user can follow your progress in the TUI. Use exactly these
3160
3172
  tasks, in this order:
3161
3173
  1. Check Self-driving access
3162
3174
  2. Read project and current Self-driving state
3163
- 3. Connect GitHub (required)
3164
- 3b. Enable products (replay, error tracking, support)
3175
+ 3. Enable products (replay, error tracking, support)
3165
3176
  4. Enable signal sources
3166
3177
  5. Offer issue-tracker integrations
3167
3178
  6. Configure the scout troop
@@ -3169,8 +3180,11 @@ tasks, in this order:
3169
3180
  6c. Set up Replay Vision scanners
3170
3181
  7. Write report and hand off
3171
3182
  Drive the list with TaskUpdate — mark a task in_progress when you start
3172
- it and completed when done. If a step turns out to be a no-op (e.g.
3173
- GitHub is already connected), still mark its task completed.
3183
+ it and completed when done. If a step turns out to be a no-op (e.g. a
3184
+ product is already enabled), still mark its task completed.
3185
+
3186
+ The PostHog GitHub App is already connected — the wizard verified it
3187
+ before this run started, so never ask the user to connect or install it.
3174
3188
 
3175
3189
  Wizard mechanics:
3176
3190
  - Ask the user things ONLY with the wizard_ask MCP tool, and batch
@@ -3206,20 +3220,12 @@ STEP 2 — Read project and current Signals state. (skill: "Read context")
3206
3220
  what neither covers. List the currently enabled signal sources so every
3207
3221
  later write is idempotent.
3208
3222
 
3209
- STEP 3 — Connect GitHub. REQUIRED. (skill: "Connect GitHub")
3210
- Signals cannot research or fix issues without code access. Check for
3211
- an existing GitHub integration first; if absent, send the user
3212
- through the GitHub App connection via wizard_ask exactly as the skill
3213
- describes (it builds the one-click authorize link), and verify the
3214
- connection after they confirm. If the user cannot connect now, emit
3215
- ${AgentSignals.ABORT} github connection declined
3216
- and halt — never finish setup without GitHub.
3217
-
3218
- STEP 3b — Enable products. (skill: "Enable products")
3223
+ STEP 3 — Enable products. (skill: "Enable products")
3219
3224
  Turn ON the PostHog products Signals reads from — Session Replay,
3220
- Error Tracking, and Support — so the sources you enable next have data
3221
- to read. These are server-side enables with conservative defaults
3222
- (owned by the server, not you). The project-state block above covers
3225
+ Error Tracking, and Support — so the sources you enable next, and the
3226
+ Replay Vision scanners in STEP 6c, have data to read. These are
3227
+ server-side enables with conservative defaults (owned by the server,
3228
+ not you). The project-state block above covers
3223
3229
  only Session Replay and Error Tracking, so you can skip those if they
3224
3230
  are already ON; it does not show Support, but every enable is idempotent
3225
3231
  so enabling any of them again is safe regardless. For a web app, also
@@ -3288,7 +3294,7 @@ STEP 6b — Design custom scouts for this product. (skill: "Custom scouts")
3288
3294
  STEP 6c — Set up Replay Vision scanners. (skill: "Replay Vision scanners")
3289
3295
  Create the scanner skeletons the skill defines, filling the per-product
3290
3296
  blanks it leaves you from this repo's code. Scanners need Session Replay
3291
- on (STEP 3b). Every failure here — no recordings yet, a backend-only
3297
+ on (STEP 3). Every failure here — no recordings yet, a backend-only
3292
3298
  project, the scanner API missing — is a follow-up, never an abort; mark
3293
3299
  the task completed regardless.
3294
3300
 
@@ -4330,7 +4336,7 @@ const mcpAddCommand = {
4330
4336
  function runMcpAdd(argv) {
4331
4337
  const features = parseFeatures(argv.features);
4332
4338
  (async () => {
4333
- const { readApiKeyFromEnv } = await import("./env-api-key-DlxCZWU0.js").then((n) => n.t);
4339
+ const { readApiKeyFromEnv } = await import("./env-api-key-9yogO8OI.js").then((n) => n.t);
4334
4340
  const apiKey = argv.apiKey || readApiKeyFromEnv();
4335
4341
  const debug = argv.debug;
4336
4342
  const localMcp = argv.local;
@@ -4344,8 +4350,8 @@ function runMcpAdd(argv) {
4344
4350
  return;
4345
4351
  }
4346
4352
  try {
4347
- const { startTUI } = await import("./start-tui-B1LrB7k1.js");
4348
- const { buildSession } = await import("./wizard-session-gbYCXdBf.js");
4353
+ const { startTUI } = await import("./start-tui-r4Spgptv.js");
4354
+ const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
4349
4355
  const tui = startTUI(VERSION, Program.McpAdd);
4350
4356
  tui.store.session = buildSession({
4351
4357
  debug,
@@ -4362,7 +4368,7 @@ function runMcpAdd(argv) {
4362
4368
  }
4363
4369
  async function runHeadlessAdd(args) {
4364
4370
  setUI(new LoggingUI());
4365
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-BCnjUqnW.js").then((n) => n.r);
4371
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-B6-ZL--P.js").then((n) => n.r);
4366
4372
  const { installed, failed } = await addMCPServerToClientsStep(args);
4367
4373
  if (failed.length > 0 || installed.length === 0) process.exitCode = 1;
4368
4374
  }
@@ -4394,8 +4400,8 @@ function runMcpRemove(argv) {
4394
4400
  return;
4395
4401
  }
4396
4402
  try {
4397
- const { startTUI } = await import("./start-tui-B1LrB7k1.js");
4398
- const { buildSession } = await import("./wizard-session-gbYCXdBf.js");
4403
+ const { startTUI } = await import("./start-tui-r4Spgptv.js");
4404
+ const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
4399
4405
  const tui = startTUI(VERSION, Program.McpRemove);
4400
4406
  tui.store.session = buildSession({
4401
4407
  debug,
@@ -4411,7 +4417,7 @@ function runMcpRemove(argv) {
4411
4417
  /** No exit code on an empty result: nothing to remove is the requested end state. */
4412
4418
  async function runHeadlessRemove(local) {
4413
4419
  setUI(new LoggingUI());
4414
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-BCnjUqnW.js").then((n) => n.r);
4420
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-B6-ZL--P.js").then((n) => n.r);
4415
4421
  await removeMCPServerFromClientsStep({ local });
4416
4422
  }
4417
4423
  //#endregion
@@ -4431,8 +4437,8 @@ function runMcpTutorial(argv) {
4431
4437
  const debug = argv.debug;
4432
4438
  const localMcp = argv.local;
4433
4439
  try {
4434
- const { startTUI } = await import("./start-tui-B1LrB7k1.js");
4435
- const { buildSession } = await import("./wizard-session-gbYCXdBf.js");
4440
+ const { startTUI } = await import("./start-tui-r4Spgptv.js");
4441
+ const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
4436
4442
  const tui = startTUI(VERSION, Program.McpTutorial);
4437
4443
  tui.store.session = buildSession({
4438
4444
  debug,
@@ -4517,17 +4523,17 @@ function runWizard(config, options) {
4517
4523
  (async () => {
4518
4524
  try {
4519
4525
  const installDir = options.installDir || process.cwd();
4520
- const { startTUI } = await import("./start-tui-B1LrB7k1.js");
4521
- const { buildSession, RunPhase } = await import("./wizard-session-gbYCXdBf.js");
4522
- const { TaskStreamPush } = await import("./task-stream-rxR1IsdJ.js");
4523
- const { PostHogDestination } = await import("./posthog-Dxr8XK4x.js");
4526
+ const { startTUI } = await import("./start-tui-r4Spgptv.js");
4527
+ const { buildSession, RunPhase } = await import("./wizard-session-Dwc1Rh_7.js");
4528
+ const { TaskStreamPush } = await import("./task-stream-CdrBraqP.js");
4529
+ const { PostHogDestination } = await import("./posthog-D9VwcWvJ.js");
4524
4530
  const local = getLocalDev();
4525
4531
  const localServicesError = await checkLocalServices({
4526
4532
  ...local,
4527
4533
  localPosthog: local.localPosthog && !options.baseUrl
4528
4534
  });
4529
4535
  if (localServicesError) {
4530
- const { wizardAbort } = await import("./wizard-abort-CW_C2EXr.js");
4536
+ const { wizardAbort } = await import("./wizard-abort-Q1NiYELE.js");
4531
4537
  await wizardAbort({ message: localServicesError });
4532
4538
  return;
4533
4539
  }
@@ -4598,7 +4604,7 @@ function runWizard(config, options) {
4598
4604
  if (shown(step)) await advanceStep(step, activeTui.store, config);
4599
4605
  }
4600
4606
  else if (skipAgent) {
4601
- const { getOrAskForProjectData } = await import("./setup-utils-Bo3WZt3a.js").then((n) => n.r);
4607
+ const { getOrAskForProjectData } = await import("./setup-utils-BRrCeajl.js").then((n) => n.r);
4602
4608
  const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
4603
4609
  signup: session.signup,
4604
4610
  ci: session.ci,
@@ -4711,11 +4717,11 @@ function runNonInteractive(config, options, mode) {
4711
4717
  analytics.setTag("build", mode);
4712
4718
  (async () => {
4713
4719
  const path = await import("path");
4714
- const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-gbYCXdBf.js");
4715
- const { readEnvironment } = await import("./environment-o-bTOuzK.js").then((n) => n.t);
4716
- const { readApiKeyFromEnv } = await import("./env-api-key-DlxCZWU0.js").then((n) => n.t);
4717
- const { configureLogFileFromEnvironment, logToFile } = await import("./debug-xr2Pq5VA.js");
4718
- const { wizardAbort, WizardError } = await import("./wizard-abort-CW_C2EXr.js");
4720
+ const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-Dwc1Rh_7.js");
4721
+ const { readEnvironment } = await import("./environment-6ZuAWRpQ.js").then((n) => n.t);
4722
+ const { readApiKeyFromEnv } = await import("./env-api-key-9yogO8OI.js").then((n) => n.t);
4723
+ const { configureLogFileFromEnvironment, logToFile } = await import("./debug-C4RPcEIX.js");
4724
+ const { wizardAbort, WizardError } = await import("./wizard-abort-Q1NiYELE.js");
4719
4725
  configureLogFileFromEnvironment();
4720
4726
  const env = readEnvironment();
4721
4727
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -4762,9 +4768,9 @@ function runNonInteractive(config, options, mode) {
4762
4768
  let store = null;
4763
4769
  let taskStream = null;
4764
4770
  if (mode === "headless") {
4765
- const { WizardStore } = await import("./store-DhNTBWQR.js").then((n) => n.n);
4766
- const { HeadlessUI } = await import("./headless-ui-C46DctKG.js");
4767
- const { TaskStreamPush, PostHogDestination } = await import("./task-stream-rxR1IsdJ.js");
4771
+ const { WizardStore } = await import("./store-DGVXu7xt.js").then((n) => n.n);
4772
+ const { HeadlessUI } = await import("./headless-ui-BxSVgNoT.js");
4773
+ const { TaskStreamPush, PostHogDestination } = await import("./task-stream-CdrBraqP.js");
4768
4774
  store = new WizardStore(config.id);
4769
4775
  store.session = session;
4770
4776
  setUI(new HeadlessUI(store));
@@ -4847,7 +4853,7 @@ function runNonInteractive(config, options, mode) {
4847
4853
  });
4848
4854
  }
4849
4855
  }
4850
- const { runAgent } = await import("./agent-runner-vKtpgqVI.js").then((n) => n.t);
4856
+ const { runAgent } = await import("./agent-runner-Cp6iLqDk.js").then((n) => n.t);
4851
4857
  await runAgent(config, session);
4852
4858
  await settleStream(RunPhase.Completed);
4853
4859
  } catch (error) {
@@ -6094,7 +6100,7 @@ async function runDoctorCI(options) {
6094
6100
  getUI().intro("Welcome to the PostHog setup wizard");
6095
6101
  getUI().log.info("Running posthog-doctor in CI mode");
6096
6102
  try {
6097
- const { getOrAskForProjectData } = await import("./setup-utils-Bo3WZt3a.js").then((n) => n.r);
6103
+ const { getOrAskForProjectData } = await import("./setup-utils-BRrCeajl.js").then((n) => n.r);
6098
6104
  const { host, accessToken, projectId } = await getOrAskForProjectData({
6099
6105
  signup: false,
6100
6106
  ci: true,
@@ -6112,7 +6118,7 @@ async function runDoctorCI(options) {
6112
6118
  for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
6113
6119
  process.exit(1);
6114
6120
  } catch (error) {
6115
- const { ApiError } = await import("./api-j-OfJ8Dz.js").then((n) => n.n);
6121
+ const { ApiError } = await import("./api-BNBVOguz.js").then((n) => n.n);
6116
6122
  const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
6117
6123
  getUI().log.error(`Doctor failed: ${message}`);
6118
6124
  emitWizardError({
@@ -6198,8 +6204,8 @@ function runSlackConnect(argv) {
6198
6204
  (async () => {
6199
6205
  const debug = argv.debug;
6200
6206
  try {
6201
- const { startTUI } = await import("./start-tui-B1LrB7k1.js");
6202
- const { buildSession } = await import("./wizard-session-gbYCXdBf.js");
6207
+ const { startTUI } = await import("./start-tui-r4Spgptv.js");
6208
+ const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
6203
6209
  const tui = startTUI(VERSION, Program.SlackConnect);
6204
6210
  tui.store.session = buildSession({
6205
6211
  debug,
@@ -6543,6 +6549,6 @@ function resolveInstallDir() {
6543
6549
  }
6544
6550
  Wizard.use(basicIntegrationCommand).use(mcpCommand).use(mcpAnalyticsCommand).use(replayVisionCommand).use(aiObservabilityCommand).use(metricsCommand).use(cliCommand).use(auditCommand).use(doctorCommand).use(migrateCommand).use(revenueCommand).use(warehouseCommand).use(selfDrivingCommand).use(slackCommand).use(uploadSourcemapsCommand).use(skillCommand).init();
6545
6551
  //#endregion
6546
- export { STRIPE_SDKS as A, MANUAL_SDK_VARIANTS as C, fetchHealthIssues as D, getKindMeta as E, getContentBlocks$3 as O, MANUAL_SDK_INSTALL as S, SOURCE_MAPS_CONTEXT_KEYS as T, detectSelfDrivingIntegrationProjects as _, useStdoutDimensions as a, DISPLAY_NAME as b, runWizardHeadless as c, PROGRAM_REGISTRY as d, Program as f, PRICING_SHORT as g, PRICING_LONG as h, useKeyboardHintsContext as i, POSTHOG_SDKS as k, runWizardCI as l, NO_DEFAULT_LIMIT as m, useKeyBindings as n, ConfirmButton as o, getProgramConfig as p, KeyboardHintsProvider as r, PromptLabel as s, PickerMenu as t, runWizard as u, SELF_DRIVING_INTEGRATE_PATH_KEY as v, RUST_SDK_CRATE as w, GO_SDK_MODULE as x, AUTOMATABLE_VARIANTS as y };
6552
+ export { getContentBlocks$3 as A, GO_SDK_MODULE as C, SOURCE_MAPS_CONTEXT_KEYS as D, RUST_SDK_CRATE as E, STRIPE_SDKS as M, getKindMeta as O, DISPLAY_NAME as S, MANUAL_SDK_VARIANTS as T, detectSelfDrivingIntegrationProjects as _, useStdoutDimensions as a, SELF_DRIVING_INTEGRATE_PATH_KEY as b, runWizardHeadless as c, PROGRAM_REGISTRY as d, Program as f, PRICING_SHORT as g, PRICING_LONG as h, useKeyboardHintsContext as i, POSTHOG_SDKS as j, fetchHealthIssues as k, runWizardCI as l, NO_DEFAULT_LIMIT as m, useKeyBindings as n, ConfirmButton as o, getProgramConfig as p, KeyboardHintsProvider as r, PromptLabel as s, PickerMenu as t, runWizard as u, GITHUB_REQUIRED_BODY as v, MANUAL_SDK_INSTALL as w, AUTOMATABLE_VARIANTS as x, GITHUB_REQUIRED_MESSAGE as y };
6547
6553
 
6548
6554
  //# sourceMappingURL=bin.js.map