@posthog/wizard 2.10.0 → 2.10.2

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 (38) hide show
  1. package/dist/{McpScreen-BmHapIaP.js → McpScreen-BUr995Wh.js} +10 -11
  2. package/dist/{McpScreen-BmHapIaP.js.map → McpScreen-BUr995Wh.js.map} +1 -1
  3. package/dist/{add-mcp-server-to-clients-DZtISNrs.js → add-mcp-server-to-clients-65h6IpxC.js} +3 -22
  4. package/dist/add-mcp-server-to-clients-65h6IpxC.js.map +1 -0
  5. package/dist/{agent-runner-CGwrcr57.js → agent-runner-DsymRIHf.js} +9 -7
  6. package/dist/{agent-runner-CGwrcr57.js.map → agent-runner-DsymRIHf.js.map} +1 -1
  7. package/dist/{analytics-C4jO5Qda.js → analytics-CpRZ9V5j.js} +2 -2
  8. package/dist/{analytics-C4jO5Qda.js.map → analytics-CpRZ9V5j.js.map} +1 -1
  9. package/dist/analytics-D6yTMqoi.js +2 -0
  10. package/dist/bin.js +22 -18
  11. package/dist/bin.js.map +1 -1
  12. package/dist/{detection-CkLpxBCD.js → detection-D8428PBG.js} +3 -3
  13. package/dist/{detection-CkLpxBCD.js.map → detection-D8428PBG.js.map} +1 -1
  14. package/dist/{package-manager-nUQ-ebjr.js → package-manager-B_VtY9ZS.js} +2 -2
  15. package/dist/{package-manager-nUQ-ebjr.js.map → package-manager-B_VtY9ZS.js.map} +1 -1
  16. package/dist/{posthog-integration-BzxdDK4z.js → posthog-integration-EeKb2FkQ.js} +7 -7
  17. package/dist/{posthog-integration-BzxdDK4z.js.map → posthog-integration-EeKb2FkQ.js.map} +1 -1
  18. package/dist/{readiness-Dn7eq8NE.js → readiness-V6pfR5tp.js} +4 -4
  19. package/dist/{readiness-Dn7eq8NE.js.map → readiness-V6pfR5tp.js.map} +1 -1
  20. package/dist/{registry-s55_iuJT.js → registry-BUdvRdBh.js} +4 -4
  21. package/dist/{registry-s55_iuJT.js.map → registry-BUdvRdBh.js.map} +1 -1
  22. package/dist/{setup-utils-CdDnllRW.js → setup-utils-DJuYiRId.js} +4 -4
  23. package/dist/{setup-utils-CdDnllRW.js.map → setup-utils-DJuYiRId.js.map} +1 -1
  24. package/dist/{start-playground-B8qCLu7U.js → start-playground-mQFlOf6e.js} +3 -3
  25. package/dist/{start-playground-B8qCLu7U.js.map → start-playground-mQFlOf6e.js.map} +1 -1
  26. package/dist/{start-tui-PygiIyNC.js → start-tui-CSLj4eU7.js} +9 -11
  27. package/dist/{start-tui-PygiIyNC.js.map → start-tui-CSLj4eU7.js.map} +1 -1
  28. package/dist/{steps-CySv8XdD.js → steps-u8U1Nz2e.js} +5 -5
  29. package/dist/{steps-CySv8XdD.js.map → steps-u8U1Nz2e.js.map} +1 -1
  30. package/dist/{telemetry-Ct_GGkSO.js → telemetry-CjokGP19.js} +2 -2
  31. package/dist/{telemetry-Ct_GGkSO.js.map → telemetry-CjokGP19.js.map} +1 -1
  32. package/dist/{wizard-abort-Dhjb2o08.js → wizard-abort-0IZHiW_d.js} +1 -1
  33. package/dist/{wizard-abort-7HUIsqv1.js → wizard-abort-DhECsFZO.js} +2 -2
  34. package/dist/{wizard-abort-7HUIsqv1.js.map → wizard-abort-DhECsFZO.js.map} +1 -1
  35. package/npm-shrinkwrap.json +2 -2
  36. package/package.json +1 -1
  37. package/dist/add-mcp-server-to-clients-DZtISNrs.js.map +0 -1
  38. package/dist/analytics-CpjaBpx6.js +0 -2
@@ -2,7 +2,7 @@ import { r as debug } from "./debug-CyJ_3dTP.js";
2
2
  import { PostHog } from "posthog-node";
3
3
  import { v4 } from "uuid";
4
4
  //#region src/lib/version.ts
5
- const VERSION = "2.10.0";
5
+ const VERSION = "2.10.2";
6
6
  //#endregion
7
7
  //#region src/lib/constants.ts
8
8
  /**
@@ -204,4 +204,4 @@ const analytics = new Analytics();
204
204
  //#endregion
205
205
  export { WIZARD_VARIANT_FLAG_KEY as C, WIZARD_VARIANTS as S, VERSION as T, POSTHOG_US_CLIENT_ID as _, DEFAULT_HOST_URL as a, WIZARD_REMARK_EVENT_NAME as b, ISSUES_URL as c, OAUTH_TIMEOUT_MS as d, POSTHOG_DEV_CLIENT_ID as f, POSTHOG_PROXY_CLIENT_ID as g, POSTHOG_PROPERTY_HEADER_PREFIX as h, CONTEXT_MILL_URL as i, Integration as l, POSTHOG_OAUTH_URL as m, analytics as n, DETECTION_TIMEOUT_MS as o, POSTHOG_FLAG_HEADER_PREFIX as p, sessionProperties as r, DUMMY_PROJECT_API_KEY as s, Analytics as t, OAUTH_PORTS as u, REMOTE_SKILLS_BASE_URL as v, getSkillsBaseUrl as w, WIZARD_USER_AGENT as x, WIZARD_INTERACTION_EVENT_NAME as y };
206
206
 
207
- //# sourceMappingURL=analytics-C4jO5Qda.js.map
207
+ //# sourceMappingURL=analytics-CpRZ9V5j.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analytics-C4jO5Qda.js","names":["uuidv4"],"sources":["../src/lib/version.ts","../src/lib/constants.ts","../src/utils/analytics.ts"],"sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.10.0';\n","/**\n * Shared constants for the PostHog wizard.\n */\n\nimport { VERSION } from './version';\n\n// ── Integration / CLI ───────────────────────────────────────────────\n\n/**\n * Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.\n */\nexport enum Integration {\n // Frameworks\n nextjs = 'nextjs',\n nuxt = 'nuxt',\n vue = 'vue',\n reactRouter = 'react-router',\n tanstackStart = 'tanstack-start',\n tanstackRouter = 'tanstack-router',\n reactNative = 'react-native',\n angular = 'angular',\n astro = 'astro',\n django = 'django',\n flask = 'flask',\n fastapi = 'fastapi',\n laravel = 'laravel',\n sveltekit = 'sveltekit',\n swift = 'swift',\n android = 'android',\n rails = 'rails',\n\n // Language fallbacks\n python = 'python',\n ruby = 'ruby',\n javascriptNode = 'javascript_node',\n javascript_web = 'javascript_web',\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\n// ── Environment ──────────────────────────────────────────────────────\n\nimport { IS_DEV } from '@env';\nexport { IS_DEV };\nexport const DEBUG = false;\n\n// ── URLs ─────────────────────────────────────────────────────────────\n\nexport const DEFAULT_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.posthog.com';\nexport const DEFAULT_HOST_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.i.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const CONTEXT_MILL_URL = 'https://github.com/PostHog/context-mill';\n\n/** Remote base URL for fetching the skill menu + downloading skills. */\nexport const REMOTE_SKILLS_BASE_URL =\n 'https://github.com/PostHog/context-mill/releases/latest/download';\n/** Local base URL when `--local-mcp` is set (served by context-mill dev server). */\nexport const LOCAL_SKILLS_BASE_URL = 'http://localhost:8765';\n\n/**\n * Pick the skills base URL based on the session's localMcp flag.\n * Single source of truth — do not inline this ternary anywhere.\n */\nexport function getSkillsBaseUrl(localMcp: boolean): string {\n return localMcp ? LOCAL_SKILLS_BASE_URL : REMOTE_SKILLS_BASE_URL;\n}\n\n// ── Analytics (internal) ──────────────────────────────────────────────\n\nexport const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';\nexport const ANALYTICS_HOST_URL = 'https://internal-j.posthog.com';\nexport const ANALYTICS_TEAM_TAG = 'docs-and-wizard';\n\n// ── OAuth / Auth ────────────────────────────────────────────────────\n\nexport const POSTHOG_OAUTH_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://oauth.posthog.com';\nexport const OAUTH_PORTS = [8239, 8238, 8240, 8237, 8236, 8235] as const;\nexport const POSTHOG_US_CLIENT_ID = 'c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM';\nexport const POSTHOG_EU_CLIENT_ID = 'bx2C5sZRN03TkdjraCcetvQFPGH6N2Y9vRLkcKEy';\nexport const POSTHOG_DEV_CLIENT_ID = 'DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ';\nexport const POSTHOG_PROXY_CLIENT_ID = POSTHOG_US_CLIENT_ID;\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_TOKEN_';\n\n// ── Wizard run / variants ───────────────────────────────────────────\n\nexport const WIZARD_INTERACTION_EVENT_NAME = 'wizard interaction';\nexport const WIZARD_REMARK_EVENT_NAME = 'wizard remark';\n/** Feature flag key whose value selects a variant from WIZARD_VARIANTS. */\nexport const WIZARD_VARIANT_FLAG_KEY = 'wizard-variant';\n/** Variant key -> metadata for wizard run (VARIANT flag selects which entry to use). */\nexport const WIZARD_VARIANTS: Record<string, Record<string, string>> = {\n base: { VARIANT: 'base' },\n subagents: { VARIANT: 'subagents' },\n};\n/** User-Agent for wizard HTTP requests and MCP server identification. */\nexport const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`;\n\n// ── HTTP headers ─────────────────────────────────────────────────────\n\n/** Header prefix for PostHog properties (e.g. X-POSTHOG-PROPERTY-VARIANT). */\nexport const POSTHOG_PROPERTY_HEADER_PREFIX = 'X-POSTHOG-PROPERTY-';\n/** Header prefix for PostHog feature flags. */\nexport const POSTHOG_FLAG_HEADER_PREFIX = 'X-POSTHOG-FLAG-';\n\n// ── Timeouts ─────────────────────────────────────────────────────────\n\n/** Timeout for framework / project detection probes (ms). */\nexport const DETECTION_TIMEOUT_MS = 10_000;\n\n/** Timeout for the OAuth authorization flow (ms). */\nexport const OAUTH_TIMEOUT_MS = 360_000;\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '../lib/constants';\nimport type { WizardSession } from '../lib/wizard-session';\nimport { v4 as uuidv4 } from 'uuid';\nimport { debug } from './debug';\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}\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 appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\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 });\n\n this.tags = { $app_name: this.appName };\n\n this.anonymousId = uuidv4();\n\n this.distinctId = undefined;\n }\n\n setDistinctId(distinctId: string) {\n this.distinctId = distinctId;\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: {\n $app_name: this.appName,\n },\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: { $app_name: this.appName },\n });\n const flags = result.featureFlags ?? {};\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n this.activeFlags = out;\n return out;\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n return {};\n }\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":";;;;AACA,MAAa,UAAU;;;;;;;;;ACUvB,IAAY,cAAL,yBAAA,aAAA;AAEL,aAAA,YAAA;AACA,aAAA,UAAA;AACA,aAAA,SAAA;AACA,aAAA,iBAAA;AACA,aAAA,mBAAA;AACA,aAAA,oBAAA;AACA,aAAA,iBAAA;AACA,aAAA,aAAA;AACA,aAAA,WAAA;AACA,aAAA,YAAA;AACA,aAAA,WAAA;AACA,aAAA,aAAA;AACA,aAAA,aAAA;AACA,aAAA,eAAA;AACA,aAAA,WAAA;AACA,aAAA,aAAA;AACA,aAAA,WAAA;AAGA,aAAA,YAAA;AACA,aAAA,UAAA;AACA,aAAA,oBAAA;AACA,aAAA,oBAAA;;KACD;AAkBD,MAAa,mBAET;AACJ,MAAa,aAAa;AAC1B,MAAa,mBAAmB;;AAGhC,MAAa,yBACX;;AAEF,MAAa,wBAAwB;;;;;AAMrC,SAAgB,iBAAiB,UAA2B;AAC1D,QAAO,WAAW,wBAAwB;;AAK5C,MAAa,6CAA6C;AAC1D,MAAa,qBAAqB;AAClC,MAAa,qBAAqB;AAIlC,MAAa,oBAET;AACJ,MAAa,cAAc;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAK;AAC/D,MAAa,uBAAuB;AAEpC,MAAa,wBAAwB;AACrC,MAAa,0BAA0B;AACvC,MAAa,wBAAwB;AAIrC,MAAa,gCAAgC;AAC7C,MAAa,2BAA2B;;AAExC,MAAa,0BAA0B;;AAEvC,MAAa,kBAA0D;CACrE,MAAM,EAAE,SAAS,QAAQ;CACzB,WAAW,EAAE,SAAS,aAAa;CACpC;;AAED,MAAa,oBAAoB,4BAA4B;;AAK7D,MAAa,iCAAiC;;AAE9C,MAAa,6BAA6B;;AAK1C,MAAa,uBAAuB;;AAGpC,MAAa,mBAAmB;;;;;;;ACzGhC,SAAgB,kBACd,SACyB;AACzB,QAAO;EACL,aAAa,QAAQ;EACrB,oBAAoB,QAAQ;EAC5B,YAAY,QAAQ;EACpB,YAAY,QAAQ,aAAa;EACjC,qBAAqB,QAAQ;EAC7B,qBAAqB,QAAQ;EAC7B,WAAW,QAAQ;EACpB;;AAEH,IAAa,YAAb,MAAuB;CACrB;CACA,OACE,EAAE;CACJ;CACA;CACA,UAAkB;CAClB,cAAqD;CAErD,cAAc;AACZ,OAAK,SAAS,IAAI,QAAQ,4CAA4C;GACpE,MAAM;GACN,SAAS;GACT,eAAe;GACf,4BAA4B;GAC7B,CAAC;AAEF,OAAK,OAAO,EAAE,WAAW,KAAK,SAAS;AAEvC,OAAK,cAAcA,IAAQ;AAE3B,OAAK,aAAa,KAAA;;CAGpB,cAAc,YAAoB;AAChC,OAAK,aAAa;AAClB,OAAK,OAAO,MAAM;GAChB;GACA,OAAO,KAAK;GACb,CAAC;;CAGJ,OAAO,KAAa,OAAqD;AACvE,OAAK,KAAK,OAAO;;CAGnB,iBAAiB,OAAc,aAAsC,EAAE,EAAE;AACvE,OAAK,OAAO,iBAAiB,OAAO,KAAK,cAAc,KAAK,aAAa;GACvE,MAAM;GACN,GAAG,KAAK;GACR,GAAG;GACJ,CAAC;;CAGJ,QAAQ,WAAmB,YAAsC;AAC/D,OAAK,OAAO,QAAQ;GAClB,YAAY,KAAK,cAAc,KAAK;GACpC,OAAO;GACP,YAAY;IACV,GAAG,KAAK;IACR,GAAG;IACJ;GACF,CAAC;;;;;;CAOJ,cAAc,WAAmB,YAA4C;AAC3E,OAAK,QAAQ,WAAW,aAAa,WAAW;;CAGlD,MAAM,eAAe,SAAwD;AAC3E,MAAI;GACF,MAAM,aAAa,KAAK,cAAc,KAAK;AAC3C,UAAO,MAAM,KAAK,OAAO,eAAe,SAAS,YAAY;IAC3D,uBAAuB;IACvB,kBAAkB,EAChB,WAAW,KAAK,SACjB;IACF,CAAC;WACK,OAAO;AACd,SAAM,+BAA+B,SAAS,MAAM;AACpD;;;;;;;;CASJ,MAAM,uBAAwD;AAC5D,MAAI,KAAK,gBAAgB,KACvB,QAAO,KAAK;AAEd,MAAI;GACF,MAAM,aAAa,KAAK,cAAc,KAAK;GAI3C,MAAM,SAHS,MAAM,KAAK,OAAO,uBAAuB,YAAY,EAClE,kBAAkB,EAAE,WAAW,KAAK,SAAS,EAC9C,CAAC,EACmB,gBAAgB,EAAE;GACvC,MAAM,MAA8B,EAAE;AACtC,QAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;AAChD,QAAI,UAAU,KAAA,EAAW;AACzB,QAAI,OAAO,OAAO,UAAU,YAAY,OAAO,MAAM,GAAG,OAAO,MAAM;;AAEvE,QAAK,cAAc;AACnB,UAAO;WACA,OAAO;AACd,SAAM,oCAAoC,MAAM;AAChD,UAAO,EAAE;;;CAIb,MAAM,SAAS,QAA2C;AACxD,MAAI,OAAO,KAAK,KAAK,KAAK,CAAC,WAAW,EACpC;AAGF,OAAK,OAAO,QAAQ;GAClB,YAAY,KAAK,cAAc,KAAK;GACpC,OAAO;GACP,YAAY;IACV;IACA,MAAM,KAAK;IACZ;GACF,CAAC;AAEF,QAAM,KAAK,OAAO,UAAU;;;AAIhC,MAAa,YAAY,IAAI,WAAW"}
1
+ {"version":3,"file":"analytics-CpRZ9V5j.js","names":["uuidv4"],"sources":["../src/lib/version.ts","../src/lib/constants.ts","../src/utils/analytics.ts"],"sourcesContent":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.10.2';\n","/**\n * Shared constants for the PostHog wizard.\n */\n\nimport { VERSION } from './version';\n\n// ── Integration / CLI ───────────────────────────────────────────────\n\n/**\n * Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.\n */\nexport enum Integration {\n // Frameworks\n nextjs = 'nextjs',\n nuxt = 'nuxt',\n vue = 'vue',\n reactRouter = 'react-router',\n tanstackStart = 'tanstack-start',\n tanstackRouter = 'tanstack-router',\n reactNative = 'react-native',\n angular = 'angular',\n astro = 'astro',\n django = 'django',\n flask = 'flask',\n fastapi = 'fastapi',\n laravel = 'laravel',\n sveltekit = 'sveltekit',\n swift = 'swift',\n android = 'android',\n rails = 'rails',\n\n // Language fallbacks\n python = 'python',\n ruby = 'ruby',\n javascriptNode = 'javascript_node',\n javascript_web = 'javascript_web',\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\n// ── Environment ──────────────────────────────────────────────────────\n\nimport { IS_DEV } from '@env';\nexport { IS_DEV };\nexport const DEBUG = false;\n\n// ── URLs ─────────────────────────────────────────────────────────────\n\nexport const DEFAULT_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.posthog.com';\nexport const DEFAULT_HOST_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.i.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const CONTEXT_MILL_URL = 'https://github.com/PostHog/context-mill';\n\n/** Remote base URL for fetching the skill menu + downloading skills. */\nexport const REMOTE_SKILLS_BASE_URL =\n 'https://github.com/PostHog/context-mill/releases/latest/download';\n/** Local base URL when `--local-mcp` is set (served by context-mill dev server). */\nexport const LOCAL_SKILLS_BASE_URL = 'http://localhost:8765';\n\n/**\n * Pick the skills base URL based on the session's localMcp flag.\n * Single source of truth — do not inline this ternary anywhere.\n */\nexport function getSkillsBaseUrl(localMcp: boolean): string {\n return localMcp ? LOCAL_SKILLS_BASE_URL : REMOTE_SKILLS_BASE_URL;\n}\n\n// ── Analytics (internal) ──────────────────────────────────────────────\n\nexport const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';\nexport const ANALYTICS_HOST_URL = 'https://internal-j.posthog.com';\nexport const ANALYTICS_TEAM_TAG = 'docs-and-wizard';\n\n// ── OAuth / Auth ────────────────────────────────────────────────────\n\nexport const POSTHOG_OAUTH_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://oauth.posthog.com';\nexport const OAUTH_PORTS = [8239, 8238, 8240, 8237, 8236, 8235] as const;\nexport const POSTHOG_US_CLIENT_ID = 'c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM';\nexport const POSTHOG_EU_CLIENT_ID = 'bx2C5sZRN03TkdjraCcetvQFPGH6N2Y9vRLkcKEy';\nexport const POSTHOG_DEV_CLIENT_ID = 'DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ';\nexport const POSTHOG_PROXY_CLIENT_ID = POSTHOG_US_CLIENT_ID;\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_TOKEN_';\n\n// ── Wizard run / variants ───────────────────────────────────────────\n\nexport const WIZARD_INTERACTION_EVENT_NAME = 'wizard interaction';\nexport const WIZARD_REMARK_EVENT_NAME = 'wizard remark';\n/** Feature flag key whose value selects a variant from WIZARD_VARIANTS. */\nexport const WIZARD_VARIANT_FLAG_KEY = 'wizard-variant';\n/** Variant key -> metadata for wizard run (VARIANT flag selects which entry to use). */\nexport const WIZARD_VARIANTS: Record<string, Record<string, string>> = {\n base: { VARIANT: 'base' },\n subagents: { VARIANT: 'subagents' },\n};\n/** User-Agent for wizard HTTP requests and MCP server identification. */\nexport const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`;\n\n// ── HTTP headers ─────────────────────────────────────────────────────\n\n/** Header prefix for PostHog properties (e.g. X-POSTHOG-PROPERTY-VARIANT). */\nexport const POSTHOG_PROPERTY_HEADER_PREFIX = 'X-POSTHOG-PROPERTY-';\n/** Header prefix for PostHog feature flags. */\nexport const POSTHOG_FLAG_HEADER_PREFIX = 'X-POSTHOG-FLAG-';\n\n// ── Timeouts ─────────────────────────────────────────────────────────\n\n/** Timeout for framework / project detection probes (ms). */\nexport const DETECTION_TIMEOUT_MS = 10_000;\n\n/** Timeout for the OAuth authorization flow (ms). */\nexport const OAUTH_TIMEOUT_MS = 360_000;\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '../lib/constants';\nimport type { WizardSession } from '../lib/wizard-session';\nimport { v4 as uuidv4 } from 'uuid';\nimport { debug } from './debug';\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}\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 appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\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 });\n\n this.tags = { $app_name: this.appName };\n\n this.anonymousId = uuidv4();\n\n this.distinctId = undefined;\n }\n\n setDistinctId(distinctId: string) {\n this.distinctId = distinctId;\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: {\n $app_name: this.appName,\n },\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: { $app_name: this.appName },\n });\n const flags = result.featureFlags ?? {};\n const out: Record<string, string> = {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n this.activeFlags = out;\n return out;\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n return {};\n }\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n 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-CpRZ9V5j.js";
2
+ export { analytics };
package/dist/bin.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
3
3
  import { c as getUI, f as runtimeEnv, l as setUI, p as red, u as LoggingUI } from "./debug-CyJ_3dTP.js";
4
- import { T as VERSION } from "./analytics-C4jO5Qda.js";
5
- import "./setup-utils-CdDnllRW.js";
6
- import { t as posthogIntegrationConfig } from "./posthog-integration-BzxdDK4z.js";
4
+ import { T as VERSION } from "./analytics-CpRZ9V5j.js";
5
+ import "./setup-utils-DJuYiRId.js";
6
+ import { t as posthogIntegrationConfig } from "./posthog-integration-EeKb2FkQ.js";
7
7
  import { t as IGNORED_DIRS } from "./file-utils-BWneZy6p.js";
8
8
  import { satisfies } from "semver";
9
9
  import yargs from "yargs";
@@ -292,6 +292,10 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
292
292
  "project-id": {
293
293
  describe: "PostHog project ID to use (optional; when not set, uses default from API key or OAuth)\nenv: POSTHOG_WIZARD_PROJECT_ID",
294
294
  type: "string"
295
+ },
296
+ email: {
297
+ describe: "Email address for signup (used with --signup)\nenv: POSTHOG_WIZARD_EMAIL",
298
+ type: "string"
295
299
  }
296
300
  }).command(["$0"], "Run the PostHog setup wizard", (yargs) => {
297
301
  return yargs.options({
@@ -362,11 +366,11 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
362
366
  return;
363
367
  }
364
368
  (async () => {
365
- const { posthogIntegrationConfig } = await import("./posthog-integration-BzxdDK4z.js").then((n) => n.n);
366
- const { FRAMEWORK_REGISTRY } = await import("./registry-s55_iuJT.js").then((n) => n.n);
367
- const { detectFramework, gatherFrameworkContext } = await import("./detection-CkLpxBCD.js").then((n) => n.t);
368
- const { analytics } = await import("./analytics-CpjaBpx6.js");
369
- const { wizardAbort } = await import("./wizard-abort-Dhjb2o08.js");
369
+ const { posthogIntegrationConfig } = await import("./posthog-integration-EeKb2FkQ.js").then((n) => n.n);
370
+ const { FRAMEWORK_REGISTRY } = await import("./registry-BUdvRdBh.js").then((n) => n.n);
371
+ const { detectFramework, gatherFrameworkContext } = await import("./detection-D8428PBG.js").then((n) => n.t);
372
+ const { analytics } = await import("./analytics-D6yTMqoi.js");
373
+ const { wizardAbort } = await import("./wizard-abort-0IZHiW_d.js");
370
374
  runWizardCI(posthogIntegrationConfig, options, async (session) => {
371
375
  const integration = session.integration ?? await detectFramework(session.installDir);
372
376
  if (!integration) {
@@ -399,7 +403,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
399
403
  getUI().log.error("This installer requires an interactive terminal (TTY) to run.\nIt appears you are running in a non-interactive environment.\nPlease run the wizard in an interactive terminal.\n\nFor CI/CD environments, use --ci mode:\n npx @posthog/wizard --ci --region us --api-key phx_xxx");
400
404
  process.exit(1);
401
405
  } else if (options.playground) (async () => {
402
- const { startPlayground } = await import("./start-playground-B8qCLu7U.js");
406
+ const { startPlayground } = await import("./start-playground-mQFlOf6e.js");
403
407
  startPlayground(WIZARD_VERSION);
404
408
  })();
405
409
  else if (options.skill) (async () => {
@@ -419,7 +423,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
419
423
  }), options);
420
424
  })();
421
425
  else (async () => {
422
- const { posthogIntegrationConfig } = await import("./posthog-integration-BzxdDK4z.js").then((n) => n.n);
426
+ const { posthogIntegrationConfig } = await import("./posthog-integration-EeKb2FkQ.js").then((n) => n.n);
423
427
  runWizard(posthogIntegrationConfig, options);
424
428
  })();
425
429
  }).command("mcp <command>", "MCP server management commands", (yargs) => {
@@ -446,7 +450,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
446
450
  const { readApiKeyFromEnv } = await import("./env-api-key-K8TdTDII.js");
447
451
  const apiKey = options.apiKey || readApiKeyFromEnv();
448
452
  try {
449
- const { startTUI } = await import("./start-tui-PygiIyNC.js");
453
+ const { startTUI } = await import("./start-tui-CSLj4eU7.js");
450
454
  const { buildSession } = await import("./wizard-session-y7nf6aKH.js");
451
455
  const { Flow } = await import("./router-D5A1Sb4p.js").then((n) => n.n);
452
456
  const tui = startTUI(WIZARD_VERSION, Flow.McpAdd);
@@ -459,7 +463,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
459
463
  tui.store.session = session;
460
464
  } catch {
461
465
  setUI(new LoggingUI());
462
- const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-DZtISNrs.js").then((n) => n.r);
466
+ const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-65h6IpxC.js").then((n) => n.r);
463
467
  await addMCPServerToClientsStep({
464
468
  local: options.local,
465
469
  features: mcpFeatures,
@@ -477,7 +481,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
477
481
  const options = { ...argv };
478
482
  (async () => {
479
483
  try {
480
- const { startTUI } = await import("./start-tui-PygiIyNC.js");
484
+ const { startTUI } = await import("./start-tui-CSLj4eU7.js");
481
485
  const { buildSession } = await import("./wizard-session-y7nf6aKH.js");
482
486
  const { Flow } = await import("./router-D5A1Sb4p.js").then((n) => n.n);
483
487
  const tui = startTUI(WIZARD_VERSION, Flow.McpRemove);
@@ -488,7 +492,7 @@ const cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options({
488
492
  tui.store.session = session;
489
493
  } catch {
490
494
  setUI(new LoggingUI());
491
- const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-DZtISNrs.js").then((n) => n.r);
495
+ const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-65h6IpxC.js").then((n) => n.r);
492
496
  await removeMCPServerFromClientsStep({ local: options.local });
493
497
  }
494
498
  })();
@@ -509,7 +513,7 @@ function runWizard(config, options) {
509
513
  (async () => {
510
514
  try {
511
515
  const installDir = options.installDir || process.cwd();
512
- const { startTUI } = await import("./start-tui-PygiIyNC.js");
516
+ const { startTUI } = await import("./start-tui-CSLj4eU7.js");
513
517
  const { buildSession } = await import("./wizard-session-y7nf6aKH.js");
514
518
  const tui = startTUI(WIZARD_VERSION, config.flowKey);
515
519
  const session = buildSession({
@@ -531,7 +535,7 @@ function runWizard(config, options) {
531
535
  tui.store.session = session;
532
536
  await tui.store.runReadyHooks();
533
537
  await tui.store.getGate("intro");
534
- const { runAgent } = await import("./agent-runner-CGwrcr57.js");
538
+ const { runAgent } = await import("./agent-runner-DsymRIHf.js");
535
539
  await runAgent(config, tui.store.session);
536
540
  await new Promise((resolve) => {
537
541
  const unsub = tui.store.subscribe(() => {
@@ -578,7 +582,7 @@ function runWizardCI(config, options, preRun) {
578
582
  const { readEnvironment } = await Promise.resolve().then(() => environment_exports);
579
583
  const { readApiKeyFromEnv } = await import("./env-api-key-K8TdTDII.js");
580
584
  const { configureLogFileFromEnvironment, logToFile } = await import("./debug-CIyf0ZGx.js");
581
- const { wizardAbort, WizardError } = await import("./wizard-abort-Dhjb2o08.js");
585
+ const { wizardAbort, WizardError } = await import("./wizard-abort-0IZHiW_d.js");
582
586
  configureLogFileFromEnvironment();
583
587
  const env = readEnvironment();
584
588
  const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
@@ -627,7 +631,7 @@ function runWizardCI(config, options, preRun) {
627
631
  })
628
632
  });
629
633
  }
630
- const { runAgent } = await import("./agent-runner-CGwrcr57.js");
634
+ const { runAgent } = await import("./agent-runner-DsymRIHf.js");
631
635
  await runAgent(config, session);
632
636
  } catch (error) {
633
637
  const errorMessage = error instanceof Error ? error.message : String(error);
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","names":[],"sources":["../src/utils/environment.ts","../src/lib/workflows/revenue-analytics/detect.ts","../src/lib/workflows/revenue-analytics/steps.ts","../src/lib/workflows/revenue-analytics/index.ts","../src/lib/workflows/workflow-registry.ts","../bin.ts"],"sourcesContent":["import readEnvModule from 'read-env';\n\nconst readEnv =\n typeof readEnvModule === 'function'\n ? readEnvModule\n : (readEnvModule as any).default;\nimport { tryGetPackageJson } from './setup-utils';\nimport type { WizardOptions } from './types';\nimport fg from 'fast-glob';\nimport { IS_DEV } from '../lib/constants';\n\nexport function isNonInteractiveEnvironment(): boolean {\n if (IS_DEV) {\n return false;\n }\n\n if (!process.stdout.isTTY || !process.stderr.isTTY) {\n return true;\n }\n\n return false;\n}\n\nexport function readEnvironment(): Record<string, unknown> {\n const result = readEnv('POSTHOG_WIZARD');\n\n return result;\n}\n\nexport async function detectEnvVarPrefix(\n options: WizardOptions,\n): Promise<string> {\n const packageJson = await tryGetPackageJson(options);\n if (!packageJson) return 'VITE_PUBLIC_';\n\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n const has = (name: string) => name in deps;\n const hasAnyFile = async (patterns: string[]) => {\n const matches = await fg(patterns, {\n cwd: options.installDir,\n absolute: false,\n onlyFiles: true,\n ignore: ['**/node_modules/**'],\n });\n return matches.length > 0;\n };\n\n // --- Next.js\n if (has('next') || (await hasAnyFile(['**/next.config.{js,ts,mjs,cjs}']))) {\n return 'NEXT_PUBLIC_';\n }\n\n // --- Create React App\n if (\n has('react-scripts') ||\n has('create-react-app') ||\n (await hasAnyFile(['**/config-overrides.js']))\n ) {\n return 'REACT_APP_';\n }\n\n // --- Vite (vanilla, TanStack, Solid, etc.)\n // Note: Vite does not need PUBLIC_ but we use it to follow the docs, to improve the chances of an LLM getting it right.\n if (has('vite') || (await hasAnyFile(['**/vite.config.{js,ts,mjs,cjs}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SvelteKit\n if (\n has('@sveltejs/kit') ||\n (await hasAnyFile(['**/svelte.config.{js,ts}']))\n ) {\n return 'PUBLIC_';\n }\n\n // --- TanStack Start (uses Vite)\n if (\n has('@tanstack/start') ||\n (await hasAnyFile(['**/tanstack.config.{js,ts}']))\n ) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SolidStart (uses Vite)\n if (has('solid-start') || (await hasAnyFile(['**/solid.config.{js,ts}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- Astro\n if (has('astro') || (await hasAnyFile(['**/astro.config.{js,ts,mjs}']))) {\n return 'PUBLIC_';\n }\n\n // We default to Vite if we can't detect a specific framework, since it's the most commonly used.\n return 'VITE_PUBLIC_';\n}\n","/**\n * Revenue analytics prerequisite detection.\n *\n * Scans the project for PostHog + Stripe SDKs and writes results\n * into frameworkContext for the intro screen to render.\n */\n\nimport type { Dirent } from 'fs';\nimport { readFileSync, readdirSync, existsSync, statSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '../../../utils/file-utils.js';\nimport type { WizardSession } from '../../wizard-session.js';\nimport type { AbortCase } from '../../agent/agent-runner.js';\n\nexport const POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\nexport const STRIPE_SDKS = [\n 'stripe',\n '@stripe/stripe-js',\n '@stripe/react-stripe-js',\n];\n\ninterface PackageMatch {\n /** Path to the package.json relative to installDir */\n path: string;\n posthogSdks: string[];\n stripeSdks: string[];\n}\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type RevenueDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-sdks'; scannedCount: number }\n | { kind: 'missing-posthog'; foundStripe: string[] }\n | { kind: 'missing-stripe'; foundPosthog: string[] };\n\n/** `[ABORT] <reason>` cases the revenue analytics skill can emit. */\nexport const REVENUE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] Could not find a PostHog distinct_id\n match: /^could not find a posthog distinct_id$/i,\n message: 'Could not find a PostHog distinct_id',\n body:\n 'The agent could not find PostHog distinct_id usage in your codebase. ' +\n 'Your users must be identified in PostHog before they can be tagged in Stripe. ' +\n 'Please identify your users and try again.',\n docsUrl: 'https://posthog.com/docs/product-analytics/identify',\n },\n {\n // Skill emits: [ABORT] Could not find a Stripe integration\n match: /^could not find a stripe integration$/i,\n message: 'Could not find a Stripe integration',\n body:\n 'The Wizard could not find an existing Stripe customer, charge, ' +\n 'subscription, or other Stripe operations. Please run the Revenue ' +\n 'Analytics Wizard on a project with an existing Stripe integration.',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n },\n];\n\n/**\n * Recursively find all package.json files under installDir (max depth 3),\n * skipping common ignored directories. Returns matches with detected SDKs.\n */\nfunction findPackageJsons(installDir: string, maxDepth = 3): PackageMatch[] {\n const matches: PackageMatch[] = [];\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile() && entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.includes(d));\n const stripeSdks = depNames.filter((d) => STRIPE_SDKS.includes(d));\n matches.push({\n path: relative(installDir, fullPath) || 'package.json',\n posthogSdks,\n stripeSdks,\n });\n } catch {\n // Skip malformed package.json\n }\n } else if (entry.isDirectory()) {\n scan(fullPath, depth + 1);\n }\n }\n }\n\n scan(installDir, 0);\n return matches;\n}\n\n/**\n * Scan `session.installDir` for PostHog + Stripe SDKs. Writes detection\n * results into frameworkContext via the callback — either the detected\n * SDK lists (for the intro screen) or a `RevenueDetectError` on failure.\n *\n * The skill install happens later in the bootstrap runner, not here.\n */\nexport function detectRevenuePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: RevenueDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n // Verify the install directory exists and is readable\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n // Find all package.json files (root + monorepo subpackages)\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n // Aggregate detected SDKs across all package.json files\n const allPosthogSdks = new Set<string>();\n const allStripeSdks = new Set<string>();\n for (const match of matches) {\n for (const sdk of match.posthogSdks) allPosthogSdks.add(sdk);\n for (const sdk of match.stripeSdks) allStripeSdks.add(sdk);\n }\n\n const detectedPosthogSdks = [...allPosthogSdks];\n const detectedStripeSdks = [...allStripeSdks];\n\n if (detectedPosthogSdks.length === 0 && detectedStripeSdks.length === 0) {\n fail({ kind: 'no-sdks', scannedCount: matches.length });\n return;\n }\n\n if (detectedPosthogSdks.length === 0) {\n fail({ kind: 'missing-posthog', foundStripe: detectedStripeSdks });\n return;\n }\n\n if (detectedStripeSdks.length === 0) {\n fail({ kind: 'missing-stripe', foundPosthog: detectedPosthogSdks });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', detectedPosthogSdks);\n setFrameworkContext('detectedStripeSdks', detectedStripeSdks);\n setFrameworkContext(\n 'detectedPackagePaths',\n matches\n .filter((m) => m.posthogSdks.length > 0 || m.stripeSdks.length > 0)\n .map((m) => m.path),\n );\n}\n","/**\n * Revenue analytics workflow step list.\n *\n * The detect step checks for PostHog + Stripe SDKs. The skill install\n * and agent run live in the workflow runner (see agent-runner.ts).\n */\n\nimport type { Workflow } from '../workflow-step.js';\nimport { RunPhase } from '../../wizard-session.js';\nimport { detectRevenuePrerequisites } from './detect.js';\n\nexport const REVENUE_ANALYTICS_WORKFLOW: Workflow = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — the hook scans for PostHog + Stripe SDKs\n // and writes the results (or a detectError) to frameworkContext\n // for the intro screen to render.\n onReady: (ctx) =>\n detectRevenuePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screen: 'revenue-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screen: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Revenue analytics',\n screen: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screen: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screen: 'keep-skills',\n },\n];\n","import type { WorkflowConfig } from '../workflow-step.js';\nimport { REVENUE_ANALYTICS_WORKFLOW } from './steps.js';\nimport { REVENUE_ABORT_CASES } from './detect.js';\n\nexport const revenueAnalyticsConfig: WorkflowConfig = {\n command: 'revenue',\n description: 'Set up PostHog revenue analytics (e.g. Stripe integration)',\n flowKey: 'revenue-analytics-setup',\n steps: REVENUE_ANALYTICS_WORKFLOW,\n run: {\n skillId: 'revenue-analytics-setup',\n integrationLabel: 'revenue-analytics-setup',\n customPrompt: () => 'Set up revenue analytics for this project.',\n successMessage: 'Revenue analytics configured!',\n reportFile: 'posthog-revenue-report.md',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n spinnerMessage: 'Setting up revenue analytics...',\n estimatedDurationMinutes: 5,\n abortCases: REVENUE_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { REVENUE_ANALYTICS_WORKFLOW } from './steps.js';\nexport {\n detectRevenuePrerequisites,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type RevenueDetectError,\n} from './detect.js';\n","/**\n * Central registry of all wizard workflows.\n *\n * Adding a new workflow:\n * 1. Create src/lib/workflows/<name>/ with index.ts exporting a WorkflowConfig\n * 2. Import and add it to WORKFLOW_REGISTRY below\n * 3. Add a matching Flow enum entry in src/ui/tui/flows.ts\n * 4. (If custom intro screen) add to src/ui/tui/screen-registry.tsx\n *\n * flows.ts, store.ts, and bin.ts all derive their wiring from this array —\n * no need to touch those files when adding a workflow.\n */\n\nimport type { WorkflowConfig } from './workflow-step.js';\nimport { posthogIntegrationConfig } from './posthog-integration/index.js';\nimport { revenueAnalyticsConfig } from './revenue-analytics/index.js';\n\nexport const WORKFLOW_REGISTRY: WorkflowConfig[] = [\n posthogIntegrationConfig,\n revenueAnalyticsConfig,\n];\n\n/** Look up a workflow config by its flowKey. */\nexport function getWorkflowConfig(flowKey: string): WorkflowConfig | undefined {\n return WORKFLOW_REGISTRY.find((c) => c.flowKey === flowKey);\n}\n\n/** All workflow configs that are exposed as CLI subcommands. */\nexport function getSubcommandWorkflows(): WorkflowConfig[] {\n return WORKFLOW_REGISTRY.filter((c) => c.command != null);\n}\n","#!/usr/bin/env node\nimport { satisfies } from 'semver';\nimport { red } from './src/utils/logging';\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { VERSION } from './src/lib/version.js';\n\nconst WIZARD_VERSION = VERSION;\n\nconst NODE_VERSION_RANGE = '>=18.17.0';\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n red(\n `PostHog wizard requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\nimport { isNonInteractiveEnvironment } from './src/utils/environment';\nimport { getUI, setUI } from './src/ui';\nimport { LoggingUI } from './src/ui/logging-ui';\nimport { getSubcommandWorkflows } from './src/lib/workflows/workflow-registry';\nimport type { WorkflowConfig } from './src/lib/workflows/workflow-step';\nimport type { WizardSession } from './src/lib/wizard-session';\nimport { runtimeEnv } from '@env';\n\n// Test mock server — only loaded when NODE_ENV is 'test'.\n// In production builds, tsdown replaces process.env.NODE_ENV with 'production',\n// making this block dead code.\nif (process.env.NODE_ENV === 'test') {\n void (async () => {\n try {\n const { server } = await import('./e2e-tests/mocks/server.js');\n server.listen({\n onUnhandledRequest: 'bypass',\n });\n } catch (error) {\n // Mock server import failed - this can happen during non-E2E tests\n }\n })();\n}\n\n/** Shared yargs options for skill-based workflow subcommands. */\nconst skillSubcommandOptions = {\n debug: {\n default: false,\n describe: 'Enable verbose logging',\n type: 'boolean' as const,\n },\n 'install-dir': {\n describe: 'Directory to install in',\n type: 'string' as const,\n },\n 'local-mcp': {\n default: false,\n describe: 'Use local MCP server',\n type: 'boolean' as const,\n },\n benchmark: {\n default: false,\n describe: 'Run in benchmark mode',\n type: 'boolean' as const,\n },\n 'yara-report': {\n default: false,\n describe: 'Print YARA scanner summary',\n type: 'boolean' as const,\n hidden: true,\n },\n};\n\nconst cli = yargs(hideBin(process.argv))\n .env('POSTHOG_WIZARD')\n // global options\n .options({\n debug: {\n default: false,\n describe: 'Enable verbose logging\\nenv: POSTHOG_WIZARD_DEBUG',\n type: 'boolean',\n },\n region: {\n describe: 'PostHog cloud region\\nenv: POSTHOG_WIZARD_REGION',\n choices: ['us', 'eu'],\n type: 'string',\n },\n default: {\n default: true,\n describe:\n 'Use default options for all prompts\\nenv: POSTHOG_WIZARD_DEFAULT',\n type: 'boolean',\n },\n signup: {\n default: false,\n describe:\n 'Create a new PostHog account during setup\\nenv: POSTHOG_WIZARD_SIGNUP',\n type: 'boolean',\n },\n 'local-mcp': {\n default: false,\n describe:\n 'Use local MCP server at http://localhost:8787/mcp\\nenv: POSTHOG_WIZARD_LOCAL_MCP',\n type: 'boolean',\n },\n ci: {\n default: false,\n describe:\n 'Enable CI mode for non-interactive execution\\nenv: POSTHOG_WIZARD_CI',\n type: 'boolean',\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for authentication\\nenv: POSTHOG_WIZARD_API_KEY',\n type: 'string',\n },\n 'project-id': {\n describe:\n 'PostHog project ID to use (optional; when not set, uses default from API key or OAuth)\\nenv: POSTHOG_WIZARD_PROJECT_ID',\n type: 'string',\n },\n })\n .command(\n ['$0'],\n 'Run the PostHog setup wizard',\n (yargs) => {\n return yargs.options({\n 'force-install': {\n default: false,\n describe:\n 'Force install packages even if peer dependency checks fail\\nenv: POSTHOG_WIZARD_FORCE_INSTALL',\n type: 'boolean',\n },\n 'install-dir': {\n describe:\n 'Directory to install PostHog in\\nenv: POSTHOG_WIZARD_INSTALL_DIR',\n type: 'string',\n },\n playground: {\n default: false,\n describe: 'Launch the TUI primitives playground',\n type: 'boolean',\n },\n integration: {\n describe: 'Integration to set up',\n choices: [\n 'nextjs',\n 'astro',\n 'react',\n 'svelte',\n 'react-native',\n 'tanstack-router',\n 'tanstack-start',\n ],\n type: 'string',\n },\n menu: {\n default: false,\n describe:\n 'Show menu for manual integration selection instead of auto-detecting\\nenv: POSTHOG_WIZARD_MENU',\n type: 'boolean',\n },\n benchmark: {\n default: false,\n describe:\n 'Run in benchmark mode with per-phase token tracking\\nenv: POSTHOG_WIZARD_BENCHMARK',\n type: 'boolean',\n },\n 'yara-report': {\n default: false,\n describe:\n 'Print YARA scanner summary after the agent run\\nenv: POSTHOG_WIZARD_YARA_REPORT',\n type: 'boolean',\n hidden: true,\n },\n skill: {\n describe:\n 'Run a specific context-mill skill by ID\\nenv: POSTHOG_WIZARD_SKILL',\n type: 'string',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n\n // CI mode validation and TTY check\n if (options.ci) {\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --api-key (personal API key phx_xxx)',\n );\n process.exit(1);\n return;\n }\n if (!options.installDir) {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n return;\n }\n void (async () => {\n const { posthogIntegrationConfig } = await import(\n './src/lib/workflows/posthog-integration/index.js'\n );\n const { FRAMEWORK_REGISTRY } = await import('./src/lib/registry.js');\n const { detectFramework, gatherFrameworkContext } = await import(\n './src/lib/detection/index.js'\n );\n const { analytics } = await import('./src/utils/analytics.js');\n const { wizardAbort } = await import('./src/utils/wizard-abort.js');\n\n // preRun: honor --integration, else auto-detect, then gather\n // framework context. Bypasses onReady hooks by design.\n runWizardCI(posthogIntegrationConfig, options, async (session) => {\n const integration =\n session.integration ??\n (await detectFramework(session.installDir));\n if (!integration) {\n await wizardAbort({\n message:\n 'Could not auto-detect your framework. Please specify --integration on the command line.',\n });\n return;\n }\n session.integration = integration;\n analytics.setTag('integration', integration);\n\n const frameworkConfig = FRAMEWORK_REGISTRY[integration];\n session.frameworkConfig = frameworkConfig;\n\n const context = await gatherFrameworkContext(frameworkConfig, {\n installDir: session.installDir,\n debug: session.debug,\n forceInstall: session.forceInstall,\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: true,\n menu: session.menu,\n benchmark: session.benchmark,\n yaraReport: session.yaraReport,\n });\n for (const [key, value] of Object.entries(context)) {\n if (!(key in session.frameworkContext)) {\n session.frameworkContext[key] = value;\n }\n }\n });\n })().catch(() => {\n process.exit(1);\n });\n } else if (isNonInteractiveEnvironment()) {\n // Non-interactive non-CI: error out\n getUI().intro(`PostHog Wizard`);\n getUI().log.error(\n 'This installer requires an interactive terminal (TTY) to run.\\n' +\n 'It appears you are running in a non-interactive environment.\\n' +\n 'Please run the wizard in an interactive terminal.\\n\\n' +\n 'For CI/CD environments, use --ci mode:\\n' +\n ' npx @posthog/wizard --ci --region us --api-key phx_xxx',\n );\n process.exit(1);\n } else if (options.playground) {\n // Playground mode: launch the TUI primitives playground\n void (async () => {\n const { startPlayground } = await import(\n './src/ui/tui/playground/start-playground.js'\n );\n (startPlayground as (version: string) => void)(WIZARD_VERSION);\n })();\n } else if (options.skill) {\n // Run a specific skill by ID\n void (async () => {\n const { createSkillWorkflow } = await import(\n './src/lib/workflows/agent-skill/index.js'\n );\n const skillId = options.skill as string;\n const config = createSkillWorkflow({\n skillId,\n command: 'skill',\n flowKey: 'agent-skill',\n description: `Run skill: ${skillId}`,\n integrationLabel: skillId,\n successMessage: `${skillId} completed!`,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: 'https://posthog.com/docs',\n spinnerMessage: `Running ${skillId}...`,\n estimatedDurationMinutes: 5,\n });\n runWizard(config, options);\n })();\n } else {\n // Interactive TTY: run core-integration through the unified workflow path.\n // Same codepath as `npx @posthog/wizard integrate`.\n void (async () => {\n const { posthogIntegrationConfig } = await import(\n './src/lib/workflows/posthog-integration/index.js'\n );\n runWizard(posthogIntegrationConfig, options);\n })();\n }\n },\n )\n .command('mcp <command>', 'MCP server management commands', (yargs) => {\n return yargs\n .command(\n 'add',\n 'Install PostHog MCP server to supported clients',\n (yargs) => {\n return yargs.options({\n local: {\n default: false,\n describe:\n 'Add local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n features: {\n describe:\n 'Comma-separated list of features to enable (default: all)',\n type: 'string',\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for MCP authentication',\n type: 'string',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n const mcpFeatures = options.features\n ?.split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n void (async () => {\n const { readApiKeyFromEnv } = await import(\n './src/utils/env-api-key.js'\n );\n const apiKey =\n (options.apiKey as string | undefined) || readApiKeyFromEnv();\n\n try {\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import(\n './src/lib/wizard-session.js'\n );\n\n const { Flow } = await import('./src/ui/tui/router.js');\n const tui = startTUI(WIZARD_VERSION, Flow.McpAdd);\n const session = buildSession({\n debug: options.debug,\n localMcp: options.local,\n mcpFeatures,\n apiKey,\n });\n tui.store.session = session;\n } catch {\n // TUI unavailable — fallback to logging\n setUI(new LoggingUI());\n const { addMCPServerToClientsStep } = await import(\n './src/steps/add-mcp-server-to-clients/index.js'\n );\n await addMCPServerToClientsStep({\n local: options.local,\n features: mcpFeatures,\n apiKey,\n });\n }\n })();\n },\n )\n .command(\n 'remove',\n 'Remove PostHog MCP server from supported clients',\n (yargs) => {\n return yargs.options({\n local: {\n default: false,\n describe:\n 'Remove local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n void (async () => {\n try {\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import(\n './src/lib/wizard-session.js'\n );\n\n const { Flow } = await import('./src/ui/tui/router.js');\n const tui = startTUI(WIZARD_VERSION, Flow.McpRemove);\n const session = buildSession({\n debug: options.debug,\n localMcp: options.local,\n });\n tui.store.session = session;\n } catch {\n // TUI unavailable — fallback to logging\n setUI(new LoggingUI());\n const { removeMCPServerFromClientsStep } = await import(\n './src/steps/add-mcp-server-to-clients/index.js'\n );\n await removeMCPServerFromClientsStep({\n local: options.local,\n });\n }\n })();\n },\n )\n .demandCommand(1, 'You must specify a subcommand (add or remove)')\n .help();\n });\n\n// ── Skill-based workflow subcommands (derived from registry) ─────────\nfor (const wfConfig of getSubcommandWorkflows()) {\n cli.command(\n wfConfig.command!,\n wfConfig.description,\n (y) => y.options(skillSubcommandOptions),\n (argv) => {\n const options = { ...argv };\n if (options.ci) {\n runWizardCI(wfConfig, options);\n } else {\n runWizard(wfConfig, options);\n }\n },\n );\n}\n\ncli\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'v')\n .wrap(process.stdout.isTTY ? cli.terminalWidth() : 80).argv;\n\n/**\n * Run a full wizard workflow in the TUI. Handles the full lifecycle: start TUI,\n * build session, run detection, wait for intro gate, execute the\n * agent pipeline, wait for outro dismissal, then exit.\n */\nfunction runWizard(\n config: WorkflowConfig,\n options: Record<string, unknown>,\n): void {\n void (async () => {\n try {\n const installDir = (options.installDir as string) || process.cwd();\n\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import('./src/lib/wizard-session.js');\n\n // flowKey values match Flow enum values by convention\n const tui = startTUI(WIZARD_VERSION, config.flowKey as any);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n forceInstall: options.forceInstall as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n installDir,\n ci: false,\n signup: options.signup as boolean | undefined,\n apiKey: options.apiKey as string | undefined,\n projectId: options.projectId as string | undefined,\n menu: options.menu as boolean | undefined,\n integration: options.integration as any,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n });\n // Set workflow metadata for TUI display\n session.workflowLabel = config.flowKey;\n const runDef = typeof config.run === 'object' ? config.run : null;\n session.skillId = runDef?.skillId ?? null;\n\n tui.store.session = session;\n\n await tui.store.runReadyHooks();\n await tui.store.getGate('intro');\n\n const { runAgent } = await import('./src/lib/agent/agent-runner.js');\n await runAgent(config, tui.store.session);\n\n await new Promise<void>((resolve) => {\n const unsub = tui.store.subscribe(() => {\n if (tui.store.session.skillsComplete) {\n unsub();\n resolve();\n }\n });\n if (tui.store.session.skillsComplete) {\n unsub();\n resolve();\n }\n });\n process.exit(0);\n } catch (err) {\n if (runtimeEnv('DEBUG') || runtimeEnv('POSTHOG_WIZARD_DEBUG')) {\n console.error('TUI init failed:', err); // eslint-disable-line no-console\n }\n }\n })();\n}\n\n/**\n * CI-mode pipeline shared by every non-interactive entry point.\n *\n * Validates flags, builds a `ci:true` session, runs `preRun` (or the\n * workflow's `onReady` hooks by default), executes `runAgent`, and\n * routes any failure through `wizardAbort`. `wizardAbort` owns all\n * exits — never add a raw `process.exit` here.\n */\nfunction runWizardCI(\n config: WorkflowConfig,\n options: Record<string, unknown>,\n preRun?: (session: WizardSession) => Promise<void>,\n): void {\n setUI(new LoggingUI());\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n if (!options.installDir) {\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n }\n\n void (async () => {\n const path = await import('path');\n const { buildSession } = await import('./src/lib/wizard-session.js');\n const { readEnvironment } = await import('./src/utils/environment.js');\n const { readApiKeyFromEnv } = await import('./src/utils/env-api-key.js');\n const { configureLogFileFromEnvironment, logToFile } = await import(\n './src/utils/debug.js'\n );\n const { wizardAbort, WizardError } = await import(\n './src/utils/wizard-abort.js'\n );\n\n configureLogFileFromEnvironment();\n\n const env = readEnvironment();\n const apiKey =\n (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n const installDir = path.isAbsolute(options.installDir as string)\n ? (options.installDir as string)\n : path.join(process.cwd(), options.installDir as string);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n forceInstall: options.forceInstall as boolean | undefined,\n installDir,\n ci: true,\n signup: options.signup as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n apiKey,\n menu: options.menu as boolean | undefined,\n integration: options.integration as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n projectId: options.projectId as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n ...env,\n });\n session.workflowLabel = config.flowKey;\n const runDef = typeof config.run === 'object' ? config.run : null;\n session.skillId = runDef?.skillId ?? null;\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info(`Running ${config.flowKey} in CI mode`);\n\n try {\n if (preRun) {\n await preRun(session);\n } else {\n // Run onReady hooks against a minimal store-less context.\n const readyCtx = {\n session,\n setFrameworkContext: (key: string, value: unknown) => {\n session.frameworkContext[key] = value;\n },\n setFrameworkConfig: () => undefined,\n setDetectedFramework: () => undefined,\n setUnsupportedVersion: () => undefined,\n addDiscoveredFeature: () => undefined,\n setDetectionComplete: () => undefined,\n };\n for (const step of config.steps) {\n if (step.onReady) {\n await step.onReady(readyCtx);\n }\n }\n\n // Surface detectError written by the workflow's detect hook.\n const detectError = session.frameworkContext.detectError as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (detectError) {\n await wizardAbort({\n message: `Prerequisites not met: ${detectError.kind}\\n\\nSee ${\n runDef?.docsUrl ?? 'https://posthog.com/docs'\n }`,\n error: new WizardError(`${config.flowKey} prerequisites failed`, {\n integration: config.flowKey,\n detect_error_kind: detectError.kind,\n }),\n });\n }\n }\n\n const { runAgent } = await import('./src/lib/agent/agent-runner.js');\n await runAgent(config, session);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const errorStack =\n error instanceof Error && error.stack ? error.stack : undefined;\n\n logToFile(`[bin.ts CI] ERROR: ${errorMessage}`);\n if (errorStack) logToFile(`[bin.ts CI] STACK: ${errorStack}`);\n\n const debugInfo = session.debug && errorStack ? `\\n\\n${errorStack}` : '';\n const docsUrl =\n session.frameworkConfig?.metadata.docsUrl ??\n runDef?.docsUrl ??\n 'https://posthog.com/docs';\n await wizardAbort({\n message: `Something went wrong: ${errorMessage}\\n\\nYou can read the documentation at ${docsUrl} to set up manually.${debugInfo}`,\n error: error as Error,\n });\n }\n })().catch(() => {\n process.exit(1);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.js","names":[],"sources":["../src/utils/environment.ts","../src/lib/workflows/revenue-analytics/detect.ts","../src/lib/workflows/revenue-analytics/steps.ts","../src/lib/workflows/revenue-analytics/index.ts","../src/lib/workflows/workflow-registry.ts","../bin.ts"],"sourcesContent":["import readEnvModule from 'read-env';\n\nconst readEnv =\n typeof readEnvModule === 'function'\n ? readEnvModule\n : (readEnvModule as any).default;\nimport { tryGetPackageJson } from './setup-utils';\nimport type { WizardOptions } from './types';\nimport fg from 'fast-glob';\nimport { IS_DEV } from '../lib/constants';\n\nexport function isNonInteractiveEnvironment(): boolean {\n if (IS_DEV) {\n return false;\n }\n\n if (!process.stdout.isTTY || !process.stderr.isTTY) {\n return true;\n }\n\n return false;\n}\n\nexport function readEnvironment(): Record<string, unknown> {\n const result = readEnv('POSTHOG_WIZARD');\n\n return result;\n}\n\nexport async function detectEnvVarPrefix(\n options: WizardOptions,\n): Promise<string> {\n const packageJson = await tryGetPackageJson(options);\n if (!packageJson) return 'VITE_PUBLIC_';\n\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n const has = (name: string) => name in deps;\n const hasAnyFile = async (patterns: string[]) => {\n const matches = await fg(patterns, {\n cwd: options.installDir,\n absolute: false,\n onlyFiles: true,\n ignore: ['**/node_modules/**'],\n });\n return matches.length > 0;\n };\n\n // --- Next.js\n if (has('next') || (await hasAnyFile(['**/next.config.{js,ts,mjs,cjs}']))) {\n return 'NEXT_PUBLIC_';\n }\n\n // --- Create React App\n if (\n has('react-scripts') ||\n has('create-react-app') ||\n (await hasAnyFile(['**/config-overrides.js']))\n ) {\n return 'REACT_APP_';\n }\n\n // --- Vite (vanilla, TanStack, Solid, etc.)\n // Note: Vite does not need PUBLIC_ but we use it to follow the docs, to improve the chances of an LLM getting it right.\n if (has('vite') || (await hasAnyFile(['**/vite.config.{js,ts,mjs,cjs}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SvelteKit\n if (\n has('@sveltejs/kit') ||\n (await hasAnyFile(['**/svelte.config.{js,ts}']))\n ) {\n return 'PUBLIC_';\n }\n\n // --- TanStack Start (uses Vite)\n if (\n has('@tanstack/start') ||\n (await hasAnyFile(['**/tanstack.config.{js,ts}']))\n ) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SolidStart (uses Vite)\n if (has('solid-start') || (await hasAnyFile(['**/solid.config.{js,ts}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- Astro\n if (has('astro') || (await hasAnyFile(['**/astro.config.{js,ts,mjs}']))) {\n return 'PUBLIC_';\n }\n\n // We default to Vite if we can't detect a specific framework, since it's the most commonly used.\n return 'VITE_PUBLIC_';\n}\n","/**\n * Revenue analytics prerequisite detection.\n *\n * Scans the project for PostHog + Stripe SDKs and writes results\n * into frameworkContext for the intro screen to render.\n */\n\nimport type { Dirent } from 'fs';\nimport { readFileSync, readdirSync, existsSync, statSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '../../../utils/file-utils.js';\nimport type { WizardSession } from '../../wizard-session.js';\nimport type { AbortCase } from '../../agent/agent-runner.js';\n\nexport const POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\nexport const STRIPE_SDKS = [\n 'stripe',\n '@stripe/stripe-js',\n '@stripe/react-stripe-js',\n];\n\ninterface PackageMatch {\n /** Path to the package.json relative to installDir */\n path: string;\n posthogSdks: string[];\n stripeSdks: string[];\n}\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type RevenueDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-sdks'; scannedCount: number }\n | { kind: 'missing-posthog'; foundStripe: string[] }\n | { kind: 'missing-stripe'; foundPosthog: string[] };\n\n/** `[ABORT] <reason>` cases the revenue analytics skill can emit. */\nexport const REVENUE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] Could not find a PostHog distinct_id\n match: /^could not find a posthog distinct_id$/i,\n message: 'Could not find a PostHog distinct_id',\n body:\n 'The agent could not find PostHog distinct_id usage in your codebase. ' +\n 'Your users must be identified in PostHog before they can be tagged in Stripe. ' +\n 'Please identify your users and try again.',\n docsUrl: 'https://posthog.com/docs/product-analytics/identify',\n },\n {\n // Skill emits: [ABORT] Could not find a Stripe integration\n match: /^could not find a stripe integration$/i,\n message: 'Could not find a Stripe integration',\n body:\n 'The Wizard could not find an existing Stripe customer, charge, ' +\n 'subscription, or other Stripe operations. Please run the Revenue ' +\n 'Analytics Wizard on a project with an existing Stripe integration.',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n },\n];\n\n/**\n * Recursively find all package.json files under installDir (max depth 3),\n * skipping common ignored directories. Returns matches with detected SDKs.\n */\nfunction findPackageJsons(installDir: string, maxDepth = 3): PackageMatch[] {\n const matches: PackageMatch[] = [];\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile() && entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.includes(d));\n const stripeSdks = depNames.filter((d) => STRIPE_SDKS.includes(d));\n matches.push({\n path: relative(installDir, fullPath) || 'package.json',\n posthogSdks,\n stripeSdks,\n });\n } catch {\n // Skip malformed package.json\n }\n } else if (entry.isDirectory()) {\n scan(fullPath, depth + 1);\n }\n }\n }\n\n scan(installDir, 0);\n return matches;\n}\n\n/**\n * Scan `session.installDir` for PostHog + Stripe SDKs. Writes detection\n * results into frameworkContext via the callback — either the detected\n * SDK lists (for the intro screen) or a `RevenueDetectError` on failure.\n *\n * The skill install happens later in the bootstrap runner, not here.\n */\nexport function detectRevenuePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: RevenueDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n // Verify the install directory exists and is readable\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n // Find all package.json files (root + monorepo subpackages)\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n // Aggregate detected SDKs across all package.json files\n const allPosthogSdks = new Set<string>();\n const allStripeSdks = new Set<string>();\n for (const match of matches) {\n for (const sdk of match.posthogSdks) allPosthogSdks.add(sdk);\n for (const sdk of match.stripeSdks) allStripeSdks.add(sdk);\n }\n\n const detectedPosthogSdks = [...allPosthogSdks];\n const detectedStripeSdks = [...allStripeSdks];\n\n if (detectedPosthogSdks.length === 0 && detectedStripeSdks.length === 0) {\n fail({ kind: 'no-sdks', scannedCount: matches.length });\n return;\n }\n\n if (detectedPosthogSdks.length === 0) {\n fail({ kind: 'missing-posthog', foundStripe: detectedStripeSdks });\n return;\n }\n\n if (detectedStripeSdks.length === 0) {\n fail({ kind: 'missing-stripe', foundPosthog: detectedPosthogSdks });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', detectedPosthogSdks);\n setFrameworkContext('detectedStripeSdks', detectedStripeSdks);\n setFrameworkContext(\n 'detectedPackagePaths',\n matches\n .filter((m) => m.posthogSdks.length > 0 || m.stripeSdks.length > 0)\n .map((m) => m.path),\n );\n}\n","/**\n * Revenue analytics workflow step list.\n *\n * The detect step checks for PostHog + Stripe SDKs. The skill install\n * and agent run live in the workflow runner (see agent-runner.ts).\n */\n\nimport type { Workflow } from '../workflow-step.js';\nimport { RunPhase } from '../../wizard-session.js';\nimport { detectRevenuePrerequisites } from './detect.js';\n\nexport const REVENUE_ANALYTICS_WORKFLOW: Workflow = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — the hook scans for PostHog + Stripe SDKs\n // and writes the results (or a detectError) to frameworkContext\n // for the intro screen to render.\n onReady: (ctx) =>\n detectRevenuePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screen: 'revenue-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screen: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Revenue analytics',\n screen: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screen: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screen: 'keep-skills',\n },\n];\n","import type { WorkflowConfig } from '../workflow-step.js';\nimport { REVENUE_ANALYTICS_WORKFLOW } from './steps.js';\nimport { REVENUE_ABORT_CASES } from './detect.js';\n\nexport const revenueAnalyticsConfig: WorkflowConfig = {\n command: 'revenue',\n description: 'Set up PostHog revenue analytics (e.g. Stripe integration)',\n flowKey: 'revenue-analytics-setup',\n steps: REVENUE_ANALYTICS_WORKFLOW,\n run: {\n skillId: 'revenue-analytics-setup',\n integrationLabel: 'revenue-analytics-setup',\n customPrompt: () => 'Set up revenue analytics for this project.',\n successMessage: 'Revenue analytics configured!',\n reportFile: 'posthog-revenue-report.md',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n spinnerMessage: 'Setting up revenue analytics...',\n estimatedDurationMinutes: 5,\n abortCases: REVENUE_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { REVENUE_ANALYTICS_WORKFLOW } from './steps.js';\nexport {\n detectRevenuePrerequisites,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type RevenueDetectError,\n} from './detect.js';\n","/**\n * Central registry of all wizard workflows.\n *\n * Adding a new workflow:\n * 1. Create src/lib/workflows/<name>/ with index.ts exporting a WorkflowConfig\n * 2. Import and add it to WORKFLOW_REGISTRY below\n * 3. Add a matching Flow enum entry in src/ui/tui/flows.ts\n * 4. (If custom intro screen) add to src/ui/tui/screen-registry.tsx\n *\n * flows.ts, store.ts, and bin.ts all derive their wiring from this array —\n * no need to touch those files when adding a workflow.\n */\n\nimport type { WorkflowConfig } from './workflow-step.js';\nimport { posthogIntegrationConfig } from './posthog-integration/index.js';\nimport { revenueAnalyticsConfig } from './revenue-analytics/index.js';\n\nexport const WORKFLOW_REGISTRY: WorkflowConfig[] = [\n posthogIntegrationConfig,\n revenueAnalyticsConfig,\n];\n\n/** Look up a workflow config by its flowKey. */\nexport function getWorkflowConfig(flowKey: string): WorkflowConfig | undefined {\n return WORKFLOW_REGISTRY.find((c) => c.flowKey === flowKey);\n}\n\n/** All workflow configs that are exposed as CLI subcommands. */\nexport function getSubcommandWorkflows(): WorkflowConfig[] {\n return WORKFLOW_REGISTRY.filter((c) => c.command != null);\n}\n","#!/usr/bin/env node\nimport { satisfies } from 'semver';\nimport { red } from './src/utils/logging';\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { VERSION } from './src/lib/version.js';\n\nconst WIZARD_VERSION = VERSION;\n\nconst NODE_VERSION_RANGE = '>=18.17.0';\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n red(\n `PostHog wizard requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\nimport { isNonInteractiveEnvironment } from './src/utils/environment';\nimport { getUI, setUI } from './src/ui';\nimport { LoggingUI } from './src/ui/logging-ui';\nimport { getSubcommandWorkflows } from './src/lib/workflows/workflow-registry';\nimport type { WorkflowConfig } from './src/lib/workflows/workflow-step';\nimport type { WizardSession } from './src/lib/wizard-session';\nimport { runtimeEnv } from '@env';\n\n// Test mock server — only loaded when NODE_ENV is 'test'.\n// In production builds, tsdown replaces process.env.NODE_ENV with 'production',\n// making this block dead code.\nif (process.env.NODE_ENV === 'test') {\n void (async () => {\n try {\n const { server } = await import('./e2e-tests/mocks/server.js');\n server.listen({\n onUnhandledRequest: 'bypass',\n });\n } catch (error) {\n // Mock server import failed - this can happen during non-E2E tests\n }\n })();\n}\n\n/** Shared yargs options for skill-based workflow subcommands. */\nconst skillSubcommandOptions = {\n debug: {\n default: false,\n describe: 'Enable verbose logging',\n type: 'boolean' as const,\n },\n 'install-dir': {\n describe: 'Directory to install in',\n type: 'string' as const,\n },\n 'local-mcp': {\n default: false,\n describe: 'Use local MCP server',\n type: 'boolean' as const,\n },\n benchmark: {\n default: false,\n describe: 'Run in benchmark mode',\n type: 'boolean' as const,\n },\n 'yara-report': {\n default: false,\n describe: 'Print YARA scanner summary',\n type: 'boolean' as const,\n hidden: true,\n },\n};\n\nconst cli = yargs(hideBin(process.argv))\n .env('POSTHOG_WIZARD')\n // global options\n .options({\n debug: {\n default: false,\n describe: 'Enable verbose logging\\nenv: POSTHOG_WIZARD_DEBUG',\n type: 'boolean',\n },\n region: {\n describe: 'PostHog cloud region\\nenv: POSTHOG_WIZARD_REGION',\n choices: ['us', 'eu'],\n type: 'string',\n },\n default: {\n default: true,\n describe:\n 'Use default options for all prompts\\nenv: POSTHOG_WIZARD_DEFAULT',\n type: 'boolean',\n },\n signup: {\n default: false,\n describe:\n 'Create a new PostHog account during setup\\nenv: POSTHOG_WIZARD_SIGNUP',\n type: 'boolean',\n },\n 'local-mcp': {\n default: false,\n describe:\n 'Use local MCP server at http://localhost:8787/mcp\\nenv: POSTHOG_WIZARD_LOCAL_MCP',\n type: 'boolean',\n },\n ci: {\n default: false,\n describe:\n 'Enable CI mode for non-interactive execution\\nenv: POSTHOG_WIZARD_CI',\n type: 'boolean',\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for authentication\\nenv: POSTHOG_WIZARD_API_KEY',\n type: 'string',\n },\n 'project-id': {\n describe:\n 'PostHog project ID to use (optional; when not set, uses default from API key or OAuth)\\nenv: POSTHOG_WIZARD_PROJECT_ID',\n type: 'string',\n },\n email: {\n describe:\n 'Email address for signup (used with --signup)\\nenv: POSTHOG_WIZARD_EMAIL',\n type: 'string',\n },\n })\n .command(\n ['$0'],\n 'Run the PostHog setup wizard',\n (yargs) => {\n return yargs.options({\n 'force-install': {\n default: false,\n describe:\n 'Force install packages even if peer dependency checks fail\\nenv: POSTHOG_WIZARD_FORCE_INSTALL',\n type: 'boolean',\n },\n 'install-dir': {\n describe:\n 'Directory to install PostHog in\\nenv: POSTHOG_WIZARD_INSTALL_DIR',\n type: 'string',\n },\n playground: {\n default: false,\n describe: 'Launch the TUI primitives playground',\n type: 'boolean',\n },\n integration: {\n describe: 'Integration to set up',\n choices: [\n 'nextjs',\n 'astro',\n 'react',\n 'svelte',\n 'react-native',\n 'tanstack-router',\n 'tanstack-start',\n ],\n type: 'string',\n },\n menu: {\n default: false,\n describe:\n 'Show menu for manual integration selection instead of auto-detecting\\nenv: POSTHOG_WIZARD_MENU',\n type: 'boolean',\n },\n benchmark: {\n default: false,\n describe:\n 'Run in benchmark mode with per-phase token tracking\\nenv: POSTHOG_WIZARD_BENCHMARK',\n type: 'boolean',\n },\n 'yara-report': {\n default: false,\n describe:\n 'Print YARA scanner summary after the agent run\\nenv: POSTHOG_WIZARD_YARA_REPORT',\n type: 'boolean',\n hidden: true,\n },\n skill: {\n describe:\n 'Run a specific context-mill skill by ID\\nenv: POSTHOG_WIZARD_SKILL',\n type: 'string',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n\n // CI mode validation and TTY check\n if (options.ci) {\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --api-key (personal API key phx_xxx)',\n );\n process.exit(1);\n return;\n }\n if (!options.installDir) {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n return;\n }\n void (async () => {\n const { posthogIntegrationConfig } = await import(\n './src/lib/workflows/posthog-integration/index.js'\n );\n const { FRAMEWORK_REGISTRY } = await import('./src/lib/registry.js');\n const { detectFramework, gatherFrameworkContext } = await import(\n './src/lib/detection/index.js'\n );\n const { analytics } = await import('./src/utils/analytics.js');\n const { wizardAbort } = await import('./src/utils/wizard-abort.js');\n\n // preRun: honor --integration, else auto-detect, then gather\n // framework context. Bypasses onReady hooks by design.\n runWizardCI(posthogIntegrationConfig, options, async (session) => {\n const integration =\n session.integration ??\n (await detectFramework(session.installDir));\n if (!integration) {\n await wizardAbort({\n message:\n 'Could not auto-detect your framework. Please specify --integration on the command line.',\n });\n return;\n }\n session.integration = integration;\n analytics.setTag('integration', integration);\n\n const frameworkConfig = FRAMEWORK_REGISTRY[integration];\n session.frameworkConfig = frameworkConfig;\n\n const context = await gatherFrameworkContext(frameworkConfig, {\n installDir: session.installDir,\n debug: session.debug,\n forceInstall: session.forceInstall,\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: true,\n menu: session.menu,\n benchmark: session.benchmark,\n yaraReport: session.yaraReport,\n });\n for (const [key, value] of Object.entries(context)) {\n if (!(key in session.frameworkContext)) {\n session.frameworkContext[key] = value;\n }\n }\n });\n })().catch(() => {\n process.exit(1);\n });\n } else if (isNonInteractiveEnvironment()) {\n // Non-interactive non-CI: error out\n getUI().intro(`PostHog Wizard`);\n getUI().log.error(\n 'This installer requires an interactive terminal (TTY) to run.\\n' +\n 'It appears you are running in a non-interactive environment.\\n' +\n 'Please run the wizard in an interactive terminal.\\n\\n' +\n 'For CI/CD environments, use --ci mode:\\n' +\n ' npx @posthog/wizard --ci --region us --api-key phx_xxx',\n );\n process.exit(1);\n } else if (options.playground) {\n // Playground mode: launch the TUI primitives playground\n void (async () => {\n const { startPlayground } = await import(\n './src/ui/tui/playground/start-playground.js'\n );\n (startPlayground as (version: string) => void)(WIZARD_VERSION);\n })();\n } else if (options.skill) {\n // Run a specific skill by ID\n void (async () => {\n const { createSkillWorkflow } = await import(\n './src/lib/workflows/agent-skill/index.js'\n );\n const skillId = options.skill as string;\n const config = createSkillWorkflow({\n skillId,\n command: 'skill',\n flowKey: 'agent-skill',\n description: `Run skill: ${skillId}`,\n integrationLabel: skillId,\n successMessage: `${skillId} completed!`,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: 'https://posthog.com/docs',\n spinnerMessage: `Running ${skillId}...`,\n estimatedDurationMinutes: 5,\n });\n runWizard(config, options);\n })();\n } else {\n // Interactive TTY: run core-integration through the unified workflow path.\n // Same codepath as `npx @posthog/wizard integrate`.\n void (async () => {\n const { posthogIntegrationConfig } = await import(\n './src/lib/workflows/posthog-integration/index.js'\n );\n runWizard(posthogIntegrationConfig, options);\n })();\n }\n },\n )\n .command('mcp <command>', 'MCP server management commands', (yargs) => {\n return yargs\n .command(\n 'add',\n 'Install PostHog MCP server to supported clients',\n (yargs) => {\n return yargs.options({\n local: {\n default: false,\n describe:\n 'Add local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n features: {\n describe:\n 'Comma-separated list of features to enable (default: all)',\n type: 'string',\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for MCP authentication',\n type: 'string',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n const mcpFeatures = options.features\n ?.split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n void (async () => {\n const { readApiKeyFromEnv } = await import(\n './src/utils/env-api-key.js'\n );\n const apiKey =\n (options.apiKey as string | undefined) || readApiKeyFromEnv();\n\n try {\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import(\n './src/lib/wizard-session.js'\n );\n\n const { Flow } = await import('./src/ui/tui/router.js');\n const tui = startTUI(WIZARD_VERSION, Flow.McpAdd);\n const session = buildSession({\n debug: options.debug,\n localMcp: options.local,\n mcpFeatures,\n apiKey,\n });\n tui.store.session = session;\n } catch {\n // TUI unavailable — fallback to logging\n setUI(new LoggingUI());\n const { addMCPServerToClientsStep } = await import(\n './src/steps/add-mcp-server-to-clients/index.js'\n );\n await addMCPServerToClientsStep({\n local: options.local,\n features: mcpFeatures,\n apiKey,\n });\n }\n })();\n },\n )\n .command(\n 'remove',\n 'Remove PostHog MCP server from supported clients',\n (yargs) => {\n return yargs.options({\n local: {\n default: false,\n describe:\n 'Remove local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n });\n },\n (argv) => {\n const options = { ...argv };\n void (async () => {\n try {\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import(\n './src/lib/wizard-session.js'\n );\n\n const { Flow } = await import('./src/ui/tui/router.js');\n const tui = startTUI(WIZARD_VERSION, Flow.McpRemove);\n const session = buildSession({\n debug: options.debug,\n localMcp: options.local,\n });\n tui.store.session = session;\n } catch {\n // TUI unavailable — fallback to logging\n setUI(new LoggingUI());\n const { removeMCPServerFromClientsStep } = await import(\n './src/steps/add-mcp-server-to-clients/index.js'\n );\n await removeMCPServerFromClientsStep({\n local: options.local,\n });\n }\n })();\n },\n )\n .demandCommand(1, 'You must specify a subcommand (add or remove)')\n .help();\n });\n\n// ── Skill-based workflow subcommands (derived from registry) ─────────\nfor (const wfConfig of getSubcommandWorkflows()) {\n cli.command(\n wfConfig.command!,\n wfConfig.description,\n (y) => y.options(skillSubcommandOptions),\n (argv) => {\n const options = { ...argv };\n if (options.ci) {\n runWizardCI(wfConfig, options);\n } else {\n runWizard(wfConfig, options);\n }\n },\n );\n}\n\ncli\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'v')\n .wrap(process.stdout.isTTY ? cli.terminalWidth() : 80).argv;\n\n/**\n * Run a full wizard workflow in the TUI. Handles the full lifecycle: start TUI,\n * build session, run detection, wait for intro gate, execute the\n * agent pipeline, wait for outro dismissal, then exit.\n */\nfunction runWizard(\n config: WorkflowConfig,\n options: Record<string, unknown>,\n): void {\n void (async () => {\n try {\n const installDir = (options.installDir as string) || process.cwd();\n\n const { startTUI } = await import('./src/ui/tui/start-tui.js');\n const { buildSession } = await import('./src/lib/wizard-session.js');\n\n // flowKey values match Flow enum values by convention\n const tui = startTUI(WIZARD_VERSION, config.flowKey as any);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n forceInstall: options.forceInstall as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n installDir,\n ci: false,\n signup: options.signup as boolean | undefined,\n apiKey: options.apiKey as string | undefined,\n projectId: options.projectId as string | undefined,\n menu: options.menu as boolean | undefined,\n integration: options.integration as any,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n });\n // Set workflow metadata for TUI display\n session.workflowLabel = config.flowKey;\n const runDef = typeof config.run === 'object' ? config.run : null;\n session.skillId = runDef?.skillId ?? null;\n\n tui.store.session = session;\n\n await tui.store.runReadyHooks();\n await tui.store.getGate('intro');\n\n const { runAgent } = await import('./src/lib/agent/agent-runner.js');\n await runAgent(config, tui.store.session);\n\n await new Promise<void>((resolve) => {\n const unsub = tui.store.subscribe(() => {\n if (tui.store.session.skillsComplete) {\n unsub();\n resolve();\n }\n });\n if (tui.store.session.skillsComplete) {\n unsub();\n resolve();\n }\n });\n process.exit(0);\n } catch (err) {\n if (runtimeEnv('DEBUG') || runtimeEnv('POSTHOG_WIZARD_DEBUG')) {\n console.error('TUI init failed:', err); // eslint-disable-line no-console\n }\n }\n })();\n}\n\n/**\n * CI-mode pipeline shared by every non-interactive entry point.\n *\n * Validates flags, builds a `ci:true` session, runs `preRun` (or the\n * workflow's `onReady` hooks by default), executes `runAgent`, and\n * routes any failure through `wizardAbort`. `wizardAbort` owns all\n * exits — never add a raw `process.exit` here.\n */\nfunction runWizardCI(\n config: WorkflowConfig,\n options: Record<string, unknown>,\n preRun?: (session: WizardSession) => Promise<void>,\n): void {\n setUI(new LoggingUI());\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n if (!options.installDir) {\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n }\n\n void (async () => {\n const path = await import('path');\n const { buildSession } = await import('./src/lib/wizard-session.js');\n const { readEnvironment } = await import('./src/utils/environment.js');\n const { readApiKeyFromEnv } = await import('./src/utils/env-api-key.js');\n const { configureLogFileFromEnvironment, logToFile } = await import(\n './src/utils/debug.js'\n );\n const { wizardAbort, WizardError } = await import(\n './src/utils/wizard-abort.js'\n );\n\n configureLogFileFromEnvironment();\n\n const env = readEnvironment();\n const apiKey =\n (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n const installDir = path.isAbsolute(options.installDir as string)\n ? (options.installDir as string)\n : path.join(process.cwd(), options.installDir as string);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n forceInstall: options.forceInstall as boolean | undefined,\n installDir,\n ci: true,\n signup: options.signup as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n apiKey,\n menu: options.menu as boolean | undefined,\n integration: options.integration as any, // eslint-disable-line @typescript-eslint/no-explicit-any\n projectId: options.projectId as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n ...env,\n });\n session.workflowLabel = config.flowKey;\n const runDef = typeof config.run === 'object' ? config.run : null;\n session.skillId = runDef?.skillId ?? null;\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info(`Running ${config.flowKey} in CI mode`);\n\n try {\n if (preRun) {\n await preRun(session);\n } else {\n // Run onReady hooks against a minimal store-less context.\n const readyCtx = {\n session,\n setFrameworkContext: (key: string, value: unknown) => {\n session.frameworkContext[key] = value;\n },\n setFrameworkConfig: () => undefined,\n setDetectedFramework: () => undefined,\n setUnsupportedVersion: () => undefined,\n addDiscoveredFeature: () => undefined,\n setDetectionComplete: () => undefined,\n };\n for (const step of config.steps) {\n if (step.onReady) {\n await step.onReady(readyCtx);\n }\n }\n\n // Surface detectError written by the workflow's detect hook.\n const detectError = session.frameworkContext.detectError as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (detectError) {\n await wizardAbort({\n message: `Prerequisites not met: ${detectError.kind}\\n\\nSee ${\n runDef?.docsUrl ?? 'https://posthog.com/docs'\n }`,\n error: new WizardError(`${config.flowKey} prerequisites failed`, {\n integration: config.flowKey,\n detect_error_kind: detectError.kind,\n }),\n });\n }\n }\n\n const { runAgent } = await import('./src/lib/agent/agent-runner.js');\n await runAgent(config, session);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const errorStack =\n error instanceof Error && error.stack ? error.stack : undefined;\n\n logToFile(`[bin.ts CI] ERROR: ${errorMessage}`);\n if (errorStack) logToFile(`[bin.ts CI] STACK: ${errorStack}`);\n\n const debugInfo = session.debug && errorStack ? `\\n\\n${errorStack}` : '';\n const docsUrl =\n session.frameworkConfig?.metadata.docsUrl ??\n runDef?.docsUrl ??\n 'https://posthog.com/docs';\n await wizardAbort({\n message: `Something went wrong: ${errorMessage}\\n\\nYou can read the documentation at ${docsUrl} to set up manually.${debugInfo}`,\n error: error as Error,\n });\n }\n })().catch(() => {\n process.exit(1);\n });\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { l as Integration, o as DETECTION_TIMEOUT_MS } from "./analytics-C4jO5Qda.js";
3
- import { t as FRAMEWORK_REGISTRY } from "./registry-s55_iuJT.js";
2
+ import { l as Integration, o as DETECTION_TIMEOUT_MS } from "./analytics-CpRZ9V5j.js";
3
+ import { t as FRAMEWORK_REGISTRY } from "./registry-BUdvRdBh.js";
4
4
  import * as semver from "semver";
5
5
  import { readFileSync } from "fs";
6
6
  import { join } from "path";
@@ -119,4 +119,4 @@ var detection_exports = /* @__PURE__ */ __exportAll({
119
119
  //#endregion
120
120
  export { detectFramework as a, discoverFeatures as i, checkFrameworkVersion as n, gatherFrameworkContext as r, detection_exports as t };
121
121
 
122
- //# sourceMappingURL=detection-CkLpxBCD.js.map
122
+ //# sourceMappingURL=detection-D8428PBG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"detection-CkLpxBCD.js","names":[],"sources":["../src/lib/detection/framework.ts","../src/lib/detection/features.ts","../src/lib/detection/context.ts","../src/lib/detection/index.ts"],"sourcesContent":["/**\n * Framework detection — identify which PostHog-supported framework\n * is present in the project directory.\n *\n * Pure function: takes an install dir, returns the detected integration\n * (or undefined). No store mutations, no UI calls.\n */\n\nimport { Integration, DETECTION_TIMEOUT_MS } from '../constants.js';\nimport { FRAMEWORK_REGISTRY } from '../registry.js';\n\n/**\n * Loop through all registered frameworks and return the first one\n * whose `detect()` predicate matches the given directory.\n * Returns undefined if no framework is detected or detection times out.\n */\nexport async function detectFramework(\n installDir: string,\n): Promise<Integration | undefined> {\n for (const integration of Object.values(Integration)) {\n const config = FRAMEWORK_REGISTRY[integration];\n try {\n const detected = await Promise.race([\n config.detection.detect({ installDir }),\n new Promise<false>((resolve) =>\n setTimeout(() => resolve(false), DETECTION_TIMEOUT_MS),\n ),\n ]);\n if (detected) {\n return integration;\n }\n } catch {\n // Skip frameworks whose detection throws\n }\n }\n}\n","/**\n * Feature discovery — scan project dependencies for known SDK patterns\n * that indicate additional PostHog workflows are relevant.\n *\n * Pure function: takes an install dir, returns a set of discovered features.\n * No store mutations, no UI calls.\n */\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { DiscoveredFeature } from '../wizard-session.js';\n\nconst STRIPE_PACKAGES = ['stripe', '@stripe/stripe-js'];\n\nconst LLM_PACKAGES = [\n 'openai',\n '@anthropic-ai/sdk',\n 'ai',\n '@ai-sdk/openai',\n 'langchain',\n '@langchain/openai',\n '@langchain/langgraph',\n '@google/generative-ai',\n '@google/genai',\n '@instructor-ai/instructor',\n '@mastra/core',\n 'portkey-ai',\n];\n\n/**\n * Scan `package.json` at `installDir` for dependencies that indicate\n * additional PostHog features (Stripe revenue analytics, LLM observability, etc.)\n *\n * Returns an array of discovered features, or empty if nothing found\n * or no package.json exists.\n */\nexport function discoverFeatures(installDir: string): DiscoveredFeature[] {\n const features: DiscoveredFeature[] = [];\n\n try {\n const pkg = JSON.parse(\n readFileSync(join(installDir, 'package.json'), 'utf-8'),\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = Object.keys({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n });\n\n if (depNames.some((d) => STRIPE_PACKAGES.includes(d))) {\n features.push(DiscoveredFeature.Stripe);\n }\n\n if (depNames.some((d) => LLM_PACKAGES.includes(d))) {\n features.push(DiscoveredFeature.LLM);\n }\n } catch {\n // No package.json or parse error — skip feature discovery\n }\n\n return features;\n}\n","/**\n * Framework context gathering — run gatherContext and version checks\n * for a detected framework.\n *\n * Pure functions: take a framework config and options, return results.\n * No store mutations, no UI calls.\n */\n\nimport * as semver from 'semver';\nimport { DETECTION_TIMEOUT_MS } from '../constants.js';\nimport type { FrameworkConfig } from '../framework-config.js';\nimport type { WizardOptions } from '../../utils/types.js';\n\n/**\n * Run a framework's `gatherContext()` to collect variant-specific\n * metadata (e.g., router type for Next.js, Expo vs bare for React Native).\n *\n * Returns the gathered context, or an empty object on failure/timeout.\n */\nexport async function gatherFrameworkContext(\n config: FrameworkConfig,\n options: WizardOptions,\n): Promise<Record<string, unknown>> {\n if (!config.metadata.gatherContext) return {};\n\n try {\n return await Promise.race([\n config.metadata.gatherContext(options),\n new Promise<Record<string, never>>((resolve) =>\n setTimeout(() => resolve({}), DETECTION_TIMEOUT_MS),\n ),\n ]);\n } catch {\n return {};\n }\n}\n\nexport interface VersionCheckResult {\n /** Whether the installed version is supported */\n supported:\n | true\n | {\n current: string;\n minimum: string;\n docsUrl: string;\n };\n}\n\n/**\n * Check whether the installed framework version meets the minimum requirement.\n *\n * Returns `{ supported: true }` if the version is fine (or no check is needed).\n * Returns the version details if unsupported.\n */\nexport async function checkFrameworkVersion(\n config: FrameworkConfig,\n options: WizardOptions,\n): Promise<VersionCheckResult> {\n if (\n !config.detection.minimumVersion ||\n !config.detection.getInstalledVersion\n ) {\n return { supported: true };\n }\n\n const version = await config.detection.getInstalledVersion(options);\n if (!version) return { supported: true };\n\n const coerced = semver.coerce(version);\n if (coerced && semver.lt(coerced, config.detection.minimumVersion)) {\n return {\n supported: {\n current: version,\n minimum: config.detection.minimumVersion,\n docsUrl:\n config.metadata.unsupportedVersionDocsUrl ?? config.metadata.docsUrl,\n },\n };\n }\n\n return { supported: true };\n}\n","export { detectFramework } from './framework.js';\nexport { discoverFeatures } from './features.js';\nexport {\n gatherFrameworkContext,\n checkFrameworkVersion,\n type VersionCheckResult,\n} from './context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,eAAsB,gBACpB,YACkC;AAClC,MAAK,MAAM,eAAe,OAAO,OAAO,YAAY,EAAE;EACpD,MAAM,SAAS,mBAAmB;AAClC,MAAI;AAOF,OANiB,MAAM,QAAQ,KAAK,CAClC,OAAO,UAAU,OAAO,EAAE,YAAY,CAAC,EACvC,IAAI,SAAgB,YAClB,iBAAiB,QAAQ,MAAM,EAAA,IAAuB,CACvD,CACF,CAAC,CAEA,QAAO;UAEH;;;;;;;;;;;;ACnBZ,MAAM,kBAAkB,CAAC,UAAU,oBAAoB;AAEvD,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;AASD,SAAgB,iBAAiB,YAAyC;CACxE,MAAM,WAAgC,EAAE;AAExC,KAAI;EACF,MAAM,MAAM,KAAK,MACf,aAAa,KAAK,YAAY,eAAe,EAAE,QAAQ,CACxD;EAID,MAAM,WAAW,OAAO,KAAK;GAC3B,GAAG,IAAI;GACP,GAAG,IAAI;GACR,CAAC;AAEF,MAAI,SAAS,MAAM,MAAM,gBAAgB,SAAS,EAAE,CAAC,CACnD,UAAS,KAAA,SAA8B;AAGzC,MAAI,SAAS,MAAM,MAAM,aAAa,SAAS,EAAE,CAAC,CAChD,UAAS,KAAA,MAA2B;SAEhC;AAIR,QAAO;;;;;;;;;;;;;;;;;AC3CT,eAAsB,uBACpB,QACA,SACkC;AAClC,KAAI,CAAC,OAAO,SAAS,cAAe,QAAO,EAAE;AAE7C,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CACxB,OAAO,SAAS,cAAc,QAAQ,EACtC,IAAI,SAAgC,YAClC,iBAAiB,QAAQ,EAAE,CAAC,EAAE,qBAAqB,CACpD,CACF,CAAC;SACI;AACN,SAAO,EAAE;;;;;;;;;AAqBb,eAAsB,sBACpB,QACA,SAC6B;AAC7B,KACE,CAAC,OAAO,UAAU,kBAClB,CAAC,OAAO,UAAU,oBAElB,QAAO,EAAE,WAAW,MAAM;CAG5B,MAAM,UAAU,MAAM,OAAO,UAAU,oBAAoB,QAAQ;AACnE,KAAI,CAAC,QAAS,QAAO,EAAE,WAAW,MAAM;CAExC,MAAM,UAAU,OAAO,OAAO,QAAQ;AACtC,KAAI,WAAW,OAAO,GAAG,SAAS,OAAO,UAAU,eAAe,CAChE,QAAO,EACL,WAAW;EACT,SAAS;EACT,SAAS,OAAO,UAAU;EAC1B,SACE,OAAO,SAAS,6BAA6B,OAAO,SAAS;EAChE,EACF;AAGH,QAAO,EAAE,WAAW,MAAM"}
1
+ {"version":3,"file":"detection-D8428PBG.js","names":[],"sources":["../src/lib/detection/framework.ts","../src/lib/detection/features.ts","../src/lib/detection/context.ts","../src/lib/detection/index.ts"],"sourcesContent":["/**\n * Framework detection — identify which PostHog-supported framework\n * is present in the project directory.\n *\n * Pure function: takes an install dir, returns the detected integration\n * (or undefined). No store mutations, no UI calls.\n */\n\nimport { Integration, DETECTION_TIMEOUT_MS } from '../constants.js';\nimport { FRAMEWORK_REGISTRY } from '../registry.js';\n\n/**\n * Loop through all registered frameworks and return the first one\n * whose `detect()` predicate matches the given directory.\n * Returns undefined if no framework is detected or detection times out.\n */\nexport async function detectFramework(\n installDir: string,\n): Promise<Integration | undefined> {\n for (const integration of Object.values(Integration)) {\n const config = FRAMEWORK_REGISTRY[integration];\n try {\n const detected = await Promise.race([\n config.detection.detect({ installDir }),\n new Promise<false>((resolve) =>\n setTimeout(() => resolve(false), DETECTION_TIMEOUT_MS),\n ),\n ]);\n if (detected) {\n return integration;\n }\n } catch {\n // Skip frameworks whose detection throws\n }\n }\n}\n","/**\n * Feature discovery — scan project dependencies for known SDK patterns\n * that indicate additional PostHog workflows are relevant.\n *\n * Pure function: takes an install dir, returns a set of discovered features.\n * No store mutations, no UI calls.\n */\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { DiscoveredFeature } from '../wizard-session.js';\n\nconst STRIPE_PACKAGES = ['stripe', '@stripe/stripe-js'];\n\nconst LLM_PACKAGES = [\n 'openai',\n '@anthropic-ai/sdk',\n 'ai',\n '@ai-sdk/openai',\n 'langchain',\n '@langchain/openai',\n '@langchain/langgraph',\n '@google/generative-ai',\n '@google/genai',\n '@instructor-ai/instructor',\n '@mastra/core',\n 'portkey-ai',\n];\n\n/**\n * Scan `package.json` at `installDir` for dependencies that indicate\n * additional PostHog features (Stripe revenue analytics, LLM observability, etc.)\n *\n * Returns an array of discovered features, or empty if nothing found\n * or no package.json exists.\n */\nexport function discoverFeatures(installDir: string): DiscoveredFeature[] {\n const features: DiscoveredFeature[] = [];\n\n try {\n const pkg = JSON.parse(\n readFileSync(join(installDir, 'package.json'), 'utf-8'),\n ) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = Object.keys({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n });\n\n if (depNames.some((d) => STRIPE_PACKAGES.includes(d))) {\n features.push(DiscoveredFeature.Stripe);\n }\n\n if (depNames.some((d) => LLM_PACKAGES.includes(d))) {\n features.push(DiscoveredFeature.LLM);\n }\n } catch {\n // No package.json or parse error — skip feature discovery\n }\n\n return features;\n}\n","/**\n * Framework context gathering — run gatherContext and version checks\n * for a detected framework.\n *\n * Pure functions: take a framework config and options, return results.\n * No store mutations, no UI calls.\n */\n\nimport * as semver from 'semver';\nimport { DETECTION_TIMEOUT_MS } from '../constants.js';\nimport type { FrameworkConfig } from '../framework-config.js';\nimport type { WizardOptions } from '../../utils/types.js';\n\n/**\n * Run a framework's `gatherContext()` to collect variant-specific\n * metadata (e.g., router type for Next.js, Expo vs bare for React Native).\n *\n * Returns the gathered context, or an empty object on failure/timeout.\n */\nexport async function gatherFrameworkContext(\n config: FrameworkConfig,\n options: WizardOptions,\n): Promise<Record<string, unknown>> {\n if (!config.metadata.gatherContext) return {};\n\n try {\n return await Promise.race([\n config.metadata.gatherContext(options),\n new Promise<Record<string, never>>((resolve) =>\n setTimeout(() => resolve({}), DETECTION_TIMEOUT_MS),\n ),\n ]);\n } catch {\n return {};\n }\n}\n\nexport interface VersionCheckResult {\n /** Whether the installed version is supported */\n supported:\n | true\n | {\n current: string;\n minimum: string;\n docsUrl: string;\n };\n}\n\n/**\n * Check whether the installed framework version meets the minimum requirement.\n *\n * Returns `{ supported: true }` if the version is fine (or no check is needed).\n * Returns the version details if unsupported.\n */\nexport async function checkFrameworkVersion(\n config: FrameworkConfig,\n options: WizardOptions,\n): Promise<VersionCheckResult> {\n if (\n !config.detection.minimumVersion ||\n !config.detection.getInstalledVersion\n ) {\n return { supported: true };\n }\n\n const version = await config.detection.getInstalledVersion(options);\n if (!version) return { supported: true };\n\n const coerced = semver.coerce(version);\n if (coerced && semver.lt(coerced, config.detection.minimumVersion)) {\n return {\n supported: {\n current: version,\n minimum: config.detection.minimumVersion,\n docsUrl:\n config.metadata.unsupportedVersionDocsUrl ?? config.metadata.docsUrl,\n },\n };\n }\n\n return { supported: true };\n}\n","export { detectFramework } from './framework.js';\nexport { discoverFeatures } from './features.js';\nexport {\n gatherFrameworkContext,\n checkFrameworkVersion,\n type VersionCheckResult,\n} from './context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,eAAsB,gBACpB,YACkC;AAClC,MAAK,MAAM,eAAe,OAAO,OAAO,YAAY,EAAE;EACpD,MAAM,SAAS,mBAAmB;AAClC,MAAI;AAOF,OANiB,MAAM,QAAQ,KAAK,CAClC,OAAO,UAAU,OAAO,EAAE,YAAY,CAAC,EACvC,IAAI,SAAgB,YAClB,iBAAiB,QAAQ,MAAM,EAAA,IAAuB,CACvD,CACF,CAAC,CAEA,QAAO;UAEH;;;;;;;;;;;;ACnBZ,MAAM,kBAAkB,CAAC,UAAU,oBAAoB;AAEvD,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;AASD,SAAgB,iBAAiB,YAAyC;CACxE,MAAM,WAAgC,EAAE;AAExC,KAAI;EACF,MAAM,MAAM,KAAK,MACf,aAAa,KAAK,YAAY,eAAe,EAAE,QAAQ,CACxD;EAID,MAAM,WAAW,OAAO,KAAK;GAC3B,GAAG,IAAI;GACP,GAAG,IAAI;GACR,CAAC;AAEF,MAAI,SAAS,MAAM,MAAM,gBAAgB,SAAS,EAAE,CAAC,CACnD,UAAS,KAAA,SAA8B;AAGzC,MAAI,SAAS,MAAM,MAAM,aAAa,SAAS,EAAE,CAAC,CAChD,UAAS,KAAA,MAA2B;SAEhC;AAIR,QAAO;;;;;;;;;;;;;;;;;AC3CT,eAAsB,uBACpB,QACA,SACkC;AAClC,KAAI,CAAC,OAAO,SAAS,cAAe,QAAO,EAAE;AAE7C,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CACxB,OAAO,SAAS,cAAc,QAAQ,EACtC,IAAI,SAAgC,YAClC,iBAAiB,QAAQ,EAAE,CAAC,EAAE,qBAAqB,CACpD,CACF,CAAC;SACI;AACN,SAAO,EAAE;;;;;;;;;AAqBb,eAAsB,sBACpB,QACA,SAC6B;AAC7B,KACE,CAAC,OAAO,UAAU,kBAClB,CAAC,OAAO,UAAU,oBAElB,QAAO,EAAE,WAAW,MAAM;CAG5B,MAAM,UAAU,MAAM,OAAO,UAAU,oBAAoB,QAAQ;AACnE,KAAI,CAAC,QAAS,QAAO,EAAE,WAAW,MAAM;CAExC,MAAM,UAAU,OAAO,OAAO,QAAQ;AACtC,KAAI,WAAW,OAAO,GAAG,SAAS,OAAO,UAAU,eAAe,CAChE,QAAO,EACL,WAAW;EACT,SAAS;EACT,SAAS,OAAO,UAAU;EAC1B,SACE,OAAO,SAAS,6BAA6B,OAAO,SAAS;EAChE,EACF;AAGH,QAAO,EAAE,WAAW,MAAM"}
@@ -1,4 +1,4 @@
1
- import { s as detectAllPackageManagers } from "./setup-utils-CdDnllRW.js";
1
+ import { s as detectAllPackageManagers } from "./setup-utils-DJuYiRId.js";
2
2
  import { execSync } from "node:child_process";
3
3
  //#region src/frameworks/python/utils.ts
4
4
  /**
@@ -219,4 +219,4 @@ function gradlePackageManager() {
219
219
  //#endregion
220
220
  export { gradlePackageManager as a, getPackageManagerName as c, detectPythonPackageManagers as i, getPythonVersion as l, composerPackageManager as n, swiftPackageManager as o, detectNodePackageManagers as r, detectPackageManager as s, bundlerPackageManager as t, getPythonVersionBucket as u };
221
221
 
222
- //# sourceMappingURL=package-manager-nUQ-ebjr.js.map
222
+ //# sourceMappingURL=package-manager-B_VtY9ZS.js.map