@posthog/wizard 2.21.0 → 2.22.1
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/README.md +14 -1
- package/dist/{OutroScreen-CqF6SdBo.js → AiOptInRequiredScreen-B8mgZbe5.js} +482 -59
- package/dist/AiOptInRequiredScreen-B8mgZbe5.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-DQHGhzt6.js → add-mcp-server-to-clients-lCxOS1A1.js} +12 -10
- package/dist/add-mcp-server-to-clients-lCxOS1A1.js.map +1 -0
- package/dist/{agent-interface-DE7txTqh.js → agent-interface-BPCzPvK-.js} +6 -5
- package/dist/{agent-interface-DE7txTqh.js.map → agent-interface-BPCzPvK-.js.map} +1 -1
- package/dist/{agent-runner-DUZ5OD6e.js → agent-runner-DgzF2mga.js} +13 -9
- package/dist/{agent-runner-DUZ5OD6e.js.map → agent-runner-DgzF2mga.js.map} +1 -1
- package/dist/{analytics-Bl5DPj_0.js → analytics-BZv-cKyn.js} +28 -4
- package/dist/analytics-BZv-cKyn.js.map +1 -0
- package/dist/{api-DuA0_88V.js → api-BkLZ8BWm.js} +3 -3
- package/dist/{api-DuA0_88V.js.map → api-BkLZ8BWm.js.map} +1 -1
- package/dist/bin.js +160 -49
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-BnOYI4mZ.js → ci-install-DBARq5LX.js} +4 -4
- package/dist/{ci-install-BnOYI4mZ.js.map → ci-install-DBARq5LX.js.map} +1 -1
- package/dist/{debug-h7Z9zEbD.js → debug-Ckumcrye.js} +189 -40
- package/dist/debug-Ckumcrye.js.map +1 -0
- package/dist/{debug-BVC48wlb.js → debug-DLsuyfln.js} +1 -1
- package/dist/{environment-uaLmtlH_.js → environment-DUh_8hqW.js} +3 -3
- package/dist/{environment-uaLmtlH_.js.map → environment-DUh_8hqW.js.map} +1 -1
- package/dist/{interactive-CW5gjyDd.js → interactive-DeiHgviS.js} +2 -2
- package/dist/{interactive-CW5gjyDd.js.map → interactive-DeiHgviS.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-DMDwaark.js → mcp-prompt-streaming-kEJgmB30.js} +4 -4
- package/dist/{mcp-prompt-streaming-DMDwaark.js.map → mcp-prompt-streaming-kEJgmB30.js.map} +1 -1
- package/dist/{non-interactive-DJrVQ4nS.js → non-interactive-I4ifOSau.js} +2 -2
- package/dist/{non-interactive-DJrVQ4nS.js.map → non-interactive-I4ifOSau.js.map} +1 -1
- package/dist/{package-manager-DCUBRbr-.js → package-manager-fUeLORHg.js} +2 -2
- package/dist/{package-manager-DCUBRbr-.js.map → package-manager-fUeLORHg.js.map} +1 -1
- package/dist/{playground-DCVaVeVD.js → playground-DLLIz4Ql.js} +135 -19
- package/dist/playground-DLLIz4Ql.js.map +1 -0
- package/dist/{posthog-integration-ChdwFPMj.js → posthog-integration-COcPewVt.js} +48 -16
- package/dist/posthog-integration-COcPewVt.js.map +1 -0
- package/dist/{provisioning-GeMkBMSR.js → provisioning-7xU12_S9.js} +3 -3
- package/dist/{provisioning-GeMkBMSR.js.map → provisioning-7xU12_S9.js.map} +1 -1
- package/dist/{registry-VSSRH3sU.js → registry-YwaF-aD8.js} +7 -20
- package/dist/registry-YwaF-aD8.js.map +1 -0
- package/dist/{setup-utils-BfV4pydt.js → setup-utils-Cr4FxJDl.js} +114 -58
- package/dist/setup-utils-Cr4FxJDl.js.map +1 -0
- package/dist/{start-tui-BRvm5VP9.js → start-tui--E4PXdwG.js} +323 -134
- package/dist/start-tui--E4PXdwG.js.map +1 -0
- package/dist/{steps-DA4uvSbg.js → steps-CxUxdK4V.js} +6 -6
- package/dist/{steps-DA4uvSbg.js.map → steps-CxUxdK4V.js.map} +1 -1
- package/dist/telemetry-BS7yw3TP.js +68 -0
- package/dist/telemetry-BS7yw3TP.js.map +1 -0
- package/dist/{urls-B66Ib2jT.js → urls-BW23_XbC.js} +2 -2
- package/dist/{urls-B66Ib2jT.js.map → urls-BW23_XbC.js.map} +1 -1
- package/dist/{wizard-abort-gMB1eV6T.js → wizard-abort-BPsnXKY5.js} +1 -1
- package/dist/{wizard-abort-D1_DnFjm.js → wizard-abort-E66_R4S7.js} +3 -3
- package/dist/{wizard-abort-D1_DnFjm.js.map → wizard-abort-E66_R4S7.js.map} +1 -1
- package/dist/wizard-session-G3VWD6hv.js.map +1 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/package.json +1 -1
- package/dist/OutroScreen-CqF6SdBo.js.map +0 -1
- package/dist/add-mcp-server-to-clients-DQHGhzt6.js.map +0 -1
- package/dist/analytics-Bl5DPj_0.js.map +0 -1
- package/dist/debug-h7Z9zEbD.js.map +0 -1
- package/dist/playground-DCVaVeVD.js.map +0 -1
- package/dist/posthog-integration-ChdwFPMj.js.map +0 -1
- package/dist/registry-VSSRH3sU.js.map +0 -1
- package/dist/setup-utils-BfV4pydt.js.map +0 -1
- package/dist/start-tui-BRvm5VP9.js.map +0 -1
- package/dist/telemetry-BRAonUea.js +0 -13
- package/dist/telemetry-BRAonUea.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { h as LoggingUI, m as setUI, p as getUI } from "./debug-
|
|
2
|
-
import { t as provisionNewAccount } from "./provisioning-
|
|
3
|
-
import { n as posthogIntegrationConfig } from "./posthog-integration-
|
|
1
|
+
import { h as LoggingUI, m as setUI, p as getUI } from "./debug-Ckumcrye.js";
|
|
2
|
+
import { t as provisionNewAccount } from "./provisioning-7xU12_S9.js";
|
|
3
|
+
import { n as posthogIntegrationConfig } from "./posthog-integration-COcPewVt.js";
|
|
4
4
|
import { t as runWizardCI } from "./bin.js";
|
|
5
5
|
//#region src/commands/basic-integration/ci-install.ts
|
|
6
6
|
/** CI-mode entry point: validate signup flags, optionally provision an account, then install. */
|
|
@@ -70,4 +70,4 @@ async function provisionForSignup(options) {
|
|
|
70
70
|
//#endregion
|
|
71
71
|
export { runCIInstall };
|
|
72
72
|
|
|
73
|
-
//# sourceMappingURL=ci-install-
|
|
73
|
+
//# sourceMappingURL=ci-install-DBARq5LX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-install-
|
|
1
|
+
{"version":3,"file":"ci-install-DBARq5LX.js","names":[],"sources":["../src/commands/basic-integration/ci-install.ts"],"sourcesContent":["import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { runWizardCI } from '@lib/runners';\nimport { provisionNewAccount } from '@utils/provisioning';\nimport { posthogIntegrationConfig } from '@lib/programs/posthog-integration/index';\n\ntype Options = Arguments & {\n region?: string;\n installDir?: string;\n apiKey?: string;\n signup?: boolean;\n email?: string;\n name?: string;\n projectId?: string;\n};\n\n/** CI-mode entry point: validate signup flags, optionally provision an account, then install. */\nexport function runCIInstall(argv: Arguments): void {\n const options = { ...argv } as Options;\n\n // Base CI validation (region/install-dir/api-key) is owned by runWizardCI.\n // runCIInstall only layers the signup branch on top.\n if (!options.apiKey && !options.signup) {\n return failCI(\n 'CI mode requires --api-key (personal API key phx_xxx). ' +\n 'To create a new account instead, use --signup --email you@example.com.',\n );\n }\n if (!options.apiKey && options.signup && !options.email) {\n return failCI('CI --signup requires --email to create a new account.');\n }\n warnOnUnexpectedKeyPrefix(options.apiKey);\n\n void (async () => {\n if (!options.apiKey && options.signup) {\n // Fail before the irreversible provisioning step rather than after it.\n if (!options.installDir) {\n return failCI(\n 'CI mode requires --install-dir (directory to install in)',\n );\n }\n const provisioned = await provisionForSignup(options);\n options.apiKey = provisioned.personalApiKey;\n if (options.projectId == null) options.projectId = provisioned.projectId;\n }\n runWizardCI(posthogIntegrationConfig, options);\n })().catch(() => {\n process.exit(1);\n });\n}\n\nfunction failCI(message: string): void {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n getUI().log.error(message);\n process.exit(1);\n}\n\n/** `phx_` is the personal-API-key prefix the LLM Gateway expects. */\nfunction warnOnUnexpectedKeyPrefix(apiKey: string | undefined): void {\n if (!apiKey || apiKey.startsWith('phx_')) return;\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n const prefix = apiKey.slice(0, 4);\n const hint =\n prefix === 'pha_'\n ? ' (pha_ is an OAuth access token — CI mode expects a personal API key)'\n : prefix === 'phc_'\n ? ' (phc_ is a project/client key — CI mode expects a personal API key)'\n : '';\n getUI().log.warn(\n `--api-key does not start with \"phx_\"${hint}. Continuing anyway, but the LLM Gateway may reject it with a 401.`,\n );\n}\n\n/**\n * Provision a new account and return its credentials. Throws on any failure\n * (after logging a user-facing message); the caller's `.catch` turns that\n * into a non-zero exit. The return type carries no failure sentinel.\n */\nasync function provisionForSignup(\n options: Options,\n): Promise<{ personalApiKey: string; projectId: string }> {\n setUI(new LoggingUI());\n getUI().intro('PostHog Wizard');\n const signupRegion = ((options.region as string) || 'us').toUpperCase() as\n | 'US'\n | 'EU';\n getUI().log.info(\n `Provisioning new PostHog account for ${String(\n options.email,\n )} in ${signupRegion}...`,\n );\n\n let result;\n try {\n result = await provisionNewAccount(\n options.email as string,\n options.name ?? '',\n signupRegion,\n );\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n getUI().log.error(`Provisioning failed: ${msg}`);\n throw error;\n }\n\n if (!result.personalApiKey) {\n getUI().log.error(\n 'Provisioning succeeded but no personal API key was returned — cannot continue install.',\n );\n throw new Error('provisioning returned no personal API key');\n }\n\n getUI().log.success('Account ready.');\n getUI().log.info(` Project API Key: ${result.projectApiKey}`);\n getUI().log.info(` Personal API Key: ${result.personalApiKey}`);\n getUI().log.info(` Host: ${result.host}`);\n return {\n personalApiKey: result.personalApiKey,\n projectId: result.projectId,\n };\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,aAAa,MAAuB;CAClD,MAAM,UAAU,EAAE,GAAG,MAAM;AAI3B,KAAI,CAAC,QAAQ,UAAU,CAAC,QAAQ,OAC9B,QAAO,OACL,gIAED;AAEH,KAAI,CAAC,QAAQ,UAAU,QAAQ,UAAU,CAAC,QAAQ,MAChD,QAAO,OAAO,wDAAwD;AAExE,2BAA0B,QAAQ,OAAO;AAEzC,EAAM,YAAY;AAChB,MAAI,CAAC,QAAQ,UAAU,QAAQ,QAAQ;AAErC,OAAI,CAAC,QAAQ,WACX,QAAO,OACL,2DACD;GAEH,MAAM,cAAc,MAAM,mBAAmB,QAAQ;AACrD,WAAQ,SAAS,YAAY;AAC7B,OAAI,QAAQ,aAAa,KAAM,SAAQ,YAAY,YAAY;;AAEjE,cAAY,0BAA0B,QAAQ;KAC5C,CAAC,YAAY;AACf,UAAQ,KAAK,EAAE;GACf;;AAGJ,SAAS,OAAO,SAAuB;AACrC,OAAM,IAAI,WAAW,CAAC;AACtB,QAAO,CAAC,MAAM,iBAAiB;AAC/B,QAAO,CAAC,IAAI,MAAM,QAAQ;AAC1B,SAAQ,KAAK,EAAE;;;AAIjB,SAAS,0BAA0B,QAAkC;AACnE,KAAI,CAAC,UAAU,OAAO,WAAW,OAAO,CAAE;AAC1C,OAAM,IAAI,WAAW,CAAC;AACtB,QAAO,CAAC,MAAM,iBAAiB;CAC/B,MAAM,SAAS,OAAO,MAAM,GAAG,EAAE;CACjC,MAAM,OACJ,WAAW,SACP,0EACA,WAAW,SACX,yEACA;AACN,QAAO,CAAC,IAAI,KACV,uCAAuC,KAAK,oEAC7C;;;;;;;AAQH,eAAe,mBACb,SACwD;AACxD,OAAM,IAAI,WAAW,CAAC;AACtB,QAAO,CAAC,MAAM,iBAAiB;CAC/B,MAAM,gBAAiB,QAAQ,UAAqB,MAAM,aAAa;AAGvE,QAAO,CAAC,IAAI,KACV,wCAAwC,OACtC,QAAQ,MACT,CAAC,MAAM,aAAa,KACtB;CAED,IAAI;AACJ,KAAI;AACF,WAAS,MAAM,oBACb,QAAQ,OACR,QAAQ,QAAQ,IAChB,aACD;UACM,OAAO;EACd,MAAM,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AAClE,SAAO,CAAC,IAAI,MAAM,wBAAwB,MAAM;AAChD,QAAM;;AAGR,KAAI,CAAC,OAAO,gBAAgB;AAC1B,SAAO,CAAC,IAAI,MACV,yFACD;AACD,QAAM,IAAI,MAAM,4CAA4C;;AAG9D,QAAO,CAAC,IAAI,QAAQ,iBAAiB;AACrC,QAAO,CAAC,IAAI,KAAK,uBAAuB,OAAO,gBAAgB;AAC/D,QAAO,CAAC,IAAI,KAAK,uBAAuB,OAAO,iBAAiB;AAChE,QAAO,CAAC,IAAI,KAAK,uBAAuB,OAAO,OAAO;AACtD,QAAO;EACL,gBAAgB,OAAO;EACvB,WAAW,OAAO;EACnB"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import "./wizard-ui-YdGFRyu_.js";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join, sep } from "node:path";
|
|
4
|
-
import { inspect } from "node:util";
|
|
5
2
|
import { appendFileSync } from "fs";
|
|
6
3
|
import path from "path";
|
|
4
|
+
import { inspect } from "node:util";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join as join$1, sep } from "node:path";
|
|
7
7
|
//#region src/env.ts
|
|
8
8
|
/**
|
|
9
9
|
* Central environment variable access for the PostHog wizard.
|
|
@@ -28,7 +28,7 @@ function runtimeEnv(key) {
|
|
|
28
28
|
}
|
|
29
29
|
//#endregion
|
|
30
30
|
//#region src/lib/version.ts
|
|
31
|
-
const VERSION = "2.
|
|
31
|
+
const VERSION = "2.22.1";
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region src/lib/constants.ts
|
|
34
34
|
/**
|
|
@@ -61,10 +61,28 @@ let Integration = /* @__PURE__ */ function(Integration) {
|
|
|
61
61
|
Integration["javascript_web"] = "javascript_web";
|
|
62
62
|
return Integration;
|
|
63
63
|
}({});
|
|
64
|
+
/**
|
|
65
|
+
* Region-agnostic PostHog app URL. Resolves to us.posthog.com or
|
|
66
|
+
* eu.posthog.com server-side based on the signed-in user's profile.
|
|
67
|
+
* Use this for share-with-user links (e.g. settings pages) so they
|
|
68
|
+
* land on the right region without us needing to know it client-side.
|
|
69
|
+
*/
|
|
70
|
+
const POSTHOG_APP_URL = "https://app.posthog.com";
|
|
64
71
|
const DEFAULT_HOST_URL = "https://us.i.posthog.com";
|
|
65
72
|
const ISSUES_URL = "https://github.com/posthog/wizard/issues";
|
|
66
73
|
const CONTEXT_MILL_URL = "https://github.com/PostHog/context-mill";
|
|
74
|
+
/**
|
|
75
|
+
* Latest context-mill release page — the BYOAI download link shown in
|
|
76
|
+
* the privacy panel. Deliberately the release PAGE, not a direct asset
|
|
77
|
+
* URL: asset URLs are ~89 chars and hard-wrap inside the 64-col panel,
|
|
78
|
+
* which corrupts terminal copy/paste with a mid-URL line break. This
|
|
79
|
+
* stays under one line; the panel names the exact asset to grab.
|
|
80
|
+
*/
|
|
81
|
+
const CONTEXT_MILL_RELEASES_URL = "https://github.com/PostHog/context-mill/releases/latest";
|
|
67
82
|
const POSTHOG_DOCS_URL = "https://posthog.com/docs";
|
|
83
|
+
const POSTHOG_TERMS_URL = "https://posthog.com/terms";
|
|
84
|
+
const POSTHOG_PRIVACY_URL = "https://posthog.com/privacy";
|
|
85
|
+
const POSTHOG_ORG_AI_SETTINGS_URL = "https://app.posthog.com/settings/organization-details#setting=organization-ai-consent";
|
|
68
86
|
/** Remote base URL for fetching the skill menu + downloading skills. */
|
|
69
87
|
const REMOTE_SKILLS_BASE_URL = "https://github.com/PostHog/context-mill/releases/latest/download";
|
|
70
88
|
/** Local base URL when `--local-mcp` is set (served by context-mill dev server). */
|
|
@@ -127,12 +145,23 @@ const WIZARD_PROVISIONING_SCOPES = [
|
|
|
127
145
|
* - health_issue:read used by `wizard doctor`
|
|
128
146
|
* - wizard_session:read list / retrieve / stream sessions
|
|
129
147
|
* - wizard_session:write stream run state to /api/projects/{id}/wizard/sessions/
|
|
148
|
+
* - organization:read read `organization.is_ai_data_processing_approved`
|
|
149
|
+
* from /api/users/@me/ for the AI opt-in gate
|
|
150
|
+
*
|
|
151
|
+
* NOTE: every scope here must be within the wizard OAuth application's
|
|
152
|
+
* server-side scope ceiling (`OAuthApplication.scopes` in posthog, set
|
|
153
|
+
* via Django admin on BOTH prod regions) — requesting anything outside
|
|
154
|
+
* it fails the WHOLE authorize request with `error=invalid_scope`
|
|
155
|
+
* before the consent screen renders. Procedure: the
|
|
156
|
+
* "scope-ceiling-invalid-scope" runbook in PostHog/runbooks. Keep the
|
|
157
|
+
* runbook's worked example in sync when this list changes.
|
|
130
158
|
*/
|
|
131
159
|
const WIZARD_OAUTH_SCOPES = [
|
|
132
160
|
...WIZARD_PROVISIONING_SCOPES,
|
|
133
161
|
"health_issue:read",
|
|
134
162
|
"wizard_session:read",
|
|
135
|
-
"wizard_session:write"
|
|
163
|
+
"wizard_session:write",
|
|
164
|
+
"organization:read"
|
|
136
165
|
];
|
|
137
166
|
const WIZARD_INTERACTION_EVENT_NAME = "wizard interaction";
|
|
138
167
|
const WIZARD_REMARK_EVENT_NAME = "wizard remark";
|
|
@@ -153,8 +182,16 @@ const POSTHOG_PROPERTY_HEADER_PREFIX = "X-POSTHOG-PROPERTY-";
|
|
|
153
182
|
const POSTHOG_FLAG_HEADER_PREFIX = "X-POSTHOG-FLAG-";
|
|
154
183
|
/** Timeout for framework / project detection probes (ms). */
|
|
155
184
|
const DETECTION_TIMEOUT_MS = 1e4;
|
|
156
|
-
/**
|
|
157
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Timeout for the OAuth authorization flow (ms).
|
|
187
|
+
*
|
|
188
|
+
* Mirrors the server-side authorization-code expiry
|
|
189
|
+
* (`AUTHORIZATION_CODE_EXPIRE_SECONDS`, 5 minutes). Once the code expires the
|
|
190
|
+
* callback is dead and the token exchange can no longer succeed, so we stop
|
|
191
|
+
* waiting at the same moment and prompt the user to re-run rather than letting
|
|
192
|
+
* them complete a login that would fail.
|
|
193
|
+
*/
|
|
194
|
+
const OAUTH_TIMEOUT_MS = 3e5;
|
|
158
195
|
//#endregion
|
|
159
196
|
//#region src/lib/health-checks/statuspage.ts
|
|
160
197
|
function mapIndicator(v) {
|
|
@@ -249,9 +286,23 @@ function mapComponentStatus(status) {
|
|
|
249
286
|
default: return "degraded";
|
|
250
287
|
}
|
|
251
288
|
}
|
|
252
|
-
|
|
289
|
+
/**
|
|
290
|
+
* Build an error result for fetch failures. The kind matters for
|
|
291
|
+
* downstream reconciliation:
|
|
292
|
+
*
|
|
293
|
+
* - 'http' (incident.io returned a bad status code) → `Down`. We
|
|
294
|
+
* reached the status page but it told us something is wrong on
|
|
295
|
+
* its side. We have a definitive response.
|
|
296
|
+
* - 'network' (timeout, DNS failure, TCP/TLS failure) → `NoConnection`.
|
|
297
|
+
* We never reached the status page. Treating this as `Degraded`
|
|
298
|
+
* (the previous behavior) silently flipped the reconciliation in
|
|
299
|
+
* `readiness.ts` from "soft" to "confirmed outage" whenever the
|
|
300
|
+
* user's own network was flaky — exactly the false positive this
|
|
301
|
+
* module is meant to help diagnose.
|
|
302
|
+
*/
|
|
303
|
+
function errResult(error, kind) {
|
|
253
304
|
return {
|
|
254
|
-
status: "
|
|
305
|
+
status: kind === "http" ? "down" : "no-connection",
|
|
255
306
|
error
|
|
256
307
|
};
|
|
257
308
|
}
|
|
@@ -263,7 +314,7 @@ async function fetchPosthogStatus(timeoutMs = 5e3) {
|
|
|
263
314
|
const res = await fetch(POSTHOG_STATUS_URL, { signal: controller.signal });
|
|
264
315
|
clearTimeout(tid);
|
|
265
316
|
if (!res.ok) {
|
|
266
|
-
const err = errResult(`HTTP ${res.status}
|
|
317
|
+
const err = errResult(`HTTP ${res.status}`, "http");
|
|
267
318
|
return {
|
|
268
319
|
overall: err,
|
|
269
320
|
components: err
|
|
@@ -296,13 +347,13 @@ async function fetchPosthogStatus(timeoutMs = 5e3) {
|
|
|
296
347
|
};
|
|
297
348
|
} catch (e) {
|
|
298
349
|
if (e instanceof Error && e.name === "AbortError") {
|
|
299
|
-
const err = errResult("Request timed out");
|
|
350
|
+
const err = errResult("Request timed out", "network");
|
|
300
351
|
return {
|
|
301
352
|
overall: err,
|
|
302
353
|
components: err
|
|
303
354
|
};
|
|
304
355
|
}
|
|
305
|
-
const err = errResult(e instanceof Error ? e.message : "Unknown error");
|
|
356
|
+
const err = errResult(e instanceof Error ? e.message : "Unknown error", "network");
|
|
306
357
|
return {
|
|
307
358
|
overall: err,
|
|
308
359
|
components: err
|
|
@@ -318,33 +369,73 @@ const checkPosthogOverallHealth = async () => (await getPosthogHealth()).overall
|
|
|
318
369
|
const checkPosthogComponentHealth = async () => (await getPosthogHealth()).components;
|
|
319
370
|
//#endregion
|
|
320
371
|
//#region src/lib/health-checks/endpoints.ts
|
|
372
|
+
function noConnectionResult(error, attempts) {
|
|
373
|
+
return {
|
|
374
|
+
status: "no-connection",
|
|
375
|
+
error,
|
|
376
|
+
rawIndicator: attempts > 1 ? `attempts=${attempts}` : void 0
|
|
377
|
+
};
|
|
378
|
+
}
|
|
321
379
|
function downResult(error) {
|
|
322
380
|
return {
|
|
323
381
|
status: "down",
|
|
324
382
|
error
|
|
325
383
|
};
|
|
326
384
|
}
|
|
385
|
+
const RETRY_BACKOFFS_MS = [500, 2e3];
|
|
386
|
+
async function attemptFetch(url, timeoutMs, redirect) {
|
|
387
|
+
const controller = new AbortController();
|
|
388
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
389
|
+
try {
|
|
390
|
+
const res = await fetch(url, {
|
|
391
|
+
signal: controller.signal,
|
|
392
|
+
redirect
|
|
393
|
+
});
|
|
394
|
+
clearTimeout(tid);
|
|
395
|
+
return {
|
|
396
|
+
kind: "response",
|
|
397
|
+
res
|
|
398
|
+
};
|
|
399
|
+
} catch (e) {
|
|
400
|
+
clearTimeout(tid);
|
|
401
|
+
const err = e instanceof Error ? e : /* @__PURE__ */ new Error("Unknown error");
|
|
402
|
+
return {
|
|
403
|
+
kind: "error",
|
|
404
|
+
error: err,
|
|
405
|
+
timedOut: err.name === "AbortError"
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
}
|
|
327
409
|
async function fetchEndpointHealth(url, timeoutMs = 5e3, isExpectedStatus = (s) => s === 200, redirect = "follow") {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
clearTimeout(tid);
|
|
337
|
-
if (isExpectedStatus(res.status)) return {
|
|
338
|
-
status: "healthy",
|
|
339
|
-
rawIndicator: `HTTP ${res.status}`
|
|
340
|
-
};
|
|
341
|
-
return downResult(`HTTP ${res.status}`);
|
|
342
|
-
} catch (e) {
|
|
343
|
-
if (e instanceof Error && e.name === "AbortError") return downResult(`Request timed out after ${timeoutMs}ms`);
|
|
344
|
-
return downResult(e instanceof Error ? e.message : "Unknown error");
|
|
410
|
+
let lastHttpStatus = null;
|
|
411
|
+
let lastError = "Unknown error";
|
|
412
|
+
let attempts = 0;
|
|
413
|
+
for (let i = 0; i <= RETRY_BACKOFFS_MS.length; i++) {
|
|
414
|
+
if (i > 0) {
|
|
415
|
+
const wait = RETRY_BACKOFFS_MS[i - 1];
|
|
416
|
+
logToFile(`[health-checks] retry ${i}/${RETRY_BACKOFFS_MS.length} for ${url} in ${wait}ms (last: ${lastError})`);
|
|
417
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
345
418
|
}
|
|
346
|
-
|
|
347
|
-
|
|
419
|
+
attempts++;
|
|
420
|
+
const outcome = await attemptFetch(url, timeoutMs, redirect);
|
|
421
|
+
if (outcome.kind === "response") {
|
|
422
|
+
const res = outcome.res;
|
|
423
|
+
if (isExpectedStatus(res.status)) {
|
|
424
|
+
const result = {
|
|
425
|
+
status: "healthy",
|
|
426
|
+
rawIndicator: attempts > 1 ? `HTTP ${res.status} (attempts=${attempts})` : `HTTP ${res.status}`
|
|
427
|
+
};
|
|
428
|
+
logToFile(`[health-checks] GET ${url} -> ${result.status} (${result.rawIndicator})`);
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
lastHttpStatus = res.status;
|
|
432
|
+
lastError = `HTTP ${res.status}`;
|
|
433
|
+
continue;
|
|
434
|
+
}
|
|
435
|
+
lastError = outcome.timedOut ? `Request timed out after ${timeoutMs}ms` : outcome.error.message;
|
|
436
|
+
}
|
|
437
|
+
const result = lastHttpStatus !== null ? downResult(`HTTP ${lastHttpStatus} (attempts=${attempts})`) : noConnectionResult(lastError, attempts);
|
|
438
|
+
logToFile(`[health-checks] GET ${url} -> ${result.status} (attempts=${attempts}, ${result.error})`);
|
|
348
439
|
return result;
|
|
349
440
|
}
|
|
350
441
|
const checkLlmGatewayHealth = () => fetchEndpointHealth("https://gateway.us.posthog.com/_liveness");
|
|
@@ -400,7 +491,7 @@ async function checkAllExternalServices() {
|
|
|
400
491
|
checkMcpHealth(),
|
|
401
492
|
checkGithubReleasesHealth()
|
|
402
493
|
]);
|
|
403
|
-
return {
|
|
494
|
+
return reconcilePosthogReachability({
|
|
404
495
|
anthropic,
|
|
405
496
|
posthogOverall,
|
|
406
497
|
posthogComponents,
|
|
@@ -412,6 +503,51 @@ async function checkAllExternalServices() {
|
|
|
412
503
|
llmGateway,
|
|
413
504
|
mcp,
|
|
414
505
|
githubReleases
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* When a PostHog-owned endpoint probe returns `NoConnection`, decide
|
|
510
|
+
* whether it's a real outage or a likely-local issue by checking the
|
|
511
|
+
* official status page (`posthogstatus.com`):
|
|
512
|
+
*
|
|
513
|
+
* - Status page says PostHog is `Down` / `Degraded` → upgrade
|
|
514
|
+
* llmGateway / mcp to `Down`. The status page corroborates.
|
|
515
|
+
* - Status page is `Healthy` → keep `NoConnection`. The status page
|
|
516
|
+
* contradicts; this is probably the user's network.
|
|
517
|
+
* - Status page is also `NoConnection` → keep `NoConnection`. User
|
|
518
|
+
* can't reach two independent PostHog properties; almost
|
|
519
|
+
* certainly their network. (This case relies on incidentio.ts
|
|
520
|
+
* correctly emitting `NoConnection` for fetch failures rather
|
|
521
|
+
* than the previous `Degraded`, which used to silently flip the
|
|
522
|
+
* reconciliation into a false positive.)
|
|
523
|
+
*
|
|
524
|
+
* Why `Degraded` corroborates: a `Degraded` reading here only fires
|
|
525
|
+
* when incident.io's API parsed successfully and reported a real
|
|
526
|
+
* `partial_outage` or `degraded_performance` for some component. That's
|
|
527
|
+
* PostHog acknowledging an issue, even if narrower than a full outage.
|
|
528
|
+
* If our gateway probe is also failing, those two signals together
|
|
529
|
+
* justify pointing at PostHog rather than the user.
|
|
530
|
+
*
|
|
531
|
+
* A narrower variant — only corroborate when the affected component is
|
|
532
|
+
* gateway-related (LLM, US/EU Cloud, app) — would be more precise. We
|
|
533
|
+
* have the data in `posthogComponents` but don't use it here. If the
|
|
534
|
+
* analytics show false positives concentrated in this case, it's a
|
|
535
|
+
* cheap follow-up.
|
|
536
|
+
*
|
|
537
|
+
* Mutates a copy of `health` and returns it.
|
|
538
|
+
*/
|
|
539
|
+
function reconcilePosthogReachability(health) {
|
|
540
|
+
const posthogStatus = health.posthogOverall.status;
|
|
541
|
+
if (!(posthogStatus === "down" || posthogStatus === "degraded")) return health;
|
|
542
|
+
const upgrade = (r) => r.status === "no-connection" ? {
|
|
543
|
+
...r,
|
|
544
|
+
status: "down",
|
|
545
|
+
error: r.error ? `${r.error} (corroborated by status page)` : "corroborated by status page"
|
|
546
|
+
} : r;
|
|
547
|
+
return {
|
|
548
|
+
...health,
|
|
549
|
+
llmGateway: upgrade(health.llmGateway),
|
|
550
|
+
mcp: upgrade(health.mcp)
|
|
415
551
|
};
|
|
416
552
|
}
|
|
417
553
|
function describeResult(label, h) {
|
|
@@ -428,7 +564,7 @@ function describeComponents(label, h) {
|
|
|
428
564
|
const suffix = affected.length > MAX_COMPONENT_NAMES ? `, +${affected.length - MAX_COMPONENT_NAMES} more` : "";
|
|
429
565
|
return `${label} components impacted: ${shown.join(", ")}${suffix}`;
|
|
430
566
|
}
|
|
431
|
-
const READINESS_TIMEOUT_MS =
|
|
567
|
+
const READINESS_TIMEOUT_MS = 2e4;
|
|
432
568
|
async function evaluateWizardReadiness(config = DEFAULT_WIZARD_READINESS_CONFIG) {
|
|
433
569
|
try {
|
|
434
570
|
const health = await Promise.race([checkAllExternalServices(), new Promise((resolve) => setTimeout(() => resolve(allUnknown("Health check timed out")), READINESS_TIMEOUT_MS))]);
|
|
@@ -478,12 +614,17 @@ const COMPONENT_KEYS = [
|
|
|
478
614
|
];
|
|
479
615
|
/**
|
|
480
616
|
* Get the keys of services that would block a wizard run per the given config.
|
|
617
|
+
*
|
|
618
|
+
* `NoConnection` blocks the same services as `Down` — the wizard genuinely
|
|
619
|
+
* can't continue if it can't reach the gateway. The screen shows softer
|
|
620
|
+
* framing in that case (HealthCheckScreen) so we don't falsely accuse
|
|
621
|
+
* PostHog of an outage when the user's network is the likely cause.
|
|
481
622
|
*/
|
|
482
623
|
function getBlockingServiceKeys(health, config = DEFAULT_WIZARD_READINESS_CONFIG) {
|
|
483
624
|
return Object.keys(health).filter((key) => {
|
|
484
625
|
if (COMPONENT_KEYS.includes(key)) return false;
|
|
485
626
|
const result = health[key];
|
|
486
|
-
if (config.downBlocksRun.includes(key) && result.status === "down") return true;
|
|
627
|
+
if (config.downBlocksRun.includes(key) && (result.status === "down" || result.status === "no-connection")) return true;
|
|
487
628
|
if ((config.degradedBlocksRun ?? []).includes(key) && result.status !== "healthy") return true;
|
|
488
629
|
return false;
|
|
489
630
|
});
|
|
@@ -525,6 +666,9 @@ var LoggingUI = class {
|
|
|
525
666
|
waitForOutroDismissed() {
|
|
526
667
|
return Promise.resolve();
|
|
527
668
|
}
|
|
669
|
+
waitForAiOptIn() {
|
|
670
|
+
return Promise.resolve();
|
|
671
|
+
}
|
|
528
672
|
cancel(message) {
|
|
529
673
|
console.log(`■ ${message}`);
|
|
530
674
|
}
|
|
@@ -624,6 +768,11 @@ var LoggingUI = class {
|
|
|
624
768
|
}
|
|
625
769
|
if (detail?.logFilePath) console.log(`│ Verbose log: ${detail.logFilePath}`);
|
|
626
770
|
}
|
|
771
|
+
showSessionTimeout() {
|
|
772
|
+
const minutes = Math.round(OAUTH_TIMEOUT_MS / 6e4);
|
|
773
|
+
console.log(`✖ Login timed out. The OAuth link timed out after ${minutes} minutes.`);
|
|
774
|
+
console.log(`│ Re-run the wizard to get a fresh link and try again.`);
|
|
775
|
+
}
|
|
627
776
|
startRun() {}
|
|
628
777
|
setCredentials(_credentials) {}
|
|
629
778
|
setRoleAtOrganization(_role) {}
|
|
@@ -651,12 +800,12 @@ function setUI(ui) {
|
|
|
651
800
|
//#endregion
|
|
652
801
|
//#region src/utils/paths.ts
|
|
653
802
|
const TMP = process.platform === "win32" ? tmpdir() : "/tmp";
|
|
654
|
-
const WIZARD_LOG_FILE = join(TMP, "posthog-wizard.log");
|
|
655
|
-
const WIZARD_BENCHMARK_FILE = join(TMP, "posthog-wizard-benchmark.json");
|
|
656
|
-
const WIZARD_YARA_REPORT_FILE = join(TMP, "posthog-wizard-yara-report.json");
|
|
803
|
+
const WIZARD_LOG_FILE = join$1(TMP, "posthog-wizard.log");
|
|
804
|
+
const WIZARD_BENCHMARK_FILE = join$1(TMP, "posthog-wizard-benchmark.json");
|
|
805
|
+
const WIZARD_YARA_REPORT_FILE = join$1(TMP, "posthog-wizard-yara-report.json");
|
|
657
806
|
/** Temp path for a skill download zip. */
|
|
658
807
|
function skillTmpPath(skillId) {
|
|
659
|
-
return join(TMP, `posthog-skill-${skillId}.zip`);
|
|
808
|
+
return join$1(TMP, `posthog-skill-${skillId}.zip`);
|
|
660
809
|
}
|
|
661
810
|
/**
|
|
662
811
|
* Strip an absolute installDir prefix off a project file path so the UI
|
|
@@ -718,6 +867,6 @@ function enableDebugLogs() {
|
|
|
718
867
|
consoleLoggingEnabled = true;
|
|
719
868
|
}
|
|
720
869
|
//#endregion
|
|
721
|
-
export {
|
|
870
|
+
export { VERSION as $, OAUTH_PORTS as A, POSTHOG_PROXY_CLIENT_ID as B, CONTEXT_MILL_RELEASES_URL as C, DUMMY_PROJECT_API_KEY as D, DETECTION_TIMEOUT_MS as E, POSTHOG_FLAG_HEADER_PREFIX as F, WIZARD_OAUTH_SCOPES as G, POSTHOG_US_CLIENT_ID as H, POSTHOG_OAUTH_URL as I, WIZARD_TOOLS_MENU_FLAG_KEY as J, WIZARD_PROVISIONING_SCOPES as K, POSTHOG_ORG_AI_SETTINGS_URL as L, POSTHOG_APP_URL as M, POSTHOG_DEV_CLIENT_ID as N, ISSUES_URL as O, POSTHOG_DOCS_URL as P, getSkillsBaseUrl as Q, POSTHOG_PRIVACY_URL as R, ANALYTICS_TEAM_TAG as S, DEFAULT_HOST_URL as T, REMOTE_SKILLS_BASE_URL as U, POSTHOG_TERMS_URL as V, WIZARD_INTERACTION_EVENT_NAME as W, WIZARD_VARIANTS as X, WIZARD_USER_AGENT as Y, WIZARD_VARIANT_FLAG_KEY as Z, SIGNUP_WIZARD_READINESS_CONFIG as _, getLogFilePath as a, ANALYTICS_HOST_URL as b, WIZARD_BENCHMARK_FILE as c, relativeToInstallDir as d, NODE_ENV as et, skillTmpPath as f, SERVICE_LABELS as g, LoggingUI as h, enableDebugLogs as i, OAUTH_TIMEOUT_MS as j, Integration as k, WIZARD_LOG_FILE as l, setUI as m, configureLogFileFromEnvironment as n, initLogFile as o, getUI as p, WIZARD_REMARK_EVENT_NAME as q, debug as r, logToFile as s, configureLogFile as t, runtimeEnv as tt, WIZARD_YARA_REPORT_FILE as u, evaluateWizardReadiness as v, CONTEXT_MILL_URL as w, ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY as x, getBlockingServiceKeys as y, POSTHOG_PROPERTY_HEADER_PREFIX as z };
|
|
722
871
|
|
|
723
|
-
//# sourceMappingURL=debug-
|
|
872
|
+
//# sourceMappingURL=debug-Ckumcrye.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-Ckumcrye.js","names":["errResult","join"],"sources":["../src/env.ts","../src/lib/version.ts","../src/lib/constants.ts","../src/lib/health-checks/statuspage.ts","../src/lib/health-checks/incidentio.ts","../src/lib/health-checks/endpoints.ts","../src/lib/health-checks/readiness.ts","../src/ui/logging-ui.ts","../src/ui/index.ts","../src/utils/paths.ts","../src/utils/debug.ts"],"sourcesContent":["/**\n * Central environment variable access for the PostHog wizard.\n *\n * ── Build-time constants ────────────────────────────────────────────\n * Inlined by tsdown's `env` option at compile time. After build, the\n * runtime value of these env vars has zero effect on the wizard.\n *\n * ── Runtime variables ───────────────────────────────────────────────\n * Read through `runtimeEnv()` with a typed allowlist. This makes every\n * runtime dependency on the environment explicit and grep-able.\n *\n * ── Direct process.env access ───────────────────────────────────────\n * Reserved for subprocess environment configuration (writes) and\n * vendored code. Production source outside those cases should use\n * this module instead.\n */\n\n// ── Build-time constants ─────────────────────────────────────────────\n// tsdown replaces `process.env.NODE_ENV` with a string literal.\n// After build these are just `\"production\"`, `false`, etc.\n\nexport const NODE_ENV = process.env.NODE_ENV as string;\nexport const IS_DEV =\n process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';\n\n/**\n * True only in published/production builds. tsdown inlines\n * `process.env.NODE_ENV` as the literal `\"production\"` at build time, so this\n * collapses to `true` in `dist/` and stays `false` for `tsx`/dev/test runs\n * (where NODE_ENV is unset, `development`, or `test`). Used to gate features\n * that aren't supported in the shipped package — e.g. `--ci` mode.\n */\nexport const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production';\n\n// ── Runtime environment ──────────────────────────────────────────────\n\n/**\n * Exhaustive allowlist of env vars the wizard reads at runtime.\n * Add new keys here when a new runtime dependency is needed.\n */\ntype RuntimeEnvKey =\n // Wizard CLI configuration (yargs POSTHOG_WIZARD_ prefix)\n | 'POSTHOG_WIZARD_BENCHMARK_CONFIG'\n | 'POSTHOG_WIZARD_BENCHMARK_FILE'\n | 'POSTHOG_WIZARD_LOG_DIR'\n | 'POSTHOG_WIZARD_DEBUG'\n | 'DEBUG'\n // Agent / MCP\n | 'MCP_URL'\n | 'POSTHOG_API_KEY'\n // Platform: terminal detection\n | 'TERM'\n | 'TERM_PROGRAM'\n | 'TERMINAL_EMULATOR'\n | 'CI'\n | 'WT_SESSION'\n | 'TERMINUS_SUBLIME'\n | 'ConEmuTask'\n // Platform: paths\n | 'APPDATA'\n | 'XDG_CONFIG_HOME';\n\n/** Read a runtime environment variable. Only allowlisted keys compile. */\nexport function runtimeEnv(key: RuntimeEnvKey): string | undefined {\n return process.env[key];\n}\n","// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.22.1';\n","/**\n * Shared constants for the PostHog wizard.\n */\n\nimport { VERSION } from './version';\n\n// ── Integration / CLI ───────────────────────────────────────────────\n\n/**\n * Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.\n */\nexport enum Integration {\n // Frameworks\n nextjs = 'nextjs',\n nuxt = 'nuxt',\n vue = 'vue',\n reactRouter = 'react-router',\n tanstackStart = 'tanstack-start',\n tanstackRouter = 'tanstack-router',\n reactNative = 'react-native',\n angular = 'angular',\n astro = 'astro',\n django = 'django',\n flask = 'flask',\n fastapi = 'fastapi',\n laravel = 'laravel',\n sveltekit = 'sveltekit',\n swift = 'swift',\n android = 'android',\n rails = 'rails',\n\n // Language fallbacks\n python = 'python',\n ruby = 'ruby',\n javascriptNode = 'javascript_node',\n javascript_web = 'javascript_web',\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\n// ── Environment ──────────────────────────────────────────────────────\n\nimport { IS_DEV } from '@env';\nexport { IS_DEV };\nexport const DEBUG = false;\n\n// ── URLs ─────────────────────────────────────────────────────────────\n\nexport const DEFAULT_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.posthog.com';\n/**\n * Region-agnostic PostHog app URL. Resolves to us.posthog.com or\n * eu.posthog.com server-side based on the signed-in user's profile.\n * Use this for share-with-user links (e.g. settings pages) so they\n * land on the right region without us needing to know it client-side.\n */\nexport const POSTHOG_APP_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://app.posthog.com';\nexport const DEFAULT_HOST_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.i.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const CONTEXT_MILL_URL = 'https://github.com/PostHog/context-mill';\n/**\n * Latest context-mill release page — the BYOAI download link shown in\n * the privacy panel. Deliberately the release PAGE, not a direct asset\n * URL: asset URLs are ~89 chars and hard-wrap inside the 64-col panel,\n * which corrupts terminal copy/paste with a mid-URL line break. This\n * stays under one line; the panel names the exact asset to grab.\n */\nexport const CONTEXT_MILL_RELEASES_URL =\n 'https://github.com/PostHog/context-mill/releases/latest';\nexport const POSTHOG_DOCS_URL = 'https://posthog.com/docs';\nexport const POSTHOG_WIZARD_REPO_URL = 'https://github.com/PostHog/wizard';\nexport const POSTHOG_TERMS_URL = 'https://posthog.com/terms';\nexport const POSTHOG_PRIVACY_URL = 'https://posthog.com/privacy';\nexport const POSTHOG_ORG_AI_SETTINGS_URL =\n 'https://app.posthog.com/settings/organization-details#setting=organization-ai-consent';\nexport const WIZARD_CONTACT_EMAIL = 'wizard@posthog.com';\n\n/** Remote base URL for fetching the skill menu + downloading skills. */\nexport const REMOTE_SKILLS_BASE_URL =\n 'https://github.com/PostHog/context-mill/releases/latest/download';\n/** Local base URL when `--local-mcp` is set (served by context-mill dev server). */\nexport const LOCAL_SKILLS_BASE_URL = 'http://localhost:8765';\n\n/**\n * Pick the skills base URL based on the session's localMcp flag.\n * Single source of truth — do not inline this ternary anywhere.\n */\nexport function getSkillsBaseUrl(localMcp: boolean): string {\n return localMcp ? LOCAL_SKILLS_BASE_URL : REMOTE_SKILLS_BASE_URL;\n}\n\n// ── Analytics (internal) ──────────────────────────────────────────────\n\nexport const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';\nexport const ANALYTICS_HOST_URL = 'https://internal-j.posthog.com';\nexport const ANALYTICS_TEAM_TAG = 'docs-and-wizard';\n\n// ── OAuth / Auth ────────────────────────────────────────────────────\n\nexport const POSTHOG_OAUTH_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://oauth.posthog.com';\nexport const OAUTH_PORTS = [8239, 8238, 8240, 8237, 8236, 8235] as const;\nexport const POSTHOG_US_CLIENT_ID = 'c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM';\nexport const POSTHOG_EU_CLIENT_ID = 'bx2C5sZRN03TkdjraCcetvQFPGH6N2Y9vRLkcKEy';\nexport const POSTHOG_DEV_CLIENT_ID = 'DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ';\nexport const POSTHOG_PROXY_CLIENT_ID = POSTHOG_US_CLIENT_ID;\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_TOKEN_';\n\n/**\n * Scopes the wizard requests during the agentic provisioning signup flow.\n *\n * Each entry is justified by what the wizard's agent step does after signup:\n * - user:read identify the user for analytics + agent context\n * - project:read look up the freshly-provisioned project\n * - llm_gateway:read authenticate to gateway.{us,eu}.posthog.com/wizard\n * (the agent's LLM calls — without this scope, every\n * agent message returns 401)\n * - query:read run HogQL queries when the agent needs data\n * - dashboard:write create the onboarding dashboard during setup\n * - insight:write create the onboarding insights during setup\n * - notebook:write upload the events-audit report as a PostHog notebook\n * in step 6 of the events-audit skill (notebooks-create\n * MCP tool requires this scope)\n *\n * Must be a subset of `ALLOWED_PROVISIONING_SCOPES` in\n * `ee/api/agentic_provisioning/views.py` on the backend.\n */\nexport const WIZARD_PROVISIONING_SCOPES = [\n 'user:read',\n 'project:read',\n 'llm_gateway:read',\n 'dashboard:write',\n 'insight:write',\n 'query:read',\n 'notebook:write',\n] as const;\n\n/**\n * Scopes the wizard requests during the OAuth login flow. Superset of\n * `WIZARD_PROVISIONING_SCOPES` with scopes that only apply to the login\n * path and are not in the provisioning allowlist:\n * - health_issue:read used by `wizard doctor`\n * - wizard_session:read list / retrieve / stream sessions\n * - wizard_session:write stream run state to /api/projects/{id}/wizard/sessions/\n * - organization:read read `organization.is_ai_data_processing_approved`\n * from /api/users/@me/ for the AI opt-in gate\n *\n * NOTE: every scope here must be within the wizard OAuth application's\n * server-side scope ceiling (`OAuthApplication.scopes` in posthog, set\n * via Django admin on BOTH prod regions) — requesting anything outside\n * it fails the WHOLE authorize request with `error=invalid_scope`\n * before the consent screen renders. Procedure: the\n * \"scope-ceiling-invalid-scope\" runbook in PostHog/runbooks. Keep the\n * runbook's worked example in sync when this list changes.\n */\nexport const WIZARD_OAUTH_SCOPES = [\n ...WIZARD_PROVISIONING_SCOPES,\n 'health_issue:read',\n 'wizard_session:read',\n 'wizard_session:write',\n 'organization:read',\n] as const;\n\n// ── Wizard run / variants ───────────────────────────────────────────\n\nexport const WIZARD_INTERACTION_EVENT_NAME = 'wizard interaction';\nexport const WIZARD_REMARK_EVENT_NAME = 'wizard remark';\n/** Feature flag key whose value selects a variant from WIZARD_VARIANTS. */\nexport const WIZARD_VARIANT_FLAG_KEY = 'wizard-variant';\n/** Feature flag key that gates the intro-screen \"Tools\" menu. */\nexport const WIZARD_TOOLS_MENU_FLAG_KEY = 'wizard-tools-menu';\n/** Variant key -> metadata for wizard run (VARIANT flag selects which entry to use). */\nexport const WIZARD_VARIANTS: Record<string, Record<string, string>> = {\n base: { VARIANT: 'base' },\n subagents: { VARIANT: 'subagents' },\n};\n/** User-Agent for wizard HTTP requests and MCP server identification. */\nexport const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`;\n\n// ── HTTP headers ─────────────────────────────────────────────────────\n\n/** Header prefix for PostHog properties (e.g. X-POSTHOG-PROPERTY-VARIANT). */\nexport const POSTHOG_PROPERTY_HEADER_PREFIX = 'X-POSTHOG-PROPERTY-';\n/** Header prefix for PostHog feature flags. */\nexport const POSTHOG_FLAG_HEADER_PREFIX = 'X-POSTHOG-FLAG-';\n\n// ── Timeouts ─────────────────────────────────────────────────────────\n\n/** Timeout for framework / project detection probes (ms). */\nexport const DETECTION_TIMEOUT_MS = 10_000;\n\n/**\n * Timeout for the OAuth authorization flow (ms).\n *\n * Mirrors the server-side authorization-code expiry\n * (`AUTHORIZATION_CODE_EXPIRE_SECONDS`, 5 minutes). Once the code expires the\n * callback is dead and the token exchange can no longer succeed, so we stop\n * waiting at the same moment and prompt the user to re-run rather than letting\n * them complete a login that would fail.\n */\nexport const OAUTH_TIMEOUT_MS = 300_000;\n","import {\n ServiceHealthStatus,\n type BaseHealthResult,\n type ComponentHealthResult,\n} from './types';\n\n// ---------------------------------------------------------------------------\n// Statuspage.io v2 API helpers\n// https://metastatuspage.com/api\n//\n// status.json – page-level rollup; indicator is one of: none | minor | major | critical\n// summary.json – same rollup + component list; component status is one of:\n// operational | degraded_performance | partial_outage | major_outage | under_maintenance\n// https://support.atlassian.com/statuspage/docs/show-service-status-with-components\n// ---------------------------------------------------------------------------\n\ninterface StatuspageStatusResponse {\n status?: { indicator?: string; description?: string };\n}\n\ninterface StatuspageSummaryResponse extends StatuspageStatusResponse {\n components?: { id: string; name: string; status: string }[];\n}\n\nfunction mapIndicator(v: string | null | undefined): ServiceHealthStatus {\n switch (v) {\n case 'none':\n return ServiceHealthStatus.Healthy;\n case 'minor':\n return ServiceHealthStatus.Degraded;\n case 'major':\n case 'critical':\n return ServiceHealthStatus.Down;\n default:\n return ServiceHealthStatus.Degraded;\n }\n}\n\nfunction mapComponentRaw(v: string | null | undefined): ServiceHealthStatus {\n switch (v) {\n case 'operational':\n return ServiceHealthStatus.Healthy;\n case 'degraded_performance':\n case 'under_maintenance':\n return ServiceHealthStatus.Degraded;\n case 'partial_outage':\n case 'major_outage':\n return ServiceHealthStatus.Down;\n default:\n return ServiceHealthStatus.Degraded;\n }\n}\n\nfunction errResult(error: string): BaseHealthResult {\n return { status: ServiceHealthStatus.Degraded, error };\n}\n\nasync function fetchStatuspageIndicator(\n url: string,\n timeoutMs = 5000,\n): Promise<BaseHealthResult> {\n try {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), timeoutMs);\n const res = await fetch(url, { signal: controller.signal });\n clearTimeout(tid);\n\n if (!res.ok) return errResult(`HTTP ${res.status}`);\n\n const data = (await res.json()) as StatuspageStatusResponse;\n const indicator = data.status?.indicator ?? null;\n return {\n status: mapIndicator(indicator),\n rawIndicator: indicator ?? undefined,\n };\n } catch (e) {\n if (e instanceof Error && e.name === 'AbortError')\n return errResult('Request timed out');\n return errResult(e instanceof Error ? e.message : 'Unknown error');\n }\n}\n\nasync function fetchStatuspageSummary(\n url: string,\n timeoutMs = 5000,\n): Promise<ComponentHealthResult> {\n try {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), timeoutMs);\n const res = await fetch(url, { signal: controller.signal });\n clearTimeout(tid);\n\n if (!res.ok) return errResult(`HTTP ${res.status}`);\n\n const data = (await res.json()) as StatuspageSummaryResponse;\n const indicator = data.status?.indicator ?? null;\n const overall = mapIndicator(indicator);\n\n const affected = (data.components ?? [])\n .map((c) => ({\n name: c.name,\n status: mapComponentRaw(c.status),\n rawStatus: c.status,\n }))\n .filter((c) => c.status !== ServiceHealthStatus.Healthy);\n\n return {\n status: affected.length > 0 ? ServiceHealthStatus.Degraded : overall,\n rawIndicator: indicator ?? undefined,\n degradedOrDownComponents: affected.length > 0 ? affected : undefined,\n };\n } catch (e) {\n if (e instanceof Error && e.name === 'AbortError')\n return errResult('Request timed out');\n return errResult(e instanceof Error ? e.message : 'Unknown error');\n }\n}\n\n// ---------------------------------------------------------------------------\n// Individual statuspage-backed checks\n// ---------------------------------------------------------------------------\n\nexport const checkAnthropicHealth = (): Promise<BaseHealthResult> =>\n fetchStatuspageIndicator('https://status.claude.com/api/v2/status.json');\n\nexport const checkGithubHealth = (): Promise<BaseHealthResult> =>\n fetchStatuspageIndicator('https://www.githubstatus.com/api/v2/status.json');\n\nexport const checkNpmOverallHealth = (): Promise<BaseHealthResult> =>\n fetchStatuspageIndicator('https://status.npmjs.org/api/v2/status.json');\n\nexport const checkNpmComponentHealth = (): Promise<ComponentHealthResult> =>\n fetchStatuspageSummary('https://status.npmjs.org/api/v2/summary.json');\n\nexport const checkCloudflareOverallHealth = (): Promise<BaseHealthResult> =>\n fetchStatuspageIndicator(\n 'https://www.cloudflarestatus.com/api/v2/status.json',\n );\n\nexport const checkCloudflareComponentHealth =\n (): Promise<ComponentHealthResult> =>\n fetchStatuspageSummary(\n 'https://www.cloudflarestatus.com/api/v2/summary.json',\n );\n","import {\n ServiceHealthStatus,\n type BaseHealthResult,\n type ComponentHealthResult,\n type ComponentStatus,\n} from './types';\n\ninterface IncidentIoAffectedComponent {\n id: string;\n name: string;\n group_name?: string;\n current_status: string;\n}\n\ninterface IncidentIoIncident {\n id: string;\n name: string;\n status: string;\n current_worst_impact: string;\n affected_components: IncidentIoAffectedComponent[];\n}\n\ninterface IncidentIoSummary {\n ongoing_incidents: IncidentIoIncident[];\n in_progress_maintenances: unknown[];\n}\n\nfunction mapIncidentImpact(impact: string): ServiceHealthStatus {\n switch (impact) {\n case 'full_outage':\n return ServiceHealthStatus.Down;\n case 'partial_outage':\n case 'degraded_performance':\n return ServiceHealthStatus.Degraded;\n default:\n return ServiceHealthStatus.Degraded;\n }\n}\n\nfunction mapComponentStatus(status: string): ServiceHealthStatus {\n switch (status) {\n case 'operational':\n return ServiceHealthStatus.Healthy;\n case 'full_outage':\n return ServiceHealthStatus.Down;\n case 'partial_outage':\n case 'degraded_performance':\n return ServiceHealthStatus.Degraded;\n default:\n return ServiceHealthStatus.Degraded;\n }\n}\n\n/**\n * Build an error result for fetch failures. The kind matters for\n * downstream reconciliation:\n *\n * - 'http' (incident.io returned a bad status code) → `Down`. We\n * reached the status page but it told us something is wrong on\n * its side. We have a definitive response.\n * - 'network' (timeout, DNS failure, TCP/TLS failure) → `NoConnection`.\n * We never reached the status page. Treating this as `Degraded`\n * (the previous behavior) silently flipped the reconciliation in\n * `readiness.ts` from \"soft\" to \"confirmed outage\" whenever the\n * user's own network was flaky — exactly the false positive this\n * module is meant to help diagnose.\n */\nfunction errResult(error: string, kind: 'http' | 'network'): BaseHealthResult {\n return {\n status:\n kind === 'http'\n ? ServiceHealthStatus.Down\n : ServiceHealthStatus.NoConnection,\n error,\n };\n}\n\nconst POSTHOG_STATUS_URL = 'https://www.posthogstatus.com/api/v1/summary';\n\nasync function fetchPosthogStatus(\n timeoutMs = 5000,\n): Promise<{ overall: BaseHealthResult; components: ComponentHealthResult }> {\n try {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), timeoutMs);\n const res = await fetch(POSTHOG_STATUS_URL, { signal: controller.signal });\n clearTimeout(tid);\n\n if (!res.ok) {\n const err = errResult(`HTTP ${res.status}`, 'http');\n return { overall: err, components: err };\n }\n\n const data = (await res.json()) as IncidentIoSummary;\n const incidents = data.ongoing_incidents ?? [];\n\n if (incidents.length === 0) {\n return {\n overall: { status: ServiceHealthStatus.Healthy },\n components: { status: ServiceHealthStatus.Healthy },\n };\n }\n\n let worstOverall = ServiceHealthStatus.Degraded;\n const affected: ComponentStatus[] = [];\n\n for (const incident of incidents) {\n const impact = mapIncidentImpact(incident.current_worst_impact);\n if (impact === ServiceHealthStatus.Down) {\n worstOverall = ServiceHealthStatus.Down;\n }\n\n for (const comp of incident.affected_components ?? []) {\n const compStatus = mapComponentStatus(comp.current_status);\n if (compStatus !== ServiceHealthStatus.Healthy) {\n affected.push({\n name: comp.group_name\n ? `${comp.group_name} — ${comp.name}`\n : comp.name,\n status: compStatus,\n rawStatus: comp.current_status,\n });\n }\n }\n }\n\n return {\n overall: { status: worstOverall },\n components: {\n status:\n affected.length > 0 ? ServiceHealthStatus.Degraded : worstOverall,\n degradedOrDownComponents: affected.length > 0 ? affected : undefined,\n },\n };\n } catch (e) {\n if (e instanceof Error && e.name === 'AbortError') {\n const err = errResult('Request timed out', 'network');\n return { overall: err, components: err };\n }\n const err = errResult(\n e instanceof Error ? e.message : 'Unknown error',\n 'network',\n );\n return { overall: err, components: err };\n }\n}\n\nlet _cache: Promise<{\n overall: BaseHealthResult;\n components: ComponentHealthResult;\n}> | null = null;\n\nfunction getPosthogHealth() {\n if (!_cache) _cache = fetchPosthogStatus();\n return _cache;\n}\n\nexport function resetPosthogHealthCache(): void {\n _cache = null;\n}\n\nexport const checkPosthogOverallHealth = async (): Promise<BaseHealthResult> =>\n (await getPosthogHealth()).overall;\n\nexport const checkPosthogComponentHealth =\n async (): Promise<ComponentHealthResult> =>\n (await getPosthogHealth()).components;\n","import { REMOTE_SKILLS_BASE_URL } from '@lib/constants';\nimport { logToFile } from '@utils/debug';\nimport { ServiceHealthStatus, type BaseHealthResult } from './types';\n\n// ---------------------------------------------------------------------------\n// Direct endpoint health checks\n//\n// These ping PostHog-owned services directly (no Statuspage intermediary).\n// Result taxonomy:\n// - HTTP 2xx-3xx (per `isExpectedStatus`) → Healthy\n// - HTTP 4xx / 5xx → Down (confirmed)\n// - Network error / DNS / timeout (after retries) → NoConnection\n// NoConnection means we don't know whose fault it is; readiness reconciles\n// against the status page before deciding how to surface it to the user.\n//\n// LLM Gateway – FastAPI service\n// Source: posthog/services/llm-gateway/src/llm_gateway/api/health.py\n// GET /_liveness → 200 {\"status\":\"alive\"}\n//\n// MCP – Cloudflare Worker\n// Source: posthog/services/mcp/src/index.ts\n// GET / → 302 to posthog.com docs. The redirect proves the worker is up.\n// ---------------------------------------------------------------------------\n\nfunction noConnectionResult(error: string, attempts: number): BaseHealthResult {\n return {\n status: ServiceHealthStatus.NoConnection,\n error,\n rawIndicator: attempts > 1 ? `attempts=${attempts}` : undefined,\n };\n}\n\nfunction downResult(error: string): BaseHealthResult {\n return { status: ServiceHealthStatus.Down, error };\n}\n\n// Backoffs sized to cover typical wifi flakiness — a single dropped\n// packet recovers via the 500ms retry; a wifi access point reconnect\n// or wifi↔LTE handoff (2-5s) is caught by the 2000ms retry. Tighter\n// schedules miss multi-second blips because all retries land in the\n// same dead window.\nconst RETRY_BACKOFFS_MS = [500, 2000];\n\nasync function attemptFetch(\n url: string,\n timeoutMs: number,\n redirect: 'follow' | 'manual' | 'error',\n): Promise<\n | { kind: 'response'; res: Response }\n | { kind: 'error'; error: Error; timedOut: boolean }\n> {\n const controller = new AbortController();\n const tid = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(url, { signal: controller.signal, redirect });\n clearTimeout(tid);\n return { kind: 'response', res };\n } catch (e) {\n clearTimeout(tid);\n const err = e instanceof Error ? e : new Error('Unknown error');\n return { kind: 'error', error: err, timedOut: err.name === 'AbortError' };\n }\n}\n\nasync function fetchEndpointHealth(\n url: string,\n timeoutMs = 5000,\n isExpectedStatus: (status: number) => boolean = (s) => s === 200,\n redirect: 'follow' | 'manual' | 'error' = 'follow',\n): Promise<BaseHealthResult> {\n // Total attempts = 1 initial + RETRY_BACKOFFS_MS.length retries. Both\n // unexpected HTTP statuses (4xx/5xx) and network errors trigger a retry:\n // transient 5xx and Cloudflare edge blips often recover on a retry, and\n // even nominally deterministic 4xx can be transient (CDN propagation\n // lag after a release, token rotation, rate-limit window resets). GETs\n // are idempotent so retrying is safe.\n //\n // Final status if every attempt fails:\n // - At least one HTTP response observed → `Down` (server-side evidence)\n // - Only network errors observed → `NoConnection`\n let lastHttpStatus: number | null = null;\n let lastError = 'Unknown error';\n let attempts = 0;\n\n for (let i = 0; i <= RETRY_BACKOFFS_MS.length; i++) {\n if (i > 0) {\n const wait = RETRY_BACKOFFS_MS[i - 1];\n logToFile(\n `[health-checks] retry ${i}/${RETRY_BACKOFFS_MS.length} for ${url} in ${wait}ms (last: ${lastError})`,\n );\n await new Promise((r) => setTimeout(r, wait));\n }\n attempts++;\n\n const outcome = await attemptFetch(url, timeoutMs, redirect);\n\n if (outcome.kind === 'response') {\n const res = outcome.res;\n if (isExpectedStatus(res.status)) {\n const result: BaseHealthResult = {\n status: ServiceHealthStatus.Healthy,\n rawIndicator:\n attempts > 1\n ? `HTTP ${res.status} (attempts=${attempts})`\n : `HTTP ${res.status}`,\n };\n logToFile(\n `[health-checks] GET ${url} -> ${result.status}` +\n ` (${result.rawIndicator})`,\n );\n return result;\n }\n lastHttpStatus = res.status;\n lastError = `HTTP ${res.status}`;\n continue;\n }\n\n lastError = outcome.timedOut\n ? `Request timed out after ${timeoutMs}ms`\n : outcome.error.message;\n }\n\n const result =\n lastHttpStatus !== null\n ? downResult(`HTTP ${lastHttpStatus} (attempts=${attempts})`)\n : noConnectionResult(lastError, attempts);\n logToFile(\n `[health-checks] GET ${url} -> ${result.status}` +\n ` (attempts=${attempts}, ${result.error})`,\n );\n return result;\n}\n\nexport const checkLlmGatewayHealth = (): Promise<BaseHealthResult> =>\n fetchEndpointHealth('https://gateway.us.posthog.com/_liveness');\n\nexport const checkMcpHealth = (): Promise<BaseHealthResult> =>\n fetchEndpointHealth(\n 'https://mcp.posthog.com/',\n 5000,\n // 2xx-3xx counts as up (redirect to docs)\n (s) => s >= 200 && s < 400,\n 'manual',\n );\n\nexport const checkGithubReleasesHealth = (): Promise<BaseHealthResult> =>\n fetchEndpointHealth(`${REMOTE_SKILLS_BASE_URL}/skill-menu.json`);\n","import {\n ServiceHealthStatus,\n type AllServicesHealth,\n type BaseHealthResult,\n type ComponentHealthResult,\n type HealthCheckKey,\n} from './types';\nimport {\n checkAnthropicHealth,\n checkGithubHealth,\n checkNpmOverallHealth,\n checkNpmComponentHealth,\n checkCloudflareOverallHealth,\n checkCloudflareComponentHealth,\n} from './statuspage';\nimport {\n checkPosthogOverallHealth,\n checkPosthogComponentHealth,\n} from './incidentio';\nimport {\n checkLlmGatewayHealth,\n checkMcpHealth,\n checkGithubReleasesHealth,\n} from './endpoints';\nimport { logToFile } from '@utils/debug';\n\n// ---------------------------------------------------------------------------\n// Service labels (used in human-readable reason strings)\n// ---------------------------------------------------------------------------\n\nexport const SERVICE_LABELS: Record<HealthCheckKey, string> = {\n anthropic: 'Anthropic',\n posthogOverall: 'PostHog',\n posthogComponents: 'PostHog (components)',\n github: 'GitHub',\n npmOverall: 'npm',\n npmComponents: 'npm (components)',\n cloudflareOverall: 'Cloudflare',\n cloudflareComponents: 'Cloudflare (components)',\n llmGateway: 'LLM Gateway',\n mcp: 'MCP',\n githubReleases: 'GitHub Releases',\n};\n\n// ---------------------------------------------------------------------------\n// Readiness config\n// ---------------------------------------------------------------------------\n\nexport interface WizardReadinessConfig {\n /** Services where status=Down blocks the run (readiness=No). */\n downBlocksRun: HealthCheckKey[];\n /** Services where status=Degraded (or worse) blocks the run (readiness=No). */\n degradedBlocksRun?: HealthCheckKey[];\n}\n\n/**\n * See README section \"Health checks\" for the full rationale.\n * Adjust these arrays to change what blocks a wizard run.\n */\nexport const DEFAULT_WIZARD_READINESS_CONFIG: WizardReadinessConfig = {\n downBlocksRun: [\n 'anthropic',\n 'npmOverall',\n 'llmGateway',\n 'mcp',\n 'githubReleases',\n ],\n degradedBlocksRun: ['anthropic'],\n};\n\n/**\n * Reduced readiness config for --signup provisioning flows.\n *\n * Provisioning only needs PostHog and the LLM Gateway - it doesn't\n * use Anthropic directly, npm, GitHub Releases, or MCP.\n */\nexport const SIGNUP_WIZARD_READINESS_CONFIG: WizardReadinessConfig = {\n downBlocksRun: ['posthogOverall', 'llmGateway'],\n};\n\n// ---------------------------------------------------------------------------\n// Aggregate check\n// ---------------------------------------------------------------------------\n\nexport async function checkAllExternalServices(): Promise<AllServicesHealth> {\n const [\n anthropic,\n posthogOverall,\n posthogComponents,\n github,\n npmOverall,\n npmComponents,\n cloudflareOverall,\n cloudflareComponents,\n llmGateway,\n mcp,\n githubReleases,\n ] = await Promise.all([\n checkAnthropicHealth(),\n checkPosthogOverallHealth(),\n checkPosthogComponentHealth(),\n checkGithubHealth(),\n checkNpmOverallHealth(),\n checkNpmComponentHealth(),\n checkCloudflareOverallHealth(),\n checkCloudflareComponentHealth(),\n checkLlmGatewayHealth(),\n checkMcpHealth(),\n checkGithubReleasesHealth(),\n ]);\n\n const health: AllServicesHealth = {\n anthropic,\n posthogOverall,\n posthogComponents,\n github,\n npmOverall,\n npmComponents,\n cloudflareOverall,\n cloudflareComponents,\n llmGateway,\n mcp,\n githubReleases,\n };\n return reconcilePosthogReachability(health);\n}\n\n/**\n * When a PostHog-owned endpoint probe returns `NoConnection`, decide\n * whether it's a real outage or a likely-local issue by checking the\n * official status page (`posthogstatus.com`):\n *\n * - Status page says PostHog is `Down` / `Degraded` → upgrade\n * llmGateway / mcp to `Down`. The status page corroborates.\n * - Status page is `Healthy` → keep `NoConnection`. The status page\n * contradicts; this is probably the user's network.\n * - Status page is also `NoConnection` → keep `NoConnection`. User\n * can't reach two independent PostHog properties; almost\n * certainly their network. (This case relies on incidentio.ts\n * correctly emitting `NoConnection` for fetch failures rather\n * than the previous `Degraded`, which used to silently flip the\n * reconciliation into a false positive.)\n *\n * Why `Degraded` corroborates: a `Degraded` reading here only fires\n * when incident.io's API parsed successfully and reported a real\n * `partial_outage` or `degraded_performance` for some component. That's\n * PostHog acknowledging an issue, even if narrower than a full outage.\n * If our gateway probe is also failing, those two signals together\n * justify pointing at PostHog rather than the user.\n *\n * A narrower variant — only corroborate when the affected component is\n * gateway-related (LLM, US/EU Cloud, app) — would be more precise. We\n * have the data in `posthogComponents` but don't use it here. If the\n * analytics show false positives concentrated in this case, it's a\n * cheap follow-up.\n *\n * Mutates a copy of `health` and returns it.\n */\nexport function reconcilePosthogReachability(\n health: AllServicesHealth,\n): AllServicesHealth {\n const posthogStatus = health.posthogOverall.status;\n const corroboratesOutage =\n posthogStatus === ServiceHealthStatus.Down ||\n posthogStatus === ServiceHealthStatus.Degraded;\n\n if (!corroboratesOutage) return health;\n\n const upgrade = (r: BaseHealthResult): BaseHealthResult =>\n r.status === ServiceHealthStatus.NoConnection\n ? {\n ...r,\n status: ServiceHealthStatus.Down,\n error: r.error\n ? `${r.error} (corroborated by status page)`\n : 'corroborated by status page',\n }\n : r;\n\n return {\n ...health,\n llmGateway: upgrade(health.llmGateway),\n mcp: upgrade(health.mcp),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Wizard readiness evaluation\n// ---------------------------------------------------------------------------\n\nexport enum WizardReadiness {\n Yes = 'yes',\n No = 'no',\n YesWithWarnings = 'yes_with_warnings',\n}\n\nexport interface WizardReadinessResult {\n decision: WizardReadiness;\n health: AllServicesHealth;\n reasons: string[];\n}\n\nfunction describeResult(label: string, h: BaseHealthResult): string {\n const parts = [`${label}: ${h.status}`];\n if (h.rawIndicator) parts.push(`indicator=${h.rawIndicator}`);\n if (h.error) parts.push(h.error);\n return parts.join(' — ');\n}\n\nconst MAX_COMPONENT_NAMES = 8;\n\nfunction describeComponents(label: string, h: ComponentHealthResult): string {\n const affected = h.degradedOrDownComponents;\n if (!affected || affected.length === 0)\n return `${label} components: all operational`;\n const shown = affected\n .slice(0, MAX_COMPONENT_NAMES)\n .map((c) => `${c.name} (${c.status})`);\n const suffix =\n affected.length > MAX_COMPONENT_NAMES\n ? `, +${affected.length - MAX_COMPONENT_NAMES} more`\n : '';\n return `${label} components impacted: ${shown.join(', ')}${suffix}`;\n}\n\n// Each probe can take up to one base timeout + two retries with the\n// 500ms / 2000ms backoffs in endpoints.ts (worst case ~17.5s for a\n// network failure that exhausts retries). Probes run in parallel so\n// the aggregate ceiling is one probe, not the sum.\nconst READINESS_TIMEOUT_MS = 20_000;\n\nexport async function evaluateWizardReadiness(\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): Promise<WizardReadinessResult> {\n try {\n const health = await Promise.race([\n checkAllExternalServices(),\n new Promise<AllServicesHealth>((resolve) =>\n setTimeout(\n () => resolve(allUnknown('Health check timed out')),\n READINESS_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const reasons: string[] = [];\n\n for (const key of Object.keys(health) as HealthCheckKey[]) {\n const result = health[key];\n const label = SERVICE_LABELS[key];\n\n reasons.push(describeResult(label, result));\n\n if ('degradedOrDownComponents' in result) {\n reasons.push(describeComponents(label, result));\n }\n }\n\n const blockingKeys = getBlockingServiceKeys(health, config);\n if (blockingKeys.length > 0) {\n const blockingDetails = blockingKeys.map((key) => {\n const h = health[key];\n return `${key} (${h.status}${h.error ? ` — ${h.error}` : ''})`;\n });\n logToFile(`[health-checks] blocked by: ${blockingDetails.join(', ')}`);\n return { decision: WizardReadiness.No, health, reasons };\n }\n\n const hasWarnings = Object.values(health).some(\n (h) => h.status !== ServiceHealthStatus.Healthy,\n );\n\n if (hasWarnings) {\n return { decision: WizardReadiness.YesWithWarnings, health, reasons };\n }\n\n return { decision: WizardReadiness.Yes, health, reasons };\n } catch (err) {\n logToFile(\n `[health-checks] error: ${err instanceof Error ? err.message : err}`,\n );\n // Health checks must never block the wizard run\n return {\n decision: WizardReadiness.Yes,\n health: allUnknown('Unexpected error'),\n reasons: ['Health check failed unexpectedly — proceeding anyway'],\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Blocking service detection\n// ---------------------------------------------------------------------------\n\n/** Keys that are component-level detail, not top-level services. */\nconst COMPONENT_KEYS: HealthCheckKey[] = [\n 'posthogComponents',\n 'npmComponents',\n 'cloudflareComponents',\n];\n\n/**\n * Get the keys of services that would block a wizard run per the given config.\n *\n * `NoConnection` blocks the same services as `Down` — the wizard genuinely\n * can't continue if it can't reach the gateway. The screen shows softer\n * framing in that case (HealthCheckScreen) so we don't falsely accuse\n * PostHog of an outage when the user's network is the likely cause.\n */\nexport function getBlockingServiceKeys(\n health: AllServicesHealth,\n config: WizardReadinessConfig = DEFAULT_WIZARD_READINESS_CONFIG,\n): HealthCheckKey[] {\n return (Object.keys(health) as HealthCheckKey[]).filter((key) => {\n if (COMPONENT_KEYS.includes(key)) return false;\n const result = health[key];\n if (\n config.downBlocksRun.includes(key) &&\n (result.status === ServiceHealthStatus.Down ||\n result.status === ServiceHealthStatus.NoConnection)\n ) {\n return true;\n }\n if (\n (config.degradedBlocksRun ?? []).includes(key) &&\n result.status !== ServiceHealthStatus.Healthy\n ) {\n return true;\n }\n return false;\n });\n}\n\n/** Build an AllServicesHealth where every service is Degraded with the given error. */\nfunction allUnknown(error: string): AllServicesHealth {\n const base: BaseHealthResult = {\n status: ServiceHealthStatus.Degraded,\n error,\n };\n return {\n anthropic: base,\n posthogOverall: base,\n posthogComponents: { ...base },\n github: base,\n npmOverall: base,\n npmComponents: { ...base },\n cloudflareOverall: base,\n cloudflareComponents: { ...base },\n llmGateway: base,\n mcp: base,\n githubReleases: base,\n };\n}\n","/* eslint-disable no-console */\n/**\n * LoggingUI — Logging-only implementation for CI mode.\n * No prompts, no TUI, no interactivity. Just console output.\n */\n\nimport {\n TaskStatus,\n type WizardUI,\n type SpinnerHandle,\n type AuthErrorDetail,\n} from './wizard-ui';\nimport type { SettingsConflict } from '@lib/agent/claude-settings';\nimport type { ApiUser } from '@lib/api';\nimport { OAUTH_TIMEOUT_MS } from '@lib/constants';\nimport {\n type WizardReadinessResult,\n getBlockingServiceKeys,\n SERVICE_LABELS,\n} from '@lib/health-checks/readiness';\nimport type {\n AskAnswers,\n OutroData,\n PendingQuestion,\n} from '@lib/wizard-session';\n\nexport class LoggingUI implements WizardUI {\n intro(message: string): void {\n console.log(`┌ ${message}`);\n }\n\n outro(message: string): void {\n console.log(`└ ${message}`);\n }\n\n outroError(data: OutroData): void {\n console.log(`✖ ${data.message ?? 'Wizard aborted'}`);\n if (data.body) console.log(`│ ${data.body}`);\n if (data.docsUrl) console.log(`│ Docs: ${data.docsUrl}`);\n }\n\n waitForOutroDismissed(): Promise<void> {\n return Promise.resolve();\n }\n\n waitForAiOptIn(): Promise<void> {\n // Non-TUI runs are CI runs, which auto-consent to AI usage.\n return Promise.resolve();\n }\n\n cancel(message: string): void {\n console.log(`■ ${message}`);\n }\n\n log = {\n info(message: string): void {\n console.log(`│ ${message}`);\n },\n warn(message: string): void {\n console.log(`▲ ${message}`);\n },\n error(message: string): void {\n console.log(`✖ ${message}`);\n },\n success(message: string): void {\n console.log(`✔ ${message}`);\n },\n step(message: string): void {\n console.log(`◇ ${message}`);\n },\n };\n\n note(message: string): void {\n console.log(`│ ${message}`);\n }\n\n spinner(): SpinnerHandle {\n return {\n start(message?: string) {\n if (message) console.log(`◌ ${message}`);\n },\n stop(message?: string) {\n if (message) console.log(`● ${message}`);\n },\n message(msg?: string) {\n if (msg) console.log(`◌ ${msg}`);\n },\n };\n }\n\n pushStatus(message: string): void {\n console.log(`◇ ${message}`);\n }\n\n setDetectedFramework(label: string): void {\n console.log(`✔ Framework: ${label}`);\n }\n\n onEnterScreen(_screen: string, _fn: () => void): void {\n // No screen transitions in CI\n }\n\n setLoginUrl(url: string | null): void {\n if (url) {\n console.log(\n `│ If the browser didn't open automatically, use this link:`,\n );\n console.log(`│ ${url}`);\n }\n }\n\n setAuthorizeUrl(_url: string | null): void {\n // Manual-paste modal is TUI-only; CI/non-interactive runs don't use it.\n }\n\n showBlockingOutage(result: WizardReadinessResult): Promise<void> {\n console.log(`▲ Service health issues detected — blocking outage.`);\n const blockingKeys = getBlockingServiceKeys(result.health);\n if (blockingKeys.length > 0) {\n console.log(`│`);\n console.log(`│ Blocking services:`);\n for (const key of blockingKeys) {\n const status = result.health[key].status;\n const error = result.health[key].error;\n const label = SERVICE_LABELS[key];\n const detail = error ? ` — ${error}` : '';\n console.log(`│ ✖ ${label}: ${status}${detail}`);\n }\n console.log(`│`);\n }\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n console.log(`│ The wizard cannot start while these services are down.`);\n return Promise.resolve();\n }\n\n setReadinessWarnings(result: WizardReadinessResult): void {\n console.log(`▲ Service health warnings detected.`);\n for (const reason of result.reasons) {\n console.log(`│ ${reason}`);\n }\n }\n\n showPortConflict(_processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void> {\n return Promise.resolve();\n }\n\n waitForManualAuthCode(): Promise<string> {\n // No interactive prompt in CI/logging mode — never resolves. CI bypasses\n // OAuth entirely, so this is only here to satisfy the interface.\n return new Promise<string>(() => {\n /* intentionally never resolves */\n });\n }\n\n showSettingsOverride(\n _conflicts: SettingsConflict[],\n _backupAndFix: () => boolean,\n ): Promise<void> {\n return Promise.resolve();\n }\n\n requestQuestion(_question: PendingQuestion): Promise<AskAnswers> {\n return Promise.reject(\n new Error(\n 'wizard_ask is not available in CI / non-interactive mode. ' +\n 'Re-run the wizard without --ci to answer interactively.',\n ),\n );\n }\n\n showAuthError(detail?: AuthErrorDetail): void {\n console.log(`✖ Authentication failed (401)`);\n if (detail?.hasSettingsConflict) {\n console.log(\n `│ Claude Code auth is conflicting with the wizard. Please try again after logging out:`,\n );\n console.log(`│ claude auth logout`);\n } else {\n console.log(\n `│ The PostHog LLM Gateway rejected the API key. Common causes:`,\n );\n console.log(\n `│ - Wrong key type: pass a personal API key (phx_xxx). pha_ is an OAuth access token, phc_ is a project key.`,\n );\n console.log(\n `│ - Missing scope: the personal API key needs the \"llm_gateway:read\" scope.`,\n );\n console.log(`│ - Expired or revoked key.`);\n console.log(\n `│ - Region mismatch: --region must match the region the key was issued in (us vs eu).`,\n );\n }\n if (detail?.logFilePath) {\n console.log(`│ Verbose log: ${detail.logFilePath}`);\n }\n }\n\n showSessionTimeout(): void {\n const minutes = Math.round(OAUTH_TIMEOUT_MS / 60_000);\n console.log(\n `✖ Login timed out. The OAuth link timed out after ${minutes} minutes.`,\n );\n console.log(`│ Re-run the wizard to get a fresh link and try again.`);\n }\n\n startRun(): void {\n // No-op in CI mode\n }\n\n setCredentials(_credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n }): void {\n // No-op in CI mode — credentials are handled directly\n }\n\n setRoleAtOrganization(_role: string | null): void {\n // No-op in CI mode — there's no TUI to render role-tailored prompts\n }\n\n setApiUser(_user: ApiUser | null): void {\n // No-op in CI mode — there's no TUI to read account context from\n // the session.\n }\n\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void {\n const completed = todos.filter(\n (t) => t.status === TaskStatus.Completed,\n ).length;\n const inProgress = todos.find((t) => t.status === TaskStatus.InProgress);\n if (inProgress) {\n console.log(\n `◌ [${completed}/${todos.length}] ${\n inProgress.activeForm || inProgress.content\n }`,\n );\n }\n }\n\n setEventPlan(_events: Array<{ name: string; description: string }>): void {\n // No-op in CI mode\n }\n\n setDashboardUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setNotebookUrl(_url: string): void {\n // No-op in CI mode\n }\n\n setOutroData(_data: import('@lib/wizard-session').OutroData): void {\n // No-op in CI mode\n }\n\n setFrameworkContext(_key: string, _value: unknown): void {\n // No-op in CI mode\n }\n}\n","/**\n * UI singleton — provides getUI() and setUI() for the wizard.\n * Default: LoggingUI. Swap to InkUI at startup for TUI mode.\n */\n\nimport type { WizardUI } from './wizard-ui';\nimport { LoggingUI } from './logging-ui';\n\nlet currentUI: WizardUI = new LoggingUI();\n\nexport function getUI(): WizardUI {\n return currentUI;\n}\n\nexport function setUI(ui: WizardUI): void {\n currentUI = ui;\n}\n\nexport type { WizardUI, SpinnerHandle } from './wizard-ui';\n","import { tmpdir } from 'node:os';\nimport { join, sep } from 'node:path';\n\n// /tmp is stable and discoverable on macOS/Linux; Windows needs os.tmpdir()\nconst TMP = process.platform === 'win32' ? tmpdir() : '/tmp';\n\nexport const WIZARD_LOG_FILE = join(TMP, 'posthog-wizard.log');\nexport const WIZARD_BENCHMARK_FILE = join(TMP, 'posthog-wizard-benchmark.json');\nexport const WIZARD_YARA_REPORT_FILE = join(\n TMP,\n 'posthog-wizard-yara-report.json',\n);\n/** Temp path for a skill download zip. */\nexport function skillTmpPath(skillId: string): string {\n return join(TMP, `posthog-skill-${skillId}.zip`);\n}\n\n/**\n * Strip an absolute installDir prefix off a project file path so the UI\n * renders `index.js:12` instead of `/Users/.../index.js:12`. Defends\n * against false matches like `/Users/foo` ⊂ `/Users/foobar/x.js` by\n * normalizing to a trailing path separator before the prefix check.\n */\nexport function relativeToInstallDir(file: string, installDir: string): string {\n const prefix = installDir.endsWith(sep) ? installDir : installDir + sep;\n return file.startsWith(prefix) ? file.slice(prefix.length) : file;\n}\n","import { appendFileSync } from 'fs';\nimport path from 'path';\nimport { inspect } from 'node:util';\nimport { getUI } from '@ui';\nimport { runtimeEnv } from '@env';\nimport { WIZARD_LOG_FILE } from './paths';\n\nlet logFilePath = WIZARD_LOG_FILE;\nlet fileLoggingEnabled = true;\nlet consoleLoggingEnabled = false;\n\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value instanceof Error) return value.stack ?? String(value);\n try {\n // JSON.stringify throws on cycles and skips some values — fall back to\n // inspect so a crash log line is never dropped.\n return JSON.stringify(value, null, 2) ?? inspect(value, { depth: 3 });\n } catch {\n return inspect(value, { depth: 3 });\n }\n}\n\nfunction renderLine(args: readonly unknown[]): string {\n return args.map(stringify).join(' ');\n}\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n}): void {\n if (opts.path !== undefined) logFilePath = opts.path;\n if (opts.enabled !== undefined) fileLoggingEnabled = opts.enabled;\n}\n\nexport function configureLogFileFromEnvironment(): void {\n const dir = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (dir) {\n configureLogFile({ path: path.join(dir, 'posthog-wizard.log') });\n }\n}\n\nexport function initLogFile(): void {\n if (!fileLoggingEnabled) return;\n try {\n const divider = '='.repeat(60);\n appendFileSync(\n logFilePath,\n `\\n${divider}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${divider}\\n`,\n );\n } catch {\n // Logging must never crash the wizard.\n }\n}\n\nexport function logToFile(...args: unknown[]): void {\n if (!fileLoggingEnabled) return;\n try {\n const ts = new Date().toISOString();\n appendFileSync(logFilePath, `[${ts}] ${renderLine(args)}\\n`);\n } catch {\n // Logging must never crash the wizard.\n }\n}\n\nexport function debug(...args: unknown[]): void {\n if (!consoleLoggingEnabled) return;\n getUI().log.info(renderLine(args));\n}\n\nexport function enableDebugLogs(): void {\n consoleLoggingEnabled = true;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as configureLogFileFromEnvironment, s as logToFile } from "./debug-
|
|
1
|
+
import { n as configureLogFileFromEnvironment, s as logToFile } from "./debug-Ckumcrye.js";
|
|
2
2
|
export { configureLogFileFromEnvironment, logToFile };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import "./debug-
|
|
3
|
-
import "./setup-utils-
|
|
2
|
+
import "./debug-Ckumcrye.js";
|
|
3
|
+
import "./setup-utils-Cr4FxJDl.js";
|
|
4
4
|
import readEnvModule from "read-env";
|
|
5
5
|
import "fast-glob";
|
|
6
6
|
//#region src/utils/environment.ts
|
|
@@ -19,4 +19,4 @@ function readEnvironment() {
|
|
|
19
19
|
//#endregion
|
|
20
20
|
export { isNonInteractiveEnvironment as n, environment_exports as t };
|
|
21
21
|
|
|
22
|
-
//# sourceMappingURL=environment-
|
|
22
|
+
//# sourceMappingURL=environment-DUh_8hqW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"environment-
|
|
1
|
+
{"version":3,"file":"environment-DUh_8hqW.js","names":[],"sources":["../src/utils/environment.ts"],"sourcesContent":["import readEnvModule from 'read-env';\n\nconst readEnv =\n typeof readEnvModule === 'function'\n ? readEnvModule\n : (readEnvModule as any).default;\nimport { tryGetPackageJson } from './setup-utils';\nimport type { WizardRunOptions } from './types';\nimport fg from 'fast-glob';\nimport { IS_DEV } from '@lib/constants';\n\nexport function isNonInteractiveEnvironment(): boolean {\n if (IS_DEV) {\n return false;\n }\n\n if (!process.stdout.isTTY || !process.stderr.isTTY) {\n return true;\n }\n\n return false;\n}\n\nexport function readEnvironment(): Record<string, unknown> {\n const result = readEnv('POSTHOG_WIZARD');\n\n return result;\n}\n\nexport async function detectEnvVarPrefix(\n options: WizardRunOptions,\n): Promise<string> {\n const packageJson = await tryGetPackageJson(options);\n if (!packageJson) return 'VITE_PUBLIC_';\n\n const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };\n const has = (name: string) => name in deps;\n const hasAnyFile = async (patterns: string[]) => {\n const matches = await fg(patterns, {\n cwd: options.installDir,\n absolute: false,\n onlyFiles: true,\n ignore: ['**/node_modules/**'],\n });\n return matches.length > 0;\n };\n\n // --- Next.js\n if (has('next') || (await hasAnyFile(['**/next.config.{js,ts,mjs,cjs}']))) {\n return 'NEXT_PUBLIC_';\n }\n\n // --- Create React App\n if (\n has('react-scripts') ||\n has('create-react-app') ||\n (await hasAnyFile(['**/config-overrides.js']))\n ) {\n return 'REACT_APP_';\n }\n\n // --- Vite (vanilla, TanStack, Solid, etc.)\n // Note: Vite does not need PUBLIC_ but we use it to follow the docs, to improve the chances of an LLM getting it right.\n if (has('vite') || (await hasAnyFile(['**/vite.config.{js,ts,mjs,cjs}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SvelteKit\n if (\n has('@sveltejs/kit') ||\n (await hasAnyFile(['**/svelte.config.{js,ts}']))\n ) {\n return 'PUBLIC_';\n }\n\n // --- TanStack Start (uses Vite)\n if (\n has('@tanstack/start') ||\n (await hasAnyFile(['**/tanstack.config.{js,ts}']))\n ) {\n return 'VITE_PUBLIC_';\n }\n\n // --- SolidStart (uses Vite)\n if (has('solid-start') || (await hasAnyFile(['**/solid.config.{js,ts}']))) {\n return 'VITE_PUBLIC_';\n }\n\n // --- Astro\n if (has('astro') || (await hasAnyFile(['**/astro.config.{js,ts,mjs}']))) {\n return 'PUBLIC_';\n }\n\n // We default to Vite if we can't detect a specific framework, since it's the most commonly used.\n return 'VITE_PUBLIC_';\n}\n"],"mappings":";;;;;;;;;;AAEA,MAAM,UACJ,OAAO,kBAAkB,aACrB,gBACC,cAAsB;AAM7B,SAAgB,8BAAuC;AAKrD,KAAI,CAAC,QAAQ,OAAO,SAAS,CAAC,QAAQ,OAAO,MAC3C,QAAO;AAGT,QAAO;;AAGT,SAAgB,kBAA2C;AAGzD,QAFe,QAAQ,iBAAiB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as posthogIntegrationConfig } from "./posthog-integration-
|
|
1
|
+
import { n as posthogIntegrationConfig } from "./posthog-integration-COcPewVt.js";
|
|
2
2
|
import { n as runWizard } from "./bin.js";
|
|
3
3
|
//#region src/commands/basic-integration/interactive.ts
|
|
4
4
|
/** Default flow: run the posthog-integration program through the TUI. */
|
|
@@ -8,4 +8,4 @@ function runInteractive(argv) {
|
|
|
8
8
|
//#endregion
|
|
9
9
|
export { runInteractive };
|
|
10
10
|
|
|
11
|
-
//# sourceMappingURL=interactive-
|
|
11
|
+
//# sourceMappingURL=interactive-DeiHgviS.js.map
|