@posthog/wizard 2.51.0 → 2.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/{add-mcp-server-to-clients-C1f2al7N.js → add-mcp-server-to-clients-DJyWMMGj.js} +4 -4
  2. package/dist/{add-mcp-server-to-clients-C1f2al7N.js.map → add-mcp-server-to-clients-DJyWMMGj.js.map} +1 -1
  3. package/dist/{agent-interface-BL2wCV3b.js → agent-interface-DoFVHRFh.js} +6 -6
  4. package/dist/{agent-interface-BL2wCV3b.js.map → agent-interface-DoFVHRFh.js.map} +1 -1
  5. package/dist/{agent-prompt-loader-CEWWA98d.js → agent-prompt-loader-D-cPVoL5.js} +5 -5
  6. package/dist/{agent-prompt-loader-CEWWA98d.js.map → agent-prompt-loader-D-cPVoL5.js.map} +1 -1
  7. package/dist/{agent-runner-DSKXFDXa.js → agent-runner-B1qCtjid.js} +13 -13
  8. package/dist/{agent-runner-DSKXFDXa.js.map → agent-runner-B1qCtjid.js.map} +1 -1
  9. package/dist/{analytics-Ddf3zJgF.js → analytics-BXz4SIuS.js} +33 -20
  10. package/dist/analytics-BXz4SIuS.js.map +1 -0
  11. package/dist/analytics-D2xds3nw.js +2 -0
  12. package/dist/{api-BdanR3Zp.js → api-BaacjH-Y.js} +3 -3
  13. package/dist/{api-BdanR3Zp.js.map → api-BaacjH-Y.js.map} +1 -1
  14. package/dist/bin.js +50 -42
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{bounded-fs-d0dw1Qv5.js → bounded-fs-Cx-8nk-1.js} +3 -3
  17. package/dist/{bounded-fs-d0dw1Qv5.js.map → bounded-fs-Cx-8nk-1.js.map} +1 -1
  18. package/dist/{ci-install-DnVNVs0f.js → ci-install-D1Mum8Ah.js} +4 -4
  19. package/dist/{ci-install-DnVNVs0f.js.map → ci-install-D1Mum8Ah.js.map} +1 -1
  20. package/dist/{debug-DaXKSXEy.js → debug-C3ZR1TVF.js} +10 -6
  21. package/dist/debug-C3ZR1TVF.js.map +1 -0
  22. package/dist/{debug-By1_VtgZ.js → debug-DsSCOPe8.js} +1 -1
  23. package/dist/{environment-DJQOs7MR.js → environment-Bi-zynk6.js} +4 -4
  24. package/dist/{environment-DJQOs7MR.js.map → environment-Bi-zynk6.js.map} +1 -1
  25. package/dist/{file-watcher-LZe_W3hM.js → file-watcher-PmRIDAfM.js} +2 -2
  26. package/dist/{file-watcher-LZe_W3hM.js.map → file-watcher-PmRIDAfM.js.map} +1 -1
  27. package/dist/{headless-ui-wIeUgvJ8.js → headless-ui-C4X9lAOY.js} +2 -2
  28. package/dist/{headless-ui-wIeUgvJ8.js.map → headless-ui-C4X9lAOY.js.map} +1 -1
  29. package/dist/{interactive-j4DoJDnk.js → interactive-HM71vLQe.js} +2 -2
  30. package/dist/{interactive-j4DoJDnk.js.map → interactive-HM71vLQe.js.map} +1 -1
  31. package/dist/mcp-D0Hpb_nk.js +64 -0
  32. package/dist/mcp-D0Hpb_nk.js.map +1 -0
  33. package/dist/{mcp-prompt-streaming-D25BQfRa.js → mcp-prompt-streaming-Crk8qFlQ.js} +3 -3
  34. package/dist/{mcp-prompt-streaming-D25BQfRa.js.map → mcp-prompt-streaming-Crk8qFlQ.js.map} +1 -1
  35. package/dist/{non-interactive-Cpof2JsA.js → non-interactive-DdUe8lqX.js} +2 -2
  36. package/dist/{non-interactive-Cpof2JsA.js.map → non-interactive-DdUe8lqX.js.map} +1 -1
  37. package/dist/{orchestrator-tools-CsJizPpV.js → orchestrator-tools-CpRruqZl.js} +3 -3
  38. package/dist/{orchestrator-tools-CsJizPpV.js.map → orchestrator-tools-CpRruqZl.js.map} +1 -1
  39. package/dist/{package-manager-DnzNEjci.js → package-manager-wkSzPJqW.js} +2 -2
  40. package/dist/{package-manager-DnzNEjci.js.map → package-manager-wkSzPJqW.js.map} +1 -1
  41. package/dist/{pi-DE2cAVfO.js → pi-CGPjm4oE.js} +14 -14
  42. package/dist/{pi-DE2cAVfO.js.map → pi-CGPjm4oE.js.map} +1 -1
  43. package/dist/{playground-C3sLBq6A.js → playground-lg7h9GHG.js} +6 -6
  44. package/dist/{playground-C3sLBq6A.js.map → playground-lg7h9GHG.js.map} +1 -1
  45. package/dist/{posthog-integration-_GSKRotZ.js → posthog-integration-pnxhTbxw.js} +14 -14
  46. package/dist/{posthog-integration-_GSKRotZ.js.map → posthog-integration-pnxhTbxw.js.map} +1 -1
  47. package/dist/{provisioning-BndgugFk.js → provisioning-T4jtJqBa.js} +3 -3
  48. package/dist/{provisioning-BndgugFk.js.map → provisioning-T4jtJqBa.js.map} +1 -1
  49. package/dist/{queue-tools-DZjAjiqk.js → queue-tools-D7ctuzyo.js} +3 -3
  50. package/dist/{queue-tools-DZjAjiqk.js.map → queue-tools-D7ctuzyo.js.map} +1 -1
  51. package/dist/{registry-BMjfECF2.js → registry-CsFuKtXn.js} +5 -5
  52. package/dist/{registry-BMjfECF2.js.map → registry-CsFuKtXn.js.map} +1 -1
  53. package/dist/{security-D5hjYVFi.js → security-YAaZfmHs.js} +4 -4
  54. package/dist/{security-D5hjYVFi.js.map → security-YAaZfmHs.js.map} +1 -1
  55. package/dist/{setup-utils-ZKEk71yV.js → setup-utils-DDzEnDxJ.js} +8 -8
  56. package/dist/{setup-utils-ZKEk71yV.js.map → setup-utils-DDzEnDxJ.js.map} +1 -1
  57. package/dist/{start-tui-B2Tb427o.js → start-tui-pCi7WVAK.js} +70 -85
  58. package/dist/start-tui-pCi7WVAK.js.map +1 -0
  59. package/dist/{steps-ClMZ6MZd.js → steps-DmsrBqb9.js} +7 -7
  60. package/dist/{steps-ClMZ6MZd.js.map → steps-DmsrBqb9.js.map} +1 -1
  61. package/dist/{store-Db77bfRv.js → store-BCRdtfOH.js} +4 -4
  62. package/dist/{store-Db77bfRv.js.map → store-BCRdtfOH.js.map} +1 -1
  63. package/dist/{subagent--VXEEc8S.js → subagent-jNXS8IPU.js} +2 -2
  64. package/dist/{subagent--VXEEc8S.js.map → subagent-jNXS8IPU.js.map} +1 -1
  65. package/dist/{task-CBQfx_f5.js → task-CSmrfyNf.js} +12 -13
  66. package/dist/task-CSmrfyNf.js.map +1 -0
  67. package/dist/{task-stream-DCrqCmFa.js → task-stream-BZOjOhKu.js} +3 -3
  68. package/dist/{task-stream-DCrqCmFa.js.map → task-stream-BZOjOhKu.js.map} +1 -1
  69. package/dist/{tasks-BJuz1XQ1.js → tasks-BMgQt251.js} +2 -2
  70. package/dist/{tasks-BJuz1XQ1.js.map → tasks-BMgQt251.js.map} +1 -1
  71. package/dist/{telemetry-tdU6F90U.js → telemetry-qeKIGkte.js} +3 -3
  72. package/dist/{telemetry-tdU6F90U.js.map → telemetry-qeKIGkte.js.map} +1 -1
  73. package/dist/{terminal-ClWui_UN.js → terminal-tbxhJGlI.js} +11 -11
  74. package/dist/{terminal-ClWui_UN.js.map → terminal-tbxhJGlI.js.map} +1 -1
  75. package/dist/{tools-DwpaEyEv.js → tools-DVnBIYFn.js} +7 -7
  76. package/dist/{tools-DwpaEyEv.js.map → tools-DVnBIYFn.js.map} +1 -1
  77. package/dist/{wizard-abort-B1iPXM3K.js → wizard-abort-AEhoDJ4P.js} +3 -3
  78. package/dist/{wizard-abort-B1iPXM3K.js.map → wizard-abort-AEhoDJ4P.js.map} +1 -1
  79. package/dist/{wizard-abort-cX4Kytai.js → wizard-abort-DHC_XStW.js} +1 -1
  80. package/dist/{yara-hooks-CEs3jx7j.js → yara-hooks-CKsVxWiN.js} +4 -4
  81. package/dist/{yara-hooks-CEs3jx7j.js.map → yara-hooks-CKsVxWiN.js.map} +1 -1
  82. package/dist/yara-hooks-DWRdZQuG.js +2 -0
  83. package/package.json +6 -6
  84. package/dist/analytics-Ddf3zJgF.js.map +0 -1
  85. package/dist/analytics-GD_xM1XO.js +0 -2
  86. package/dist/debug-DaXKSXEy.js.map +0 -1
  87. package/dist/mcp-Butt7ktW.js +0 -104
  88. package/dist/mcp-Butt7ktW.js.map +0 -1
  89. package/dist/start-tui-B2Tb427o.js.map +0 -1
  90. package/dist/task-CBQfx_f5.js.map +0 -1
  91. package/dist/yara-hooks-gz4AceFG.js +0 -2
@@ -1,4 +1,4 @@
1
- import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, gt as RUN_SURFACE, mt as VERSION, r as debug, s as logToFile, w as ANALYTICS_TEAM_TAG } from "./debug-DaXKSXEy.js";
1
+ import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, gt as RUN_SURFACE, mt as VERSION, r as debug, rt as WIZARD_FLAG_KEYS, s as logToFile, w as ANALYTICS_TEAM_TAG } from "./debug-C3ZR1TVF.js";
2
2
  import { PostHog } from "posthog-node";
3
3
  import { v4 } from "uuid";
4
4
  //#region src/utils/ci-flag-overrides.ts
@@ -58,6 +58,12 @@ function groupsFromUser(user, host) {
58
58
  if (projectUuid) groups.project = projectUuid;
59
59
  return groups;
60
60
  }
61
+ const WIZARD_FLAGS = new Set(WIZARD_FLAG_KEYS);
62
+ function flagResponseValue(value) {
63
+ if (value === "true") return true;
64
+ if (value === "false") return false;
65
+ return value;
66
+ }
61
67
  var Analytics = class {
62
68
  client;
63
69
  tags = {};
@@ -91,6 +97,10 @@ var Analytics = class {
91
97
  ...properties
92
98
  };
93
99
  }
100
+ if (event.event === "$feature_flag_called") event.properties = {
101
+ ...this.tags,
102
+ ...event.properties ?? {}
103
+ };
94
104
  return event;
95
105
  }
96
106
  });
@@ -174,10 +184,24 @@ var Analytics = class {
174
184
  event: eventName,
175
185
  properties: {
176
186
  ...this.tags,
187
+ ...this.wizardFlagFeatureProperties(),
177
188
  ...properties
178
189
  }
179
190
  });
180
191
  }
192
+ wizardFlagFeatureProperties() {
193
+ if (this.activeFlags === null) return {};
194
+ const props = {};
195
+ const active = [];
196
+ for (const [key, value] of Object.entries(this.activeFlags)) {
197
+ if (!WIZARD_FLAGS.has(key)) continue;
198
+ const resolved = flagResponseValue(value);
199
+ props[`$feature/${key}`] = resolved;
200
+ if (resolved !== false) active.push(key);
201
+ }
202
+ if (active.length > 0) props.$active_feature_flags = active.sort();
203
+ return props;
204
+ }
181
205
  /**
182
206
  * Capture a wizard-specific event. Automatically prepends "wizard: " to the event name.
183
207
  * All new wizard analytics should use this method instead of capture() directly.
@@ -194,18 +218,6 @@ var Analytics = class {
194
218
  async flush() {
195
219
  await this.client.shutdown();
196
220
  }
197
- async getFeatureFlag(flagKey) {
198
- try {
199
- const distinctId = this.distinctId ?? this.anonymousId;
200
- return await this.client.getFeatureFlag(flagKey, distinctId, {
201
- sendFeatureFlagEvents: true,
202
- personProperties: this.flagPersonProperties()
203
- });
204
- } catch (error) {
205
- debug("Failed to get feature flag:", flagKey, error);
206
- return;
207
- }
208
- }
209
221
  /**
210
222
  * Evaluate all feature flags for the current user at the start of a run.
211
223
  * Result is cached; subsequent calls in the same run return the same map.
@@ -214,7 +226,7 @@ var Analytics = class {
214
226
  async getAllFlagsForWizard() {
215
227
  if (this.activeFlags !== null) return this.activeFlags;
216
228
  const out = {};
217
- let payloads = {};
229
+ const payloads = {};
218
230
  try {
219
231
  const distinctId = this.distinctId ?? this.anonymousId;
220
232
  logToFile("[flags] evaluating as", {
@@ -222,13 +234,14 @@ var Analytics = class {
222
234
  identified: this.distinctId !== void 0,
223
235
  personProperties: this.flagPersonProperties()
224
236
  });
225
- const result = await this.client.getAllFlagsAndPayloads(distinctId, { personProperties: this.flagPersonProperties() });
226
- const flags = result.featureFlags ?? {};
227
- for (const [key, value] of Object.entries(flags)) {
237
+ const evaluation = await this.client.evaluateFlags(distinctId, { personProperties: this.flagPersonProperties() });
238
+ for (const key of WIZARD_FLAG_KEYS) {
239
+ const value = evaluation.getFlag(key);
228
240
  if (value === void 0) continue;
229
- out[key] = typeof value === "boolean" ? String(value) : String(value);
241
+ out[key] = String(value);
242
+ const payload = evaluation.getFlagPayload(key);
243
+ if (payload !== void 0) payloads[key] = payload;
230
244
  }
231
- payloads = result.featureFlagPayloads ?? {};
232
245
  } catch (error) {
233
246
  debug("Failed to get all feature flags:", error);
234
247
  this.captureException(error instanceof Error ? error : new Error(String(error)), { step: "get_all_flags" });
@@ -265,4 +278,4 @@ const analytics = new Analytics();
265
278
  //#endregion
266
279
  export { ciExcludedTaskTypes as a, sessionProperties as i, analytics as n, groupsFromUser as r, Analytics as t };
267
280
 
268
- //# sourceMappingURL=analytics-Ddf3zJgF.js.map
281
+ //# sourceMappingURL=analytics-BXz4SIuS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics-BXz4SIuS.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n payloads: Record<string, unknown> = {},\n): { flags: Record<string, string>; payloads: Record<string, unknown> } {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return { flags, payloads };\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return { flags, payloads };\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const mergedFlags = { ...flags };\n const mergedPayloads = { ...payloads };\n for (const [key, value] of Object.entries(overrides)) {\n // An object/array override is a flag payload: the flag reads 'true' and\n // the value rides the payload channel, matching a payload-carrying flag.\n if (typeof value === 'object' && value !== null) {\n mergedFlags[key] = 'true';\n mergedPayloads[key] = value;\n } else {\n mergedFlags[key] = String(value);\n }\n }\n logToFile('[flags] CI overrides applied', overrides);\n return { flags: mergedFlags, payloads: mergedPayloads };\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n WIZARD_FLAG_KEYS,\n} from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE } from '@env';\nimport { VERSION } from '@lib/version';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * The invocation, reduced to flag-safe strings: the command word (first\n * positional, 'default' for the bare flow) and the sorted option NAMES.\n * Option values never leave the machine — they carry paths, emails, keys.\n */\nfunction invocationProperties(): { command: string; cli_flags: string } {\n const args = process.argv.slice(2);\n const command = args.find((a) => !a.startsWith('-')) ?? 'default';\n const flags = [\n ...new Set(\n args\n .filter((a) => a.startsWith('--'))\n .map((a) => a.slice(2).split('=')[0]),\n ),\n ].sort();\n return { command, cli_flags: flags.join(',') };\n}\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n discovered_features: session.discoveredFeatures,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nconst WIZARD_FLAGS: ReadonlySet<string> = new Set(WIZARD_FLAG_KEYS);\n\n// Widen back to the SDK's shape — a filter on `true` never matches `'true'`.\nfunction flagResponseValue(value: string): string | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return value;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private activeFlagPayloads: Record<string, unknown> = {};\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n // The SDK captures this one itself, bypassing capture(), so tags merge here.\n if (event.event === '$feature_flag_called') {\n event.properties = { ...this.tags, ...(event.properties ?? {}) };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n this.activeFlagPayloads = {};\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n // Environment facts flag conditions can scope on — evaluation-time only,\n // never persisted onto the person. `version` gates an experiment to\n // releases that implement it (a condition on a property older builds\n // don't send silently never matches them); `run_surface`/`build` scope\n // by invocation surface; `command`/`cli_flags` by subcommand; `os`/\n // `node_major` by platform.\n return {\n $app_name: this.appName,\n version: VERSION,\n run_surface: RUN_SURFACE,\n build: String(this.tags.build ?? 'dev'),\n os: process.platform,\n node_major: process.versions.node.split('.')[0],\n ...invocationProperties(),\n ...this.personProperties,\n };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...this.wizardFlagFeatureProperties(),\n ...properties,\n },\n });\n }\n\n // Built from the resolved map, not the SDK snapshot: a CI-forced variant must own its events.\n private wizardFlagFeatureProperties(): Record<string, unknown> {\n if (this.activeFlags === null) return {};\n const props: Record<string, unknown> = {};\n const active: string[] = [];\n for (const [key, value] of Object.entries(this.activeFlags)) {\n if (!WIZARD_FLAGS.has(key)) continue;\n const resolved = flagResponseValue(value);\n props[`$feature/${key}`] = resolved;\n if (resolved !== false) active.push(key);\n }\n if (active.length > 0) props.$active_feature_flags = active.sort();\n return props;\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n // Only a getFlag read records an exposure; the bulk response records none.\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n const payloads: Record<string, unknown> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const evaluation = await this.client.evaluateFlags(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n for (const key of WIZARD_FLAG_KEYS) {\n const value = evaluation.getFlag(key);\n if (value === undefined) continue;\n out[key] = String(value);\n const payload = evaluation.getFlagPayload(key);\n if (payload !== undefined) payloads[key] = payload;\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n const merged = applyCiFlagOverrides(out, payloads);\n this.activeFlags = merged.flags;\n this.activeFlagPayloads = merged.payloads;\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n /** Flag payloads from the same snapshot; empty until the flags are fetched. */\n getWizardFlagPayloads(): Record<string, unknown> {\n return this.activeFlagPayloads;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { n as analytics } from "./analytics-BXz4SIuS.js";
2
+ export { analytics };
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { dt as WIZARD_USER_AGENT } from "./debug-DaXKSXEy.js";
3
- import { n as analytics } from "./analytics-Ddf3zJgF.js";
2
+ import { dt as WIZARD_USER_AGENT } from "./debug-C3ZR1TVF.js";
3
+ import { n as analytics } from "./analytics-BXz4SIuS.js";
4
4
  import axios from "axios";
5
5
  import { z } from "zod";
6
6
  //#region src/lib/api.ts
@@ -170,4 +170,4 @@ function handleApiError(error, operation) {
170
170
  //#endregion
171
171
  export { fetchUserData as a, fetchSlackConnected as i, api_exports as n, handleApiError as o, fetchProjectData as r, ApiError as t };
172
172
 
173
- //# sourceMappingURL=api-BdanR3Zp.js.map
173
+ //# sourceMappingURL=api-BaacjH-Y.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api-BdanR3Zp.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"api-BaacjH-Y.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
package/dist/bin.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
- import { H as POSTHOG_DOCS_URL, I as Integration, a as getLogFilePath, bt as regionOption, dt as WIZARD_USER_AGENT, f as getUI, ft as getSkillsBaseUrl, m as LoggingUI, mt as VERSION, p as setUI, r as debug, s as logToFile, vt as headlessOption, yt as isHeadless } from "./debug-DaXKSXEy.js";
3
- import { n as analytics } from "./analytics-Ddf3zJgF.js";
4
- import { r as setEntryCommand } from "./telemetry-tdU6F90U.js";
5
- import { a as walkProjectFiles, i as safeReadFile } from "./bounded-fs-d0dw1Qv5.js";
6
- import { n as isUsingTypeScript } from "./setup-utils-ZKEk71yV.js";
7
- import { o as handleApiError } from "./api-BdanR3Zp.js";
2
+ import { H as POSTHOG_DOCS_URL, I as Integration, a as getLogFilePath, bt as regionOption, dt as WIZARD_USER_AGENT, f as getUI, ft as getSkillsBaseUrl, m as LoggingUI, mt as VERSION, p as setUI, r as debug, s as logToFile, vt as headlessOption, yt as isHeadless } from "./debug-C3ZR1TVF.js";
3
+ import { n as analytics } from "./analytics-BXz4SIuS.js";
4
+ import { r as setEntryCommand } from "./telemetry-qeKIGkte.js";
5
+ import { a as walkProjectFiles, i as safeReadFile } from "./bounded-fs-Cx-8nk-1.js";
6
+ import { n as isUsingTypeScript } from "./setup-utils-DDzEnDxJ.js";
7
+ import { o as handleApiError } from "./api-BaacjH-Y.js";
8
8
  import "./wizard-session-BAZql11N.js";
9
- import { r as runCleanups } from "./wizard-abort-B1iPXM3K.js";
10
- import { n as isNonInteractiveEnvironment } from "./environment-DJQOs7MR.js";
11
- import { n as runAgent, o as authenticate } from "./agent-runner-DSKXFDXa.js";
12
- import { _ as WIZARD_TOOL_NAMES, b as fetchSkillMenu, l as recoverOrphanedSettingsBackups, p as AgentSignals } from "./agent-interface-BL2wCV3b.js";
13
- import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-CEs3jx7j.js";
14
- import { i as SPINNER_MESSAGE } from "./registry-BMjfECF2.js";
15
- import { S as gatherFrameworkContext, _ as detectWarehousePrerequisites, a as LINE_CHART_BLOCK, g as WAREHOUSE_ABORT_CASES, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as getDetectedWarehouseSources, x as resolveProjectDir, y as detectIntegrationProjects } from "./posthog-integration-_GSKRotZ.js";
9
+ import { r as runCleanups } from "./wizard-abort-AEhoDJ4P.js";
10
+ import { n as isNonInteractiveEnvironment } from "./environment-Bi-zynk6.js";
11
+ import { n as runAgent, o as authenticate } from "./agent-runner-B1qCtjid.js";
12
+ import { _ as WIZARD_TOOL_NAMES, b as fetchSkillMenu, l as recoverOrphanedSettingsBackups, p as AgentSignals } from "./agent-interface-DoFVHRFh.js";
13
+ import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-CKsVxWiN.js";
14
+ import { i as SPINNER_MESSAGE } from "./registry-CsFuKtXn.js";
15
+ import { S as gatherFrameworkContext, _ as detectWarehousePrerequisites, a as LINE_CHART_BLOCK, g as WAREHOUSE_ABORT_CASES, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as getDetectedWarehouseSources, x as resolveProjectDir, y as detectIntegrationProjects } from "./posthog-integration-pnxhTbxw.js";
16
16
  import { n as readApiKeyFromEnv } from "./env-api-key-DDVkPQmo.js";
17
17
  import { satisfies } from "semver";
18
18
  import yargs from "yargs";
@@ -200,7 +200,7 @@ function runProvision(argv) {
200
200
  }
201
201
  async function provision({ email, region, name, baseUrl, jsonMode }) {
202
202
  try {
203
- const { provisionNewAccount } = await import("./provisioning-BndgugFk.js").then((n) => n.n);
203
+ const { provisionNewAccount } = await import("./provisioning-T4jtJqBa.js").then((n) => n.n);
204
204
  if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
205
205
  emitResult(await provisionNewAccount(email, name, region, { baseUrl }), jsonMode);
206
206
  process.exit(0);
@@ -267,22 +267,22 @@ const basicIntegrationCommand = {
267
267
  setEntryCommand("integrate");
268
268
  (async () => {
269
269
  if (isHeadless(argv)) {
270
- const { runHeadlessInstall } = await import("./ci-install-DnVNVs0f.js");
270
+ const { runHeadlessInstall } = await import("./ci-install-D1Mum8Ah.js");
271
271
  return runHeadlessInstall(argv);
272
272
  }
273
273
  if (argv.ci) {
274
- const { runCIInstall } = await import("./ci-install-DnVNVs0f.js");
274
+ const { runCIInstall } = await import("./ci-install-D1Mum8Ah.js");
275
275
  return runCIInstall(argv);
276
276
  }
277
277
  if (isNonInteractiveEnvironment()) {
278
- const { failNonInteractive } = await import("./non-interactive-Cpof2JsA.js");
278
+ const { failNonInteractive } = await import("./non-interactive-DdUe8lqX.js");
279
279
  return failNonInteractive();
280
280
  }
281
281
  if (argv.playground) {
282
- const { runPlayground } = await import("./playground-C3sLBq6A.js");
282
+ const { runPlayground } = await import("./playground-lg7h9GHG.js");
283
283
  return runPlayground();
284
284
  }
285
- const { runInteractive } = await import("./interactive-j4DoJDnk.js");
285
+ const { runInteractive } = await import("./interactive-HM71vLQe.js");
286
286
  runInteractive(argv);
287
287
  })();
288
288
  }
@@ -1788,13 +1788,14 @@ const DISPLAY_NAME = {
1788
1788
  rollup: "Rollup"
1789
1789
  };
1790
1790
  /**
1791
- * Variants the wizard can wire up source-map upload for automatically. The
1792
- * native variants (react-native, flutter) are recognised but not yet
1793
- * automatable, so the agentic picker treats them as non-instrumentable.
1791
+ * Variants the wizard can wire up source-map upload for automatically. React
1792
+ * Native is recognised but not yet automatable, so the agentic picker treats
1793
+ * it as non-instrumentable.
1794
1794
  */
1795
1795
  const AUTOMATABLE_VARIANTS = [
1796
1796
  "android",
1797
1797
  "ios",
1798
+ "flutter",
1798
1799
  "web",
1799
1800
  "nextjs",
1800
1801
  "node",
@@ -1807,9 +1808,16 @@ const AUTOMATABLE_VARIANTS = [
1807
1808
  ];
1808
1809
  /**
1809
1810
  * Variants the wizard pre-installs a machine-global `posthog-cli` for — their
1810
- * build shells out to it with no npx / local-dep fallback. JS variants stay out.
1811
+ * build shells out to it with no npx / local-dep fallback. JS variants stay
1812
+ * out. Flutter counts here despite emitting plain `.js.map` files: a Flutter
1813
+ * project has no `package.json`, so there is no npx or local dependency to
1814
+ * fall back to when the post-build step invokes the CLI.
1811
1815
  */
1812
- const VARIANTS_REQUIRING_POSTHOG_CLI = new Set(["ios", "android"]);
1816
+ const VARIANTS_REQUIRING_POSTHOG_CLI = new Set([
1817
+ "ios",
1818
+ "android",
1819
+ "flutter"
1820
+ ]);
1813
1821
  /** `[ABORT] <reason>` cases the source maps skill can emit. */
1814
1822
  const SOURCE_MAPS_ABORT_CASES = [{
1815
1823
  match: /^no posthog sdk detected$/i,
@@ -3790,7 +3798,7 @@ function runMcpAdd(argv) {
3790
3798
  const debug = argv.debug;
3791
3799
  const localMcp = argv.local;
3792
3800
  try {
3793
- const { startTUI } = await import("./start-tui-B2Tb427o.js");
3801
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3794
3802
  const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3795
3803
  const tui = startTUI(VERSION, Program.McpAdd);
3796
3804
  tui.store.session = buildSession({
@@ -3803,7 +3811,7 @@ function runMcpAdd(argv) {
3803
3811
  } catch (error) {
3804
3812
  if (!isTUIUnavailable(error)) throw error;
3805
3813
  setUI(new LoggingUI());
3806
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-C1f2al7N.js").then((n) => n.r);
3814
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-DJyWMMGj.js").then((n) => n.r);
3807
3815
  await addMCPServerToClientsStep({
3808
3816
  local: localMcp,
3809
3817
  features,
@@ -3842,7 +3850,7 @@ function runMcpRemove(argv) {
3842
3850
  const debug = argv.debug;
3843
3851
  const localMcp = argv.local;
3844
3852
  try {
3845
- const { startTUI } = await import("./start-tui-B2Tb427o.js");
3853
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3846
3854
  const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3847
3855
  const tui = startTUI(VERSION, Program.McpRemove);
3848
3856
  tui.store.session = buildSession({
@@ -3852,7 +3860,7 @@ function runMcpRemove(argv) {
3852
3860
  });
3853
3861
  } catch {
3854
3862
  setUI(new LoggingUI());
3855
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-C1f2al7N.js").then((n) => n.r);
3863
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-DJyWMMGj.js").then((n) => n.r);
3856
3864
  await removeMCPServerFromClientsStep({ local: localMcp });
3857
3865
  }
3858
3866
  })();
@@ -3874,7 +3882,7 @@ function runMcpTutorial(argv) {
3874
3882
  const debug = argv.debug;
3875
3883
  const localMcp = argv.local;
3876
3884
  try {
3877
- const { startTUI } = await import("./start-tui-B2Tb427o.js");
3885
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3878
3886
  const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
3879
3887
  const tui = startTUI(VERSION, Program.McpTutorial);
3880
3888
  tui.store.session = buildSession({
@@ -3955,9 +3963,9 @@ function runWizard(config, options) {
3955
3963
  (async () => {
3956
3964
  try {
3957
3965
  const installDir = options.installDir || process.cwd();
3958
- const { startTUI } = await import("./start-tui-B2Tb427o.js");
3966
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
3959
3967
  const { buildSession, RunPhase } = await import("./wizard-session-C5lZPPEc.js");
3960
- const { TaskStreamPush } = await import("./task-stream-DCrqCmFa.js");
3968
+ const { TaskStreamPush } = await import("./task-stream-BZOjOhKu.js");
3961
3969
  const { PostHogDestination } = await import("./posthog-mgz-FQlS.js");
3962
3970
  tui = startTUI(WIZARD_VERSION, config.id);
3963
3971
  const activeTui = tui;
@@ -4023,7 +4031,7 @@ function runWizard(config, options) {
4023
4031
  if (shown(step)) await advanceStep(step, activeTui.store, config);
4024
4032
  }
4025
4033
  else if (skipAgent) {
4026
- const { getOrAskForProjectData } = await import("./setup-utils-ZKEk71yV.js").then((n) => n.r);
4034
+ const { getOrAskForProjectData } = await import("./setup-utils-DDzEnDxJ.js").then((n) => n.r);
4027
4035
  const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
4028
4036
  signup: session.signup,
4029
4037
  ci: session.ci,
@@ -4125,10 +4133,10 @@ function runNonInteractive(config, options, mode) {
4125
4133
  (async () => {
4126
4134
  const path = await import("path");
4127
4135
  const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-C5lZPPEc.js");
4128
- const { readEnvironment } = await import("./environment-DJQOs7MR.js").then((n) => n.t);
4136
+ const { readEnvironment } = await import("./environment-Bi-zynk6.js").then((n) => n.t);
4129
4137
  const { readApiKeyFromEnv } = await import("./env-api-key-DDVkPQmo.js").then((n) => n.t);
4130
- const { configureLogFileFromEnvironment, logToFile } = await import("./debug-By1_VtgZ.js");
4131
- const { wizardAbort, WizardError } = await import("./wizard-abort-cX4Kytai.js");
4138
+ const { configureLogFileFromEnvironment, logToFile } = await import("./debug-DsSCOPe8.js");
4139
+ const { wizardAbort, WizardError } = await import("./wizard-abort-DHC_XStW.js");
4132
4140
  configureLogFileFromEnvironment();
4133
4141
  const env = readEnvironment();
4134
4142
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -4160,9 +4168,9 @@ function runNonInteractive(config, options, mode) {
4160
4168
  let store = null;
4161
4169
  let taskStream = null;
4162
4170
  if (mode === "headless") {
4163
- const { WizardStore } = await import("./store-Db77bfRv.js").then((n) => n.n);
4164
- const { HeadlessUI } = await import("./headless-ui-wIeUgvJ8.js");
4165
- const { TaskStreamPush, PostHogDestination } = await import("./task-stream-DCrqCmFa.js");
4171
+ const { WizardStore } = await import("./store-BCRdtfOH.js").then((n) => n.n);
4172
+ const { HeadlessUI } = await import("./headless-ui-C4X9lAOY.js");
4173
+ const { TaskStreamPush, PostHogDestination } = await import("./task-stream-BZOjOhKu.js");
4166
4174
  store = new WizardStore(config.id);
4167
4175
  store.session = session;
4168
4176
  setUI(new HeadlessUI(store));
@@ -4218,7 +4226,7 @@ function runNonInteractive(config, options, mode) {
4218
4226
  });
4219
4227
  }
4220
4228
  }
4221
- const { runAgent } = await import("./agent-runner-DSKXFDXa.js").then((n) => n.t);
4229
+ const { runAgent } = await import("./agent-runner-B1qCtjid.js").then((n) => n.t);
4222
4230
  await runAgent(config, session);
4223
4231
  await settleStream(RunPhase.Completed);
4224
4232
  } catch (error) {
@@ -5161,7 +5169,7 @@ async function runDoctorCI(options) {
5161
5169
  getUI().intro("Welcome to the PostHog setup wizard");
5162
5170
  getUI().log.info("Running posthog-doctor in CI mode");
5163
5171
  try {
5164
- const { getOrAskForProjectData } = await import("./setup-utils-ZKEk71yV.js").then((n) => n.r);
5172
+ const { getOrAskForProjectData } = await import("./setup-utils-DDzEnDxJ.js").then((n) => n.r);
5165
5173
  const { host, accessToken, projectId } = await getOrAskForProjectData({
5166
5174
  signup: false,
5167
5175
  ci: true,
@@ -5179,7 +5187,7 @@ async function runDoctorCI(options) {
5179
5187
  for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
5180
5188
  process.exit(1);
5181
5189
  } catch (error) {
5182
- const { ApiError } = await import("./api-BdanR3Zp.js").then((n) => n.n);
5190
+ const { ApiError } = await import("./api-BaacjH-Y.js").then((n) => n.n);
5183
5191
  const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
5184
5192
  getUI().log.error(`Doctor failed: ${message}`);
5185
5193
  process.exit(1);
@@ -5261,7 +5269,7 @@ function runSlackConnect(argv) {
5261
5269
  (async () => {
5262
5270
  const debug = argv.debug;
5263
5271
  try {
5264
- const { startTUI } = await import("./start-tui-B2Tb427o.js");
5272
+ const { startTUI } = await import("./start-tui-pCi7WVAK.js");
5265
5273
  const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
5266
5274
  const tui = startTUI(VERSION, Program.SlackConnect);
5267
5275
  tui.store.session = buildSession({