@posthog/wizard 2.38.0 → 2.38.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-mcp-server-to-clients-CeoyDLC-.js → add-mcp-server-to-clients-CHSzsAG8.js} +6 -6
- package/dist/{add-mcp-server-to-clients-CeoyDLC-.js.map → add-mcp-server-to-clients-CHSzsAG8.js.map} +1 -1
- package/dist/{agent-interface-BAodys0H.js → agent-interface-DExARWay.js} +13 -11
- package/dist/{agent-interface-BAodys0H.js.map → agent-interface-DExARWay.js.map} +1 -1
- package/dist/{agent-runner-BMuJP8fb.js → agent-runner-CMfTmM3B.js} +20 -18
- package/dist/{agent-runner-BMuJP8fb.js.map → agent-runner-CMfTmM3B.js.map} +1 -1
- package/dist/{analytics-CvIK_07d.js → analytics-Ciob-x8a.js} +3 -3
- package/dist/{analytics-CvIK_07d.js.map → analytics-Ciob-x8a.js.map} +1 -1
- package/dist/analytics-DbfiRvPS.js +2 -0
- package/dist/{api-CyA47qug.js → api-T_WHs3qZ.js} +3 -3
- package/dist/{api-CyA47qug.js.map → api-T_WHs3qZ.js.map} +1 -1
- package/dist/bin.js +176 -82
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-C_o0Q7Fg.js → ci-install-DJN5aT7W.js} +4 -4
- package/dist/{ci-install-C_o0Q7Fg.js.map → ci-install-DJN5aT7W.js.map} +1 -1
- package/dist/{debug-BhGq9rn9.js → debug-Cne-cLxd.js} +1 -1
- package/dist/{debug-CgdI7Rd-.js → debug-D1lORUFs.js} +41 -19
- package/dist/debug-D1lORUFs.js.map +1 -0
- package/dist/{defaults-b2Bo9Wid.js → defaults-a0e6IRjP.js} +1 -1
- package/dist/{defaults-b2Bo9Wid.js.map → defaults-a0e6IRjP.js.map} +1 -1
- package/dist/{env-api-key-Bezg_uXQ.js → env-api-key-DEl3LJBv.js} +1 -1
- package/dist/{env-api-key-Bezg_uXQ.js.map → env-api-key-DEl3LJBv.js.map} +1 -1
- package/dist/{environment-v22_Genm.js → environment-BEsDCA2q.js} +3 -3
- package/dist/{environment-v22_Genm.js.map → environment-BEsDCA2q.js.map} +1 -1
- package/dist/{file-utils-Gvc2Ysa_.js → file-utils-Cn3dzlo-.js} +2 -2
- package/dist/{file-utils-Gvc2Ysa_.js.map → file-utils-Cn3dzlo-.js.map} +1 -1
- package/dist/{headless-ui-BtBcuxOj.js → headless-ui-DGunpK-s.js} +2 -2
- package/dist/{headless-ui-BtBcuxOj.js.map → headless-ui-DGunpK-s.js.map} +1 -1
- package/dist/{host-resolution-CUjt6efz.js → host-resolution-BnUJZKId.js} +3 -3
- package/dist/{host-resolution-CUjt6efz.js.map → host-resolution-BnUJZKId.js.map} +1 -1
- package/dist/{interactive-CRdgBMxk.js → interactive-BB2IDSWP.js} +2 -2
- package/dist/{interactive-CRdgBMxk.js.map → interactive-BB2IDSWP.js.map} +1 -1
- package/dist/{mcp-XWzcKTeK.js → mcp-CgA5vyiS.js} +2 -2
- package/dist/{mcp-XWzcKTeK.js.map → mcp-CgA5vyiS.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-DeC85Icy.js → mcp-prompt-streaming-CGAkq9qR.js} +4 -4
- package/dist/{mcp-prompt-streaming-DeC85Icy.js.map → mcp-prompt-streaming-CGAkq9qR.js.map} +1 -1
- package/dist/{non-interactive-B-Ku4EOx.js → non-interactive-Dko5F3vh.js} +2 -2
- package/dist/{non-interactive-B-Ku4EOx.js.map → non-interactive-Dko5F3vh.js.map} +1 -1
- package/dist/{package-json-DCuoye-H.js → package-json-CDs1ZVKu.js} +1 -1
- package/dist/{package-json-DCuoye-H.js.map → package-json-CDs1ZVKu.js.map} +1 -1
- package/dist/{package-manager-Dj6dTKlK.js → package-manager-WKKQADHM.js} +2 -2
- package/dist/{package-manager-Dj6dTKlK.js.map → package-manager-WKKQADHM.js.map} +1 -1
- package/dist/{playground-CmKFAlCE.js → playground-UtT6zbjE.js} +6 -6
- package/dist/{playground-CmKFAlCE.js.map → playground-UtT6zbjE.js.map} +1 -1
- package/dist/{posthog-Dnl6wsYc.js → posthog-BESrI6-T.js} +1 -1
- package/dist/{posthog-Dnl6wsYc.js.map → posthog-BESrI6-T.js.map} +1 -1
- package/dist/{posthog-integration-CcJWXPDa.js → posthog-integration-CWXSng0W.js} +41 -22
- package/dist/posthog-integration-CWXSng0W.js.map +1 -0
- package/dist/{provisioning-BIuAPRcH.js → provisioning-CgomM26T.js} +4 -4
- package/dist/{provisioning-BIuAPRcH.js.map → provisioning-CgomM26T.js.map} +1 -1
- package/dist/{registry-ByrVTIE9.js → registry-BQIX-25O.js} +12 -9
- package/dist/{registry-ByrVTIE9.js.map → registry-BQIX-25O.js.map} +1 -1
- package/dist/{security-uSP4HiC0.js → security-pJOYY5LO.js} +3 -3
- package/dist/{security-uSP4HiC0.js.map → security-pJOYY5LO.js.map} +1 -1
- package/dist/{setup-utils-DhmigSLO.js → setup-utils-DLGNk8T6.js} +9 -9
- package/dist/{setup-utils-DhmigSLO.js.map → setup-utils-DLGNk8T6.js.map} +1 -1
- package/dist/{start-tui-DKHnPg5a.js → start-tui-BjCKghQq.js} +133 -73
- package/dist/start-tui-BjCKghQq.js.map +1 -0
- package/dist/{steps-BBzIrOMY.js → steps-XjV9CiqH.js} +7 -7
- package/dist/{steps-BBzIrOMY.js.map → steps-XjV9CiqH.js.map} +1 -1
- package/dist/{store-BV1a-8Wp.js → store-CDIxU0rr.js} +8 -6
- package/dist/{store-BV1a-8Wp.js.map → store-CDIxU0rr.js.map} +1 -1
- package/dist/{subagent-fP1QmYBX.js → subagent-S5Yh16IJ.js} +2 -2
- package/dist/{subagent-fP1QmYBX.js.map → subagent-S5Yh16IJ.js.map} +1 -1
- package/dist/{task-stream-C6s7qUCE.js → task-stream-rC4IEUHC.js} +3 -3
- package/dist/{task-stream-C6s7qUCE.js.map → task-stream-rC4IEUHC.js.map} +1 -1
- package/dist/{tasks-YFkqfEio.js → tasks-wbjOdifO.js} +2 -2
- package/dist/{tasks-YFkqfEio.js.map → tasks-wbjOdifO.js.map} +1 -1
- package/dist/{telemetry-wOdXbZLp.js → telemetry-BfnR7gtf.js} +3 -3
- package/dist/{telemetry-wOdXbZLp.js.map → telemetry-BfnR7gtf.js.map} +1 -1
- package/dist/{terminal-IAHPQoAT.js → terminal-BvRwVeQp.js} +13 -13
- package/dist/{terminal-IAHPQoAT.js.map → terminal-BvRwVeQp.js.map} +1 -1
- package/dist/{tools-DdzmiBKF.js → tools-CbtYlZV4.js} +4 -4
- package/dist/{tools-DdzmiBKF.js.map → tools-CbtYlZV4.js.map} +1 -1
- package/dist/{urls-BR7jQgQp.js → urls-CilgPbS-.js} +2 -2
- package/dist/{urls-BR7jQgQp.js.map → urls-CilgPbS-.js.map} +1 -1
- package/dist/{wizard-abort-bulz-_og.js → wizard-abort-Cp5Y7f8C.js} +4 -4
- package/dist/{wizard-abort-bulz-_og.js.map → wizard-abort-Cp5Y7f8C.js.map} +1 -1
- package/dist/{wizard-abort-lbH6n2WG.js → wizard-abort-DHrEGqaC.js} +1 -1
- package/dist/{wizard-session-DWeUEncV.js → wizard-session-BoXAZEOf.js} +1 -1
- package/dist/{wizard-session-DWeUEncV.js.map → wizard-session-BoXAZEOf.js.map} +1 -1
- package/dist/{wizard-session-B1ZM4OBv.js → wizard-session-C8W_6X0j.js} +1 -1
- package/dist/{wizard-tools-CGrE1O_b.js → wizard-tools-DQTfAzSV.js} +53 -32
- package/dist/wizard-tools-DQTfAzSV.js.map +1 -0
- package/package.json +2 -1
- package/dist/debug-CgdI7Rd-.js.map +0 -1
- package/dist/posthog-integration-CcJWXPDa.js.map +0 -1
- package/dist/start-tui-DKHnPg5a.js.map +0 -1
- package/dist/wizard-tools-CGrE1O_b.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posthog-
|
|
1
|
+
{"version":3,"file":"posthog-BESrI6-T.js","names":[],"sources":["../src/lib/task-stream/destinations/posthog.ts"],"sourcesContent":["/**\n * PostHog destination — pushes wizard run state to the PostHog backend\n * via `POST /api/projects/{project_id}/wizard/sessions/`.\n *\n * The endpoint is an upsert keyed by `(team, session_id)`: 201 means\n * the row was created, 200 means it was updated. Both are success.\n *\n * Failure handling is fail-silent: never throws to the caller, never\n * writes to stdout/stderr, never blocks the agent. Errors flow through\n * the optional `onError` callback for the wizard's debug log.\n *\n * Retry policy:\n * 5xx / network → exponential backoff base 500ms cap 8s, max 3 attempts\n * 429 → honour `Retry-After` (seconds), single retry\n * 401 / 403 → disable for the rest of the run, no further pushes\n * 400 → give up for this push, do not disable\n * other 4xx → give up for this push, do not disable\n */\n\nimport type {\n TaskStreamDestination,\n TaskStreamUpdate,\n StreamEvent,\n} from '@lib/task-stream/types';\nimport type { Credentials } from '@lib/wizard-session';\n\nexport interface PostHogDestinationOptions {\n /**\n * Lazy credential resolver — called on every send. Returns null\n * before authentication has completed; in that case the send is a\n * no-op (no HTTP request).\n */\n getCredentials: () => Credentials | null;\n /** Receives every error for the wizard's internal logfile. */\n onError?: (err: Error) => void;\n /** Override for tests. Defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Override for tests. Defaults to setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst MAX_ATTEMPTS = 3;\nconst BASE_BACKOFF_MS = 500;\nconst MAX_BACKOFF_MS = 8000;\nconst DEFAULT_RETRY_AFTER_MS = 1000;\n// setTimeout silently clamps anything above 2^31-1 ms to fire\n// immediately, so any Retry-After-derived sleep must be capped.\nconst MAX_RETRY_AFTER_MS = 60_000;\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseRetryAfter(value: string | null): number {\n if (!value) return DEFAULT_RETRY_AFTER_MS;\n const seconds = Number(value);\n if (Number.isFinite(seconds) && seconds >= 0) {\n return Math.min(Math.ceil(seconds * 1000), MAX_RETRY_AFTER_MS);\n }\n // HTTP-date form — best-effort.\n const date = Date.parse(value);\n if (Number.isFinite(date)) {\n return Math.min(Math.max(0, date - Date.now()), MAX_RETRY_AFTER_MS);\n }\n return DEFAULT_RETRY_AFTER_MS;\n}\n\n/**\n * Strip the internal-only `timestamp` field before sending. The\n * backend schema in the RFC does not define it.\n */\nfunction toWirePayload(\n payload: TaskStreamUpdate,\n): Omit<TaskStreamUpdate, 'timestamp'> {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { timestamp: _unused, ...rest } = payload;\n return rest;\n}\n\nexport class PostHogDestination implements TaskStreamDestination {\n readonly name = 'posthog';\n\n private readonly getCredentials: () => Credentials | null;\n private readonly onError: (err: Error) => void;\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: (ms: number) => Promise<void>;\n\n private disabled = false;\n\n constructor(opts: PostHogDestinationOptions) {\n this.getCredentials = opts.getCredentials;\n this.onError = opts.onError ?? (() => undefined);\n this.fetchImpl = opts.fetchImpl ?? ((...args) => fetch(...args));\n this.sleep = opts.sleep ?? defaultSleep;\n }\n\n async send(_event: StreamEvent, payload: TaskStreamUpdate): Promise<void> {\n if (this.disabled) return;\n const creds = this.getCredentials();\n if (!creds) return;\n\n await this.postWithRetry(creds, toWirePayload(payload));\n }\n\n private buildRequest(\n creds: Credentials,\n body: object,\n ): { url: string; init: Parameters<typeof fetch>[1] } {\n const url = `${creds.host.replace(/\\/$/, '')}/api/projects/${\n creds.projectId\n }/wizard/sessions/`;\n return {\n url,\n init: {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${creds.accessToken}`,\n },\n body: JSON.stringify(body),\n },\n };\n }\n\n private async postWithRetry(creds: Credentials, body: object): Promise<void> {\n const { url, init } = this.buildRequest(creds, body);\n let attempt = 0;\n let backoff = BASE_BACKOFF_MS;\n let retriedAfter429 = false;\n\n while (attempt < MAX_ATTEMPTS) {\n attempt += 1;\n let response: Response;\n try {\n response = await this.fetchImpl(url, init);\n } catch (err) {\n if (attempt >= MAX_ATTEMPTS) {\n this.onError(err instanceof Error ? err : new Error(String(err)));\n return;\n }\n await this.sleep(backoff);\n backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);\n continue;\n }\n\n if (response.ok) return;\n\n const status = response.status;\n\n if (status === 401 || status === 403) {\n this.disabled = true;\n this.onError(new Error(`wizard/sessions auth failed: ${status}`));\n return;\n }\n\n if (status === 429) {\n if (retriedAfter429) {\n this.onError(new Error('wizard/sessions rate limited'));\n return;\n }\n retriedAfter429 = true;\n const wait = parseRetryAfter(response.headers.get('Retry-After'));\n await this.sleep(wait);\n // Don't count this against the 5xx attempt budget.\n attempt -= 1;\n continue;\n }\n\n if (status >= 500) {\n if (attempt >= MAX_ATTEMPTS) {\n this.onError(new Error(`wizard/sessions server error: ${status}`));\n return;\n }\n await this.sleep(backoff);\n backoff = Math.min(backoff * 2, MAX_BACKOFF_MS);\n continue;\n }\n\n if (status === 400) {\n let detail = '';\n try {\n detail = await response.text();\n } catch {\n // ignore\n }\n this.onError(new Error(`wizard/sessions bad request (400): ${detail}`));\n return;\n }\n\n this.onError(new Error(`wizard/sessions unexpected status: ${status}`));\n return;\n }\n }\n}\n"],"mappings":";AAyCA,MAAM,eAAe;AACrB,MAAM,kBAAkB;AACxB,MAAM,iBAAiB;AACvB,MAAM,yBAAyB;AAG/B,MAAM,qBAAqB;AAE3B,SAAS,aAAa,IAA2B;AAC/C,QAAO,IAAI,SAAS,YAAY,WAAW,SAAS,GAAG,CAAC;;AAG1D,SAAS,gBAAgB,OAA8B;AACrD,KAAI,CAAC,MAAO,QAAO;CACnB,MAAM,UAAU,OAAO,MAAM;AAC7B,KAAI,OAAO,SAAS,QAAQ,IAAI,WAAW,EACzC,QAAO,KAAK,IAAI,KAAK,KAAK,UAAU,IAAK,EAAE,mBAAmB;CAGhE,MAAM,OAAO,KAAK,MAAM,MAAM;AAC9B,KAAI,OAAO,SAAS,KAAK,CACvB,QAAO,KAAK,IAAI,KAAK,IAAI,GAAG,OAAO,KAAK,KAAK,CAAC,EAAE,mBAAmB;AAErE,QAAO;;;;;;AAOT,SAAS,cACP,SACqC;CAErC,MAAM,EAAE,WAAW,SAAS,GAAG,SAAS;AACxC,QAAO;;AAGT,IAAa,qBAAb,MAAiE;CAC/D,OAAgB;CAEhB;CACA;CACA;CACA;CAEA,WAAmB;CAEnB,YAAY,MAAiC;AAC3C,OAAK,iBAAiB,KAAK;AAC3B,OAAK,UAAU,KAAK,kBAAkB,KAAA;AACtC,OAAK,YAAY,KAAK,eAAe,GAAG,SAAS,MAAM,GAAG,KAAK;AAC/D,OAAK,QAAQ,KAAK,SAAS;;CAG7B,MAAM,KAAK,QAAqB,SAA0C;AACxE,MAAI,KAAK,SAAU;EACnB,MAAM,QAAQ,KAAK,gBAAgB;AACnC,MAAI,CAAC,MAAO;AAEZ,QAAM,KAAK,cAAc,OAAO,cAAc,QAAQ,CAAC;;CAGzD,aACE,OACA,MACoD;AAIpD,SAAO;GACL,KAJU,GAAG,MAAM,KAAK,QAAQ,OAAO,GAAG,CAAC,gBAC3C,MAAM,UACP;GAGC,MAAM;IACJ,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,eAAe,UAAU,MAAM;KAChC;IACD,MAAM,KAAK,UAAU,KAAK;IAC3B;GACF;;CAGH,MAAc,cAAc,OAAoB,MAA6B;EAC3E,MAAM,EAAE,KAAK,SAAS,KAAK,aAAa,OAAO,KAAK;EACpD,IAAI,UAAU;EACd,IAAI,UAAU;EACd,IAAI,kBAAkB;AAEtB,SAAO,UAAU,cAAc;AAC7B,cAAW;GACX,IAAI;AACJ,OAAI;AACF,eAAW,MAAM,KAAK,UAAU,KAAK,KAAK;YACnC,KAAK;AACZ,QAAI,WAAW,cAAc;AAC3B,UAAK,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,CAAC;AACjE;;AAEF,UAAM,KAAK,MAAM,QAAQ;AACzB,cAAU,KAAK,IAAI,UAAU,GAAG,eAAe;AAC/C;;AAGF,OAAI,SAAS,GAAI;GAEjB,MAAM,SAAS,SAAS;AAExB,OAAI,WAAW,OAAO,WAAW,KAAK;AACpC,SAAK,WAAW;AAChB,SAAK,wBAAQ,IAAI,MAAM,gCAAgC,SAAS,CAAC;AACjE;;AAGF,OAAI,WAAW,KAAK;AAClB,QAAI,iBAAiB;AACnB,UAAK,wBAAQ,IAAI,MAAM,+BAA+B,CAAC;AACvD;;AAEF,sBAAkB;IAClB,MAAM,OAAO,gBAAgB,SAAS,QAAQ,IAAI,cAAc,CAAC;AACjE,UAAM,KAAK,MAAM,KAAK;AAEtB,eAAW;AACX;;AAGF,OAAI,UAAU,KAAK;AACjB,QAAI,WAAW,cAAc;AAC3B,UAAK,wBAAQ,IAAI,MAAM,iCAAiC,SAAS,CAAC;AAClE;;AAEF,UAAM,KAAK,MAAM,QAAQ;AACzB,cAAU,KAAK,IAAI,UAAU,GAAG,eAAe;AAC/C;;AAGF,OAAI,WAAW,KAAK;IAClB,IAAI,SAAS;AACb,QAAI;AACF,cAAS,MAAM,SAAS,MAAM;YACxB;AAGR,SAAK,wBAAQ,IAAI,MAAM,sCAAsC,SAAS,CAAC;AACvE;;AAGF,QAAK,wBAAQ,IAAI,MAAM,sCAAsC,SAAS,CAAC;AACvE"}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { i as withUtm, n as openTrackedLink } from "./telemetry-
|
|
4
|
-
import { i as tryGetPackageJson, n as isUsingTypeScript } from "./setup-utils-
|
|
5
|
-
import { t as HostResolution } from "./host-resolution-
|
|
6
|
-
import { r as requestDeepLink } from "./provisioning-
|
|
7
|
-
import "./wizard-session-
|
|
8
|
-
import { i as wizardAbort } from "./wizard-abort-
|
|
9
|
-
import { n as runAgent } from "./agent-runner-
|
|
10
|
-
import { i as runAgent$1, p as AgentSignals, r as initializeAgent } from "./agent-interface-
|
|
11
|
-
import { t as WIZARD_TOOL_NAMES } from "./wizard-tools-
|
|
12
|
-
import { r as detectNodePackageManagers } from "./package-manager-
|
|
13
|
-
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-
|
|
1
|
+
import { $ as WIZARD_INTERACTION_EVENT_NAME, E as DETECTION_TIMEOUT_MS, P as Integration, _ as evaluateWizardReadiness, f as getUI, g as SIGNUP_WIZARD_READINESS_CONFIG, j as HAIKU_MODEL, s as logToFile, ut as getSkillsBaseUrl, v as getBlockingServiceKeys } from "./debug-D1lORUFs.js";
|
|
2
|
+
import { n as analytics } from "./analytics-Ciob-x8a.js";
|
|
3
|
+
import { i as withUtm, n as openTrackedLink } from "./telemetry-BfnR7gtf.js";
|
|
4
|
+
import { i as tryGetPackageJson, n as isUsingTypeScript } from "./setup-utils-DLGNk8T6.js";
|
|
5
|
+
import { t as HostResolution } from "./host-resolution-BnUJZKId.js";
|
|
6
|
+
import { r as requestDeepLink } from "./provisioning-CgomM26T.js";
|
|
7
|
+
import "./wizard-session-BoXAZEOf.js";
|
|
8
|
+
import { i as wizardAbort } from "./wizard-abort-Cp5Y7f8C.js";
|
|
9
|
+
import { n as runAgent } from "./agent-runner-CMfTmM3B.js";
|
|
10
|
+
import { i as runAgent$1, p as AgentSignals, r as initializeAgent } from "./agent-interface-DExARWay.js";
|
|
11
|
+
import { t as WIZARD_TOOL_NAMES } from "./wizard-tools-DQTfAzSV.js";
|
|
12
|
+
import { r as detectNodePackageManagers } from "./package-manager-WKKQADHM.js";
|
|
13
|
+
import { i as SPINNER_MESSAGE, t as FRAMEWORK_REGISTRY } from "./registry-BQIX-25O.js";
|
|
14
14
|
import * as semver from "semver";
|
|
15
15
|
import { readFileSync } from "fs";
|
|
16
|
-
import { join } from "path";
|
|
16
|
+
import { isAbsolute, join } from "path";
|
|
17
17
|
import { Text } from "ink";
|
|
18
18
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
19
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -227,6 +227,9 @@ async function checkFrameworkVersion(config, options) {
|
|
|
227
227
|
* Every project-manifest / workspace-marker filename the wizard's frameworks
|
|
228
228
|
* are identified by. One brace-expansion Glob over all of these locates every
|
|
229
229
|
* project root in the repo in a single call, regardless of language.
|
|
230
|
+
*
|
|
231
|
+
* Counterpart: POSTHOG_MANIFESTS in @lib/programs/self-driving/detect (SDK
|
|
232
|
+
* grep); keep the two in sync.
|
|
230
233
|
*/
|
|
231
234
|
const PROJECT_MANIFESTS = [
|
|
232
235
|
"package.json",
|
|
@@ -243,13 +246,19 @@ const PROJECT_MANIFESTS = [
|
|
|
243
246
|
"composer.json",
|
|
244
247
|
"Cargo.toml",
|
|
245
248
|
"go.mod",
|
|
249
|
+
"mix.exs",
|
|
250
|
+
"pom.xml",
|
|
251
|
+
"*.csproj",
|
|
246
252
|
"Package.swift",
|
|
247
253
|
"Podfile",
|
|
254
|
+
"project.yml",
|
|
255
|
+
"project.pbxproj",
|
|
248
256
|
"pubspec.yaml",
|
|
249
257
|
"build.gradle",
|
|
250
258
|
"build.gradle.kts",
|
|
251
259
|
"settings.gradle",
|
|
252
|
-
"settings.gradle.kts"
|
|
260
|
+
"settings.gradle.kts",
|
|
261
|
+
"gradle/libs.versions.toml"
|
|
253
262
|
];
|
|
254
263
|
/** The single brace-expansion glob covering every supported manifest. */
|
|
255
264
|
function manifestGlob() {
|
|
@@ -265,12 +274,12 @@ function buildPrompt(cwd, targets, purpose) {
|
|
|
265
274
|
"A \"project\" is a directory containing one or more of the manifest files below. Find projects by their manifests, NOT by walking directories — never report a directory that has no manifest.",
|
|
266
275
|
"",
|
|
267
276
|
"Do exactly this:",
|
|
268
|
-
`1. Run Glob ONCE with this pattern to find every project manifest in the repo in a single call: "${manifestGlob()}". Discard any result whose path contains node_modules/, dist/, build/, .next/, out/, coverage/, vendor/, .venv/, site-packages/, or
|
|
277
|
+
`1. Run Glob ONCE with this pattern to find every project manifest in the repo in a single call: "${manifestGlob()}". Discard any result whose path contains node_modules/, dist/, build/, .next/, out/, coverage/, vendor/, .venv/, site-packages/, target/, Pods/, Carthage/, or DerivedData/. Group the remaining results by directory — each directory is one project. Three exceptions to "directory = project": a project.pbxproj lives inside a "<Name>.xcodeproj/" wrapper, so the project root is the PARENT of that .xcodeproj directory; a project.yml at a directory root is an XcodeGen-generated Xcode app rooted at that directory; a gradle/libs.versions.toml is a version catalog belonging to the gradle project rooted at the PARENT of that gradle/ directory (read it alongside the build.gradle when deciding hasPostHog), never its own project.`,
|
|
269
278
|
"2. Decide repoType: \"monorepo\" if the root package.json has a \"workspaces\" field OR a pnpm-workspace.yaml / turbo.json / nx.json / lerna.json was found at the root, else \"single\".",
|
|
270
279
|
"3. For EACH project directory, Read its manifest(s) ONCE. From the dependency lists decide:",
|
|
271
280
|
" - the human-readable framework name (e.g. \"Next.js\", \"Django\", \"Rails\"),",
|
|
272
281
|
" - the matching target id from the list below. That list is ordered by priority — most specific first — so when a project could match more than one target (e.g. it uses several of the listed technologies), pick the one listed EARLIEST. Use null only if none matches,",
|
|
273
|
-
|
|
282
|
+
` - hasPostHog: true if any dependency is a PostHog SDK. This includes: a name containing "posthog" in any ecosystem (e.g. posthog-js, posthog-node, @posthog/*, posthog for pip/gem/hex, a com.posthog:* gradle/maven coordinate, a PostHog NuGet PackageReference); an SPM package named "PostHog" or a repositoryURL of github.com/PostHog/posthog-ios (in Package.swift or a .pbxproj); or a "pod 'PostHog'" line in a Podfile. Else false.`,
|
|
274
283
|
" Do NOT read any file other than these manifests.",
|
|
275
284
|
"",
|
|
276
285
|
"Target ids (id → name), in priority order — most specific first; if several match a project, keep the one listed earliest:",
|
|
@@ -294,8 +303,18 @@ function extractJson(text) {
|
|
|
294
303
|
return JSON.parse(candidate.slice(start, end + 1));
|
|
295
304
|
}
|
|
296
305
|
/**
|
|
306
|
+
* Clamp an agent-reported project path to a safe repo-relative dir. The path
|
|
307
|
+
* is LLM output: absolute paths or `..` segments could steer later phases
|
|
308
|
+
* (e.g. integrate-run's targetDir) outside the repo, so they clamp to '.'.
|
|
309
|
+
*/
|
|
310
|
+
function coercePath(raw) {
|
|
311
|
+
if (typeof raw !== "string" || raw.length === 0) return ".";
|
|
312
|
+
if (isAbsolute(raw) || raw.split(/[\\/]/).includes("..")) return ".";
|
|
313
|
+
return raw;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
297
316
|
* Validate the agent's raw JSON into a report, clamping each targetId to the
|
|
298
|
-
* supplied set. Exported for testing.
|
|
317
|
+
* supplied set and each path to a repo-relative dir. Exported for testing.
|
|
299
318
|
*/
|
|
300
319
|
function coerceAgenticReport(parsed, validTargetIds) {
|
|
301
320
|
const obj = parsed ?? {};
|
|
@@ -305,7 +324,7 @@ function coerceAgenticReport(parsed, validTargetIds) {
|
|
|
305
324
|
const p = raw ?? {};
|
|
306
325
|
const targetId = typeof p.targetId === "string" && validTargetIds.includes(p.targetId) ? p.targetId : null;
|
|
307
326
|
return {
|
|
308
|
-
path:
|
|
327
|
+
path: coercePath(p.path),
|
|
309
328
|
framework: typeof p.framework === "string" ? p.framework : "Unknown",
|
|
310
329
|
targetId,
|
|
311
330
|
hasPostHog: p.hasPostHog === true
|
|
@@ -1581,7 +1600,7 @@ const posthogIntegrationConfig = {
|
|
|
1581
1600
|
if (usesPackageJson) {
|
|
1582
1601
|
const packageJson = await tryGetPackageJson({ installDir: session.installDir });
|
|
1583
1602
|
if (packageJson) {
|
|
1584
|
-
const { hasDeclaredDependency } = await import("./package-json-
|
|
1603
|
+
const { hasDeclaredDependency } = await import("./package-json-CDs1ZVKu.js").then((n) => n.i);
|
|
1585
1604
|
if (!hasDeclaredDependency(config.detection.packageName, packageJson)) getUI().log.warn(`${config.detection.packageDisplayName} does not seem to be installed. Continuing anyway — the agent will handle it.`);
|
|
1586
1605
|
frameworkVersion = config.detection.getVersion(packageJson);
|
|
1587
1606
|
} else getUI().log.warn("Could not find package.json. Continuing anyway — the agent will handle it.");
|
|
@@ -1648,7 +1667,7 @@ Important: Use the detect_package_manager tool (from the wizard-tools MCP server
|
|
|
1648
1667
|
postRun: async (sess, credentials) => {
|
|
1649
1668
|
const envVars = config.environment.getEnvVars(credentials.projectApiKey, credentials.host);
|
|
1650
1669
|
if (config.environment.uploadToHosting) {
|
|
1651
|
-
const { uploadEnvironmentVariablesStep } = await import("./steps-
|
|
1670
|
+
const { uploadEnvironmentVariablesStep } = await import("./steps-XjV9CiqH.js");
|
|
1652
1671
|
const uploadedEnvVars = await uploadEnvironmentVariablesStep(envVars, {
|
|
1653
1672
|
integration: config.metadata.integration,
|
|
1654
1673
|
session: sess
|
|
@@ -1703,4 +1722,4 @@ const integrationRunStep = {
|
|
|
1703
1722
|
//#endregion
|
|
1704
1723
|
export { gatherFrameworkContext as _, LINE_CHART_BLOCK as a, parseRequirementsTxt as b, TextBlock as c, isLinesBlock as d, isObjectBlock as f, detectProjectsWithAgent as g, HEALTH_CHECK_STEP as h, FUNNEL_BLOCK as i, computeVisibleRange as l, Icons as m, integrationRunStep as n, PRODUCT_SUITE_BLOCK as o, Colors as p, posthogIntegrationConfig as r, StatusPeekTrigger as s, SETUP_REPORT_FILE as t, isClearBlock as u, parsePipfile as v, parsePyprojectToml as y };
|
|
1705
1724
|
|
|
1706
|
-
//# sourceMappingURL=posthog-integration-
|
|
1725
|
+
//# sourceMappingURL=posthog-integration-CWXSng0W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posthog-integration-CWXSng0W.js","names":["executeAgent"],"sources":["../src/lib/detection/framework.ts","../src/lib/detection/features.ts","../src/lib/detection/context.ts","../src/lib/detection/agentic.ts","../src/lib/programs/shared/health-check-step.ts","../src/lib/programs/posthog-integration/detect.ts","../src/lib/programs/posthog-integration/steps.ts","../src/ui/tui/styles.ts","../src/ui/tui/primitives/text-helpers.ts","../src/ui/tui/primitives/content-types.ts","../src/ui/tui/primitives/layout-helpers.ts","../src/ui/tui/primitives/TextBlock.tsx","../src/ui/tui/components/StatusPeekTrigger.tsx","../src/lib/programs/posthog-integration/content/data-flow.tsx","../src/lib/programs/posthog-integration/content/product-suite.tsx","../src/lib/programs/posthog-integration/content/line-chart.tsx","../src/lib/programs/posthog-integration/content/funnel.tsx","../src/lib/programs/posthog-integration/content/index.tsx","../src/lib/programs/posthog-integration/handoff.ts","../src/lib/programs/posthog-integration/index.ts"],"sourcesContent":["/**\n * Framework detection — identify which PostHog-supported framework\n * is present in the project directory.\n *\n * Pure function: takes an install dir, returns the detected integration\n * (or undefined). No store mutations, no UI calls.\n */\n\nimport { Integration, DETECTION_TIMEOUT_MS } from '@lib/constants';\nimport { FRAMEWORK_REGISTRY } from '@lib/registry';\n\n/**\n * Loop through all registered frameworks and return the first one\n * whose `detect()` predicate matches the given directory.\n * Returns undefined if no framework is detected or detection times out.\n */\nexport async function detectFramework(\n installDir: string,\n): Promise<Integration | undefined> {\n for (const integration of Object.values(Integration)) {\n const config = FRAMEWORK_REGISTRY[integration];\n try {\n const detected = await Promise.race([\n config.detection.detect({ installDir }),\n new Promise<false>((resolve) =>\n setTimeout(() => resolve(false), DETECTION_TIMEOUT_MS),\n ),\n ]);\n if (detected) {\n return integration;\n }\n } catch {\n // Skip frameworks whose detection throws\n }\n }\n}\n","/**\n * Feature discovery — scan project dependencies for known SDK patterns\n * that indicate additional PostHog programs are relevant.\n *\n * Pure function: takes an install dir, returns a set of discovered features.\n * No store mutations, no UI calls.\n */\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { DiscoveredFeature } from '@lib/wizard-session';\n\nconst STRIPE_PACKAGES = ['stripe', '@stripe/stripe-js'];\n\nconst LLM_PACKAGES = [\n 'openai',\n '@anthropic-ai/sdk',\n 'ai',\n '@ai-sdk/openai',\n 'langchain',\n '@langchain/openai',\n '@langchain/langgraph',\n '@google/generative-ai',\n '@google/genai',\n '@instructor-ai/instructor',\n '@mastra/core',\n 'portkey-ai',\n];\n\n// PyPI normalizes `_` to `-` and is case-insensitive; compare via normalizePyName.\nconst PYTHON_LLM_PACKAGES = [\n 'openai',\n 'anthropic',\n 'langchain',\n 'langchain-openai',\n 'langchain-anthropic',\n 'langchain-google-genai',\n 'langgraph',\n 'litellm',\n 'llama-index',\n 'pydantic-ai',\n 'crewai',\n 'instructor',\n 'dspy-ai',\n 'mistralai',\n 'cohere',\n 'google-generativeai',\n 'google-genai',\n 'portkey-ai',\n];\n\nexport function discoverFeatures(installDir: string): DiscoveredFeature[] {\n const features: DiscoveredFeature[] = [];\n discoverNodeFeatures(installDir, features);\n discoverPythonFeatures(installDir, features);\n return features;\n}\n\nfunction discoverNodeFeatures(\n installDir: string,\n features: DiscoveredFeature[],\n): void {\n const packageJsonText = safeRead(installDir, 'package.json');\n if (!packageJsonText) return;\n\n let packageJson: {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n try {\n packageJson = JSON.parse(packageJsonText);\n } catch {\n return;\n }\n\n const depNames = Object.keys({\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n });\n\n if (depNames.some((depName) => STRIPE_PACKAGES.includes(depName))) {\n features.push(DiscoveredFeature.Stripe);\n }\n if (depNames.some((depName) => LLM_PACKAGES.includes(depName))) {\n features.push(DiscoveredFeature.LLM);\n }\n}\n\nfunction discoverPythonFeatures(\n installDir: string,\n features: DiscoveredFeature[],\n): void {\n if (features.includes(DiscoveredFeature.LLM)) return;\n\n const depNames: string[] = [];\n\n const requirementsTxt = safeRead(installDir, 'requirements.txt');\n if (requirementsTxt) depNames.push(...parseRequirementsTxt(requirementsTxt));\n\n const pyprojectToml = safeRead(installDir, 'pyproject.toml');\n if (pyprojectToml) depNames.push(...parsePyprojectToml(pyprojectToml));\n\n const pipfile = safeRead(installDir, 'Pipfile');\n if (pipfile) depNames.push(...parsePipfile(pipfile));\n\n if (depNames.some((depName) => PYTHON_LLM_PACKAGES.includes(depName))) {\n features.push(DiscoveredFeature.LLM);\n }\n}\n\nfunction safeRead(installDir: string, file: string): string | null {\n try {\n return readFileSync(join(installDir, file), 'utf-8');\n } catch {\n return null;\n }\n}\n\nfunction normalizePyName(name: string): string {\n return name.toLowerCase().replace(/_/g, '-');\n}\n\nexport function parseRequirementsTxt(content: string): string[] {\n return content\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line && !line.startsWith('#') && !line.startsWith('-'))\n .map((line) => line.replace(/\\[[^\\]]*\\]/, ''))\n .map((line) => line.split(/[<>=!~;\\s]/)[0])\n .filter(Boolean)\n .map(normalizePyName);\n}\n\n// Pragmatic, not a full TOML parser — only the dep shapes we care about.\nexport function parsePyprojectToml(content: string): string[] {\n const depNames: string[] = [];\n\n for (const arrayMatch of content.matchAll(\n /dependencies\\s*=\\s*\\[([^\\]]*)\\]/g,\n )) {\n const arrayBody = arrayMatch[1];\n for (const quotedMatch of arrayBody.matchAll(/[\"']([^\"']+)[\"']/g)) {\n const depSpec = quotedMatch[1];\n const name = depSpec.replace(/\\[[^\\]]*\\]/, '').split(/[<>=!~;\\s]/)[0];\n if (name) depNames.push(normalizePyName(name));\n }\n }\n\n const poetrySectionRe =\n /\\[tool\\.poetry\\.(?:dev-dependencies|dependencies|group\\.[^.\\]]+\\.dependencies)\\]([\\s\\S]*?)(?=\\n\\[|$)/g;\n for (const sectionMatch of content.matchAll(poetrySectionRe)) {\n const sectionBody = sectionMatch[1];\n depNames.push(...extractTomlSectionKeys(sectionBody, { skip: ['python'] }));\n }\n\n return depNames;\n}\n\nexport function parsePipfile(content: string): string[] {\n const depNames: string[] = [];\n const sectionRe = /\\[(packages|dev-packages)\\]([\\s\\S]*?)(?=\\n\\[|$)/g;\n for (const sectionMatch of content.matchAll(sectionRe)) {\n const sectionBody = sectionMatch[2];\n depNames.push(...extractTomlSectionKeys(sectionBody));\n }\n return depNames;\n}\n\nfunction extractTomlSectionKeys(\n sectionBody: string,\n opts: { skip?: string[] } = {},\n): string[] {\n const skipNames = new Set(opts.skip ?? []);\n const depNames: string[] = [];\n for (const line of sectionBody.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const equalsIndex = trimmed.indexOf('=');\n if (equalsIndex <= 0) continue;\n const name = trimmed.slice(0, equalsIndex).trim();\n if (!/^[a-zA-Z0-9._-]+$/.test(name)) continue;\n if (skipNames.has(name.toLowerCase())) continue;\n depNames.push(normalizePyName(name));\n }\n return depNames;\n}\n","/**\n * Framework context gathering — run gatherContext and version checks\n * for a detected framework.\n *\n * Pure functions: take a framework config and options, return results.\n * No store mutations, no UI calls.\n */\n\nimport * as semver from 'semver';\nimport { DETECTION_TIMEOUT_MS } from '@lib/constants';\nimport type { FrameworkConfig } from '@lib/framework-config';\nimport type { WizardRunOptions } from '@utils/types';\n\n/**\n * Run a framework's `gatherContext()` to collect variant-specific\n * metadata (e.g., router type for Next.js, Expo vs bare for React Native).\n *\n * Returns the gathered context, or an empty object on failure/timeout.\n */\nexport async function gatherFrameworkContext(\n config: FrameworkConfig,\n options: WizardRunOptions,\n): Promise<Record<string, unknown>> {\n if (!config.metadata.gatherContext) return {};\n\n try {\n return await Promise.race([\n config.metadata.gatherContext(options),\n new Promise<Record<string, never>>((resolve) =>\n setTimeout(() => resolve({}), DETECTION_TIMEOUT_MS),\n ),\n ]);\n } catch {\n return {};\n }\n}\n\nexport interface VersionCheckResult {\n /** Whether the installed version is supported */\n supported:\n | true\n | {\n current: string;\n minimum: string;\n docsUrl: string;\n };\n}\n\n/**\n * Check whether the installed framework version meets the minimum requirement.\n *\n * Returns `{ supported: true }` if the version is fine (or no check is needed).\n * Returns the version details if unsupported.\n */\nexport async function checkFrameworkVersion(\n config: FrameworkConfig,\n options: WizardRunOptions,\n): Promise<VersionCheckResult> {\n if (\n !config.detection.minimumVersion ||\n !config.detection.getInstalledVersion\n ) {\n return { supported: true };\n }\n\n const version = await config.detection.getInstalledVersion(options);\n if (!version) return { supported: true };\n\n const coerced = semver.coerce(version);\n if (coerced && semver.lt(coerced, config.detection.minimumVersion)) {\n return {\n supported: {\n current: version,\n minimum: config.detection.minimumVersion,\n docsUrl:\n config.metadata.unsupportedVersionDocsUrl ?? config.metadata.docsUrl,\n },\n };\n }\n\n return { supported: true };\n}\n","/**\n * Agentic project detection.\n *\n * A reusable detection tool that drives a Haiku agent over the repo: it finds\n * project roots, resolves monorepo/workspace markers, reads package manifests,\n * classifies each project against a caller-supplied set of targets, and reports\n * which projects already have a PostHog SDK installed.\n *\n * Product-knowledge-free by design — the caller passes the targets to classify\n * into (e.g. source-map skill variants) and maps the result back. Sits next to\n * the other detection tools (framework, features, package-manager) so it's\n * discoverable. Runs AFTER auth: it uses the same agent loop every program\n * uses, which needs credentials.\n */\n\nimport {\n initializeAgent,\n runAgent as executeAgent,\n AgentSignals,\n} from '@lib/agent/agent-interface';\nimport { isAbsolute } from 'path';\nimport { detectNodePackageManagers } from './package-manager.js';\nimport { getSkillsBaseUrl, HAIKU_MODEL } from '@lib/constants';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { WizardRunOptions } from '@utils/types';\nimport type { SpinnerHandle } from '@ui';\n\n/** A category the agent classifies each project into (id the agent returns). */\nexport type DetectTarget = { id: string; name: string };\n\n/** One project the agent found in the repo. */\nexport type AgenticProject = {\n /** Path relative to the working directory (\".\" for the repo root). */\n path: string;\n /** Human-readable framework the agent detected (e.g. \"Next.js\"). */\n framework: string;\n /** A target id when the project matches one of the supplied targets, else null. */\n targetId: string | null;\n /** Whether a PostHog SDK is already installed in this project. */\n hasPostHog: boolean;\n};\n\nexport type AgenticDetectionReport = {\n repoType: 'monorepo' | 'single';\n projects: AgenticProject[];\n};\n\n/** Streaming progress callback — one short activity line per agent step. */\nexport type DetectEvent = (line: string) => void;\n\n/**\n * Every project-manifest / workspace-marker filename the wizard's frameworks\n * are identified by. One brace-expansion Glob over all of these locates every\n * project root in the repo in a single call, regardless of language.\n *\n * Counterpart: POSTHOG_MANIFESTS in @lib/programs/self-driving/detect (SDK\n * grep); keep the two in sync.\n */\nexport const PROJECT_MANIFESTS: readonly string[] = [\n // JS/TS + workspace markers\n 'package.json',\n 'pnpm-workspace.yaml',\n 'turbo.json',\n 'nx.json',\n 'lerna.json',\n // Python\n 'requirements.txt',\n 'pyproject.toml',\n 'setup.py',\n 'Pipfile',\n 'manage.py',\n // Ruby / PHP\n 'Gemfile',\n 'composer.json',\n // Rust / Go / Elixir / JVM / .NET: no framework targets yet, but found so\n // an existing PostHog SDK is reported (feeds self-driving's \"continue\" path).\n 'Cargo.toml',\n 'go.mod',\n 'mix.exs',\n 'pom.xml',\n '*.csproj',\n // Mobile / native\n 'Package.swift',\n 'Podfile',\n 'project.yml',\n 'project.pbxproj',\n 'pubspec.yaml',\n 'build.gradle',\n 'build.gradle.kts',\n 'settings.gradle',\n 'settings.gradle.kts',\n // Gradle version catalog (holds dependency coordinates).\n 'gradle/libs.versions.toml',\n];\n\n/** The single brace-expansion glob covering every supported manifest. */\nexport function manifestGlob(): string {\n return `**/{${PROJECT_MANIFESTS.join(',')}}`;\n}\n\nexport type AgenticDetectOptions = {\n /**\n * Categories to classify each project into. Order matters: list targets by\n * priority, most specific first. When a project could match more than one,\n * the agent keeps the earliest — so the caller encodes precedence purely\n * through ordering (e.g. a bundler target before a generic framework target).\n */\n targets: readonly DetectTarget[];\n /** One short clause describing what the scan is for (frames the prompt). */\n purpose?: string;\n /** Streaming activity callback for the UI. */\n onEvent?: DetectEvent;\n};\n\nfunction buildPrompt(\n cwd: string,\n targets: readonly DetectTarget[],\n purpose: string,\n): string {\n const targetList = targets.map((t) => `- ${t.id} → ${t.name}`).join('\\n');\n return [\n `You are scanning a code repository to ${purpose}. Be fast and mechanical — do not over-explore. Keep any reasoning to one short sentence, then run the tool calls and output the JSON.`,\n '',\n `Working directory: ${cwd}`,\n '',\n 'A \"project\" is a directory containing one or more of the manifest files below. Find projects by their manifests, NOT by walking directories — never report a directory that has no manifest.',\n '',\n 'Do exactly this:',\n `1. Run Glob ONCE with this pattern to find every project manifest in the repo in a single call: \"${manifestGlob()}\". Discard any result whose path contains node_modules/, dist/, build/, .next/, out/, coverage/, vendor/, .venv/, site-packages/, target/, Pods/, Carthage/, or DerivedData/. Group the remaining results by directory — each directory is one project. Three exceptions to \"directory = project\": a project.pbxproj lives inside a \"<Name>.xcodeproj/\" wrapper, so the project root is the PARENT of that .xcodeproj directory; a project.yml at a directory root is an XcodeGen-generated Xcode app rooted at that directory; a gradle/libs.versions.toml is a version catalog belonging to the gradle project rooted at the PARENT of that gradle/ directory (read it alongside the build.gradle when deciding hasPostHog), never its own project.`,\n '2. Decide repoType: \"monorepo\" if the root package.json has a \"workspaces\" field OR a pnpm-workspace.yaml / turbo.json / nx.json / lerna.json was found at the root, else \"single\".',\n '3. For EACH project directory, Read its manifest(s) ONCE. From the dependency lists decide:',\n ' - the human-readable framework name (e.g. \"Next.js\", \"Django\", \"Rails\"),',\n ' - the matching target id from the list below. That list is ordered by priority — most specific first — so when a project could match more than one target (e.g. it uses several of the listed technologies), pick the one listed EARLIEST. Use null only if none matches,',\n ` - hasPostHog: true if any dependency is a PostHog SDK. This includes: a name containing \"posthog\" in any ecosystem (e.g. posthog-js, posthog-node, @posthog/*, posthog for pip/gem/hex, a com.posthog:* gradle/maven coordinate, a PostHog NuGet PackageReference); an SPM package named \"PostHog\" or a repositoryURL of github.com/PostHog/posthog-ios (in Package.swift or a .pbxproj); or a \"pod 'PostHog'\" line in a Podfile. Else false.`,\n ' Do NOT read any file other than these manifests.',\n '',\n 'Target ids (id → name), in priority order — most specific first; if several match a project, keep the one listed earliest:',\n targetList,\n '',\n 'Output requirements:',\n '- Respond with ONLY a single JSON object. No prose, no markdown code fences.',\n '- Shape: {\"repoType\":\"monorepo\"|\"single\",\"projects\":[{\"path\":string,\"framework\":string,\"targetId\":string|null,\"hasPostHog\":boolean}]}',\n '- \"path\" is the project directory relative to the working directory; use \".\" for the repo root.',\n '- \"targetId\" MUST be exactly one of the target ids above when it matches; if several match, use the one listed earliest; otherwise null.',\n '- Include projects whose stack matches no target too (targetId: null).',\n `- If there are no manifests at all, respond with exactly: ${AgentSignals.ABORT} detection failed`,\n ].join('\\n');\n}\n\nfunction extractJson(text: string): unknown {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\n const candidate = fenced ? fenced[1] : text;\n const start = candidate.indexOf('{');\n const end = candidate.lastIndexOf('}');\n if (start === -1 || end === -1 || end < start) {\n throw new Error('Agent did not return a JSON object');\n }\n return JSON.parse(candidate.slice(start, end + 1));\n}\n\n/**\n * Clamp an agent-reported project path to a safe repo-relative dir. The path\n * is LLM output: absolute paths or `..` segments could steer later phases\n * (e.g. integrate-run's targetDir) outside the repo, so they clamp to '.'.\n */\nfunction coercePath(raw: unknown): string {\n if (typeof raw !== 'string' || raw.length === 0) return '.';\n if (isAbsolute(raw) || raw.split(/[\\\\/]/).includes('..')) return '.';\n return raw;\n}\n\n/**\n * Validate the agent's raw JSON into a report, clamping each targetId to the\n * supplied set and each path to a repo-relative dir. Exported for testing.\n */\nexport function coerceAgenticReport(\n parsed: unknown,\n validTargetIds: readonly string[],\n): AgenticDetectionReport {\n const obj = (parsed ?? {}) as Record<string, unknown>;\n const repoType = obj.repoType === 'monorepo' ? 'monorepo' : 'single';\n const rawProjects = Array.isArray(obj.projects) ? obj.projects : [];\n const projects: AgenticProject[] = rawProjects.map((raw) => {\n const p = (raw ?? {}) as Record<string, unknown>;\n const targetId =\n typeof p.targetId === 'string' && validTargetIds.includes(p.targetId)\n ? p.targetId\n : null;\n return {\n path: coercePath(p.path),\n framework: typeof p.framework === 'string' ? p.framework : 'Unknown',\n targetId,\n hasPostHog: p.hasPostHog === true,\n };\n });\n return { repoType, projects };\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction formatToolUse(block: any): string {\n const name = typeof block?.name === 'string' ? block.name : 'tool';\n const input = (block?.input ?? {}) as Record<string, unknown>;\n const detail =\n (input.file_path as string) ||\n (input.pattern as string) ||\n (input.path as string) ||\n '';\n return detail ? `${name} ${detail}` : name;\n}\n\nfunction sessionToWizardOptions(session: WizardSession): WizardRunOptions {\n return {\n installDir: session.installDir,\n ci: session.ci,\n debug: session.debug,\n default: false,\n benchmark: session.benchmark,\n yaraReport: session.yaraReport,\n signup: session.signup,\n apiKey: session.apiKey,\n projectId: session.projectId,\n localMcp: session.localMcp,\n };\n}\n\nconst NOOP_SPINNER: SpinnerHandle = {\n start: () => undefined,\n stop: () => undefined,\n message: () => undefined,\n};\n\n/**\n * Drive the wizard's agent loop on HAIKU_MODEL to scan the repo and return a\n * structured detection report. Reuses the same setup every program uses, so\n * MCP, tools, and credentials are wired identically.\n */\nexport async function detectProjectsWithAgent(\n session: WizardSession,\n options: AgenticDetectOptions,\n): Promise<AgenticDetectionReport> {\n if (!session.credentials) {\n throw new Error('Detection requires authenticated credentials.');\n }\n const {\n targets,\n purpose = 'set up a PostHog integration',\n onEvent,\n } = options;\n const { accessToken, host } = session.credentials;\n const cwd = session.installDir;\n const runOptions = sessionToWizardOptions(session);\n\n const mcpUrl = session.localMcp\n ? 'http://localhost:8787/mcp'\n : 'https://mcp.posthog.com/mcp';\n\n const agent = await initializeAgent(\n {\n workingDirectory: cwd,\n posthogMcpUrl: mcpUrl,\n posthogApiKey: accessToken,\n posthogApiHost: host,\n detectPackageManager: detectNodePackageManagers,\n skillsBaseUrl: getSkillsBaseUrl(session.localMcp),\n integrationLabel: 'agentic-detect',\n allowedTools: ['Read', 'Grep', 'Glob'],\n modelOverride: HAIKU_MODEL,\n },\n runOptions,\n );\n\n const collected: string[] = [];\n let resultText = '';\n\n const middleware = {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onMessage: (message: any): void => {\n if (message?.type === 'assistant') {\n for (const block of message.message?.content ?? []) {\n if (block?.type === 'text' && typeof block.text === 'string') {\n collected.push(block.text);\n const line = block.text.trim();\n if (line && onEvent) {\n onEvent(line.length > 100 ? `${line.slice(0, 100)}…` : line);\n }\n } else if (block?.type === 'tool_use') {\n onEvent?.(formatToolUse(block));\n }\n }\n } else if (\n message?.type === 'result' &&\n typeof message.result === 'string'\n ) {\n resultText = message.result;\n }\n },\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n finalize: (_resultMessage: any, _durationMs: number): unknown => undefined,\n };\n\n const result = await executeAgent(\n agent,\n buildPrompt(cwd, targets, purpose),\n runOptions,\n NOOP_SPINNER,\n {\n spinnerMessage: 'Scanning the repo...',\n successMessage: 'Detection complete',\n errorMessage: 'Detection failed',\n requestRemark: false,\n },\n middleware,\n );\n\n if (result.error) {\n throw new Error(result.message || `Agent error: ${result.error}`);\n }\n\n const output = resultText || collected.join('\\n');\n try {\n return coerceAgenticReport(\n extractJson(output),\n targets.map((t) => t.id),\n );\n } catch (err) {\n // The prompt tells the agent to emit `[ABORT] detection failed` when the\n // repo has no recognizable project manifests. Surface that (and any other\n // non-JSON terminal output that carries the abort signal) as an empty\n // report so the screen renders a friendly \"nothing to instrument\" state\n // instead of a cryptic \"Agent did not return a JSON object\" error.\n if (output.includes(AgentSignals.ABORT)) {\n return { repoType: 'single', projects: [] };\n }\n throw err;\n }\n}\n","/**\n * Shared health-check step used by every program that runs an agent.\n *\n * Renders the HealthCheckScreen between intro and auth, kicks off the\n * readiness probe in onInit, and gates the screen on either a clean\n * readiness result or an explicit user dismissal of the outage.\n *\n * Programs without this step that hit a blocking outage gridlock the\n * router: agent-runner calls wizardAbort, which awaits outroDismissed,\n * but the router can't advance past the still-incomplete auth step to\n * render the OutroScreen.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport {\n evaluateWizardReadiness,\n WizardReadiness,\n SIGNUP_WIZARD_READINESS_CONFIG,\n getBlockingServiceKeys,\n} from '@lib/health-checks/readiness';\nimport { logToFile } from '@utils/debug';\n\nexport function healthCheckReady(session: WizardSession): boolean {\n if (!session.readinessResult) return false;\n\n if (session.signup) {\n const hardBlocking = getBlockingServiceKeys(\n session.readinessResult.health,\n SIGNUP_WIZARD_READINESS_CONFIG,\n );\n const defaultBlocking = getBlockingServiceKeys(\n session.readinessResult.health,\n );\n if (hardBlocking.length === 0 && defaultBlocking.length === 0) return true;\n return session.outageDismissed;\n }\n\n if (session.readinessResult.decision === WizardReadiness.No) {\n return session.outageDismissed;\n }\n return true;\n}\n\nexport const HEALTH_CHECK_STEP: ProgramStep = {\n id: 'health-check',\n label: 'Health check',\n screenId: 'health-check',\n gate: healthCheckReady,\n onInit: (ctx) => {\n evaluateWizardReadiness()\n .then((readiness) => {\n logToFile(\n `[health-checks] TUI pre-flight complete: decision=${readiness.decision}`,\n );\n ctx.setReadinessResult(readiness);\n })\n .catch((err) => {\n logToFile('[health-checks] TUI pre-flight failed:', err);\n ctx.setReadinessResult({\n decision: WizardReadiness.Yes,\n health: {} as never,\n reasons: [],\n });\n });\n },\n};\n","/**\n * Core integration detection step.\n *\n * Runs framework detection, context gathering, version checking,\n * and feature discovery. Writes results to the store via the\n * ProgramReadyContext so the IntroScreen can display them.\n *\n * This is the same work that bin.ts $0 handler does inline —\n * extracted here so the `integrate` subcommand can reuse it.\n */\n\nimport type { ProgramReadyContext } from '@lib/programs/program-step';\nimport { FRAMEWORK_REGISTRY } from '@lib/registry';\nimport {\n detectFramework,\n discoverFeatures,\n gatherFrameworkContext,\n checkFrameworkVersion,\n} from '@lib/detection/index';\n\nexport async function detectPostHogIntegration(\n ctx: ProgramReadyContext,\n): Promise<void> {\n const session = ctx.session;\n const installDir = session.installDir;\n\n const detectedIntegration = await detectFramework(installDir);\n\n if (detectedIntegration) {\n const config = FRAMEWORK_REGISTRY[detectedIntegration];\n\n const sessionOptions = {\n installDir,\n debug: session.debug,\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: session.ci,\n benchmark: session.benchmark,\n yaraReport: session.yaraReport,\n };\n\n // Gather framework-specific context (e.g., router type)\n const context = await gatherFrameworkContext(config, sessionOptions);\n for (const [key, value] of Object.entries(context)) {\n if (!(key in session.frameworkContext)) {\n ctx.setFrameworkContext(key, value);\n }\n }\n\n ctx.setFrameworkConfig(detectedIntegration, config);\n // Must go through the store setter: setFrameworkConfig (above) calls\n // nanostore setKey, which replaces the session with a shallow copy —\n // a direct `session.skillId = ...` here would write to the stale\n // pre-copy object and the live session would never see it.\n ctx.setSkillId(detectedIntegration);\n\n if (!session.detectedFrameworkLabel) {\n ctx.setDetectedFramework(config.metadata.name);\n }\n\n // Version check\n const versionResult = await checkFrameworkVersion(config, sessionOptions);\n if (versionResult.supported !== true) {\n ctx.setUnsupportedVersion(versionResult.supported);\n }\n }\n\n // Feature discovery\n for (const feature of discoverFeatures(installDir)) {\n ctx.addDiscoveredFeature(feature);\n }\n\n ctx.setDetectionComplete();\n}\n","/**\n * PostHog integration program — the default wizard flow.\n *\n * Steps define their own gate predicates and onInit callbacks.\n * The store derives gate promises and fires init work from these\n * definitions — no hardcoded per-flow logic in the store.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\nimport { detectPostHogIntegration } from './detect.js';\n\nfunction needsSetup(session: WizardSession): boolean {\n const config = session.frameworkConfig;\n if (!config?.metadata.setup?.questions) return false;\n\n return config.metadata.setup.questions.some(\n (q: { key: string }) => !(q.key in session.frameworkContext),\n );\n}\n\nexport const POSTHOG_INTEGRATION_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting framework',\n // Headless step: no screen. onReady fires after bin.ts assigns the\n // session — runs framework detection, context gathering, version\n // check, and feature discovery. Results are written to the store\n // for the IntroScreen to render.\n onReady: (ctx) => detectPostHogIntegration(ctx),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'setup',\n label: 'Setup',\n screenId: 'setup',\n show: needsSetup,\n isComplete: (session) => !needsSetup(session),\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Integration',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'mcp',\n label: 'MCP servers',\n screenId: 'mcp',\n isComplete: (session) => session.mcpComplete,\n },\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n // Always shown — the user declines via Skip/esc, never bypassed.\n isComplete: (session) => session.slackStepDismissed,\n },\n {\n id: 'keep-skills',\n label: 'Keep Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Shared style constants for TUI layout primitives.\n */\n\nexport enum HAlign {\n Left = 'flex-start',\n Center = 'center',\n Right = 'flex-end',\n}\n\nexport enum VAlign {\n Top = 'flex-start',\n Center = 'center',\n Bottom = 'flex-end',\n}\n\nexport const Colors = {\n primary: 'cyan',\n accent: '#DC9300',\n titleColor: '#3D2800',\n success: 'green',\n error: 'red',\n muted: 'gray',\n} as const;\n\nexport const Icons = {\n diamond: '\\u25C6',\n diamondOpen: '\\u25C7',\n check: '\\u2714',\n warning: '\\u26A0',\n squareFilled: '\\u25FC',\n squareOpen: '\\u25FB',\n triangleRight: '\\u25B6',\n triangleSmallRight: '\\u25B8',\n bullet: '\\u2022',\n} as const;\n","/**\n * Text-splitting helpers for sentence boundary detection.\n * Used by TextBlock for animation pauses at punctuation.\n */\n\n/** Split text into sentences (keeps the delimiter attached) */\nexport function splitSentences(text: string): string[] {\n const parts: string[] = [];\n const re = /[^.!?]*[.!?]+\\s*/g;\n let match: RegExpExecArray | null;\n let lastIndex = 0;\n while ((match = re.exec(text)) !== null) {\n parts.push(match[0]);\n lastIndex = re.lastIndex;\n }\n if (lastIndex < text.length) {\n parts.push(text.slice(lastIndex));\n }\n return parts;\n}\n\n/** Build a set of character indices where sentences end (for typewriter pause) */\nexport function sentenceEndChars(text: string): Set<number> {\n const ends = new Set<number>();\n const sentences = splitSentences(text);\n let pos = 0;\n for (const s of sentences) {\n pos += s.length;\n ends.add(pos - 1);\n }\n return ends;\n}\n\n/** Build a set of word indices where sentences end (for word-by-word pause) */\nexport function sentenceEndWords(text: string): Set<number> {\n const ends = new Set<number>();\n const sentences = splitSentences(text);\n let wordCount = 0;\n for (const s of sentences) {\n const words = s.trim().split(/\\s+/).filter(Boolean);\n wordCount += words.length;\n ends.add(wordCount - 1);\n }\n return ends;\n}\n","/**\n * Content block types and type guards.\n *\n * Extracted from ContentSequencer so that pure-logic modules (like\n * layout-helpers) can import them without pulling in Ink/React.\n */\n\nimport type { ReactNode } from 'react';\nimport type { TextRevealMode } from './TextBlock.js';\n\n/** Object form — string or ReactNode content with per-block overrides. */\nexport interface ContentObjectBlock {\n content: string | ReactNode;\n mode?: TextRevealMode;\n animationInterval?: number;\n sentenceInterval?: number;\n pause?: number;\n persist?: boolean;\n /**\n * When the sequencer advances past this block, should it render dim?\n * Defaults to `true` — the standard \"completed step\" treatment. Set to\n * `false` to keep the block at full opacity even after it's complete\n * (useful for headings or greetings that should stay readable while\n * later blocks animate in).\n *\n * Only meaningful for blocks whose `content` is a string (TextBlock\n * renders the dim treatment). NodeBlocks render whatever JSX you pass\n * verbatim regardless of completion state.\n */\n dimWhenComplete?: boolean;\n}\n\n/** Lines block — reveals ReactNode lines one at a time. */\nexport interface ContentLinesBlock {\n type: 'lines';\n lines: ReactNode[];\n interval?: number;\n pause?: number;\n}\n\n/** Clear block — page break that hides all prior blocks. */\nexport interface ContentClearBlock {\n type: 'clear';\n pause?: number;\n}\n\n/** A content block in the sequence. Bare strings are sugar for { content: '...' }. */\nexport type ContentBlock =\n | string\n | ContentObjectBlock\n | ContentLinesBlock\n | ContentClearBlock;\n\n/** Type guard for lines blocks. */\nexport function isLinesBlock(block: ContentBlock): block is ContentLinesBlock {\n return typeof block !== 'string' && 'type' in block && block.type === 'lines';\n}\n\n/** Type guard for clear blocks. */\nexport function isClearBlock(block: ContentBlock): block is ContentClearBlock {\n return typeof block !== 'string' && 'type' in block && block.type === 'clear';\n}\n\n/** Type guard for object blocks (text or node content). */\nexport function isObjectBlock(\n block: ContentBlock,\n): block is ContentObjectBlock {\n return typeof block !== 'string' && !('type' in block);\n}\n","/**\n * Layout helpers — pure functions for height estimation and viewport eviction.\n *\n * These are the core of the responsive content system. They estimate how many\n * terminal rows a content block will occupy and determine which blocks fit\n * within a given height budget.\n */\n\nimport type { ContentBlock } from './content-types.js';\nimport { isLinesBlock, isClearBlock, isObjectBlock } from './content-types.js';\n\n/**\n * Estimate the number of terminal rows a content block will occupy,\n * including 1 row of marginBottom.\n */\nexport function estimateBlockHeight(\n block: ContentBlock,\n availableWidth: number,\n): number {\n if (typeof block === 'string') {\n return wordWrap(block, availableWidth).length + 1; // +1 for marginBottom\n }\n\n if (isClearBlock(block)) return 0;\n\n if (isLinesBlock(block)) {\n return block.lines.length + 1;\n }\n\n if (isObjectBlock(block)) {\n if (typeof block.content === 'string') {\n return wordWrap(block.content, availableWidth).length + 1;\n }\n return 4; // conservative fixed estimate for ReactNode\n }\n\n return 1;\n}\n\n/**\n * Given all blocks, the active index, available width, and a row budget,\n * return [startIdx, endIdx] — the range of blocks to render.\n *\n * Always includes activeIdx. Walks backward to include as many completed\n * blocks as fit within maxHeight.\n */\nexport function computeVisibleRange(\n blocks: ContentBlock[],\n activeIdx: number,\n availableWidth: number,\n maxHeight: number,\n): [number, number] {\n // Reserve a 2-row buffer so resize-induced estimate drift doesn't\n // cause overflow=\"hidden\" to clip the margin between blocks.\n const budget = Math.max(4, maxHeight - 2);\n\n let totalHeight = estimateBlockHeight(blocks[activeIdx], availableWidth);\n let start = activeIdx;\n\n for (let i = activeIdx - 1; i >= 0; i--) {\n // Clear blocks act as a hard boundary — don't show anything before them\n if (isClearBlock(blocks[i])) break;\n const h = estimateBlockHeight(blocks[i], availableWidth);\n if (totalHeight + h > budget) break;\n totalHeight += h;\n start = i;\n }\n\n return [start, activeIdx];\n}\n\n/**\n * Word-wrap text at clean word boundaries. Always returns pre-wrapped text\n * joined with \\n — this avoids Ink's native wrap which can leave leading\n * spaces on continuation lines.\n *\n * Uses a 1-char safety margin so slight width estimate mismatches don't\n * cause Ink to re-wrap our already-wrapped lines.\n */\nexport function wordWrap(text: string, availableWidth: number): string[] {\n const safeWidth = Math.max(10, availableWidth - 1);\n const words = text.split(/\\s+/);\n const lines: string[] = [];\n let currentLine = '';\n\n for (const word of words) {\n if (\n currentLine.length + word.length + 1 > safeWidth &&\n currentLine.length > 0\n ) {\n lines.push(currentLine);\n currentLine = word;\n } else {\n currentLine += (currentLine.length > 0 ? ' ' : '') + word;\n }\n }\n if (currentLine.length > 0) {\n lines.push(currentLine);\n }\n\n return lines;\n}\n\n/**\n * Word-wrap text and return only the last `maxRows` lines.\n * Used for intra-block truncation when a single text block exceeds the viewport.\n * Also used for normal rendering to avoid Ink's leading-space wrap artifacts.\n */\nexport function wrapAndTruncate(\n text: string,\n availableWidth: number,\n maxRows: number,\n): string {\n const lines = wordWrap(text, availableWidth);\n\n if (lines.length <= maxRows) {\n return lines.join('\\n');\n }\n\n return lines.slice(-maxRows).join('\\n');\n}\n","/**\n * TextBlock — Animates a single string paragraph.\n *\n * Self-contained: owns its own animIdx and timer.\n * Calls onComplete() when the animation finishes.\n *\n * Five animation modes:\n * 1. Typewriter — character-by-character reveal\n * 2. Word by word — each word appears in order\n * 3. Sentence by sentence — sentences appear one at a time\n * 4. Paragraph fade — paragraph appears at full opacity immediately\n * 5. Sentence fade — paragraph dim, sentences light up in order\n */\n\nimport { Text } from 'ink';\nimport { useState, useEffect, useRef, useMemo, type ReactNode } from 'react';\nimport { Colors } from '@ui/tui/styles';\nimport {\n splitSentences,\n sentenceEndChars,\n sentenceEndWords,\n} from './text-helpers.js';\nimport { wrapAndTruncate } from './layout-helpers.js';\n\nexport enum TextRevealMode {\n Typewriter = 0,\n WordByWord = 1,\n SentenceBySentence = 2,\n ParagraphFade = 3,\n SentenceFade = 4,\n}\n\nexport const TEXT_REVEAL_MODE_LABELS = [\n 'Typewriter',\n 'Word by word',\n 'Sentence by sentence',\n 'Paragraph fade',\n 'Sentence fade',\n];\n\nexport const TEXT_REVEAL_MODE_COUNT = 5;\n\n/** Default interval per mode (ms) */\nexport const TEXT_REVEAL_MODE_DEFAULTS: Record<TextRevealMode, number> = {\n [TextRevealMode.WordByWord]: 240,\n [TextRevealMode.Typewriter]: 32,\n [TextRevealMode.SentenceBySentence]: 1800,\n [TextRevealMode.ParagraphFade]: 4800,\n [TextRevealMode.SentenceFade]: 2400,\n};\n\ninterface TextBlockProps {\n text: string;\n active: boolean;\n completed: boolean;\n onComplete: () => void;\n mode: TextRevealMode;\n bullet?: ReactNode;\n animationInterval?: number;\n sentenceInterval?: number;\n /** Max rows this block may occupy. When exceeded, top lines are truncated. */\n maxHeight?: number;\n /** Available text width in columns (for truncation wrapping). */\n availableWidth?: number;\n /**\n * When `completed === true`, render the text dim. Defaults to `true` —\n * the standard \"completed step\" treatment. Pass `false` to keep the\n * text at full opacity even after the sequencer has moved on.\n */\n dimWhenComplete?: boolean;\n}\n\nexport const TextBlock = ({\n text,\n active,\n completed,\n onComplete,\n mode,\n bullet,\n animationInterval,\n sentenceInterval = 1600,\n maxHeight,\n availableWidth,\n dimWhenComplete = true,\n}: TextBlockProps) => {\n const speed = animationInterval ?? TEXT_REVEAL_MODE_DEFAULTS[mode];\n\n const [animIdx, setAnimIdx] = useState(\n mode === TextRevealMode.SentenceFade ? 1 : 0,\n );\n\n // Reset synchronously during render to avoid a one-frame flash\n const resetRef = useRef(0);\n const prevMode = useRef(mode);\n if (prevMode.current !== mode) {\n prevMode.current = mode;\n resetRef.current += 1;\n setAnimIdx(mode === TextRevealMode.SentenceFade ? 1 : 0);\n }\n\n const words = text.split(/\\s+/);\n const sentences = splitSentences(text);\n\n const sentenceCharEnds = useMemo(() => sentenceEndChars(text), [text]);\n const sentenceWordEnds = useMemo(() => sentenceEndWords(text), [text]);\n\n const isDone =\n mode === TextRevealMode.Typewriter\n ? animIdx >= text.length\n : mode === TextRevealMode.ParagraphFade\n ? true\n : mode === TextRevealMode.WordByWord\n ? animIdx >= words.length\n : mode === TextRevealMode.SentenceFade ||\n mode === TextRevealMode.SentenceBySentence\n ? animIdx >= sentences.length\n : true;\n\n // Fire onComplete when done\n useEffect(() => {\n if (isDone && active) onComplete();\n }, [isDone, active, onComplete]);\n\n // Animate: single effect for all tick-based modes\n useEffect(() => {\n if (!active || mode === TextRevealMode.ParagraphFade || isDone) return;\n const token = resetRef.current;\n\n const isFirstTick = animIdx === 0;\n\n let delay = isFirstTick ? 0 : speed;\n if (\n !isFirstTick &&\n mode === TextRevealMode.Typewriter &&\n animIdx > 0 &&\n sentenceCharEnds.has(animIdx - 1)\n ) {\n delay = sentenceInterval;\n } else if (\n !isFirstTick &&\n mode === TextRevealMode.WordByWord &&\n animIdx > 0 &&\n sentenceWordEnds.has(animIdx - 1)\n ) {\n delay = sentenceInterval;\n }\n\n const timer = setTimeout(() => {\n if (token !== resetRef.current) return;\n setAnimIdx((c) => c + 1);\n }, delay);\n return () => clearTimeout(timer);\n }, [\n active,\n mode,\n animIdx,\n isDone,\n speed,\n sentenceInterval,\n sentenceCharEnds,\n sentenceWordEnds,\n ]);\n\n // Pre-wrap text ourselves to avoid Ink's native wrap leaving leading spaces\n // on continuation lines. When maxHeight is set, also truncates to last N rows.\n const wrap = (visibleText: string): string => {\n if (availableWidth == null) return visibleText;\n if (maxHeight == null) {\n return wrapAndTruncate(visibleText, availableWidth, Infinity);\n }\n return wrapAndTruncate(visibleText, availableWidth, maxHeight);\n };\n\n // Completed: dimmed by default, but can be overridden per-block.\n if (completed) {\n return (\n <Text dimColor={dimWhenComplete}>\n {bullet}\n {wrap(text)}\n </Text>\n );\n }\n\n // Active: mode-specific rendering\n if (mode === TextRevealMode.Typewriter) {\n const revealed = text.slice(0, animIdx);\n const atSentenceEnd = /[.!?]\\s*$/.test(revealed);\n const display = atSentenceEnd ? revealed.trimEnd() : revealed;\n return (\n <Text>\n {bullet}\n {wrap(display)}\n <Text color={Colors.muted}>{'\\u258C'}</Text>\n </Text>\n );\n }\n\n if (mode === TextRevealMode.WordByWord) {\n const visible = words.slice(0, animIdx).join(' ');\n return (\n <Text>\n {bullet}\n {wrap(visible)}\n </Text>\n );\n }\n\n if (mode === TextRevealMode.ParagraphFade) {\n return (\n <Text>\n {bullet}\n {wrap(text)}\n </Text>\n );\n }\n\n if (mode === TextRevealMode.SentenceBySentence) {\n const visible = sentences.slice(0, animIdx).join('');\n return (\n <Text>\n {bullet}\n {wrap(visible)}\n </Text>\n );\n }\n\n // SentenceFade\n return (\n <Text>\n {bullet}\n {sentences.map((s, si) => (\n <Text key={si} dimColor={si >= animIdx}>\n {s}\n </Text>\n ))}\n </Text>\n );\n};\n","/**\n * StatusPeekTrigger — Fires the status-bar expansion once, renders a hint.\n *\n * Module-level `peekedOnce` guards against re-mounts (resize, tab switch)\n * so the peek only happens a single time per process.\n */\n\nimport { Text } from 'ink';\nimport { useEffect } from 'react';\nimport type { WizardStore } from '@ui/tui/store';\n\nlet peekedOnce = false;\n\ninterface StatusPeekTriggerProps {\n store?: WizardStore;\n /** How long the status bar stays expanded, in ms. */\n duration?: number;\n}\n\nexport const StatusPeekTrigger = ({\n store,\n duration = 10000,\n}: StatusPeekTriggerProps) => {\n useEffect(() => {\n if (peekedOnce) return;\n peekedOnce = true;\n store?.setStatusExpanded(true);\n // No cleanup — the store call is safe after unmount and the component\n // may be evicted before the timer fires (non-persist NodeBlock).\n setTimeout(() => {\n store?.setStatusExpanded(false);\n }, duration);\n }, [store, duration]);\n\n return <Text>You can view the Wizard's status below.</Text>;\n};\n","/**\n * POSTHOG_DATA_FLOW — ASCII diagram of the PostHog event ingestion flow.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const POSTHOG_DATA_FLOW: ContentBlock = {\n type: 'lines',\n interval: 500,\n pause: 8000,\n // Box is 30 chars wide between │ borders.\n // Labels: 1-char indent. Arrows: \" ↓ \" (5). Sub-items: \" │ \" (7).\n lines: [\n <Text color=\"gray\">{' ┌──────────────────────────────┐'}</Text>,\n <Text>\n <Text color=\"gray\">{' │ '}</Text>\n <Text bold color=\"cyan\">\n Your App\n </Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ │ '}</Text>\n <Text>posthog.capture()</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ │ '}</Text>\n <Text dimColor>custom events</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ │ '}</Text>\n <Text dimColor>custom properties</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ │ '}</Text>\n <Text dimColor>person profiles</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ ↓ '}</Text>\n <Text dimColor>groups</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ '}</Text>\n <Text bold color={Colors.accent}>\n PostHog SDK\n </Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ ↓ '}</Text>\n <Text>HTTP</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ '}</Text>\n <Text bold color={Colors.accent}>\n PostHog Cloud\n </Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ ↓ '}</Text>\n <Text>query + visualize</Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │ '}</Text>\n <Text bold color=\"green\">\n Dashboards & Insights\n </Text>\n <Text color=\"gray\">{' │'}</Text>\n </Text>,\n <Text color=\"gray\">{' └──────────────────────────────┘'}</Text>,\n ],\n};\n","/**\n * PRODUCT_SUITE_BLOCK — Two-column listing of PostHog products.\n */\n\nimport { Text } from 'ink';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const PRODUCT_SUITE_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 1000,\n pause: 15000,\n lines: [\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Product Analytics '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Error Tracking'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Web Analytics '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Session Replay'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Feature Flags '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Data Pipelines'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Experiments '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Data Warehouse'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'LLM Analytics '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Surveys'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Workflows '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Logs'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Product Tours '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Support'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Revenue Analytics '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'Endpoints'}\n </Text>,\n <Text>\n <Text color=\"cyan\">{' ◆ '}</Text>\n {'Customer Analytics '}\n <Text color=\"cyan\">{'◆ '}</Text>\n {'PostHog Code'}\n </Text>,\n ],\n};\n","/**\n * LINE_CHART_BLOCK — ASCII trends chart illustrating an insight.\n */\n\nimport { Text } from 'ink';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const LINE_CHART_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 300,\n pause: 6000,\n lines: [\n <Text bold>{' Trends · user signups (monthly)'}</Text>,\n <Text> </Text>,\n // 10k\n <Text>\n <Text color=\"gray\">{' 10k ┤'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭──'}</Text>\n <Text dimColor>{' 9,575'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭╯'}</Text>\n </Text>,\n // 7.5k\n <Text>\n <Text color=\"gray\">{' 7.5k ┤'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭╯'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭─╯'}</Text>\n </Text>,\n // 5k\n <Text>\n <Text color=\"gray\">{' 5k ┤'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭─╯'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭──╯'}</Text>\n </Text>,\n // 2.5k\n <Text>\n <Text color=\"gray\">{' 2.5k ┤'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭───╯'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' │'}</Text>\n {' '}\n <Text color=\"cyan\">{'╭──────╯'}</Text>\n </Text>,\n // 0\n <Text>\n <Text color=\"gray\">{' 0 ┤'}</Text>\n <Text color=\"cyan\">{'──────╯'}</Text>\n </Text>,\n // X-axis\n <Text color=\"gray\">{' └┬─────┬─────┬─────┬─────┬──'}</Text>,\n <Text dimColor>{' May Aug Nov Feb May'}</Text>,\n ],\n};\n","/**\n * FUNNEL_BLOCK — ASCII funnel illustrating step conversion.\n */\n\nimport { Text } from 'ink';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const FUNNEL_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 200,\n pause: 8000,\n lines: [\n <Text bold>{' Funnel · ride conversion'}</Text>,\n <Text> </Text>,\n // Step 1\n <Text>\n {' '}\n <Text bold>1</Text>\n {' app_launched'}\n {' '}\n <Text bold color=\"green\">\n 100.00%\n </Text>\n </Text>,\n <Text color=\"cyan\">{' ██████████████████████████████'}</Text>,\n <Text dimColor>{' → 1,200 users'}</Text>,\n <Text> </Text>,\n // Step 2\n <Text>\n {' '}\n <Text bold>2</Text>\n {' ride_requested'}\n {' '}\n <Text dimColor>{'avg 2m 30s'}</Text>\n {' '}\n <Text bold color=\"green\">\n 72.00%\n </Text>\n </Text>,\n <Text>\n {' '}\n <Text color=\"cyan\">{'██████████████████████'}</Text>\n <Text dimColor>{'░░░░░░░░░'}</Text>\n </Text>,\n <Text>\n {' '}\n <Text dimColor>→ 864 users</Text>\n {' '}\n <Text color=\"red\">↘</Text>\n <Text dimColor>{' 336 (28%)'}</Text>\n </Text>,\n <Text> </Text>,\n // Step 3\n <Text>\n {' '}\n <Text bold>3</Text>\n {' ride_accepted'}\n {' '}\n <Text dimColor>{'avg 5m 12s'}</Text>\n {' '}\n <Text bold color=\"green\">\n 51.00%\n </Text>\n </Text>,\n <Text>\n {' '}\n <Text color=\"cyan\">{'██████████████████'}</Text>\n <Text dimColor>{'░░░░░░░░░░░░░'}</Text>\n </Text>,\n <Text>\n {' '}\n <Text dimColor>→ 612 users</Text>\n {' '}\n <Text color=\"red\">↘</Text>\n <Text dimColor>{' 252 (29%)'}</Text>\n </Text>,\n <Text> </Text>,\n // Step 4\n <Text>\n {' '}\n <Text bold>4</Text>\n {' ride_started'}\n {' '}\n <Text dimColor>{'avg 1m 45s'}</Text>\n {' '}\n <Text bold color=\"green\">\n 38.00%\n </Text>\n </Text>,\n <Text>\n {' '}\n <Text color=\"cyan\">{'█████████████'}</Text>\n <Text dimColor>{'░░░░░░░░░░░░░░░░░░'}</Text>\n </Text>,\n <Text>\n {' '}\n <Text dimColor>→ 456 users</Text>\n {' '}\n <Text color=\"red\">↘</Text>\n <Text dimColor>{' 156 (25%)'}</Text>\n </Text>,\n ],\n};\n","/**\n * Integration learn-deck — the narrative script played while the agent\n * runs the PostHog integration flow. Weaves typewriter lines, pauses,\n * `clear` markers, and the diagram blocks into one sequence.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { WizardStore } from '@ui/tui/store';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\nimport { StatusPeekTrigger } from '@ui/tui/components/StatusPeekTrigger';\nimport { POSTHOG_DATA_FLOW } from './data-flow.js';\nimport { PRODUCT_SUITE_BLOCK } from './product-suite.js';\nimport { LINE_CHART_BLOCK } from './line-chart.js';\nimport { FUNNEL_BLOCK } from './funnel.js';\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] => [\n {\n content: 'Welcome.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n\n { content: 'The Wizard is an agent.', pause: 4000 },\n\n {\n content: 'It handles the entire PostHog setup process on your behalf.',\n pause: 5000,\n },\n\n {\n content:\n \"As we speak, it's building a plan to set up PostHog in your project.\",\n pause: 6000,\n },\n\n { type: 'clear', pause: 2000 },\n\n {\n pause: 5000,\n persist: true,\n content: <StatusPeekTrigger store={store} />,\n },\n\n {\n pause: 6000,\n content: (\n <Text>\n Press{' '}\n <Text color={Colors.accent} bold>\n S\n </Text>{' '}\n to expand or collapse the status.\n </Text>\n ),\n },\n\n { type: 'clear', pause: 2000 },\n\n {\n content: 'It takes about eight minutes.',\n pause: 2000,\n },\n\n {\n content: 'So grab some coffee ☕️.',\n pause: 2000,\n },\n\n {\n content: 'Or stick around and learn about PostHog.',\n pause: 5000,\n },\n\n { type: 'clear', pause: 3000 },\n\n {\n content: 'Events are the foundation of the PostHog platform.',\n pause: 4000,\n },\n\n {\n content:\n 'Every time an action is performed in your codebase — like button clicks, function calls, or thrown errors — we can capture an event.',\n pause: 6000,\n },\n\n {\n content: 'Events are sent to PostHog and joined with other product data.',\n pause: 6000,\n },\n\n { type: 'clear', pause: 1000 },\n\n { content: \"Here's the flow.\", pause: 1000 },\n\n POSTHOG_DATA_FLOW,\n\n { type: 'clear', pause: 2000 },\n\n {\n content:\n 'With enough event data, you can answer powerful questions about your product.',\n pause: 4000,\n },\n\n { content: 'And create insights.', pause: 4000 },\n\n { type: 'clear', pause: 500 },\n\n { content: 'Like trends to measure growth.', pause: 2500 },\n\n LINE_CHART_BLOCK,\n\n { type: 'clear', pause: 500 },\n\n { content: 'Or funnels to reveal bottlenecks.', pause: 2500 },\n\n FUNNEL_BLOCK,\n\n { type: 'clear', pause: 1000 },\n\n {\n content: 'Use those signals to decide what to build next.',\n pause: 4000,\n },\n\n { content: 'PostHog has all the dev tools you need.', pause: 3000 },\n\n PRODUCT_SUITE_BLOCK,\n];\n","/**\n * The coding-agent handoff prompt.\n *\n * The wizard finishes a successful run by emitting `posthog-setup-report.md` —\n * which now ends with a \"Verify before merging\" checklist the agent fills in\n * from the context-mill skill (see the basic-integration conclude step). This\n * is the one-line prompt the operator pastes into their own coding agent to\n * close the gap between \"wizard finished\" and \"PostHog merged\": read the\n * report, work the checklist, open a PR.\n *\n * Kept as a pure helper so the exact wording is easy to review and test in\n * isolation. It is surfaced through `OutroData.handoffPrompt`, which the wizard\n * prints to the terminal's main buffer on exit (where it survives in scrollback\n * and stays triple-click-selectable); it is NOT written into any file — the\n * verification content itself lives in the report.\n *\n * The wording asks the agent to investigate each checklist item and get the\n * operator's explicit consent before making any changes — so actions with real\n * implications (e.g. uploading source maps, editing CI) are surfaced and\n * approved, not applied silently. It deliberately stops there: no PR mandate or\n * edit-style rules, since the operator pastes this into their own agent and\n * governs how changes ultimately land.\n *\n * Background: https://github.com/PostHog/wizard/issues/447\n */\nexport function buildCodingAgentPrompt(reportFile: string): string {\n return `Read \\`${reportFile}\\` and work through its \"Verify before merging\" checklist: investigate each item, then list the changes you'd make and get my approval before applying any of them.`;\n}\n","import type { ProgramConfig, ProgramStep } from '@lib/programs/program-step';\nimport { runAgent, type ProgramRun } from '@lib/agent/agent-runner';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind, RunPhase } from '@lib/wizard-session';\nimport { AgentSignals } from '@lib/agent/agent-interface';\nimport {\n DEFAULT_PACKAGE_INSTALLATION,\n SPINNER_MESSAGE,\n} from '@lib/framework-config';\nimport { tryGetPackageJson, isUsingTypeScript } from '@utils/setup-utils';\nimport { analytics } from '@utils/analytics';\nimport { detectFramework, gatherFrameworkContext } from '@lib/detection/index';\nimport { FRAMEWORK_REGISTRY } from '@lib/registry';\nimport { wizardAbort } from '@utils/wizard-abort';\nimport { WIZARD_INTERACTION_EVENT_NAME } from '@lib/constants';\nimport { getUI } from '@ui/index';\nimport { HostResolution } from '@lib/host-resolution';\nimport { requestDeepLink } from '@utils/provisioning';\nimport { openTrackedLink, withUtm } from '@utils/links';\nimport type { CloudRegion } from '@utils/types';\nimport { POSTHOG_INTEGRATION_PROGRAM } from './steps.js';\nimport { getContentBlocks } from './content/index.js';\nimport { buildCodingAgentPrompt } from './handoff.js';\n\nconst DASHBOARD_DEEP_LINK_KEY = 'dashboardDeepLink';\n\nfunction resolveContinueUrl(\n session: WizardSession,\n cloudRegion: CloudRegion | undefined,\n deepLink: unknown,\n): string | undefined {\n if (!session.signup) return undefined;\n if (typeof deepLink === 'string' && deepLink) return deepLink;\n if (cloudRegion)\n // TODO: clean up in #755\n return withUtm(\n `${\n HostResolution.fromRegion(cloudRegion, { baseUrl: session.baseUrl })\n .appHost\n }/products?source=wizard`,\n 'outro-continue',\n );\n return undefined;\n}\n\nexport const SETUP_REPORT_FILE = 'posthog-setup-report.md';\nexport { EVENT_PLAN_FILE } from './constants.js';\n\nexport const posthogIntegrationConfig: ProgramConfig = {\n command: 'integrate',\n description: 'Set up PostHog SDK integration',\n id: 'posthog-integration',\n steps: POSTHOG_INTEGRATION_PROGRAM,\n getContentBlocks,\n // Basic integration runs without structured user input; drop wizard_ask\n // so the model can't pop modal prompts mid-run. The runner forwards this\n // list to the general-purpose subagent as well, so dispatched subagents\n // can't reach around the parent and ask either.\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n\n // CI-mode prerequisite work: the headless equivalent of the detect step's\n // onReady hook. Auto-detect the framework, then gather context.\n ciPreRun: async (session: WizardSession): Promise<void> => {\n const integration = await detectFramework(session.installDir);\n if (!integration) {\n await wizardAbort({\n message: 'Could not auto-detect your framework for this project.',\n });\n return;\n }\n session.integration = integration;\n analytics.setTag('integration', integration);\n\n const frameworkConfig = FRAMEWORK_REGISTRY[integration];\n session.frameworkConfig = frameworkConfig;\n\n const context = await gatherFrameworkContext(frameworkConfig, {\n installDir: session.installDir,\n debug: session.debug,\n // `default` is required by WizardRunOptions but unused by detection; the\n // --default CLI flag was removed, so this is always false here.\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: true,\n benchmark: session.benchmark,\n yaraReport: session.yaraReport,\n });\n for (const [key, value] of Object.entries(context)) {\n if (!(key in session.frameworkContext)) {\n session.frameworkContext[key] = value;\n }\n }\n },\n\n run: async (session: WizardSession): Promise<ProgramRun> => {\n const config = session.frameworkConfig!;\n\n const typeScriptDetected = isUsingTypeScript({\n installDir: session.installDir,\n });\n session.typescript = typeScriptDetected;\n\n // Read package.json and resolve framework version\n const usesPackageJson = config.detection.usesPackageJson !== false;\n let frameworkVersion: string | undefined;\n\n if (usesPackageJson) {\n const packageJson = await tryGetPackageJson({\n installDir: session.installDir,\n });\n if (packageJson) {\n const { hasDeclaredDependency } = await import('@utils/package-json');\n if (!hasDeclaredDependency(config.detection.packageName, packageJson)) {\n getUI().log.warn(\n `${config.detection.packageDisplayName} does not seem to be installed. Continuing anyway — the agent will handle it.`,\n );\n }\n frameworkVersion = config.detection.getVersion(packageJson);\n } else {\n getUI().log.warn(\n 'Could not find package.json. Continuing anyway — the agent will handle it.',\n );\n }\n } else {\n frameworkVersion = config.detection.getVersion(null);\n }\n\n // Analytics tags\n if (frameworkVersion && config.detection.getVersionBucket) {\n const versionBucket = config.detection.getVersionBucket(frameworkVersion);\n analytics.setTag(`${config.metadata.integration}-version`, versionBucket);\n }\n const frameworkContext = session.frameworkContext;\n const contextTags = config.analytics.getTags(frameworkContext);\n Object.entries(contextTags).forEach(([key, value]) => {\n analytics.setTag(key, value);\n });\n\n return {\n integrationLabel: config.metadata.integration,\n additionalMcpServers: config.metadata.additionalMcpServers,\n detectPackageManager: config.detection.detectPackageManager,\n spinnerMessage: SPINNER_MESSAGE,\n successMessage: config.ui.successMessage,\n estimatedDurationMinutes: config.ui.estimatedDurationMinutes,\n reportFile: SETUP_REPORT_FILE,\n docsUrl: config.metadata.docsUrl,\n errorMessage: 'Integration failed',\n additionalFeatureQueue: session.additionalFeatureQueue,\n\n customPrompt: (ctx) => {\n const additionalLines = config.prompts.getAdditionalContextLines\n ? config.prompts.getAdditionalContextLines(frameworkContext)\n : [];\n const additionalContext =\n additionalLines.length > 0\n ? '\\n' + additionalLines.map((line) => `- ${line}`).join('\\n')\n : '';\n\n return `You have access to the PostHog MCP server which provides skills to integrate PostHog into this ${\n config.metadata.name\n } project.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- Framework: ${config.metadata.name} ${frameworkVersion || 'latest'}\n- TypeScript: ${typeScriptDetected ? 'Yes' : 'No'}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host}\n- Project type: ${config.prompts.projectTypeDetection}\n- Package installation: ${\n config.prompts.packageInstallation ?? DEFAULT_PACKAGE_INSTALLATION\n }${additionalContext}\n\nInstructions (follow these steps IN ORDER - do not skip or reorder):\n\nSTEP 1: Call load_skill_menu (from the wizard-tools MCP server) to see available skills.\n If the tool fails, emit: ${\n AgentSignals.ERROR_MCP_MISSING\n } Could not load skill menu and halt.\n\n Choose a skill from the \\`integration\\` category that matches this project's framework. Do NOT pick skills from other categories (llm-analytics, error-tracking, feature-flags, omnibus, etc.) — those are handled separately.\n If no suitable integration skill is found, emit: ${\n AgentSignals.ERROR_RESOURCE_MISSING\n } Could not find a suitable skill for this project.\n\nSTEP 2: Call install_skill (from the wizard-tools MCP server) with the chosen skill ID (e.g., \"integration-nextjs-app-router\").\n Do NOT run any shell commands to install skills.\n\nSTEP 3: Load the installed skill's SKILL.md file to understand what references are available.\n\nSTEP 4: Follow the skill's program files in sequence. Look for numbered program files in the references (e.g., files with patterns like \"1-\", \"2-\", \"3-\"). Start with the first one and proceed through each step until completion. Each program file will tell you what to do and which file comes next. Never directly write PostHog tokens directly to code files; always use environment variables.\n\nSTEP 5: Set up environment variables for PostHog using the wizard-tools MCP server (this runs locally — secret values never leave the machine):\n - Use check_env_keys to see which keys already exist in the project's .env file (e.g. .env.local or .env).\n - Use set_env_values to create or update the PostHog public token and host, using the appropriate environment variable naming convention for ${\n config.metadata.name\n }, which you'll find in example code. The tool will also ensure .gitignore coverage. Don't assume the presence of keys means the value is up to date. Write the correct value each time.\n - Reference these environment variables in the code files you create instead of hardcoding the public token and host.\n\nImportant: Use the detect_package_manager tool (from the wizard-tools MCP server) to determine which package manager the project uses, then run its install command to add the SDK. Do not manually search for lockfiles or config files. You must read a file immediately before attempting to write it, even if you have previously read it; failure to do so will cause a tool failure.\n\n\n`;\n },\n\n postRun: async (sess, credentials) => {\n const envVars = config.environment.getEnvVars(\n credentials.projectApiKey,\n credentials.host,\n );\n if (config.environment.uploadToHosting) {\n const { uploadEnvironmentVariablesStep } = await import(\n '@steps/index'\n );\n const uploadedEnvVars = await uploadEnvironmentVariablesStep(\n envVars,\n {\n integration: config.metadata.integration,\n session: sess,\n },\n );\n if (uploadedEnvVars.length > 0) {\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'wizard_env_vars_uploaded',\n integration: config.metadata.integration,\n variable_count: uploadedEnvVars.length,\n variable_keys: uploadedEnvVars,\n });\n }\n }\n\n if (sess.signup) {\n const deepLink = await requestDeepLink(\n credentials.accessToken,\n credentials.host,\n );\n if (deepLink) {\n const taggedDeepLink = withUtm(deepLink, 'dashboard-deeplink');\n sess.frameworkContext[DASHBOARD_DEEP_LINK_KEY] = taggedDeepLink;\n openTrackedLink(taggedDeepLink, 'dashboard-deeplink', {\n auto: true,\n });\n }\n }\n },\n\n buildOutroData: (sess, credentials, cloudRegion) => {\n const envVars = config.environment.getEnvVars(\n credentials.projectApiKey,\n credentials.host,\n );\n const deepLink = sess.frameworkContext[DASHBOARD_DEEP_LINK_KEY];\n const continueUrl = resolveContinueUrl(sess, cloudRegion, deepLink);\n\n const changes = [\n ...config.ui.getOutroChanges(frameworkContext),\n Object.keys(envVars).length > 0\n ? 'Added environment variables to .env file'\n : '',\n ].filter(Boolean);\n\n return {\n kind: OutroKind.Success as const,\n message: 'Successfully installed PostHog!',\n reportFile: SETUP_REPORT_FILE,\n changes,\n docsUrl: config.metadata.docsUrl,\n continueUrl,\n handoffPrompt: buildCodingAgentPrompt(SETUP_REPORT_FILE),\n };\n },\n };\n },\n};\n\nexport { POSTHOG_INTEGRATION_PROGRAM } from './steps.js';\n\n/**\n * Self-contained run step that runs the integration agent. Other programs\n * import this and splice it into their own step list to compose the\n * integration's work as one of their run steps — self-driving sets up PostHog\n * this way before its own run. The host program supplies `show`/`onRunPrep`/\n * `targetDir`; this carries the run.\n */\nexport const integrationRunStep: ProgramStep = {\n id: 'run',\n label: 'Integration',\n screenId: 'run',\n // composed: runs inside the host program (self-driving), so skip the\n // integration's terminal outro + analytics shutdown of the shared client.\n run: (session) =>\n runAgent(posthogIntegrationConfig, session, { composed: true }),\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n};\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { s as resolveBaseUrl } from "./urls-
|
|
2
|
+
import { J as POSTHOG_US_CLIENT_ID, it as WIZARD_PROVISIONING_SCOPES, s as logToFile, st as WIZARD_USER_AGENT, z as POSTHOG_DEV_CLIENT_ID } from "./debug-D1lORUFs.js";
|
|
3
|
+
import { n as analytics } from "./analytics-Ciob-x8a.js";
|
|
4
|
+
import { s as resolveBaseUrl } from "./urls-CilgPbS-.js";
|
|
5
5
|
import axios from "axios";
|
|
6
6
|
import * as crypto from "node:crypto";
|
|
7
7
|
import { z } from "zod";
|
|
@@ -191,4 +191,4 @@ async function requestDeepLink(accessToken, host, opts) {
|
|
|
191
191
|
//#endregion
|
|
192
192
|
export { provisioning_exports as n, requestDeepLink as r, provisionNewAccount as t };
|
|
193
193
|
|
|
194
|
-
//# sourceMappingURL=provisioning-
|
|
194
|
+
//# sourceMappingURL=provisioning-CgomM26T.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioning-BIuAPRcH.js","names":[],"sources":["../src/utils/provisioning.ts"],"sourcesContent":["/**\n * Provisioning API client for creating new PostHog accounts.\n *\n * Uses the agentic provisioning API with PKCE auth:\n * 1. POST /account_requests - create account, get auth code\n * 2. POST /oauth/token - exchange code for tokens (with PKCE)\n * 3. POST /resources - provision project, get API key\n */\n\nimport * as crypto from 'node:crypto';\nimport axios from 'axios';\nimport { z } from 'zod';\nimport {\n POSTHOG_DEV_CLIENT_ID,\n POSTHOG_US_CLIENT_ID,\n WIZARD_PROVISIONING_SCOPES,\n WIZARD_USER_AGENT,\n} from '@lib/constants';\nimport { resolveBaseUrl } from './urls';\nimport { logToFile } from './debug';\nimport { analytics } from './analytics';\n\nconst API_VERSION = '0.1d';\n\n/**\n * Provisioning host. Follows a `--base-url` override (and IS_DEV → localhost),\n * else the region-agnostic prod provisioning host (always US; the target region\n * is passed in the request body).\n *\n * // TODO: Make this work with EU provisioning.\n */\nconst getProvisioningBaseUrl = (baseUrl?: string): string =>\n resolveBaseUrl(baseUrl) ?? 'https://us.posthog.com';\n\n/**\n * OAuth client ID for provisioning. A pinned base URL means a dev-seeded stack\n * that registers the dev client; prod uses the US client.\n *\n * TODO: same assumption as `getOAuthClientId` in oauth.ts — a pinned base URL is\n * treated as a dev-seeded instance. Make configurable if we ever point\n * `--base-url` at a non-dev instance with its own OAuth app.\n *\n * TODO: Make this work with EU provisioning.\n */\nconst getProvisioningClientId = (baseUrl?: string): string =>\n resolveBaseUrl(baseUrl) ? POSTHOG_DEV_CLIENT_ID : POSTHOG_US_CLIENT_ID;\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\n// --- Response schemas ---\n\nconst AccountRequestResponseSchema = z.object({\n id: z.string(),\n type: z.enum(['oauth', 'requires_auth', 'error']),\n oauth: z\n .object({\n code: z.string(),\n })\n .optional(),\n error: z\n .object({\n code: z.string(),\n message: z.string(),\n })\n .optional(),\n});\n\nconst TokenResponseSchema = z.object({\n token_type: z.string(),\n access_token: z.string(),\n refresh_token: z.string(),\n expires_in: z.number(),\n account: z\n .object({\n id: z.string(),\n })\n .optional(),\n});\n\nconst ResourceResponseSchema = z.object({\n status: z.string(),\n id: z.string(),\n service_id: z.string(),\n complete: z\n .object({\n access_configuration: z.object({\n api_key: z.string(),\n host: z.string(),\n personal_api_key: z.string().optional(),\n }),\n })\n .optional(),\n});\n\nexport interface ProvisioningResult {\n accessToken: string;\n refreshToken: string;\n projectApiKey: string;\n host: string;\n personalApiKey?: string;\n projectId: string;\n accountId: string;\n}\n\n/**\n * Create a new PostHog account and provision a project via the provisioning API.\n *\n * This is the \"no browser\" signup path: the wizard collects the email,\n * calls the provisioning API to create the account, and gets back\n * credentials without opening a browser.\n */\nexport async function provisionNewAccount(\n email: string,\n name: string,\n region: 'US' | 'EU' = 'US',\n opts?: { orgName?: string; projectName?: string; baseUrl?: string },\n): Promise<ProvisioningResult> {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n const provisioningBaseUrl = getProvisioningBaseUrl(opts?.baseUrl);\n\n logToFile('[provisioning] starting account creation');\n\n // Step 1: Create account\n const accountRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/provisioning/account_requests`,\n {\n id: crypto.randomUUID(),\n email,\n name,\n client_id: getProvisioningClientId(opts?.baseUrl),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n scopes: WIZARD_PROVISIONING_SCOPES,\n configuration: {\n region,\n ...(opts?.orgName ? { organization_name: opts.orgName } : {}),\n },\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const accountData = AccountRequestResponseSchema.parse(accountRes.data);\n\n if (accountData.type === 'error') {\n const msg = accountData.error?.message ?? 'Account creation failed';\n analytics.captureException(new Error(msg), {\n step: 'provisioning_account_request',\n error_code: accountData.error?.code,\n });\n throw new Error(msg);\n }\n\n if (accountData.type === 'requires_auth') {\n throw new Error(\n 'This email is already associated with a PostHog account. Please use the login flow instead.',\n );\n }\n\n const code = accountData.oauth?.code;\n if (!code) {\n throw new Error('No authorization code received from account creation');\n }\n\n logToFile('[provisioning] account created, exchanging code for tokens');\n\n // Step 2: Exchange code for tokens\n const tokenRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/oauth/token`,\n new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n code_verifier: codeVerifier,\n }).toString(),\n {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const tokenData = TokenResponseSchema.parse(tokenRes.data);\n\n logToFile('[provisioning] tokens received, provisioning resources');\n\n // Step 3: Provision resources\n const resourceRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/provisioning/resources`,\n {\n service_id: 'analytics',\n ...(opts?.projectName\n ? { configuration: { project_name: opts.projectName } }\n : {}),\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${tokenData.access_token}`,\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const resourceData = ResourceResponseSchema.parse(resourceRes.data);\n\n if (resourceData.status !== 'complete' || !resourceData.complete) {\n throw new Error('Resource provisioning did not complete');\n }\n\n logToFile('[provisioning] resources provisioned successfully');\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n projectApiKey: resourceData.complete.access_configuration.api_key,\n host: resourceData.complete.access_configuration.host,\n personalApiKey: resourceData.complete.access_configuration.personal_api_key,\n projectId: resourceData.id,\n accountId: tokenData.account?.id ?? '',\n };\n}\n\n/**\n * Request a one-time deep link URL that logs the user into PostHog\n * and redirects to their project dashboard — or, when `opts.path` is\n * given, to any safe in-app relative path (e.g. the Signals inbox).\n */\nexport async function requestDeepLink(\n accessToken: string,\n host: string,\n opts?: { purpose?: string; path?: string },\n): Promise<string | null> {\n try {\n const baseUrl = host\n .replace('us.i.posthog.com', 'us.posthog.com')\n .replace('eu.i.posthog.com', 'eu.posthog.com');\n\n const res = await axios.post(\n `${baseUrl}/api/agentic/provisioning/deep_links`,\n {\n purpose: opts?.purpose ?? 'dashboard',\n ...(opts?.path ? { path: opts.path } : {}),\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 10_000,\n },\n );\n\n const url = res.data?.url;\n if (typeof url === 'string') {\n logToFile(`[provisioning] deep link created: ${url}`);\n return url;\n }\n return null;\n } catch {\n logToFile('[provisioning] deep link request failed, skipping');\n return null;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"provisioning-CgomM26T.js","names":[],"sources":["../src/utils/provisioning.ts"],"sourcesContent":["/**\n * Provisioning API client for creating new PostHog accounts.\n *\n * Uses the agentic provisioning API with PKCE auth:\n * 1. POST /account_requests - create account, get auth code\n * 2. POST /oauth/token - exchange code for tokens (with PKCE)\n * 3. POST /resources - provision project, get API key\n */\n\nimport * as crypto from 'node:crypto';\nimport axios from 'axios';\nimport { z } from 'zod';\nimport {\n POSTHOG_DEV_CLIENT_ID,\n POSTHOG_US_CLIENT_ID,\n WIZARD_PROVISIONING_SCOPES,\n WIZARD_USER_AGENT,\n} from '@lib/constants';\nimport { resolveBaseUrl } from './urls';\nimport { logToFile } from './debug';\nimport { analytics } from './analytics';\n\nconst API_VERSION = '0.1d';\n\n/**\n * Provisioning host. Follows a `--base-url` override (and IS_DEV → localhost),\n * else the region-agnostic prod provisioning host (always US; the target region\n * is passed in the request body).\n *\n * // TODO: Make this work with EU provisioning.\n */\nconst getProvisioningBaseUrl = (baseUrl?: string): string =>\n resolveBaseUrl(baseUrl) ?? 'https://us.posthog.com';\n\n/**\n * OAuth client ID for provisioning. A pinned base URL means a dev-seeded stack\n * that registers the dev client; prod uses the US client.\n *\n * TODO: same assumption as `getOAuthClientId` in oauth.ts — a pinned base URL is\n * treated as a dev-seeded instance. Make configurable if we ever point\n * `--base-url` at a non-dev instance with its own OAuth app.\n *\n * TODO: Make this work with EU provisioning.\n */\nconst getProvisioningClientId = (baseUrl?: string): string =>\n resolveBaseUrl(baseUrl) ? POSTHOG_DEV_CLIENT_ID : POSTHOG_US_CLIENT_ID;\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\n// --- Response schemas ---\n\nconst AccountRequestResponseSchema = z.object({\n id: z.string(),\n type: z.enum(['oauth', 'requires_auth', 'error']),\n oauth: z\n .object({\n code: z.string(),\n })\n .optional(),\n error: z\n .object({\n code: z.string(),\n message: z.string(),\n })\n .optional(),\n});\n\nconst TokenResponseSchema = z.object({\n token_type: z.string(),\n access_token: z.string(),\n refresh_token: z.string(),\n expires_in: z.number(),\n account: z\n .object({\n id: z.string(),\n })\n .optional(),\n});\n\nconst ResourceResponseSchema = z.object({\n status: z.string(),\n id: z.string(),\n service_id: z.string(),\n complete: z\n .object({\n access_configuration: z.object({\n api_key: z.string(),\n host: z.string(),\n personal_api_key: z.string().optional(),\n }),\n })\n .optional(),\n});\n\nexport interface ProvisioningResult {\n accessToken: string;\n refreshToken: string;\n projectApiKey: string;\n host: string;\n personalApiKey?: string;\n projectId: string;\n accountId: string;\n}\n\n/**\n * Create a new PostHog account and provision a project via the provisioning API.\n *\n * This is the \"no browser\" signup path: the wizard collects the email,\n * calls the provisioning API to create the account, and gets back\n * credentials without opening a browser.\n */\nexport async function provisionNewAccount(\n email: string,\n name: string,\n region: 'US' | 'EU' = 'US',\n opts?: { orgName?: string; projectName?: string; baseUrl?: string },\n): Promise<ProvisioningResult> {\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n const provisioningBaseUrl = getProvisioningBaseUrl(opts?.baseUrl);\n\n logToFile('[provisioning] starting account creation');\n\n // Step 1: Create account\n const accountRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/provisioning/account_requests`,\n {\n id: crypto.randomUUID(),\n email,\n name,\n client_id: getProvisioningClientId(opts?.baseUrl),\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n scopes: WIZARD_PROVISIONING_SCOPES,\n configuration: {\n region,\n ...(opts?.orgName ? { organization_name: opts.orgName } : {}),\n },\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const accountData = AccountRequestResponseSchema.parse(accountRes.data);\n\n if (accountData.type === 'error') {\n const msg = accountData.error?.message ?? 'Account creation failed';\n analytics.captureException(new Error(msg), {\n step: 'provisioning_account_request',\n error_code: accountData.error?.code,\n });\n throw new Error(msg);\n }\n\n if (accountData.type === 'requires_auth') {\n throw new Error(\n 'This email is already associated with a PostHog account. Please use the login flow instead.',\n );\n }\n\n const code = accountData.oauth?.code;\n if (!code) {\n throw new Error('No authorization code received from account creation');\n }\n\n logToFile('[provisioning] account created, exchanging code for tokens');\n\n // Step 2: Exchange code for tokens\n const tokenRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/oauth/token`,\n new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n code_verifier: codeVerifier,\n }).toString(),\n {\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const tokenData = TokenResponseSchema.parse(tokenRes.data);\n\n logToFile('[provisioning] tokens received, provisioning resources');\n\n // Step 3: Provision resources\n const resourceRes = await axios.post(\n `${provisioningBaseUrl}/api/agentic/provisioning/resources`,\n {\n service_id: 'analytics',\n ...(opts?.projectName\n ? { configuration: { project_name: opts.projectName } }\n : {}),\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${tokenData.access_token}`,\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 30_000,\n },\n );\n\n const resourceData = ResourceResponseSchema.parse(resourceRes.data);\n\n if (resourceData.status !== 'complete' || !resourceData.complete) {\n throw new Error('Resource provisioning did not complete');\n }\n\n logToFile('[provisioning] resources provisioned successfully');\n\n return {\n accessToken: tokenData.access_token,\n refreshToken: tokenData.refresh_token,\n projectApiKey: resourceData.complete.access_configuration.api_key,\n host: resourceData.complete.access_configuration.host,\n personalApiKey: resourceData.complete.access_configuration.personal_api_key,\n projectId: resourceData.id,\n accountId: tokenData.account?.id ?? '',\n };\n}\n\n/**\n * Request a one-time deep link URL that logs the user into PostHog\n * and redirects to their project dashboard — or, when `opts.path` is\n * given, to any safe in-app relative path (e.g. the Signals inbox).\n */\nexport async function requestDeepLink(\n accessToken: string,\n host: string,\n opts?: { purpose?: string; path?: string },\n): Promise<string | null> {\n try {\n const baseUrl = host\n .replace('us.i.posthog.com', 'us.posthog.com')\n .replace('eu.i.posthog.com', 'eu.posthog.com');\n\n const res = await axios.post(\n `${baseUrl}/api/agentic/provisioning/deep_links`,\n {\n purpose: opts?.purpose ?? 'dashboard',\n ...(opts?.path ? { path: opts.path } : {}),\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${accessToken}`,\n 'API-Version': API_VERSION,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n timeout: 10_000,\n },\n );\n\n const url = res.data?.url;\n if (typeof url === 'string') {\n logToFile(`[provisioning] deep link created: ${url}`);\n return url;\n }\n return null;\n } catch {\n logToFile('[provisioning] deep link request failed, skipping');\n return null;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import { a as createVersionBucket, i as tryGetPackageJson, s as detectAllPackageManagers } from "./setup-utils-
|
|
4
|
-
import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-
|
|
5
|
-
import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-
|
|
2
|
+
import { f as getUI } from "./debug-D1lORUFs.js";
|
|
3
|
+
import { a as createVersionBucket, i as tryGetPackageJson, s as detectAllPackageManagers } from "./setup-utils-DLGNk8T6.js";
|
|
4
|
+
import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-CDs1ZVKu.js";
|
|
5
|
+
import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-WKKQADHM.js";
|
|
6
6
|
import * as semver from "semver";
|
|
7
7
|
import { major, minVersion } from "semver";
|
|
8
8
|
import path from "path";
|
|
@@ -1967,11 +1967,12 @@ function getSwiftProjectTypeName(projectType) {
|
|
|
1967
1967
|
async function detectSwiftProjectType(options) {
|
|
1968
1968
|
const { installDir } = options;
|
|
1969
1969
|
const hasPackageSwift = fs$1.existsSync(path$1.join(installDir, "Package.swift"));
|
|
1970
|
-
const
|
|
1970
|
+
const hasXcodeGenSpec = fs$1.existsSync(path$1.join(installDir, "project.yml"));
|
|
1971
|
+
const xcodeProjects = await fg("*.{xcodeproj,xcworkspace}", {
|
|
1971
1972
|
cwd: installDir,
|
|
1972
1973
|
onlyDirectories: true
|
|
1973
1974
|
});
|
|
1974
|
-
if (hasPackageSwift && xcodeProjects.length === 0) return "spm";
|
|
1975
|
+
if (hasPackageSwift && xcodeProjects.length === 0 && !hasXcodeGenSpec) return "spm";
|
|
1975
1976
|
const swiftFiles = await fg("**/*.swift", {
|
|
1976
1977
|
cwd: installDir,
|
|
1977
1978
|
ignore: [
|
|
@@ -2013,10 +2014,12 @@ const SWIFT_AGENT_CONFIG = {
|
|
|
2013
2014
|
getVersion: () => void 0,
|
|
2014
2015
|
detect: async (options) => {
|
|
2015
2016
|
const { installDir } = options;
|
|
2016
|
-
|
|
2017
|
+
const xcodeProjects = await fg("*.{xcodeproj,xcworkspace}", {
|
|
2017
2018
|
cwd: installDir,
|
|
2018
2019
|
onlyDirectories: true
|
|
2019
|
-
})
|
|
2020
|
+
});
|
|
2021
|
+
const hasXcodeGenSpec = fs$1.existsSync(path$1.join(installDir, "project.yml"));
|
|
2022
|
+
if (xcodeProjects.length > 0 || hasXcodeGenSpec) {
|
|
2020
2023
|
if ((await fg("**/*.swift", {
|
|
2021
2024
|
cwd: installDir,
|
|
2022
2025
|
ignore: [
|
|
@@ -2905,4 +2908,4 @@ const FRAMEWORK_REGISTRY = {
|
|
|
2905
2908
|
//#endregion
|
|
2906
2909
|
export { SPINNER_MESSAGE as i, registry_exports as n, DEFAULT_PACKAGE_INSTALLATION as r, FRAMEWORK_REGISTRY as t };
|
|
2907
2910
|
|
|
2908
|
-
//# sourceMappingURL=registry-
|
|
2911
|
+
//# sourceMappingURL=registry-BQIX-25O.js.map
|