@posthog/wizard 2.70.1 → 2.71.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-mcp-server-to-clients-BCnjUqnW.js → add-mcp-server-to-clients-B6-ZL--P.js} +4 -4
- package/dist/{add-mcp-server-to-clients-BCnjUqnW.js.map → add-mcp-server-to-clients-B6-ZL--P.js.map} +1 -1
- package/dist/{agent-interface-Lu7tnLr0.js → agent-interface-DFm4jB4d.js} +108 -15
- package/dist/agent-interface-DFm4jB4d.js.map +1 -0
- package/dist/{agent-prompt-loader-y5GxgEkc.js → agent-prompt-loader-Bi3IzSBW.js} +5 -5
- package/dist/{agent-prompt-loader-y5GxgEkc.js.map → agent-prompt-loader-Bi3IzSBW.js.map} +1 -1
- package/dist/{agent-runner-vKtpgqVI.js → agent-runner-Cp6iLqDk.js} +49 -16
- package/dist/agent-runner-Cp6iLqDk.js.map +1 -0
- package/dist/{analytics-DTyJClPr.js → analytics-D54mLptm.js} +3 -3
- package/dist/{analytics-DTyJClPr.js.map → analytics-D54mLptm.js.map} +1 -1
- package/dist/analytics-Ge1LsCNg.js +2 -0
- package/dist/{api-j-OfJ8Dz.js → api-BNBVOguz.js} +23 -4
- package/dist/{api-j-OfJ8Dz.js.map → api-BNBVOguz.js.map} +1 -1
- package/dist/bin.js +79 -73
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-BWX25ixc.js → bounded-fs-DHIaH3Sc.js} +3 -3
- package/dist/{bounded-fs-BWX25ixc.js.map → bounded-fs-DHIaH3Sc.js.map} +1 -1
- package/dist/{ci-install-zNWgp1TL.js → ci-install-Can8LRdJ.js} +5 -5
- package/dist/{ci-install-zNWgp1TL.js.map → ci-install-Can8LRdJ.js.map} +1 -1
- package/dist/{debug-xr2Pq5VA.js → debug-C4RPcEIX.js} +1 -1
- package/dist/{debug-BM0fZaGl.js → debug-YQdeZulR.js} +4 -3
- package/dist/debug-YQdeZulR.js.map +1 -0
- package/dist/{env-api-key-DlxCZWU0.js → env-api-key-9yogO8OI.js} +2 -2
- package/dist/{env-api-key-DlxCZWU0.js.map → env-api-key-9yogO8OI.js.map} +1 -1
- package/dist/{environment-o-bTOuzK.js → environment-6ZuAWRpQ.js} +4 -4
- package/dist/{environment-o-bTOuzK.js.map → environment-6ZuAWRpQ.js.map} +1 -1
- package/dist/{errors-BSdz2lsl.js → errors-u8z27V-x.js} +4 -2
- package/dist/errors-u8z27V-x.js.map +1 -0
- package/dist/{file-watcher-D7G4f5sP.js → file-watcher-CeWdvMVT.js} +2 -2
- package/dist/{file-watcher-D7G4f5sP.js.map → file-watcher-CeWdvMVT.js.map} +1 -1
- package/dist/{headless-ui-C46DctKG.js → headless-ui-BxSVgNoT.js} +2 -2
- package/dist/{headless-ui-C46DctKG.js.map → headless-ui-BxSVgNoT.js.map} +1 -1
- package/dist/{interactive-B5zy3Gxk.js → interactive-CRR9zPl4.js} +2 -2
- package/dist/{interactive-B5zy3Gxk.js.map → interactive-CRR9zPl4.js.map} +1 -1
- package/dist/{mcp-lJRwE-YW.js → mcp-D_rRzruj.js} +2 -2
- package/dist/{mcp-lJRwE-YW.js.map → mcp-D_rRzruj.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-Dsos09hT.js → mcp-prompt-streaming-DRAK8CMP.js} +5 -4
- package/dist/mcp-prompt-streaming-DRAK8CMP.js.map +1 -0
- package/dist/{non-interactive-qcCCtiYQ.js → non-interactive-1EJRlN6u.js} +3 -3
- package/dist/{non-interactive-qcCCtiYQ.js.map → non-interactive-1EJRlN6u.js.map} +1 -1
- package/dist/{orchestrator-tools-ezFTbAIp.js → orchestrator-tools-DjZWqWmd.js} +3 -3
- package/dist/{orchestrator-tools-ezFTbAIp.js.map → orchestrator-tools-DjZWqWmd.js.map} +1 -1
- package/dist/{package-manager-CGfN9UhH.js → package-manager-DMbzbdkL.js} +2 -2
- package/dist/{package-manager-CGfN9UhH.js.map → package-manager-DMbzbdkL.js.map} +1 -1
- package/dist/{pi-DzQLHIcQ.js → pi-D4JQMC-7.js} +18 -15
- package/dist/pi-D4JQMC-7.js.map +1 -0
- package/dist/{playground-DLN31BPV.js → playground-Y1nSGXpn.js} +43 -8
- package/dist/playground-Y1nSGXpn.js.map +1 -0
- package/dist/{posthog-Dxr8XK4x.js → posthog-D9VwcWvJ.js} +2 -2
- package/dist/{posthog-Dxr8XK4x.js.map → posthog-D9VwcWvJ.js.map} +1 -1
- package/dist/{posthog-integration-MDfRO911.js → posthog-integration-B8f4xRBd.js} +18 -18
- package/dist/posthog-integration-B8f4xRBd.js.map +1 -0
- package/dist/{provisioning-Di5GNV9k.js → provisioning-f7lA29tW.js} +14 -5
- package/dist/provisioning-f7lA29tW.js.map +1 -0
- package/dist/{queue-tools-KosDptd6.js → queue-tools-DGaHf3n-.js} +3 -3
- package/dist/{queue-tools-KosDptd6.js.map → queue-tools-DGaHf3n-.js.map} +1 -1
- package/dist/{registry-BBdaIFWq.js → registry-D1By1SgH.js} +5 -5
- package/dist/{registry-BBdaIFWq.js.map → registry-D1By1SgH.js.map} +1 -1
- package/dist/{security-BwOvjMaq.js → security-C2c3_Ycy.js} +5 -5
- package/dist/{security-BwOvjMaq.js.map → security-C2c3_Ycy.js.map} +1 -1
- package/dist/{setup-utils-Bo3WZt3a.js → setup-utils-BRrCeajl.js} +42 -11
- package/dist/setup-utils-BRrCeajl.js.map +1 -0
- package/dist/{start-tui-B1LrB7k1.js → start-tui-r4Spgptv.js} +257 -23
- package/dist/start-tui-r4Spgptv.js.map +1 -0
- package/dist/{steps-BMrQJpQh.js → steps-BZd65XfI.js} +7 -7
- package/dist/{steps-BMrQJpQh.js.map → steps-BZd65XfI.js.map} +1 -1
- package/dist/{store-DhNTBWQR.js → store-DGVXu7xt.js} +25 -6
- package/dist/store-DGVXu7xt.js.map +1 -0
- package/dist/{subagent-q6M-mBHo.js → subagent-BaMxO7OT.js} +2 -2
- package/dist/{subagent-q6M-mBHo.js.map → subagent-BaMxO7OT.js.map} +1 -1
- package/dist/{task-CgAOxod7.js → task-DpKoEZ5I.js} +13 -13
- package/dist/{task-CgAOxod7.js.map → task-DpKoEZ5I.js.map} +1 -1
- package/dist/{task-stream-rxR1IsdJ.js → task-stream-CdrBraqP.js} +6 -6
- package/dist/{task-stream-rxR1IsdJ.js.map → task-stream-CdrBraqP.js.map} +1 -1
- package/dist/{tasks-lzvWF__k.js → tasks-KsP66Cis.js} +2 -2
- package/dist/{tasks-lzvWF__k.js.map → tasks-KsP66Cis.js.map} +1 -1
- package/dist/{telemetry-CickTk_7.js → telemetry-DedDTtSa.js} +3 -3
- package/dist/{telemetry-CickTk_7.js.map → telemetry-DedDTtSa.js.map} +1 -1
- package/dist/{terminal-BjUFxn_x.js → terminal-BH8yLclG.js} +107 -61
- package/dist/terminal-BH8yLclG.js.map +1 -0
- package/dist/{tools-MKXGXFSk.js → tools-CJw5vnZd.js} +6 -6
- package/dist/{tools-MKXGXFSk.js.map → tools-CJw5vnZd.js.map} +1 -1
- package/dist/{wizard-abort-CooWEh9N.js → wizard-abort-D54j2gmb.js} +5 -5
- package/dist/{wizard-abort-CooWEh9N.js.map → wizard-abort-D54j2gmb.js.map} +1 -1
- package/dist/{wizard-abort-CW_C2EXr.js → wizard-abort-Q1NiYELE.js} +1 -1
- package/dist/{wizard-session-Bki7dQhv.js → wizard-session-CwQPZN4y.js} +3 -1
- package/dist/wizard-session-CwQPZN4y.js.map +1 -0
- package/dist/{wizard-session-gbYCXdBf.js → wizard-session-Dwc1Rh_7.js} +1 -1
- package/dist/yara-hooks-BI6WY0Sl.js +2 -0
- package/dist/{yara-hooks-BpngckdZ.js → yara-hooks-CL2LVEgO.js} +4 -4
- package/dist/{yara-hooks-BpngckdZ.js.map → yara-hooks-CL2LVEgO.js.map} +1 -1
- package/package.json +1 -1
- package/dist/agent-interface-Lu7tnLr0.js.map +0 -1
- package/dist/agent-runner-vKtpgqVI.js.map +0 -1
- package/dist/analytics-D-bMEYjD.js +0 -2
- package/dist/debug-BM0fZaGl.js.map +0 -1
- package/dist/errors-BSdz2lsl.js.map +0 -1
- package/dist/mcp-prompt-streaming-Dsos09hT.js.map +0 -1
- package/dist/pi-DzQLHIcQ.js.map +0 -1
- package/dist/playground-DLN31BPV.js.map +0 -1
- package/dist/posthog-integration-MDfRO911.js.map +0 -1
- package/dist/provisioning-Di5GNV9k.js.map +0 -1
- package/dist/setup-utils-Bo3WZt3a.js.map +0 -1
- package/dist/start-tui-B1LrB7k1.js.map +0 -1
- package/dist/store-DhNTBWQR.js.map +0 -1
- package/dist/terminal-BjUFxn_x.js.map +0 -1
- package/dist/wizard-session-Bki7dQhv.js.map +0 -1
- package/dist/yara-hooks-C-qG6EJt.js +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, bt as TASK_RUN_ID, gt as VERSION, it as WIZARD_FLAG_KEYS, r as debug, s as logToFile, vt as RUN_SURFACE, w as ANALYTICS_TEAM_TAG, yt as TASK_ID } from "./debug-
|
|
2
|
-
import { s as reportableDiscoveredFeatures } from "./wizard-session-
|
|
1
|
+
import { C as ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, S as ANALYTICS_HOST_URL, bt as TASK_RUN_ID, gt as VERSION, it as WIZARD_FLAG_KEYS, r as debug, s as logToFile, vt as RUN_SURFACE, w as ANALYTICS_TEAM_TAG, yt as TASK_ID } from "./debug-YQdeZulR.js";
|
|
2
|
+
import { s as reportableDiscoveredFeatures } from "./wizard-session-CwQPZN4y.js";
|
|
3
3
|
import { PostHog } from "posthog-node";
|
|
4
4
|
import { v4 } from "uuid";
|
|
5
5
|
//#region src/utils/ci-flag-overrides.ts
|
|
@@ -291,4 +291,4 @@ const analytics = new Analytics();
|
|
|
291
291
|
//#endregion
|
|
292
292
|
export { ciExcludedTaskTypes as a, sessionProperties as i, analytics as n, groupsFromUser as r, Analytics as t };
|
|
293
293
|
|
|
294
|
-
//# sourceMappingURL=analytics-
|
|
294
|
+
//# sourceMappingURL=analytics-D54mLptm.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics-DTyJClPr.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n payloads: Record<string, unknown> = {},\n): { flags: Record<string, string>; payloads: Record<string, unknown> } {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return { flags, payloads };\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return { flags, payloads };\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const mergedFlags = { ...flags };\n const mergedPayloads = { ...payloads };\n for (const [key, value] of Object.entries(overrides)) {\n // An object/array override is a flag payload: the flag reads 'true' and\n // the value rides the payload channel, matching a payload-carrying flag.\n if (typeof value === 'object' && value !== null) {\n mergedFlags[key] = 'true';\n mergedPayloads[key] = value;\n } else {\n mergedFlags[key] = String(value);\n }\n }\n logToFile('[flags] CI overrides applied', overrides);\n return { flags: mergedFlags, payloads: mergedPayloads };\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n WIZARD_FLAG_KEYS,\n} from '@lib/constants';\nimport {\n reportableDiscoveredFeatures,\n type WizardSession,\n} from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } from '@env';\nimport { VERSION } from '@lib/version';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * The invocation, reduced to flag-safe strings: the command word (first\n * positional, 'default' for the bare flow) and the sorted option NAMES.\n * Option values never leave the machine — they carry paths, emails, keys.\n */\nfunction invocationProperties(): { command: string; cli_flags: string } {\n const args = process.argv.slice(2);\n const command = args.find((a) => !a.startsWith('-')) ?? 'default';\n const flags = [\n ...new Set(\n args\n .filter((a) => a.startsWith('--'))\n .map((a) => a.slice(2).split('=')[0]),\n ),\n ].sort();\n return { command, cli_flags: flags.join(',') };\n}\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n // reportableDiscoveredFeatures() owns the consent decision; this file\n // never needs to know what `scanConsent` means, only that the result\n // might be absent. An absent key is unambiguous, while an empty array\n // would read as \"we looked and found nothing\" instead of \"not reported\".\n const discoveredFeatures = reportableDiscoveredFeatures(session);\n\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n ...(discoveredFeatures !== undefined\n ? { discovered_features: discoveredFeatures }\n : {}),\n scan_consent: session.scanConsent,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nconst WIZARD_FLAGS: ReadonlySet<string> = new Set(WIZARD_FLAG_KEYS);\n\n// Widen back to the SDK's shape — a filter on `true` never matches `'true'`.\nfunction flagResponseValue(value: string): string | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return value;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private activeFlagPayloads: Record<string, unknown> = {};\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n // The SDK captures this one itself, bypassing capture(), so tags merge here.\n if (event.event === '$feature_flag_called') {\n event.properties = { ...this.tags, ...(event.properties ?? {}) };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n // The build this run came from. Already sent as a flag-evaluation person\n // property; tagging it makes every event attributable to a release, so a\n // regression can be bounded to the versions that carry it.\n this.tags.version = VERSION;\n\n // Cloud runs only: the task run that owns the sandbox. Without these the\n // wizard's events and the run that launched it are two unrelated streams,\n // since run_id above is minted per process and never leaves the wizard.\n // Left unset for local runs so the properties stay absent rather than null.\n if (TASK_RUN_ID) this.tags.task_run_id = TASK_RUN_ID;\n if (TASK_ID) this.tags.task_id = TASK_ID;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n this.activeFlagPayloads = {};\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n // Environment facts flag conditions can scope on — evaluation-time only,\n // never persisted onto the person. `version` gates an experiment to\n // releases that implement it (a condition on a property older builds\n // don't send silently never matches them); `run_surface`/`build` scope\n // by invocation surface; `command`/`cli_flags` by subcommand; `os`/\n // `node_major` by platform.\n return {\n $app_name: this.appName,\n version: VERSION,\n run_surface: RUN_SURFACE,\n build: String(this.tags.build ?? 'dev'),\n os: process.platform,\n node_major: process.versions.node.split('.')[0],\n ...invocationProperties(),\n ...this.personProperties,\n };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...this.wizardFlagFeatureProperties(),\n ...properties,\n },\n });\n }\n\n groupIdentify(\n groupType: string,\n groupKey: string,\n properties: Record<string, unknown>,\n ) {\n this.client.groupIdentify({ groupType, groupKey, properties });\n }\n\n // Built from the resolved map, not the SDK snapshot: a CI-forced variant must own its events.\n private wizardFlagFeatureProperties(): Record<string, unknown> {\n if (this.activeFlags === null) return {};\n const props: Record<string, unknown> = {};\n const active: string[] = [];\n for (const [key, value] of Object.entries(this.activeFlags)) {\n if (!WIZARD_FLAGS.has(key)) continue;\n const resolved = flagResponseValue(value);\n props[`$feature/${key}`] = resolved;\n if (resolved !== false) active.push(key);\n }\n if (active.length > 0) props.$active_feature_flags = active.sort();\n return props;\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n // Only a getFlag read records an exposure; the bulk response records none.\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n const payloads: Record<string, unknown> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const evaluation = await this.client.evaluateFlags(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n for (const key of WIZARD_FLAG_KEYS) {\n const value = evaluation.getFlag(key);\n if (value === undefined) continue;\n out[key] = String(value);\n const payload = evaluation.getFlagPayload(key);\n if (payload !== undefined) payloads[key] = payload;\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n const merged = applyCiFlagOverrides(out, payloads);\n this.activeFlags = merged.flags;\n this.activeFlagPayloads = merged.payloads;\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n /** Flag payloads from the same snapshot; empty until the flags are fetched. */\n getWizardFlagPayloads(): Record<string, unknown> {\n return this.activeFlagPayloads;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"analytics-D54mLptm.js","names":["uuidv4"],"sources":["../src/utils/ci-flag-overrides.ts","../src/utils/analytics.ts"],"sourcesContent":["/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n payloads: Record<string, unknown> = {},\n): { flags: Record<string, string>; payloads: Record<string, unknown> } {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return { flags, payloads };\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return { flags, payloads };\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const mergedFlags = { ...flags };\n const mergedPayloads = { ...payloads };\n for (const [key, value] of Object.entries(overrides)) {\n // An object/array override is a flag payload: the flag reads 'true' and\n // the value rides the payload channel, matching a payload-carrying flag.\n if (typeof value === 'object' && value !== null) {\n mergedFlags[key] = 'true';\n mergedPayloads[key] = value;\n } else {\n mergedFlags[key] = String(value);\n }\n }\n logToFile('[flags] CI overrides applied', overrides);\n return { flags: mergedFlags, payloads: mergedPayloads };\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n WIZARD_FLAG_KEYS,\n} from '@lib/constants';\nimport {\n reportableDiscoveredFeatures,\n type WizardSession,\n} from '@lib/wizard-session';\nimport type { ApiUser } from '@lib/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } from '@env';\nimport { VERSION } from '@lib/version';\nimport { debug, logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * The invocation, reduced to flag-safe strings: the command word (first\n * positional, 'default' for the bare flow) and the sorted option NAMES.\n * Option values never leave the machine — they carry paths, emails, keys.\n */\nfunction invocationProperties(): { command: string; cli_flags: string } {\n const args = process.argv.slice(2);\n const command = args.find((a) => !a.startsWith('-')) ?? 'default';\n const flags = [\n ...new Set(\n args\n .filter((a) => a.startsWith('--'))\n .map((a) => a.slice(2).split('=')[0]),\n ),\n ].sort();\n return { command, cli_flags: flags.join(',') };\n}\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: WizardSession,\n): Record<string, unknown> {\n // reportableDiscoveredFeatures() owns the consent decision; this file\n // never needs to know what `scanConsent` means, only that the result\n // might be absent. An absent key is unambiguous, while an empty array\n // would read as \"we looked and found nothing\" instead of \"not reported\".\n const discoveredFeatures = reportableDiscoveredFeatures(session);\n\n return {\n integration: session.integration,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n ...(discoveredFeatures !== undefined\n ? { discovered_features: discoveredFeatures }\n : {}),\n scan_consent: session.scanConsent,\n additional_features: session.additionalFeatureQueue,\n run_phase: session.runPhase,\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nconst WIZARD_FLAGS: ReadonlySet<string> = new Set(WIZARD_FLAG_KEYS);\n\n// Widen back to the SDK's shape — a filter on `true` never matches `'true'`.\nfunction flagResponseValue(value: string): string | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return value;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private activeFlagPayloads: Record<string, unknown> = {};\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n // The SDK captures this one itself, bypassing capture(), so tags merge here.\n if (event.event === '$feature_flag_called') {\n event.properties = { ...this.tags, ...(event.properties ?? {}) };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n // The build this run came from. Already sent as a flag-evaluation person\n // property; tagging it makes every event attributable to a release, so a\n // regression can be bounded to the versions that carry it.\n this.tags.version = VERSION;\n\n // Cloud runs only: the task run that owns the sandbox. Without these the\n // wizard's events and the run that launched it are two unrelated streams,\n // since run_id above is minted per process and never leaves the wizard.\n // Left unset for local runs so the properties stay absent rather than null.\n if (TASK_RUN_ID) this.tags.task_run_id = TASK_RUN_ID;\n if (TASK_ID) this.tags.task_id = TASK_ID;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n this.activeFlagPayloads = {};\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n // Environment facts flag conditions can scope on — evaluation-time only,\n // never persisted onto the person. `version` gates an experiment to\n // releases that implement it (a condition on a property older builds\n // don't send silently never matches them); `run_surface`/`build` scope\n // by invocation surface; `command`/`cli_flags` by subcommand; `os`/\n // `node_major` by platform.\n return {\n $app_name: this.appName,\n version: VERSION,\n run_surface: RUN_SURFACE,\n build: String(this.tags.build ?? 'dev'),\n os: process.platform,\n node_major: process.versions.node.split('.')[0],\n ...invocationProperties(),\n ...this.personProperties,\n };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...this.wizardFlagFeatureProperties(),\n ...properties,\n },\n });\n }\n\n groupIdentify(\n groupType: string,\n groupKey: string,\n properties: Record<string, unknown>,\n ) {\n this.client.groupIdentify({ groupType, groupKey, properties });\n }\n\n // Built from the resolved map, not the SDK snapshot: a CI-forced variant must own its events.\n private wizardFlagFeatureProperties(): Record<string, unknown> {\n if (this.activeFlags === null) return {};\n const props: Record<string, unknown> = {};\n const active: string[] = [];\n for (const [key, value] of Object.entries(this.activeFlags)) {\n if (!WIZARD_FLAGS.has(key)) continue;\n const resolved = flagResponseValue(value);\n props[`$feature/${key}`] = resolved;\n if (resolved !== false) active.push(key);\n }\n if (active.length > 0) props.$active_feature_flags = active.sort();\n return props;\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n // Only a getFlag read records an exposure; the bulk response records none.\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n const payloads: Record<string, unknown> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const evaluation = await this.client.evaluateFlags(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n for (const key of WIZARD_FLAG_KEYS) {\n const value = evaluation.getFlag(key);\n if (value === undefined) continue;\n out[key] = String(value);\n const payload = evaluation.getFlagPayload(key);\n if (payload !== undefined) payloads[key] = payload;\n }\n } catch (error) {\n debug('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n const merged = applyCiFlagOverrides(out, payloads);\n this.activeFlags = merged.flags;\n this.activeFlagPayloads = merged.payloads;\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n /** Flag payloads from the same snapshot; empty until the flags are fetched. */\n getWizardFlagPayloads(): Record<string, unknown> {\n return this.activeFlagPayloads;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { pt as WIZARD_USER_AGENT } from "./debug-
|
|
3
|
-
import { n as analytics } from "./analytics-
|
|
2
|
+
import { pt as WIZARD_USER_AGENT } from "./debug-YQdeZulR.js";
|
|
3
|
+
import { n as analytics } from "./analytics-D54mLptm.js";
|
|
4
4
|
import axios from "axios";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
//#region src/lib/api.ts
|
|
@@ -9,6 +9,7 @@ var api_exports = /* @__PURE__ */ __exportAll({
|
|
|
9
9
|
ApiError: () => ApiError,
|
|
10
10
|
ApiProjectSchema: () => ApiProjectSchema,
|
|
11
11
|
ApiUserSchema: () => ApiUserSchema,
|
|
12
|
+
fetchGithubConnected: () => fetchGithubConnected,
|
|
12
13
|
fetchProjectData: () => fetchProjectData,
|
|
13
14
|
fetchSlackConnected: () => fetchSlackConnected,
|
|
14
15
|
fetchUserData: () => fetchUserData,
|
|
@@ -153,6 +154,24 @@ async function fetchSlackConnected(accessToken, projectId, baseUrl, signal) {
|
|
|
153
154
|
if (!parsed.success) return false;
|
|
154
155
|
return parsed.data.results.some((i) => i.kind === "slack");
|
|
155
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* Check whether the project already has a GitHub App integration connected.
|
|
159
|
+
* Requires the `integration:read` scope. Throws on failure — callers (the
|
|
160
|
+
* SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for
|
|
161
|
+
* capturing the error exactly once.
|
|
162
|
+
*/
|
|
163
|
+
async function fetchGithubConnected(accessToken, projectId, baseUrl, signal) {
|
|
164
|
+
const response = await axios.get(`${baseUrl}/api/projects/${projectId}/integrations/`, {
|
|
165
|
+
headers: {
|
|
166
|
+
Authorization: `Bearer ${accessToken}`,
|
|
167
|
+
"User-Agent": WIZARD_USER_AGENT
|
|
168
|
+
},
|
|
169
|
+
signal
|
|
170
|
+
});
|
|
171
|
+
const parsed = IntegrationsResponseSchema.safeParse(response.data);
|
|
172
|
+
if (!parsed.success) return false;
|
|
173
|
+
return parsed.data.results.some((i) => i.kind === "github");
|
|
174
|
+
}
|
|
156
175
|
function handleApiError(error, operation) {
|
|
157
176
|
if (axios.isAxiosError(error)) {
|
|
158
177
|
const axiosError = error;
|
|
@@ -168,6 +187,6 @@ function handleApiError(error, operation) {
|
|
|
168
187
|
return new ApiError(`Unexpected error while trying to ${operation}: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
169
188
|
}
|
|
170
189
|
//#endregion
|
|
171
|
-
export {
|
|
190
|
+
export { fetchSlackConnected as a, fetchProjectData as i, api_exports as n, fetchUserData as o, fetchGithubConnected as r, handleApiError as s, ApiError as t };
|
|
172
191
|
|
|
173
|
-
//# sourceMappingURL=api-
|
|
192
|
+
//# sourceMappingURL=api-BNBVOguz.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-j-OfJ8Dz.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"api-BNBVOguz.js","names":[],"sources":["../src/lib/api.ts"],"sourcesContent":["import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\n/**\n * User payload from `/api/users/@me/`. Schema typed for the fields the\n * wizard actually reads + passthrough on everything else so the full\n * upstream response rides through to the session for downstream features\n * (account-aware copy, plan-gated flows, org/team metadata, etc.).\n *\n * Top-level uses `.passthrough()` so unknown fields aren't stripped;\n * the few nested objects we care about (team, organization,\n * organizations[]) do the same so their additional fields survive too.\n *\n * Keep `distinct_id` required — analytics depends on it. Everything\n * else added here is nullish so partial responses don't fail parsing.\n */\nexport const ApiUserSchema = z\n .object({\n // Identifiers\n distinct_id: z.string(),\n uuid: z.string().nullish(),\n id: z.number().nullish(),\n\n // Profile\n email: z.string().nullish(),\n first_name: z.string().nullish(),\n last_name: z.string().nullish(),\n date_joined: z.string().nullish(),\n is_email_verified: z.boolean().nullish(),\n is_2fa_enabled: z.boolean().nullish(),\n is_staff: z.boolean().nullish(),\n\n // Preferences\n theme_mode: z.string().nullish(),\n toolbar_mode: z.string().nullish(),\n hide_mcp_hints: z.boolean().nullish(),\n\n // Optional / nullable on the backend — pre-onboarding signup paths\n // return null and older accounts may not have it set. Treat as a\n // hint, never a guarantee.\n role_at_organization: z.string().nullish(),\n\n // Current team + organization (objects from the API, kept typed on\n // the fields the wizard uses; passthrough preserves the rest).\n team: z\n .object({\n id: z.number(),\n uuid: z.string().nullish(),\n organization: z.string().uuid(),\n api_token: z.string().nullish(),\n project_id: z.number().nullish(),\n name: z.string().nullish(),\n timezone: z.string().nullish(),\n })\n .passthrough(),\n organization: z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n slug: z.string().nullish(),\n membership_level: z.number().nullish(),\n customer_id: z.string().nullish(),\n // Org-level AI consent gate. Signals drops all findings while\n // this is not true. Null on older orgs (pre-2026-05 default\n // flip) — treat null as \"unknown\", not \"off\".\n is_ai_data_processing_approved: z.boolean().nullish(),\n })\n .passthrough(),\n organizations: z.array(\n z\n .object({\n id: z.string().uuid(),\n name: z.string().nullish(),\n membership_level: z.number().nullish(),\n })\n .passthrough(),\n ),\n })\n .passthrough();\n\n/**\n * Single activity log entry the wizard cares about. The PostHog endpoint\n * returns much more — schema kept minimal so changes upstream don't break us.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling. Deliberately retained: this is a thin,\n * well-typed wrapper around a stable PostHog endpoint, and we're likely\n * to want it again for a future feature (e.g. \"what changed in your\n * project recently\"). Re-deriving the schema is more work than letting\n * it sit dormant.\n */\nexport const ActivityLogEntrySchema = z\n .object({\n scope: z.string().nullish(),\n activity: z.string().nullish(),\n created_at: z.string().nullish(),\n })\n .passthrough();\n\n/** @unused — see ActivityLogEntrySchema. */\nexport const ActivityLogResponseSchema = z.object({\n results: z.array(ActivityLogEntrySchema),\n});\n\n/** @unused — see ActivityLogEntrySchema. */\nexport type ActivityLogEntry = z.infer<typeof ActivityLogEntrySchema>;\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n // Product opt-ins (TeamSerializer-compat fields on /api/projects/:id).\n // Project-level truth for \"is this product enabled\" — a product can be\n // instrumented from another repo or the snippet, so these settings\n // override repo-local evidence. Null/absent = unknown. Only the\n // opt-ins a signals decision consumes: replay + exception autocapture\n // feed signal-source choices; surveys feeds the surveys-scout tuning.\n session_recording_opt_in: z.boolean().nullish(),\n autocapture_exceptions_opt_in: z.boolean().nullish(),\n surveys_opt_in: z.boolean().nullish(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\n/**\n * Best-effort fetch of recent activity log entries. Returns [] on any error\n * so callers can treat absence of results as \"haven't detected anything yet\"\n * rather than a hard failure.\n *\n * @unused — no current caller after the Phase 6 streaming-agent pivot\n * dropped activity_log polling from McpSuggestedPromptsScreen.\n * Deliberately retained for future features that want a soft signal of\n * recent project changes (e.g. dashboards, audit summaries). See the\n * ActivityLogEntrySchema doc comment for the keep-vs-delete rationale.\n */\nexport async function fetchRecentActivity(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n since: Date,\n): Promise<ActivityLogEntry[]> {\n try {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/activity_log/`,\n {\n params: { limit: 10 },\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n // Short timeout — best-effort probe, not a critical path.\n timeout: 4000,\n },\n );\n const parsed = ActivityLogResponseSchema.safeParse(response.data);\n if (!parsed.success) return [];\n const sinceMs = since.getTime();\n return parsed.data.results.filter((entry) => {\n if (!entry.created_at) return false;\n const t = Date.parse(entry.created_at);\n return Number.isFinite(t) && t >= sinceMs;\n });\n } catch {\n return [];\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\n/** Minimal shape of `/api/projects/:id/integrations/` — we only read `kind`. */\nconst IntegrationsResponseSchema = z.object({\n results: z.array(z.object({ kind: z.string().nullish() }).passthrough()),\n});\n\n/**\n * Check whether the project already has a Slack integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers\n * (including the SlackConnectScreen poll) decide how to degrade and\n * are responsible for capturing the error exactly once.\n */\nexport async function fetchSlackConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'slack');\n}\n\n/**\n * Check whether the project already has a GitHub App integration connected.\n * Requires the `integration:read` scope. Throws on failure — callers (the\n * SelfDrivingGitHubScreen poll) decide how to degrade and are responsible for\n * capturing the error exactly once.\n */\nexport async function fetchGithubConnected(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n signal?: AbortSignal,\n): Promise<boolean> {\n const response = await axios.get(\n `${baseUrl}/api/projects/${projectId}/integrations/`,\n {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n signal,\n },\n );\n const parsed = IntegrationsResponseSchema.safeParse(response.data);\n if (!parsed.success) return false;\n return parsed.data.results.some((i) => i.kind === 'github');\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n"],"mappings":"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"}
|
package/dist/bin.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as AgentSignals, c as emitWizardError, l as ErrorCodes, r as detectErrorCode } from "./errors-
|
|
3
|
-
import { Ct as isHeadless, L as Integration, St as headlessOption, U as POSTHOG_DOCS_URL, a as getLogFilePath, f as getUI, gt as VERSION, m as LoggingUI, mt as getSkillsBaseUrl, p as setUI, pt as WIZARD_USER_AGENT, r as debug, s as logToFile, wt as regionOption } from "./debug-
|
|
2
|
+
import { a as AgentSignals, c as emitWizardError, l as ErrorCodes, r as detectErrorCode } from "./errors-u8z27V-x.js";
|
|
3
|
+
import { Ct as isHeadless, L as Integration, St as headlessOption, U as POSTHOG_DOCS_URL, a as getLogFilePath, f as getUI, gt as VERSION, m as LoggingUI, mt as getSkillsBaseUrl, p as setUI, pt as WIZARD_USER_AGENT, r as debug, s as logToFile, wt as regionOption } from "./debug-YQdeZulR.js";
|
|
4
4
|
import { a as getLocalDev, i as checkLocalServices, o as initLocalDev, r as POSTHOG_LOCAL_URL, s as localMcpSkillsNotice } from "./local-dev-DPZiIPCK.js";
|
|
5
|
-
import "./wizard-session-
|
|
6
|
-
import { n as analytics } from "./analytics-
|
|
7
|
-
import { r as setEntryCommand } from "./telemetry-
|
|
8
|
-
import { a as safeReadFile, o as walkProjectFiles } from "./bounded-fs-
|
|
9
|
-
import { n as isUsingTypeScript } from "./setup-utils-
|
|
10
|
-
import {
|
|
11
|
-
import { i as wizardAbort, r as runCleanups } from "./wizard-abort-
|
|
12
|
-
import { n as isNonInteractiveEnvironment } from "./environment-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import { m as writeJsonAtomic } from "./queue-tools-
|
|
16
|
-
import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-
|
|
17
|
-
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-
|
|
18
|
-
import { C as detectIntegrationProjects, D as gatherFrameworkContext, E as resolveProjectDir, O as detectFramework, S as detectWarehouseSources, a as LINE_CHART_BLOCK, b as detectWarehousePrerequisites, d as isClearBlock, g as detectPostHogIntegration, h as Icons, i as FUNNEL_BLOCK, m as Colors, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as wordWrap, v as HEALTH_CHECK_STEP, w as scopeInstallDirToProject, x as getDetectedWarehouseSources, y as WAREHOUSE_ABORT_CASES } from "./posthog-integration-
|
|
19
|
-
import { n as readApiKeyFromEnv } from "./env-api-key-
|
|
5
|
+
import "./wizard-session-CwQPZN4y.js";
|
|
6
|
+
import { n as analytics } from "./analytics-D54mLptm.js";
|
|
7
|
+
import { r as setEntryCommand } from "./telemetry-DedDTtSa.js";
|
|
8
|
+
import { a as safeReadFile, o as walkProjectFiles } from "./bounded-fs-DHIaH3Sc.js";
|
|
9
|
+
import { n as isUsingTypeScript } from "./setup-utils-BRrCeajl.js";
|
|
10
|
+
import { s as handleApiError } from "./api-BNBVOguz.js";
|
|
11
|
+
import { i as wizardAbort, r as runCleanups } from "./wizard-abort-D54j2gmb.js";
|
|
12
|
+
import { n as isNonInteractiveEnvironment } from "./environment-6ZuAWRpQ.js";
|
|
13
|
+
import { A as fetchSkillMenu, E as WIZARD_TOOL_NAMES, u as recoverOrphanedSettingsBackups } from "./agent-interface-DFm4jB4d.js";
|
|
14
|
+
import { n as runAgent, s as authenticate } from "./agent-runner-Cp6iLqDk.js";
|
|
15
|
+
import { m as writeJsonAtomic } from "./queue-tools-DGaHf3n-.js";
|
|
16
|
+
import { S as SETUP_REPORT_FILE, _ as AUDIT_CHECKS_KEY, g as AUDIT_CHECKS_FILE, v as AUDIT_REPORT_FILE } from "./yara-hooks-CL2LVEgO.js";
|
|
17
|
+
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-D1By1SgH.js";
|
|
18
|
+
import { C as detectIntegrationProjects, D as gatherFrameworkContext, E as resolveProjectDir, O as detectFramework, S as detectWarehouseSources, a as LINE_CHART_BLOCK, b as detectWarehousePrerequisites, d as isClearBlock, g as detectPostHogIntegration, h as Icons, i as FUNNEL_BLOCK, m as Colors, n as integrationRunStep, o as PRODUCT_SUITE_BLOCK, r as posthogIntegrationConfig, s as StatusPeekTrigger, u as wordWrap, v as HEALTH_CHECK_STEP, w as scopeInstallDirToProject, x as getDetectedWarehouseSources, y as WAREHOUSE_ABORT_CASES } from "./posthog-integration-B8f4xRBd.js";
|
|
19
|
+
import { n as readApiKeyFromEnv } from "./env-api-key-9yogO8OI.js";
|
|
20
20
|
import { satisfies } from "semver";
|
|
21
21
|
import yargs from "yargs";
|
|
22
22
|
import { hideBin } from "yargs/helpers";
|
|
@@ -242,7 +242,7 @@ function runProvision(argv) {
|
|
|
242
242
|
}
|
|
243
243
|
async function provision({ email, region, name, baseUrl, jsonMode }) {
|
|
244
244
|
try {
|
|
245
|
-
const { provisionNewAccount } = await import("./provisioning-
|
|
245
|
+
const { provisionNewAccount } = await import("./provisioning-f7lA29tW.js").then((n) => n.r);
|
|
246
246
|
if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
|
|
247
247
|
emitResult(await provisionNewAccount(email, name, region, { baseUrl }), jsonMode);
|
|
248
248
|
process.exit(0);
|
|
@@ -309,22 +309,22 @@ const basicIntegrationCommand = {
|
|
|
309
309
|
setEntryCommand("integrate");
|
|
310
310
|
(async () => {
|
|
311
311
|
if (isHeadless(argv)) {
|
|
312
|
-
const { runHeadlessInstall } = await import("./ci-install-
|
|
312
|
+
const { runHeadlessInstall } = await import("./ci-install-Can8LRdJ.js");
|
|
313
313
|
return runHeadlessInstall(argv);
|
|
314
314
|
}
|
|
315
315
|
if (argv.ci) {
|
|
316
|
-
const { runCIInstall } = await import("./ci-install-
|
|
316
|
+
const { runCIInstall } = await import("./ci-install-Can8LRdJ.js");
|
|
317
317
|
return runCIInstall(argv);
|
|
318
318
|
}
|
|
319
319
|
if (isNonInteractiveEnvironment()) {
|
|
320
|
-
const { failNonInteractive } = await import("./non-interactive-
|
|
320
|
+
const { failNonInteractive } = await import("./non-interactive-1EJRlN6u.js");
|
|
321
321
|
return failNonInteractive();
|
|
322
322
|
}
|
|
323
323
|
if (argv.playground) {
|
|
324
|
-
const { runPlayground } = await import("./playground-
|
|
324
|
+
const { runPlayground } = await import("./playground-Y1nSGXpn.js");
|
|
325
325
|
return runPlayground();
|
|
326
326
|
}
|
|
327
|
-
const { runInteractive } = await import("./interactive-
|
|
327
|
+
const { runInteractive } = await import("./interactive-CRR9zPl4.js");
|
|
328
328
|
runInteractive(argv);
|
|
329
329
|
})();
|
|
330
330
|
}
|
|
@@ -2865,6 +2865,10 @@ function detectPostHogPresent(installDir) {
|
|
|
2865
2865
|
* reason strings are part of the skill contract — the context-mill
|
|
2866
2866
|
* `self-driving-setup` skill emits these exact strings.
|
|
2867
2867
|
*/
|
|
2868
|
+
/** Headline shown when the run ends because GitHub was not connected. */
|
|
2869
|
+
const GITHUB_REQUIRED_MESSAGE = "GitHub connection required";
|
|
2870
|
+
/** Body for {@link GITHUB_REQUIRED_MESSAGE}. Shared by the pre-run gate and the abort case. */
|
|
2871
|
+
const GITHUB_REQUIRED_BODY = "Self-driving needs GitHub access to research issues in your code and open fixes, so setup cannot finish without it. Nothing was changed. When you are ready to install the PostHog GitHub App, run the wizard again.";
|
|
2868
2872
|
const SELF_DRIVING_ABORT_CASES = [
|
|
2869
2873
|
{
|
|
2870
2874
|
match: /^self-driving is not available for this project$/i,
|
|
@@ -2873,8 +2877,8 @@ const SELF_DRIVING_ABORT_CASES = [
|
|
|
2873
2877
|
},
|
|
2874
2878
|
{
|
|
2875
2879
|
match: /^github connection declined$/i,
|
|
2876
|
-
message:
|
|
2877
|
-
body:
|
|
2880
|
+
message: GITHUB_REQUIRED_MESSAGE,
|
|
2881
|
+
body: GITHUB_REQUIRED_BODY
|
|
2878
2882
|
},
|
|
2879
2883
|
{
|
|
2880
2884
|
match: /^requires-interactive-mode$/i,
|
|
@@ -3075,10 +3079,18 @@ const SELF_DRIVING_PROGRAM = [
|
|
|
3075
3079
|
show: (session) => session.integrate === true,
|
|
3076
3080
|
isComplete: (session) => session.selfDrivingHandoffConfirmed
|
|
3077
3081
|
},
|
|
3082
|
+
{
|
|
3083
|
+
id: "self-driving-github",
|
|
3084
|
+
label: "GitHub",
|
|
3085
|
+
screenId: "self-driving-github",
|
|
3086
|
+
isComplete: (session) => session.githubConnected === true || session.githubDeclined,
|
|
3087
|
+
gate: (session) => session.githubConnected === true || session.githubDeclined
|
|
3088
|
+
},
|
|
3078
3089
|
{
|
|
3079
3090
|
id: "run",
|
|
3080
3091
|
label: "Self-driving",
|
|
3081
3092
|
screenId: "run",
|
|
3093
|
+
show: (session) => !session.githubDeclined,
|
|
3082
3094
|
isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
|
|
3083
3095
|
},
|
|
3084
3096
|
{
|
|
@@ -3131,7 +3143,7 @@ function buildSelfDrivingPrompt(ctx, detectedSources = []) {
|
|
|
3131
3143
|
const inboxUrl = `${projectBase}/inbox`;
|
|
3132
3144
|
const optIn = (value) => value === true ? "ON" : value === false ? "OFF" : "unknown";
|
|
3133
3145
|
const optIns = ctx.teamProductOptIns;
|
|
3134
|
-
return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources,
|
|
3146
|
+
return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, tune the scout troop, design custom scouts for what this product uniquely needs, put Replay Vision scanners on its key flows, and hand the user a configured inbox.
|
|
3135
3147
|
|
|
3136
3148
|
Project URLs:
|
|
3137
3149
|
- Integrations settings: ${integrationsSettingsUrl}
|
|
@@ -3160,8 +3172,7 @@ call so the user can follow your progress in the TUI. Use exactly these
|
|
|
3160
3172
|
tasks, in this order:
|
|
3161
3173
|
1. Check Self-driving access
|
|
3162
3174
|
2. Read project and current Self-driving state
|
|
3163
|
-
3.
|
|
3164
|
-
3b. Enable products (replay, error tracking, support)
|
|
3175
|
+
3. Enable products (replay, error tracking, support)
|
|
3165
3176
|
4. Enable signal sources
|
|
3166
3177
|
5. Offer issue-tracker integrations
|
|
3167
3178
|
6. Configure the scout troop
|
|
@@ -3169,8 +3180,11 @@ tasks, in this order:
|
|
|
3169
3180
|
6c. Set up Replay Vision scanners
|
|
3170
3181
|
7. Write report and hand off
|
|
3171
3182
|
Drive the list with TaskUpdate — mark a task in_progress when you start
|
|
3172
|
-
it and completed when done. If a step turns out to be a no-op (e.g.
|
|
3173
|
-
|
|
3183
|
+
it and completed when done. If a step turns out to be a no-op (e.g. a
|
|
3184
|
+
product is already enabled), still mark its task completed.
|
|
3185
|
+
|
|
3186
|
+
The PostHog GitHub App is already connected — the wizard verified it
|
|
3187
|
+
before this run started, so never ask the user to connect or install it.
|
|
3174
3188
|
|
|
3175
3189
|
Wizard mechanics:
|
|
3176
3190
|
- Ask the user things ONLY with the wizard_ask MCP tool, and batch
|
|
@@ -3206,20 +3220,12 @@ STEP 2 — Read project and current Signals state. (skill: "Read context")
|
|
|
3206
3220
|
what neither covers. List the currently enabled signal sources so every
|
|
3207
3221
|
later write is idempotent.
|
|
3208
3222
|
|
|
3209
|
-
STEP 3 —
|
|
3210
|
-
Signals cannot research or fix issues without code access. Check for
|
|
3211
|
-
an existing GitHub integration first; if absent, send the user
|
|
3212
|
-
through the GitHub App connection via wizard_ask exactly as the skill
|
|
3213
|
-
describes (it builds the one-click authorize link), and verify the
|
|
3214
|
-
connection after they confirm. If the user cannot connect now, emit
|
|
3215
|
-
${AgentSignals.ABORT} github connection declined
|
|
3216
|
-
and halt — never finish setup without GitHub.
|
|
3217
|
-
|
|
3218
|
-
STEP 3b — Enable products. (skill: "Enable products")
|
|
3223
|
+
STEP 3 — Enable products. (skill: "Enable products")
|
|
3219
3224
|
Turn ON the PostHog products Signals reads from — Session Replay,
|
|
3220
|
-
Error Tracking, and Support — so the sources you enable next
|
|
3221
|
-
to read. These are
|
|
3222
|
-
(owned by the server,
|
|
3225
|
+
Error Tracking, and Support — so the sources you enable next, and the
|
|
3226
|
+
Replay Vision scanners in STEP 6c, have data to read. These are
|
|
3227
|
+
server-side enables with conservative defaults (owned by the server,
|
|
3228
|
+
not you). The project-state block above covers
|
|
3223
3229
|
only Session Replay and Error Tracking, so you can skip those if they
|
|
3224
3230
|
are already ON; it does not show Support, but every enable is idempotent
|
|
3225
3231
|
so enabling any of them again is safe regardless. For a web app, also
|
|
@@ -3288,7 +3294,7 @@ STEP 6b — Design custom scouts for this product. (skill: "Custom scouts")
|
|
|
3288
3294
|
STEP 6c — Set up Replay Vision scanners. (skill: "Replay Vision scanners")
|
|
3289
3295
|
Create the scanner skeletons the skill defines, filling the per-product
|
|
3290
3296
|
blanks it leaves you from this repo's code. Scanners need Session Replay
|
|
3291
|
-
on (STEP
|
|
3297
|
+
on (STEP 3). Every failure here — no recordings yet, a backend-only
|
|
3292
3298
|
project, the scanner API missing — is a follow-up, never an abort; mark
|
|
3293
3299
|
the task completed regardless.
|
|
3294
3300
|
|
|
@@ -4330,7 +4336,7 @@ const mcpAddCommand = {
|
|
|
4330
4336
|
function runMcpAdd(argv) {
|
|
4331
4337
|
const features = parseFeatures(argv.features);
|
|
4332
4338
|
(async () => {
|
|
4333
|
-
const { readApiKeyFromEnv } = await import("./env-api-key-
|
|
4339
|
+
const { readApiKeyFromEnv } = await import("./env-api-key-9yogO8OI.js").then((n) => n.t);
|
|
4334
4340
|
const apiKey = argv.apiKey || readApiKeyFromEnv();
|
|
4335
4341
|
const debug = argv.debug;
|
|
4336
4342
|
const localMcp = argv.local;
|
|
@@ -4344,8 +4350,8 @@ function runMcpAdd(argv) {
|
|
|
4344
4350
|
return;
|
|
4345
4351
|
}
|
|
4346
4352
|
try {
|
|
4347
|
-
const { startTUI } = await import("./start-tui-
|
|
4348
|
-
const { buildSession } = await import("./wizard-session-
|
|
4353
|
+
const { startTUI } = await import("./start-tui-r4Spgptv.js");
|
|
4354
|
+
const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
4349
4355
|
const tui = startTUI(VERSION, Program.McpAdd);
|
|
4350
4356
|
tui.store.session = buildSession({
|
|
4351
4357
|
debug,
|
|
@@ -4362,7 +4368,7 @@ function runMcpAdd(argv) {
|
|
|
4362
4368
|
}
|
|
4363
4369
|
async function runHeadlessAdd(args) {
|
|
4364
4370
|
setUI(new LoggingUI());
|
|
4365
|
-
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-
|
|
4371
|
+
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-B6-ZL--P.js").then((n) => n.r);
|
|
4366
4372
|
const { installed, failed } = await addMCPServerToClientsStep(args);
|
|
4367
4373
|
if (failed.length > 0 || installed.length === 0) process.exitCode = 1;
|
|
4368
4374
|
}
|
|
@@ -4394,8 +4400,8 @@ function runMcpRemove(argv) {
|
|
|
4394
4400
|
return;
|
|
4395
4401
|
}
|
|
4396
4402
|
try {
|
|
4397
|
-
const { startTUI } = await import("./start-tui-
|
|
4398
|
-
const { buildSession } = await import("./wizard-session-
|
|
4403
|
+
const { startTUI } = await import("./start-tui-r4Spgptv.js");
|
|
4404
|
+
const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
4399
4405
|
const tui = startTUI(VERSION, Program.McpRemove);
|
|
4400
4406
|
tui.store.session = buildSession({
|
|
4401
4407
|
debug,
|
|
@@ -4411,7 +4417,7 @@ function runMcpRemove(argv) {
|
|
|
4411
4417
|
/** No exit code on an empty result: nothing to remove is the requested end state. */
|
|
4412
4418
|
async function runHeadlessRemove(local) {
|
|
4413
4419
|
setUI(new LoggingUI());
|
|
4414
|
-
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-
|
|
4420
|
+
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-B6-ZL--P.js").then((n) => n.r);
|
|
4415
4421
|
await removeMCPServerFromClientsStep({ local });
|
|
4416
4422
|
}
|
|
4417
4423
|
//#endregion
|
|
@@ -4431,8 +4437,8 @@ function runMcpTutorial(argv) {
|
|
|
4431
4437
|
const debug = argv.debug;
|
|
4432
4438
|
const localMcp = argv.local;
|
|
4433
4439
|
try {
|
|
4434
|
-
const { startTUI } = await import("./start-tui-
|
|
4435
|
-
const { buildSession } = await import("./wizard-session-
|
|
4440
|
+
const { startTUI } = await import("./start-tui-r4Spgptv.js");
|
|
4441
|
+
const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
4436
4442
|
const tui = startTUI(VERSION, Program.McpTutorial);
|
|
4437
4443
|
tui.store.session = buildSession({
|
|
4438
4444
|
debug,
|
|
@@ -4517,17 +4523,17 @@ function runWizard(config, options) {
|
|
|
4517
4523
|
(async () => {
|
|
4518
4524
|
try {
|
|
4519
4525
|
const installDir = options.installDir || process.cwd();
|
|
4520
|
-
const { startTUI } = await import("./start-tui-
|
|
4521
|
-
const { buildSession, RunPhase } = await import("./wizard-session-
|
|
4522
|
-
const { TaskStreamPush } = await import("./task-stream-
|
|
4523
|
-
const { PostHogDestination } = await import("./posthog-
|
|
4526
|
+
const { startTUI } = await import("./start-tui-r4Spgptv.js");
|
|
4527
|
+
const { buildSession, RunPhase } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
4528
|
+
const { TaskStreamPush } = await import("./task-stream-CdrBraqP.js");
|
|
4529
|
+
const { PostHogDestination } = await import("./posthog-D9VwcWvJ.js");
|
|
4524
4530
|
const local = getLocalDev();
|
|
4525
4531
|
const localServicesError = await checkLocalServices({
|
|
4526
4532
|
...local,
|
|
4527
4533
|
localPosthog: local.localPosthog && !options.baseUrl
|
|
4528
4534
|
});
|
|
4529
4535
|
if (localServicesError) {
|
|
4530
|
-
const { wizardAbort } = await import("./wizard-abort-
|
|
4536
|
+
const { wizardAbort } = await import("./wizard-abort-Q1NiYELE.js");
|
|
4531
4537
|
await wizardAbort({ message: localServicesError });
|
|
4532
4538
|
return;
|
|
4533
4539
|
}
|
|
@@ -4598,7 +4604,7 @@ function runWizard(config, options) {
|
|
|
4598
4604
|
if (shown(step)) await advanceStep(step, activeTui.store, config);
|
|
4599
4605
|
}
|
|
4600
4606
|
else if (skipAgent) {
|
|
4601
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
4607
|
+
const { getOrAskForProjectData } = await import("./setup-utils-BRrCeajl.js").then((n) => n.r);
|
|
4602
4608
|
const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
|
|
4603
4609
|
signup: session.signup,
|
|
4604
4610
|
ci: session.ci,
|
|
@@ -4711,11 +4717,11 @@ function runNonInteractive(config, options, mode) {
|
|
|
4711
4717
|
analytics.setTag("build", mode);
|
|
4712
4718
|
(async () => {
|
|
4713
4719
|
const path = await import("path");
|
|
4714
|
-
const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-
|
|
4715
|
-
const { readEnvironment } = await import("./environment-
|
|
4716
|
-
const { readApiKeyFromEnv } = await import("./env-api-key-
|
|
4717
|
-
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-
|
|
4718
|
-
const { wizardAbort, WizardError } = await import("./wizard-abort-
|
|
4720
|
+
const { buildSession, RunPhase, OutroKind } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
4721
|
+
const { readEnvironment } = await import("./environment-6ZuAWRpQ.js").then((n) => n.t);
|
|
4722
|
+
const { readApiKeyFromEnv } = await import("./env-api-key-9yogO8OI.js").then((n) => n.t);
|
|
4723
|
+
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-C4RPcEIX.js");
|
|
4724
|
+
const { wizardAbort, WizardError } = await import("./wizard-abort-Q1NiYELE.js");
|
|
4719
4725
|
configureLogFileFromEnvironment();
|
|
4720
4726
|
const env = readEnvironment();
|
|
4721
4727
|
const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
|
|
@@ -4762,9 +4768,9 @@ function runNonInteractive(config, options, mode) {
|
|
|
4762
4768
|
let store = null;
|
|
4763
4769
|
let taskStream = null;
|
|
4764
4770
|
if (mode === "headless") {
|
|
4765
|
-
const { WizardStore } = await import("./store-
|
|
4766
|
-
const { HeadlessUI } = await import("./headless-ui-
|
|
4767
|
-
const { TaskStreamPush, PostHogDestination } = await import("./task-stream-
|
|
4771
|
+
const { WizardStore } = await import("./store-DGVXu7xt.js").then((n) => n.n);
|
|
4772
|
+
const { HeadlessUI } = await import("./headless-ui-BxSVgNoT.js");
|
|
4773
|
+
const { TaskStreamPush, PostHogDestination } = await import("./task-stream-CdrBraqP.js");
|
|
4768
4774
|
store = new WizardStore(config.id);
|
|
4769
4775
|
store.session = session;
|
|
4770
4776
|
setUI(new HeadlessUI(store));
|
|
@@ -4847,7 +4853,7 @@ function runNonInteractive(config, options, mode) {
|
|
|
4847
4853
|
});
|
|
4848
4854
|
}
|
|
4849
4855
|
}
|
|
4850
|
-
const { runAgent } = await import("./agent-runner-
|
|
4856
|
+
const { runAgent } = await import("./agent-runner-Cp6iLqDk.js").then((n) => n.t);
|
|
4851
4857
|
await runAgent(config, session);
|
|
4852
4858
|
await settleStream(RunPhase.Completed);
|
|
4853
4859
|
} catch (error) {
|
|
@@ -6094,7 +6100,7 @@ async function runDoctorCI(options) {
|
|
|
6094
6100
|
getUI().intro("Welcome to the PostHog setup wizard");
|
|
6095
6101
|
getUI().log.info("Running posthog-doctor in CI mode");
|
|
6096
6102
|
try {
|
|
6097
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
6103
|
+
const { getOrAskForProjectData } = await import("./setup-utils-BRrCeajl.js").then((n) => n.r);
|
|
6098
6104
|
const { host, accessToken, projectId } = await getOrAskForProjectData({
|
|
6099
6105
|
signup: false,
|
|
6100
6106
|
ci: true,
|
|
@@ -6112,7 +6118,7 @@ async function runDoctorCI(options) {
|
|
|
6112
6118
|
for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
|
|
6113
6119
|
process.exit(1);
|
|
6114
6120
|
} catch (error) {
|
|
6115
|
-
const { ApiError } = await import("./api-
|
|
6121
|
+
const { ApiError } = await import("./api-BNBVOguz.js").then((n) => n.n);
|
|
6116
6122
|
const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
|
|
6117
6123
|
getUI().log.error(`Doctor failed: ${message}`);
|
|
6118
6124
|
emitWizardError({
|
|
@@ -6198,8 +6204,8 @@ function runSlackConnect(argv) {
|
|
|
6198
6204
|
(async () => {
|
|
6199
6205
|
const debug = argv.debug;
|
|
6200
6206
|
try {
|
|
6201
|
-
const { startTUI } = await import("./start-tui-
|
|
6202
|
-
const { buildSession } = await import("./wizard-session-
|
|
6207
|
+
const { startTUI } = await import("./start-tui-r4Spgptv.js");
|
|
6208
|
+
const { buildSession } = await import("./wizard-session-Dwc1Rh_7.js");
|
|
6203
6209
|
const tui = startTUI(VERSION, Program.SlackConnect);
|
|
6204
6210
|
tui.store.session = buildSession({
|
|
6205
6211
|
debug,
|
|
@@ -6543,6 +6549,6 @@ function resolveInstallDir() {
|
|
|
6543
6549
|
}
|
|
6544
6550
|
Wizard.use(basicIntegrationCommand).use(mcpCommand).use(mcpAnalyticsCommand).use(replayVisionCommand).use(aiObservabilityCommand).use(metricsCommand).use(cliCommand).use(auditCommand).use(doctorCommand).use(migrateCommand).use(revenueCommand).use(warehouseCommand).use(selfDrivingCommand).use(slackCommand).use(uploadSourcemapsCommand).use(skillCommand).init();
|
|
6545
6551
|
//#endregion
|
|
6546
|
-
export {
|
|
6552
|
+
export { getContentBlocks$3 as A, GO_SDK_MODULE as C, SOURCE_MAPS_CONTEXT_KEYS as D, RUST_SDK_CRATE as E, STRIPE_SDKS as M, getKindMeta as O, DISPLAY_NAME as S, MANUAL_SDK_VARIANTS as T, detectSelfDrivingIntegrationProjects as _, useStdoutDimensions as a, SELF_DRIVING_INTEGRATE_PATH_KEY as b, runWizardHeadless as c, PROGRAM_REGISTRY as d, Program as f, PRICING_SHORT as g, PRICING_LONG as h, useKeyboardHintsContext as i, POSTHOG_SDKS as j, fetchHealthIssues as k, runWizardCI as l, NO_DEFAULT_LIMIT as m, useKeyBindings as n, ConfirmButton as o, getProgramConfig as p, KeyboardHintsProvider as r, PromptLabel as s, PickerMenu as t, runWizard as u, GITHUB_REQUIRED_BODY as v, MANUAL_SDK_INSTALL as w, AUTOMATABLE_VARIANTS as x, GITHUB_REQUIRED_MESSAGE as y };
|
|
6547
6553
|
|
|
6548
6554
|
//# sourceMappingURL=bin.js.map
|