@posthog/wizard 2.42.0 → 2.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-mcp-server-to-clients-fGAJ6wRG.js → add-mcp-server-to-clients-D5qsqCkj.js} +5 -5
- package/dist/{add-mcp-server-to-clients-fGAJ6wRG.js.map → add-mcp-server-to-clients-D5qsqCkj.js.map} +1 -1
- package/dist/{agent-interface-dPcuJv8g.js → agent-interface-BvTxWiol.js} +8 -8
- package/dist/agent-interface-BvTxWiol.js.map +1 -0
- package/dist/{agent-runner-3bDJ_WLl.js → agent-runner-BF6_f8Qh.js} +40 -18
- package/dist/agent-runner-BF6_f8Qh.js.map +1 -0
- package/dist/analytics-C7Xx6csw.js +2 -0
- package/dist/{analytics-jQRtyqzG.js → analytics-DSlQuwOT.js} +2 -2
- package/dist/{analytics-jQRtyqzG.js.map → analytics-DSlQuwOT.js.map} +1 -1
- package/dist/{api-Bweisj9K.js → api-BXduJZrw.js} +3 -3
- package/dist/{api-Bweisj9K.js.map → api-BXduJZrw.js.map} +1 -1
- package/dist/bin.js +78 -63
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-BoATzVVs.js → ci-install-GirEJqu2.js} +4 -4
- package/dist/{ci-install-BoATzVVs.js.map → ci-install-GirEJqu2.js.map} +1 -1
- package/dist/{debug-DCQHRXu9.js → debug-BOFxiVVs.js} +1 -1
- package/dist/{debug--QPXcpzv.js → debug-DXfQFmcM.js} +30 -20
- package/dist/debug-DXfQFmcM.js.map +1 -0
- package/dist/{defaults-CeNThA-1.js → defaults-BWLIffh5.js} +2 -2
- package/dist/defaults-BWLIffh5.js.map +1 -0
- package/dist/{environment-Xdauxvph.js → environment-F1yw21dG.js} +3 -3
- package/dist/{environment-Xdauxvph.js.map → environment-F1yw21dG.js.map} +1 -1
- package/dist/{file-utils-BJhGBl-W.js → file-utils-D-7YfJ7A.js} +2 -2
- package/dist/{file-utils-BJhGBl-W.js.map → file-utils-D-7YfJ7A.js.map} +1 -1
- package/dist/{headless-ui-XdCxxQ0b.js → headless-ui-Dni0gPND.js} +2 -2
- package/dist/{headless-ui-XdCxxQ0b.js.map → headless-ui-Dni0gPND.js.map} +1 -1
- package/dist/{interactive-CwtUeGJT.js → interactive-Bmi82rsO.js} +2 -2
- package/dist/{interactive-CwtUeGJT.js.map → interactive-Bmi82rsO.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-CCS2EkfY.js → mcp-prompt-streaming-AtntLsJ8.js} +3 -3
- package/dist/{mcp-prompt-streaming-CCS2EkfY.js.map → mcp-prompt-streaming-AtntLsJ8.js.map} +1 -1
- package/dist/{mcp-DIuzSJ8f.js → mcp-xKRDnrcq.js} +2 -2
- package/dist/{mcp-DIuzSJ8f.js.map → mcp-xKRDnrcq.js.map} +1 -1
- package/dist/{non-interactive-Cjb5uLLn.js → non-interactive-BIHqcW8g.js} +2 -2
- package/dist/{non-interactive-Cjb5uLLn.js.map → non-interactive-BIHqcW8g.js.map} +1 -1
- package/dist/{package-manager-D_05Bmr0.js → package-manager-C6R_zpML.js} +2 -2
- package/dist/{package-manager-D_05Bmr0.js.map → package-manager-C6R_zpML.js.map} +1 -1
- package/dist/{playground-BtB7RvUT.js → playground-DwL36I2u.js} +7 -7
- package/dist/{playground-BtB7RvUT.js.map → playground-DwL36I2u.js.map} +1 -1
- package/dist/{posthog-integration-Cw1QDMFi.js → posthog-integration-BhLKCFsI.js} +16 -15
- package/dist/{posthog-integration-Cw1QDMFi.js.map → posthog-integration-BhLKCFsI.js.map} +1 -1
- package/dist/{provisioning-CmpiiTaR.js → provisioning-jVZm2E-A.js} +21 -14
- package/dist/provisioning-jVZm2E-A.js.map +1 -0
- package/dist/{registry-DPriFJQI.js → registry-DcoBCMQR.js} +4 -4
- package/dist/{registry-DPriFJQI.js.map → registry-DcoBCMQR.js.map} +1 -1
- package/dist/{security-DJrWWO0M.js → security-jxjVsOpd.js} +4 -4
- package/dist/{security-DJrWWO0M.js.map → security-jxjVsOpd.js.map} +1 -1
- package/dist/{setup-utils-C8yipMUt.js → setup-utils-BQCl28D8.js} +7 -7
- package/dist/{setup-utils-C8yipMUt.js.map → setup-utils-BQCl28D8.js.map} +1 -1
- package/dist/{start-tui-BMZL7mKh.js → start-tui-DgSKFMVh.js} +431 -172
- package/dist/start-tui-DgSKFMVh.js.map +1 -0
- package/dist/{steps-Dhq5VReA.js → steps-erepgD0V.js} +7 -7
- package/dist/{steps-Dhq5VReA.js.map → steps-erepgD0V.js.map} +1 -1
- package/dist/{store-Bu1xO0_5.js → store-C79GoHCQ.js} +30 -8
- package/dist/store-C79GoHCQ.js.map +1 -0
- package/dist/{subagent-mVY-kDU0.js → subagent-aDlD_Ltz.js} +2 -2
- package/dist/{subagent-mVY-kDU0.js.map → subagent-aDlD_Ltz.js.map} +1 -1
- package/dist/{task-stream-Ne-9ZOnf.js → task-stream-0Pk0tPBN.js} +2 -2
- package/dist/{task-stream-Ne-9ZOnf.js.map → task-stream-0Pk0tPBN.js.map} +1 -1
- package/dist/{tasks-2af2kDE3.js → tasks-ZkrluXCa.js} +2 -2
- package/dist/{tasks-2af2kDE3.js.map → tasks-ZkrluXCa.js.map} +1 -1
- package/dist/{telemetry-wGk3UsDw.js → telemetry-DZShaH-y.js} +3 -3
- package/dist/{telemetry-wGk3UsDw.js.map → telemetry-DZShaH-y.js.map} +1 -1
- package/dist/{terminal-CnYduoIp.js → terminal-CEhufbJ4.js} +13 -13
- package/dist/terminal-CEhufbJ4.js.map +1 -0
- package/dist/{tools-BTq5sLH9.js → tools-BIPMan6l.js} +4 -4
- package/dist/{tools-BTq5sLH9.js.map → tools-BIPMan6l.js.map} +1 -1
- package/dist/{wizard-abort-CSMnla3D.js → wizard-abort-C14PzXZ8.js} +4 -4
- package/dist/{wizard-abort-CSMnla3D.js.map → wizard-abort-C14PzXZ8.js.map} +1 -1
- package/dist/{wizard-abort-D8Lj609C.js → wizard-abort-UCm4Pd5m.js} +1 -1
- package/dist/{wizard-session-BudcixsA.js → wizard-session-BAZql11N.js} +3 -3
- package/dist/wizard-session-BAZql11N.js.map +1 -0
- package/dist/{wizard-session-DXivb7kv.js → wizard-session-C5lZPPEc.js} +1 -1
- package/dist/{wizard-tools-BBLQk1YC.js → wizard-tools-B7SLjCic.js} +5 -3
- package/dist/wizard-tools-B7SLjCic.js.map +1 -0
- package/dist/wizard-ui-WZ48rUgr.js.map +1 -1
- package/dist/{yara-hooks-Ciy8d0ok.js → yara-hooks-CPH8N4yz.js} +3 -3
- package/dist/{yara-hooks-Ciy8d0ok.js.map → yara-hooks-CPH8N4yz.js.map} +1 -1
- package/dist/yara-hooks-VZlj4Lib.js +2 -0
- package/package.json +1 -1
- package/dist/agent-interface-dPcuJv8g.js.map +0 -1
- package/dist/agent-runner-3bDJ_WLl.js.map +0 -1
- package/dist/analytics-B33Hy7zS.js +0 -2
- package/dist/debug--QPXcpzv.js.map +0 -1
- package/dist/defaults-CeNThA-1.js.map +0 -1
- package/dist/provisioning-CmpiiTaR.js.map +0 -1
- package/dist/start-tui-BMZL7mKh.js.map +0 -1
- package/dist/store-Bu1xO0_5.js.map +0 -1
- package/dist/terminal-CnYduoIp.js.map +0 -1
- package/dist/wizard-session-BudcixsA.js.map +0 -1
- package/dist/wizard-tools-BBLQk1YC.js.map +0 -1
- package/dist/yara-hooks-B42cYxIF.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _t as RUN_SURFACE, b as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, r as debug, s as logToFile, x as ANALYTICS_TEAM_TAG, y as ANALYTICS_HOST_URL } from "./debug-DXfQFmcM.js";
|
|
2
2
|
import { PostHog } from "posthog-node";
|
|
3
3
|
import { v4 } from "uuid";
|
|
4
4
|
//#region src/utils/ci-flag-overrides.ts
|
|
@@ -233,4 +233,4 @@ const analytics = new Analytics();
|
|
|
233
233
|
//#endregion
|
|
234
234
|
export { ciExcludedTaskTypes as a, sessionProperties as i, analytics as n, groupsFromUser as r, Analytics as t };
|
|
235
235
|
|
|
236
|
-
//# sourceMappingURL=analytics-
|
|
236
|
+
//# sourceMappingURL=analytics-DSlQuwOT.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics-jQRtyqzG.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n): Record<string, string> {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return flags;\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return flags;\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const merged = { ...flags };\n for (const [key, value] of Object.entries(overrides)) {\n merged[key] = String(value);\n }\n logToFile('[flags] CI overrides applied', overrides);\n return merged;\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE } from '@env';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n discovered_features: session.discoveredFeatures,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n return { $app_name: this.appName, ...this.personProperties };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: this.flagPersonProperties(),\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n const flags = result.featureFlags ?? {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n this.activeFlags = applyCiFlagOverrides(out);\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analytics-DSlQuwOT.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n): Record<string, string> {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return flags;\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return flags;\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const merged = { ...flags };\n for (const [key, value] of Object.entries(overrides)) {\n merged[key] = String(value);\n }\n logToFile('[flags] CI overrides applied', overrides);\n return merged;\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n} from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE } from '@env';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n discovered_features: session.discoveredFeatures,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n return { $app_name: this.appName, ...this.personProperties };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...properties,\n },\n });\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n async getFeatureFlag(flagKey: string): Promise<string | boolean | undefined> {\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n return await this.client.getFeatureFlag(flagKey, distinctId, {\n sendFeatureFlagEvents: true,\n personProperties: this.flagPersonProperties(),\n });\n } catch (error) {\n debug('Failed to get feature flag:', flagKey, error);\n return undefined;\n }\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const result = await this.client.getAllFlagsAndPayloads(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n const flags = result.featureFlags ?? {};\n for (const [key, value] of Object.entries(flags)) {\n if (value === undefined) continue;\n out[key] = typeof value === 'boolean' ? String(value) : String(value);\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n this.activeFlags = applyCiFlagOverrides(out);\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as analytics } from "./analytics-
|
|
2
|
+
import { dt as WIZARD_USER_AGENT } from "./debug-DXfQFmcM.js";
|
|
3
|
+
import { n as analytics } from "./analytics-DSlQuwOT.js";
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/lib/api.ts
|
|
@@ -170,4 +170,4 @@ function handleApiError(error, operation) {
|
|
|
170
170
|
//#endregion
|
|
171
171
|
export { fetchUserData as a, fetchSlackConnected as i, api_exports as n, handleApiError as o, fetchProjectData as r, ApiError as t };
|
|
172
172
|
|
|
173
|
-
//# sourceMappingURL=api-
|
|
173
|
+
//# sourceMappingURL=api-BXduJZrw.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-Bweisj9K.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-BXduJZrw.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAa,gBAAgB,EAC1B,OAAO;CAEN,aAAa,EAAE,QAAQ;CACvB,MAAM,EAAE,QAAQ,CAAC,SAAS;CAC1B,IAAI,EAAE,QAAQ,CAAC,SAAS;CAGxB,OAAO,EAAE,QAAQ,CAAC,SAAS;CAC3B,YAAY,EAAE,QAAQ,CAAC,SAAS;CAChC,WAAW,EAAE,QAAQ,CAAC,SAAS;CAC/B,aAAa,EAAE,QAAQ,CAAC,SAAS;CACjC,mBAAmB,EAAE,SAAS,CAAC,SAAS;CACxC,gBAAgB,EAAE,SAAS,CAAC,SAAS;CACrC,UAAU,EAAE,SAAS,CAAC,SAAS;CAG/B,YAAY,EAAE,QAAQ,CAAC,SAAS;CAChC,cAAc,EAAE,QAAQ,CAAC,SAAS;CAClC,gBAAgB,EAAE,SAAS,CAAC,SAAS;CAKrC,sBAAsB,EAAE,QAAQ,CAAC,SAAS;CAI1C,MAAM,EACH,OAAO;EACN,IAAI,EAAE,QAAQ;EACd,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,cAAc,EAAE,QAAQ,CAAC,MAAM;EAC/B,WAAW,EAAE,QAAQ,CAAC,SAAS;EAC/B,YAAY,EAAE,QAAQ,CAAC,SAAS;EAChC,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,UAAU,EAAE,QAAQ,CAAC,SAAS;EAC/B,CAAC,CACD,aAAa;CAChB,cAAc,EACX,OAAO;EACN,IAAI,EAAE,QAAQ,CAAC,MAAM;EACrB,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,kBAAkB,EAAE,QAAQ,CAAC,SAAS;EACtC,aAAa,EAAE,QAAQ,CAAC,SAAS;EAIjC,gCAAgC,EAAE,SAAS,CAAC,SAAS;EACtD,CAAC,CACD,aAAa;CAChB,eAAe,EAAE,MACf,EACG,OAAO;EACN,IAAI,EAAE,QAAQ,CAAC,MAAM;EACrB,MAAM,EAAE,QAAQ,CAAC,SAAS;EAC1B,kBAAkB,EAAE,QAAQ,CAAC,SAAS;EACvC,CAAC,CACD,aAAa,CACjB;CACF,CAAC,CACD,aAAa;;;;;;;;;;;;AAahB,MAAa,yBAAyB,EACnC,OAAO;CACN,OAAO,EAAE,QAAQ,CAAC,SAAS;CAC3B,UAAU,EAAE,QAAQ,CAAC,SAAS;CAC9B,YAAY,EAAE,QAAQ,CAAC,SAAS;CACjC,CAAC,CACD,aAAa;AAGyB,EAAE,OAAO,EAChD,SAAS,EAAE,MAAM,uBAAuB,EACzC,CAAC;AAKF,MAAa,mBAAmB,EAAE,OAAO;CACvC,IAAI,EAAE,QAAQ;CACd,MAAM,EAAE,QAAQ,CAAC,MAAM;CACvB,cAAc,EAAE,QAAQ,CAAC,MAAM;CAC/B,WAAW,EAAE,QAAQ;CACrB,MAAM,EAAE,QAAQ;CAOhB,0BAA0B,EAAE,SAAS,CAAC,SAAS;CAC/C,+BAA+B,EAAE,SAAS,CAAC,SAAS;CACpD,gBAAgB,EAAE,SAAS,CAAC,SAAS;CACtC,CAAC;AAKF,IAAa,WAAb,cAA8B,MAAM;CAClC,YACE,SACA,YACA,UACA;AACA,QAAM,QAAQ;AAHE,OAAA,aAAA;AACA,OAAA,WAAA;AAGhB,OAAK,OAAO;;;AAIhB,eAAsB,cACpB,aACA,SACkB;AAClB,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,IAAI,GAAG,QAAQ,kBAAkB,EAC5D,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,CAAC;AAEF,SAAO,cAAc,MAAM,SAAS,KAAK;UAClC,OAAO;EACd,MAAM,WAAW,eAAe,OAAO,kBAAkB;AACzD,YAAU,iBAAiB,UAAU;GACnC,UAAU;GACV;GACD,CAAC;AACF,QAAM;;;AA+CV,eAAsB,iBACpB,aACA,WACA,SACqB;AACrB,KAAI;EACF,MAAM,WAAW,MAAM,MAAM,IAAI,GAAG,QAAQ,gBAAgB,UAAU,IAAI,EACxE,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf,EACF,CAAC;AAEF,SAAO,iBAAiB,MAAM,SAAS,KAAK;UACrC,OAAO;EACd,MAAM,WAAW,eAAe,OAAO,qBAAqB;AAC5D,YAAU,iBAAiB,UAAU;GACnC,UAAU,iBAAiB,UAAU;GACrC;GACA;GACD,CAAC;AACF,QAAM;;;;AAKV,MAAM,6BAA6B,EAAE,OAAO,EAC1C,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,aAAa,CAAC,EACzE,CAAC;;;;;;;AAQF,eAAsB,oBACpB,aACA,WACA,SACA,QACkB;CAClB,MAAM,WAAW,MAAM,MAAM,IAC3B,GAAG,QAAQ,gBAAgB,UAAU,iBACrC;EACE,SAAS;GACP,eAAe,UAAU;GACzB,cAAc;GACf;EACD;EACD,CACF;CACD,MAAM,SAAS,2BAA2B,UAAU,SAAS,KAAK;AAClE,KAAI,CAAC,OAAO,QAAS,QAAO;AAC5B,QAAO,OAAO,KAAK,QAAQ,MAAM,MAAM,EAAE,SAAS,QAAQ;;AAG5D,SAAgB,eAAe,OAAgB,WAA6B;AAC1E,KAAI,MAAM,aAAa,MAAM,EAAE;EAC7B,MAAM,aAAa;EACnB,MAAM,SAAS,WAAW,UAAU;EACpC,MAAM,SAAS,WAAW,UAAU,MAAM;EAC1C,MAAM,WAAW,WAAW,QAAQ;AAEpC,MAAI,WAAW,IACb,QAAO,IAAI,SACT,yCAAyC,aACzC,QACA,SACD;AAGH,MAAI,WAAW,IACb,QAAO,IAAI,SACT,iCAAiC,aACjC,QACA,SACD;AAGH,MAAI,WAAW,IACb,QAAO,IAAI,SACT,sCAAsC,aACtC,QACA,SACD;AAIH,SAAO,IAAI,SADK,UAAU,aAAa,aACV,QAAQ,SAAS;;AAGhD,KAAI,iBAAiB,EAAE,SACrB,QAAO,IAAI,SAAS,2CAA2C,YAAY;AAG7E,QAAO,IAAI,SACT,oCAAoC,UAAU,IAC5C,iBAAiB,QAAQ,MAAM,UAAU,kBAE5C"}
|
package/dist/bin.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { n as analytics } from "./analytics-
|
|
4
|
-
import { r as setEntryCommand } from "./telemetry-
|
|
5
|
-
import { n as isUsingTypeScript } from "./setup-utils-
|
|
6
|
-
import { o as handleApiError } from "./api-
|
|
7
|
-
import "./wizard-session-
|
|
8
|
-
import { r as runCleanups } from "./wizard-abort-
|
|
9
|
-
import { n as isNonInteractiveEnvironment } from "./environment-
|
|
10
|
-
import { n as runAgent, o as authenticate } from "./agent-runner-
|
|
11
|
-
import { l as recoverOrphanedSettingsBackups, p as AgentSignals } from "./agent-interface-
|
|
12
|
-
import { i as fetchSkillMenu, t as WIZARD_TOOL_NAMES } from "./wizard-tools-
|
|
2
|
+
import { L as Integration, U as POSTHOG_DOCS_URL, a as getLogFilePath, bt as isHeadless, dt as WIZARD_USER_AGENT, f as getUI, ht as VERSION, m as LoggingUI, p as setUI, pt as getSkillsBaseUrl, r as debug, s as logToFile, yt as headlessOption } from "./debug-DXfQFmcM.js";
|
|
3
|
+
import { n as analytics } from "./analytics-DSlQuwOT.js";
|
|
4
|
+
import { r as setEntryCommand } from "./telemetry-DZShaH-y.js";
|
|
5
|
+
import { n as isUsingTypeScript } from "./setup-utils-BQCl28D8.js";
|
|
6
|
+
import { o as handleApiError } from "./api-BXduJZrw.js";
|
|
7
|
+
import "./wizard-session-BAZql11N.js";
|
|
8
|
+
import { r as runCleanups } from "./wizard-abort-C14PzXZ8.js";
|
|
9
|
+
import { n as isNonInteractiveEnvironment } from "./environment-F1yw21dG.js";
|
|
10
|
+
import { n as runAgent, o as authenticate } from "./agent-runner-BF6_f8Qh.js";
|
|
11
|
+
import { l as recoverOrphanedSettingsBackups, p as AgentSignals } from "./agent-interface-BvTxWiol.js";
|
|
12
|
+
import { i as fetchSkillMenu, t as WIZARD_TOOL_NAMES } from "./wizard-tools-B7SLjCic.js";
|
|
13
13
|
import { n as AUDIT_CHECKS_KEY, r as AUDIT_REPORT_FILE, t as AUDIT_CHECKS_FILE } from "./types-y3HkjtSq.js";
|
|
14
|
-
import { h as SETUP_REPORT_FILE } from "./yara-hooks-
|
|
15
|
-
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-
|
|
16
|
-
import { _ as gatherFrameworkContext, a as LINE_CHART_BLOCK, b as parseRequirementsTxt, g as detectProjectsWithAgent, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as parsePipfile, y as parsePyprojectToml } from "./posthog-integration-
|
|
17
|
-
import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-
|
|
14
|
+
import { h as SETUP_REPORT_FILE } from "./yara-hooks-CPH8N4yz.js";
|
|
15
|
+
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-DcoBCMQR.js";
|
|
16
|
+
import { _ as gatherFrameworkContext, a as LINE_CHART_BLOCK, b as parseRequirementsTxt, g as detectProjectsWithAgent, h as HEALTH_CHECK_STEP, i as FUNNEL_BLOCK, m as Icons, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, p as Colors, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as isClearBlock, v as parsePipfile, y as parsePyprojectToml } from "./posthog-integration-BhLKCFsI.js";
|
|
17
|
+
import { n as safeReadFile, r as walkProjectFiles, t as IGNORED_DIRS } from "./file-utils-D-7YfJ7A.js";
|
|
18
18
|
import { n as readApiKeyFromEnv } from "./env-api-key-cjD4yfGT.js";
|
|
19
19
|
import { satisfies } from "semver";
|
|
20
20
|
import yargs from "yargs";
|
|
@@ -101,12 +101,6 @@ const GLOBAL_OPTIONS = {
|
|
|
101
101
|
describe: "Email address for signup (used with --signup)\nenv: POSTHOG_WIZARD_EMAIL",
|
|
102
102
|
type: "string"
|
|
103
103
|
},
|
|
104
|
-
[HEADLESS_FLAG]: {
|
|
105
|
-
default: false,
|
|
106
|
-
describe: "EXPERIMENTAL — do not use. Unstable, subject to breaking changes.",
|
|
107
|
-
type: "boolean",
|
|
108
|
-
hidden: true
|
|
109
|
-
},
|
|
110
104
|
"local-mcp": {
|
|
111
105
|
default: false,
|
|
112
106
|
describe: "Use local MCP server at http://localhost:8787/mcp\nenv: POSTHOG_WIZARD_LOCAL_MCP",
|
|
@@ -212,7 +206,7 @@ function runProvision(argv) {
|
|
|
212
206
|
}
|
|
213
207
|
async function provision({ email, region, name, baseUrl, jsonMode }) {
|
|
214
208
|
try {
|
|
215
|
-
const { provisionNewAccount } = await import("./provisioning-
|
|
209
|
+
const { provisionNewAccount } = await import("./provisioning-jVZm2E-A.js").then((n) => n.n);
|
|
216
210
|
if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
|
|
217
211
|
emitResult(await provisionNewAccount(email, name, region, { baseUrl }), jsonMode);
|
|
218
212
|
process.exit(0);
|
|
@@ -267,7 +261,8 @@ const basicIntegrationCommand = {
|
|
|
267
261
|
describe: "Launch the TUI primitives playground",
|
|
268
262
|
type: "boolean",
|
|
269
263
|
hidden: true
|
|
270
|
-
}
|
|
264
|
+
},
|
|
265
|
+
...headlessOption
|
|
271
266
|
},
|
|
272
267
|
check: (argv) => {
|
|
273
268
|
if (argv.playground && (argv.ci || isHeadless(argv))) throw new Error("--playground cannot be combined with a headless run.");
|
|
@@ -277,22 +272,22 @@ const basicIntegrationCommand = {
|
|
|
277
272
|
setEntryCommand("integrate");
|
|
278
273
|
(async () => {
|
|
279
274
|
if (isHeadless(argv)) {
|
|
280
|
-
const { runHeadlessInstall } = await import("./ci-install-
|
|
275
|
+
const { runHeadlessInstall } = await import("./ci-install-GirEJqu2.js");
|
|
281
276
|
return runHeadlessInstall(argv);
|
|
282
277
|
}
|
|
283
278
|
if (argv.ci) {
|
|
284
|
-
const { runCIInstall } = await import("./ci-install-
|
|
279
|
+
const { runCIInstall } = await import("./ci-install-GirEJqu2.js");
|
|
285
280
|
return runCIInstall(argv);
|
|
286
281
|
}
|
|
287
282
|
if (isNonInteractiveEnvironment()) {
|
|
288
|
-
const { failNonInteractive } = await import("./non-interactive-
|
|
283
|
+
const { failNonInteractive } = await import("./non-interactive-BIHqcW8g.js");
|
|
289
284
|
return failNonInteractive();
|
|
290
285
|
}
|
|
291
286
|
if (argv.playground) {
|
|
292
|
-
const { runPlayground } = await import("./playground-
|
|
287
|
+
const { runPlayground } = await import("./playground-DwL36I2u.js");
|
|
293
288
|
return runPlayground();
|
|
294
289
|
}
|
|
295
|
-
const { runInteractive } = await import("./interactive-
|
|
290
|
+
const { runInteractive } = await import("./interactive-Bmi82rsO.js");
|
|
296
291
|
runInteractive(argv);
|
|
297
292
|
})();
|
|
298
293
|
}
|
|
@@ -1640,7 +1635,8 @@ const auditConfig = {
|
|
|
1640
1635
|
steps: auditSteps,
|
|
1641
1636
|
run: auditRun,
|
|
1642
1637
|
allowedTools: ["Agent"],
|
|
1643
|
-
disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk]
|
|
1638
|
+
disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],
|
|
1639
|
+
cliOptions: { ...headlessOption }
|
|
1644
1640
|
};
|
|
1645
1641
|
//#endregion
|
|
1646
1642
|
//#region src/lib/programs/events-audit/steps.ts
|
|
@@ -2136,7 +2132,7 @@ const VENDOR_STACK_BLOCK = {
|
|
|
2136
2132
|
color: "gray",
|
|
2137
2133
|
children: " Braintrust"
|
|
2138
2134
|
}),
|
|
2139
|
-
/* @__PURE__ */ jsx(Text, { children: "
|
|
2135
|
+
/* @__PURE__ */ jsx(Text, { children: " AI observability " }),
|
|
2140
2136
|
/* @__PURE__ */ jsx(Text, {
|
|
2141
2137
|
color: "red",
|
|
2142
2138
|
children: "$50/mo+"
|
|
@@ -2229,7 +2225,7 @@ const FREE_TIER_BLOCK = {
|
|
|
2229
2225
|
/* @__PURE__ */ jsx(Text, { children: "events " }),
|
|
2230
2226
|
/* @__PURE__ */ jsx(Text, {
|
|
2231
2227
|
dimColor: true,
|
|
2232
|
-
children: "
|
|
2228
|
+
children: "AI observability"
|
|
2233
2229
|
})
|
|
2234
2230
|
] }),
|
|
2235
2231
|
/* @__PURE__ */ jsxs(Text, { children: [
|
|
@@ -3744,7 +3740,11 @@ STEP 5 — Offer issue-tracker integrations. (skill: "Connected tools")
|
|
|
3744
3740
|
One batched multi-select wizard_ask for the external tools the skill
|
|
3745
3741
|
lists. The run auto-connects the ones it can (GitHub Issues, and
|
|
3746
3742
|
Linear via a one-click OAuth link), verifying each with a single
|
|
3747
|
-
silent check — never nudge.
|
|
3743
|
+
silent check — never nudge. For GitHub Issues: when the GitHub
|
|
3744
|
+
integration has exactly one repository connected, use that repo by
|
|
3745
|
+
default and skip repo research entirely — research which repo
|
|
3746
|
+
matches this project only when several are connected. It arms the
|
|
3747
|
+
rest as dormant responders to
|
|
3748
3748
|
finish later: for tools it can't auto-connect (Zendesk, pganalyze) it
|
|
3749
3749
|
never sends the user to paste credentials and never re-prompts. Enable
|
|
3750
3750
|
a source only for a tool the user picked.
|
|
@@ -3758,7 +3758,11 @@ STEP 6b — Design custom scouts for this product. (skill: "Custom scouts")
|
|
|
3758
3758
|
You are the only actor that has read this repo — turn that into
|
|
3759
3759
|
coverage per the skill: a real gap analysis of the project's
|
|
3760
3760
|
watchable surfaces against what the built-in troop already covers,
|
|
3761
|
-
then custom scouts for the uncovered ones.
|
|
3761
|
+
then custom scouts for the uncovered ones. Start the gap analysis
|
|
3762
|
+
from the repo's for-agents context when present (AGENTS.md,
|
|
3763
|
+
CLAUDE.md, ARCHITECTURE.md, .cursor/rules, agent-facing docs) — it
|
|
3764
|
+
is a maintained map of the product's surfaces and vocabulary, so
|
|
3765
|
+
read it before scanning source. Keep scout bodies
|
|
3762
3766
|
high-level: describe the behavior and signal conditions to watch,
|
|
3763
3767
|
referencing repo evidence by file/function name — never paste raw
|
|
3764
3768
|
source, secrets, env values, or customer data into a scout body.
|
|
@@ -3796,6 +3800,11 @@ const SELF_DRIVING_TIPS = [
|
|
|
3796
3800
|
title: "The loop",
|
|
3797
3801
|
description: "After a fix ships, PostHog measures the result. If the pattern persists, a new signal reopens the work."
|
|
3798
3802
|
},
|
|
3803
|
+
{
|
|
3804
|
+
id: "pricing",
|
|
3805
|
+
title: "What it costs",
|
|
3806
|
+
description: "Watching is free. You pay a flat $15 only when a report ships a PR."
|
|
3807
|
+
},
|
|
3799
3808
|
{
|
|
3800
3809
|
id: "work-anywhere",
|
|
3801
3810
|
title: "Work anywhere",
|
|
@@ -4032,6 +4041,10 @@ const getContentBlocks = (store) => {
|
|
|
4032
4041
|
content: "Investigate with the agent, tag teammates, or kick off a PR.",
|
|
4033
4042
|
pause: 6e3
|
|
4034
4043
|
},
|
|
4044
|
+
{
|
|
4045
|
+
content: "That PR is the only thing you pay for: a flat $15 per report that ships a PR. Watching is free.",
|
|
4046
|
+
pause: 6e3
|
|
4047
|
+
},
|
|
4035
4048
|
CLEAR,
|
|
4036
4049
|
{
|
|
4037
4050
|
content: "And after the PR ships, PostHog measures the result.",
|
|
@@ -4165,10 +4178,11 @@ const run = {
|
|
|
4165
4178
|
items: [
|
|
4166
4179
|
"Investigate reports with the agent",
|
|
4167
4180
|
"Tag teammates to loop them in",
|
|
4168
|
-
"Kick off a PR when you like the proposed fix",
|
|
4181
|
+
"Kick off a PR when you like the proposed fix ($15 flat)",
|
|
4169
4182
|
"Or work from Slack (tag @PostHog) and MCP"
|
|
4170
4183
|
]
|
|
4171
4184
|
},
|
|
4185
|
+
body: "Pricing: scouts, signals, and reports are free. You pay a flat $15 only when a report ships a PR.",
|
|
4172
4186
|
reportFile: REPORT_FILE
|
|
4173
4187
|
};
|
|
4174
4188
|
}
|
|
@@ -4424,8 +4438,8 @@ function runMcpAdd(argv) {
|
|
|
4424
4438
|
const debug = argv.debug;
|
|
4425
4439
|
const localMcp = argv.local;
|
|
4426
4440
|
try {
|
|
4427
|
-
const { startTUI } = await import("./start-tui-
|
|
4428
|
-
const { buildSession } = await import("./wizard-session-
|
|
4441
|
+
const { startTUI } = await import("./start-tui-DgSKFMVh.js");
|
|
4442
|
+
const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
|
|
4429
4443
|
const tui = startTUI(VERSION, Program.McpAdd);
|
|
4430
4444
|
tui.store.session = buildSession({
|
|
4431
4445
|
debug,
|
|
@@ -4437,7 +4451,7 @@ function runMcpAdd(argv) {
|
|
|
4437
4451
|
} catch (error) {
|
|
4438
4452
|
if (!isTUIUnavailable(error)) throw error;
|
|
4439
4453
|
setUI(new LoggingUI());
|
|
4440
|
-
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-
|
|
4454
|
+
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-D5qsqCkj.js").then((n) => n.r);
|
|
4441
4455
|
await addMCPServerToClientsStep({
|
|
4442
4456
|
local: localMcp,
|
|
4443
4457
|
features,
|
|
@@ -4476,8 +4490,8 @@ function runMcpRemove(argv) {
|
|
|
4476
4490
|
const debug = argv.debug;
|
|
4477
4491
|
const localMcp = argv.local;
|
|
4478
4492
|
try {
|
|
4479
|
-
const { startTUI } = await import("./start-tui-
|
|
4480
|
-
const { buildSession } = await import("./wizard-session-
|
|
4493
|
+
const { startTUI } = await import("./start-tui-DgSKFMVh.js");
|
|
4494
|
+
const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
|
|
4481
4495
|
const tui = startTUI(VERSION, Program.McpRemove);
|
|
4482
4496
|
tui.store.session = buildSession({
|
|
4483
4497
|
debug,
|
|
@@ -4486,7 +4500,7 @@ function runMcpRemove(argv) {
|
|
|
4486
4500
|
});
|
|
4487
4501
|
} catch {
|
|
4488
4502
|
setUI(new LoggingUI());
|
|
4489
|
-
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-
|
|
4503
|
+
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-D5qsqCkj.js").then((n) => n.r);
|
|
4490
4504
|
await removeMCPServerFromClientsStep({ local: localMcp });
|
|
4491
4505
|
}
|
|
4492
4506
|
})();
|
|
@@ -4508,8 +4522,8 @@ function runMcpTutorial(argv) {
|
|
|
4508
4522
|
const debug = argv.debug;
|
|
4509
4523
|
const localMcp = argv.local;
|
|
4510
4524
|
try {
|
|
4511
|
-
const { startTUI } = await import("./start-tui-
|
|
4512
|
-
const { buildSession } = await import("./wizard-session-
|
|
4525
|
+
const { startTUI } = await import("./start-tui-DgSKFMVh.js");
|
|
4526
|
+
const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
|
|
4513
4527
|
const tui = startTUI(VERSION, Program.McpTutorial);
|
|
4514
4528
|
tui.store.session = buildSession({
|
|
4515
4529
|
debug,
|
|
@@ -4589,9 +4603,9 @@ function runWizard(config, options) {
|
|
|
4589
4603
|
(async () => {
|
|
4590
4604
|
try {
|
|
4591
4605
|
const installDir = options.installDir || process.cwd();
|
|
4592
|
-
const { startTUI } = await import("./start-tui-
|
|
4593
|
-
const { buildSession, RunPhase } = await import("./wizard-session-
|
|
4594
|
-
const { TaskStreamPush } = await import("./task-stream-
|
|
4606
|
+
const { startTUI } = await import("./start-tui-DgSKFMVh.js");
|
|
4607
|
+
const { buildSession, RunPhase } = await import("./wizard-session-C5lZPPEc.js");
|
|
4608
|
+
const { TaskStreamPush } = await import("./task-stream-0Pk0tPBN.js");
|
|
4595
4609
|
const { PostHogDestination } = await import("./posthog-DwKlq0HM.js");
|
|
4596
4610
|
tui = startTUI(WIZARD_VERSION, config.id);
|
|
4597
4611
|
const activeTui = tui;
|
|
@@ -4656,7 +4670,7 @@ function runWizard(config, options) {
|
|
|
4656
4670
|
if (shown(step)) await advanceStep(step, activeTui.store, config);
|
|
4657
4671
|
}
|
|
4658
4672
|
else if (skipAgent) {
|
|
4659
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
4673
|
+
const { getOrAskForProjectData } = await import("./setup-utils-BQCl28D8.js").then((n) => n.r);
|
|
4660
4674
|
const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
|
|
4661
4675
|
signup: session.signup,
|
|
4662
4676
|
ci: session.ci,
|
|
@@ -4758,11 +4772,11 @@ function runNonInteractive(config, options, mode) {
|
|
|
4758
4772
|
analytics.setTag("build", mode);
|
|
4759
4773
|
(async () => {
|
|
4760
4774
|
const path = await import("path");
|
|
4761
|
-
const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-
|
|
4762
|
-
const { readEnvironment } = await import("./environment-
|
|
4775
|
+
const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-C5lZPPEc.js");
|
|
4776
|
+
const { readEnvironment } = await import("./environment-F1yw21dG.js").then((n) => n.t);
|
|
4763
4777
|
const { readApiKeyFromEnv } = await import("./env-api-key-cjD4yfGT.js").then((n) => n.t);
|
|
4764
|
-
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-
|
|
4765
|
-
const { wizardAbort, WizardError } = await import("./wizard-abort-
|
|
4778
|
+
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-BOFxiVVs.js");
|
|
4779
|
+
const { wizardAbort, WizardError } = await import("./wizard-abort-UCm4Pd5m.js");
|
|
4766
4780
|
configureLogFileFromEnvironment();
|
|
4767
4781
|
const env = readEnvironment();
|
|
4768
4782
|
const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
|
|
@@ -4793,9 +4807,9 @@ function runNonInteractive(config, options, mode) {
|
|
|
4793
4807
|
let store = null;
|
|
4794
4808
|
let taskStream = null;
|
|
4795
4809
|
if (mode === "headless") {
|
|
4796
|
-
const { WizardStore } = await import("./store-
|
|
4797
|
-
const { HeadlessUI } = await import("./headless-ui-
|
|
4798
|
-
const { TaskStreamPush, PostHogDestination } = await import("./task-stream-
|
|
4810
|
+
const { WizardStore } = await import("./store-C79GoHCQ.js").then((n) => n.n);
|
|
4811
|
+
const { HeadlessUI } = await import("./headless-ui-Dni0gPND.js");
|
|
4812
|
+
const { TaskStreamPush, PostHogDestination } = await import("./task-stream-0Pk0tPBN.js");
|
|
4799
4813
|
store = new WizardStore(config.id);
|
|
4800
4814
|
store.session = session;
|
|
4801
4815
|
setUI(new HeadlessUI(store));
|
|
@@ -4850,7 +4864,7 @@ function runNonInteractive(config, options, mode) {
|
|
|
4850
4864
|
});
|
|
4851
4865
|
}
|
|
4852
4866
|
}
|
|
4853
|
-
const { runAgent } = await import("./agent-runner-
|
|
4867
|
+
const { runAgent } = await import("./agent-runner-BF6_f8Qh.js").then((n) => n.t);
|
|
4854
4868
|
await runAgent(config, session);
|
|
4855
4869
|
await settleStream(RunPhase.Completed);
|
|
4856
4870
|
} catch (error) {
|
|
@@ -4917,8 +4931,8 @@ const skillProgramOptions = { "install-dir": {
|
|
|
4917
4931
|
//#region src/commands/factories/shared.ts
|
|
4918
4932
|
/**
|
|
4919
4933
|
* Dispatch a parsed yargs invocation to the wizard runner. Applies the
|
|
4920
|
-
* program's `mapCliOptions` transform, then routes to `
|
|
4921
|
-
* `runWizardCI` based on the `--ci`
|
|
4934
|
+
* program's `mapCliOptions` transform, then routes to `runWizardHeadless`,
|
|
4935
|
+
* `runWizardCI`, or `runWizard` based on the headless / `--ci` flags.
|
|
4922
4936
|
*
|
|
4923
4937
|
* Every command file used to inline this; the factories call it instead.
|
|
4924
4938
|
*/
|
|
@@ -4947,7 +4961,8 @@ function dispatchProgram(config, argv) {
|
|
|
4947
4961
|
...argvRecord,
|
|
4948
4962
|
...extras
|
|
4949
4963
|
};
|
|
4950
|
-
if (options
|
|
4964
|
+
if (isHeadless(options)) runWizardHeadless(config, options);
|
|
4965
|
+
else if (options.ci) runWizardCI(config, options);
|
|
4951
4966
|
else runWizard(config, options);
|
|
4952
4967
|
}
|
|
4953
4968
|
/**
|
|
@@ -5778,7 +5793,7 @@ async function runDoctorCI(options) {
|
|
|
5778
5793
|
getUI().intro("Welcome to the PostHog setup wizard");
|
|
5779
5794
|
getUI().log.info("Running posthog-doctor in CI mode");
|
|
5780
5795
|
try {
|
|
5781
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
5796
|
+
const { getOrAskForProjectData } = await import("./setup-utils-BQCl28D8.js").then((n) => n.r);
|
|
5782
5797
|
const { host, accessToken, projectId } = await getOrAskForProjectData({
|
|
5783
5798
|
signup: false,
|
|
5784
5799
|
ci: true,
|
|
@@ -5796,7 +5811,7 @@ async function runDoctorCI(options) {
|
|
|
5796
5811
|
for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
|
|
5797
5812
|
process.exit(1);
|
|
5798
5813
|
} catch (error) {
|
|
5799
|
-
const { ApiError } = await import("./api-
|
|
5814
|
+
const { ApiError } = await import("./api-BXduJZrw.js").then((n) => n.n);
|
|
5800
5815
|
const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
|
|
5801
5816
|
getUI().log.error(`Doctor failed: ${message}`);
|
|
5802
5817
|
process.exit(1);
|
|
@@ -5841,14 +5856,14 @@ const selfDrivingCommand = {
|
|
|
5841
5856
|
options: {
|
|
5842
5857
|
...skillProgramOptions,
|
|
5843
5858
|
integrate: {
|
|
5844
|
-
describe: "Integrate the PostHog SDK first, then set up Self-driving — skips the
|
|
5859
|
+
describe: "Integrate the PostHog SDK first, then set up Self-driving — skips the integration prompt and logs you in via OAuth (no \"create an account?\" question). Use when the project isn't set up yet but you already have a PostHog account.",
|
|
5845
5860
|
type: "boolean",
|
|
5846
5861
|
default: false
|
|
5847
5862
|
},
|
|
5848
5863
|
...selfDrivingConfig.cliOptions ?? {}
|
|
5849
5864
|
},
|
|
5850
5865
|
check: (argv) => {
|
|
5851
|
-
if (argv.signup) throw new Error("`self-driving` cannot run with --signup.
|
|
5866
|
+
if (argv.signup) throw new Error("`self-driving` cannot run with --signup. Just run `wizard self-driving`: when your project has no PostHog, it asks whether you already have an account and offers to create one for you (no flag needed).");
|
|
5852
5867
|
if (argv.ci) throw new Error("`self-driving` cannot run in CI mode — it requires interactive steps (GitHub connect, issue-tracker selection, custom-scout approval).");
|
|
5853
5868
|
return true;
|
|
5854
5869
|
},
|
|
@@ -5878,8 +5893,8 @@ function runSlackConnect(argv) {
|
|
|
5878
5893
|
(async () => {
|
|
5879
5894
|
const debug = argv.debug;
|
|
5880
5895
|
try {
|
|
5881
|
-
const { startTUI } = await import("./start-tui-
|
|
5882
|
-
const { buildSession } = await import("./wizard-session-
|
|
5896
|
+
const { startTUI } = await import("./start-tui-DgSKFMVh.js");
|
|
5897
|
+
const { buildSession } = await import("./wizard-session-C5lZPPEc.js");
|
|
5883
5898
|
const tui = startTUI(VERSION, Program.SlackConnect);
|
|
5884
5899
|
tui.store.session = buildSession({
|
|
5885
5900
|
debug,
|