@posthog/wizard 2.14.3 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -1
- package/dist/{TextBlock-DEHERFec.js → TextBlock-B_8bXLLs.js} +2 -2
- package/dist/{TextBlock-DEHERFec.js.map → TextBlock-B_8bXLLs.js.map} +1 -1
- package/dist/{add-mcp-server-to-clients-B48J7VVO.js → add-mcp-server-to-clients-Dq0n2yzq.js} +5 -5
- package/dist/{add-mcp-server-to-clients-B48J7VVO.js.map → add-mcp-server-to-clients-Dq0n2yzq.js.map} +1 -1
- package/dist/{agent-interface-cEdS_bNo.js → agent-interface-yB_27jG8.js} +106 -21
- package/dist/agent-interface-yB_27jG8.js.map +1 -0
- package/dist/{agent-runner-CK5r-zQF.js → agent-runner-C9sSudE0.js} +7 -8
- package/dist/agent-runner-C9sSudE0.js.map +1 -0
- package/dist/analytics-BnR9904x.js +2 -0
- package/dist/{analytics-DaDpDus8.js → analytics-Da4QHjMw.js} +2 -2
- package/dist/{analytics-DaDpDus8.js.map → analytics-Da4QHjMw.js.map} +1 -1
- package/dist/bin.js +896 -80
- package/dist/bin.js.map +1 -1
- package/dist/{debug-B_PK52GI.js → debug-D5kt4fxB.js} +1 -1
- package/dist/{debug-BOogNcWX.js → debug-DRKLej5r.js} +55 -46
- package/dist/debug-DRKLej5r.js.map +1 -0
- package/dist/{defaults-DgKAzsD1.js → defaults-CPH6eWhN.js} +1 -1
- package/dist/{defaults-DgKAzsD1.js.map → defaults-CPH6eWhN.js.map} +1 -1
- package/dist/{detection-OCF8fpfp.js → detection-0Pz2NncX.js} +3 -3
- package/dist/{detection-OCF8fpfp.js.map → detection-0Pz2NncX.js.map} +1 -1
- package/dist/{env-api-key-D5G2PrXW.js → env-api-key-HFqv1l-z.js} +1 -1
- package/dist/{env-api-key-D5G2PrXW.js.map → env-api-key-HFqv1l-z.js.map} +1 -1
- package/dist/{file-utils-DPmgn9Vm.js → file-utils-DnTSiTJw.js} +1 -1
- package/dist/file-utils-DnTSiTJw.js.map +1 -0
- package/dist/package-json-Cttzi3C8.js +2 -0
- package/dist/package-json-v_g2YlN1.js +35 -0
- package/dist/package-json-v_g2YlN1.js.map +1 -0
- package/dist/{package-manager-CmMJAD-V.js → package-manager-DlTISyej.js} +2 -2
- package/dist/package-manager-DlTISyej.js.map +1 -0
- package/dist/posthog-B1G0raJU.js +120 -0
- package/dist/posthog-B1G0raJU.js.map +1 -0
- package/dist/{posthog-integration-By5930Gz.js → posthog-integration-D-DyEJvz.js} +13 -12
- package/dist/{posthog-integration-By5930Gz.js.map → posthog-integration-D-DyEJvz.js.map} +1 -1
- package/dist/provisioning-COeHnCVG.js +2 -0
- package/dist/{provisioning-BHa8VWaa.js → provisioning-DmN8ZDbE.js} +3 -3
- package/dist/{provisioning-BHa8VWaa.js.map → provisioning-DmN8ZDbE.js.map} +1 -1
- package/dist/{registry-DpROZPnl.js → registry-CofBzIdU.js} +31 -31
- package/dist/registry-CofBzIdU.js.map +1 -0
- package/dist/setup-utils-C5iSJ3eg.js +2 -0
- package/dist/{setup-utils-Mzpk1vqG.js → setup-utils-_P-or31U.js} +91 -51
- package/dist/setup-utils-_P-or31U.js.map +1 -0
- package/dist/{slides-BtDXEXdn.js → slides-D3I6JzlG.js} +41 -8
- package/dist/slides-D3I6JzlG.js.map +1 -0
- package/dist/smoke-test-ci.sh +5 -2
- package/dist/smoke-test.sh +43 -0
- package/dist/{start-playground-zZL5y9id.js → start-playground-Bxd2KG2L.js} +5 -6
- package/dist/{start-playground-zZL5y9id.js.map → start-playground-Bxd2KG2L.js.map} +1 -1
- package/dist/{start-tui-Cz7RZSn_.js → start-tui-Bl8fCbp_.js} +576 -23
- package/dist/start-tui-Bl8fCbp_.js.map +1 -0
- package/dist/{steps-C2XEzN79.js → steps-B-vmvb2V.js} +6 -6
- package/dist/{steps-C2XEzN79.js.map → steps-B-vmvb2V.js.map} +1 -1
- package/dist/task-stream-z6QFZtpC.js +195 -0
- package/dist/task-stream-z6QFZtpC.js.map +1 -0
- package/dist/{telemetry-BG2bOwCp.js → telemetry-XO0SlTFs.js} +2 -2
- package/dist/{telemetry-BG2bOwCp.js.map → telemetry-XO0SlTFs.js.map} +1 -1
- package/dist/{wizard-abort-CYW83OG5.js → wizard-abort-CuaS1eXn.js} +1 -1
- package/dist/{wizard-abort-BmT-F0Vr.js → wizard-abort-uolun8Q3.js} +3 -3
- package/dist/{wizard-abort-BmT-F0Vr.js.map → wizard-abort-uolun8Q3.js.map} +1 -1
- package/dist/{wizard-session-CsI33S4_.js → wizard-session-BlgiX-5d.js} +16 -2
- package/dist/wizard-session-BlgiX-5d.js.map +1 -0
- package/dist/wizard-session-DxU5ZMBN.js +2 -0
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/package.json +3 -2
- package/dist/agent-interface-cEdS_bNo.js.map +0 -1
- package/dist/agent-runner-CK5r-zQF.js.map +0 -1
- package/dist/analytics-Bw8E-yhX.js +0 -2
- package/dist/craft-pre-release.sh +0 -10
- package/dist/debug-BOogNcWX.js.map +0 -1
- package/dist/file-BKbKreWF.js +0 -16
- package/dist/file-BKbKreWF.js.map +0 -1
- package/dist/file-utils-DPmgn9Vm.js.map +0 -1
- package/dist/package-json-DZpnf6vU.js +0 -23
- package/dist/package-json-DZpnf6vU.js.map +0 -1
- package/dist/package-json-_4PEss19.js +0 -2
- package/dist/package-manager-CmMJAD-V.js.map +0 -1
- package/dist/paths-DJS47p5x.js +0 -26
- package/dist/paths-DJS47p5x.js.map +0 -1
- package/dist/posthog-BbQf_Hzq.js +0 -11
- package/dist/posthog-BbQf_Hzq.js.map +0 -1
- package/dist/provisioning-gHqu_MXL.js +0 -2
- package/dist/registry-DpROZPnl.js.map +0 -1
- package/dist/setup-utils-Mzpk1vqG.js.map +0 -1
- package/dist/setup-utils-ptemIB6g.js +0 -2
- package/dist/slides-BtDXEXdn.js.map +0 -1
- package/dist/start-tui-Cz7RZSn_.js.map +0 -1
- package/dist/task-stream-DUpUZmFQ.js +0 -61
- package/dist/task-stream-DUpUZmFQ.js.map +0 -1
- package/dist/wizard-session-CPhhll4P.js +0 -2
- package/dist/wizard-session-CsI33S4_.js.map +0 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as configureLogFileFromEnvironment, s as logToFile } from "./debug-
|
|
1
|
+
import { n as configureLogFileFromEnvironment, s as logToFile } from "./debug-DRKLej5r.js";
|
|
2
2
|
export { configureLogFileFromEnvironment, logToFile };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import "./wizard-ui-YdGFRyu_.js";
|
|
2
|
-
import {
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join, sep } from "node:path";
|
|
3
4
|
import { appendFileSync } from "fs";
|
|
4
5
|
import path from "path";
|
|
5
6
|
//#region src/lib/version.ts
|
|
6
|
-
const VERSION = "2.
|
|
7
|
+
const VERSION = "2.15.0";
|
|
7
8
|
//#endregion
|
|
8
9
|
//#region src/env.ts
|
|
9
10
|
/**
|
|
@@ -116,15 +117,17 @@ const WIZARD_PROVISIONING_SCOPES = [
|
|
|
116
117
|
];
|
|
117
118
|
/**
|
|
118
119
|
* Scopes the wizard requests during the OAuth login flow. Superset of
|
|
119
|
-
* `WIZARD_PROVISIONING_SCOPES` with
|
|
120
|
+
* `WIZARD_PROVISIONING_SCOPES` with scopes that only apply to the login
|
|
120
121
|
* path and are not in the provisioning allowlist:
|
|
121
|
-
* -
|
|
122
|
-
* -
|
|
122
|
+
* - health_issue:read used by `wizard doctor`
|
|
123
|
+
* - wizard_session:read list / retrieve / stream sessions
|
|
124
|
+
* - wizard_session:write stream run state to /api/projects/{id}/wizard/sessions/
|
|
123
125
|
*/
|
|
124
126
|
const WIZARD_OAUTH_SCOPES = [
|
|
125
127
|
...WIZARD_PROVISIONING_SCOPES,
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
+
"health_issue:read",
|
|
129
|
+
"wizard_session:read",
|
|
130
|
+
"wizard_session:write"
|
|
128
131
|
];
|
|
129
132
|
const WIZARD_INTERACTION_EVENT_NAME = "wizard interaction";
|
|
130
133
|
const WIZARD_REMARK_EVENT_NAME = "wizard remark";
|
|
@@ -556,6 +559,7 @@ var LoggingUI = class {
|
|
|
556
559
|
console.log(`│ ${url}`);
|
|
557
560
|
}
|
|
558
561
|
}
|
|
562
|
+
setAuthorizeUrl(_url) {}
|
|
559
563
|
showBlockingOutage(result) {
|
|
560
564
|
console.log(`▲ Service health issues detected — blocking outage.`);
|
|
561
565
|
const blockingKeys = getBlockingServiceKeys(result.health);
|
|
@@ -582,6 +586,9 @@ var LoggingUI = class {
|
|
|
582
586
|
showPortConflict(_processInfo) {
|
|
583
587
|
return Promise.resolve();
|
|
584
588
|
}
|
|
589
|
+
waitForManualAuthCode() {
|
|
590
|
+
return new Promise(() => {});
|
|
591
|
+
}
|
|
585
592
|
showSettingsOverride(_conflicts, _backupAndFix) {
|
|
586
593
|
return Promise.resolve();
|
|
587
594
|
}
|
|
@@ -623,69 +630,71 @@ function setUI(ui) {
|
|
|
623
630
|
currentUI = ui;
|
|
624
631
|
}
|
|
625
632
|
//#endregion
|
|
633
|
+
//#region src/utils/paths.ts
|
|
634
|
+
const TMP = process.platform === "win32" ? tmpdir() : "/tmp";
|
|
635
|
+
const WIZARD_LOG_FILE = join(TMP, "posthog-wizard.log");
|
|
636
|
+
const WIZARD_BENCHMARK_FILE = join(TMP, "posthog-wizard-benchmark.json");
|
|
637
|
+
const WIZARD_YARA_REPORT_FILE = join(TMP, "posthog-wizard-yara-report.json");
|
|
638
|
+
/** Temp path for a skill download zip. */
|
|
639
|
+
function skillTmpPath(skillId) {
|
|
640
|
+
return join(TMP, `posthog-skill-${skillId}.zip`);
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Strip an absolute installDir prefix off a project file path so the UI
|
|
644
|
+
* renders `index.js:12` instead of `/Users/.../index.js:12`. Defends
|
|
645
|
+
* against false matches like `/Users/foo` ⊂ `/Users/foobar/x.js` by
|
|
646
|
+
* normalizing to a trailing path separator before the prefix check.
|
|
647
|
+
*/
|
|
648
|
+
function relativeToInstallDir(file, installDir) {
|
|
649
|
+
const prefix = installDir.endsWith(sep) ? installDir : installDir + sep;
|
|
650
|
+
return file.startsWith(prefix) ? file.slice(prefix.length) : file;
|
|
651
|
+
}
|
|
652
|
+
//#endregion
|
|
626
653
|
//#region src/utils/debug.ts
|
|
627
|
-
|
|
654
|
+
let logFilePath = WIZARD_LOG_FILE;
|
|
655
|
+
let fileLoggingEnabled = true;
|
|
656
|
+
let consoleLoggingEnabled = false;
|
|
657
|
+
function stringify(value) {
|
|
628
658
|
if (typeof value === "string") return value;
|
|
629
659
|
if (value instanceof Error) return value.stack ?? "";
|
|
630
660
|
return JSON.stringify(value, null, 2);
|
|
631
661
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
662
|
+
function renderLine(args) {
|
|
663
|
+
return args.map(stringify).join(" ");
|
|
664
|
+
}
|
|
635
665
|
function getLogFilePath() {
|
|
636
666
|
return logFilePath;
|
|
637
667
|
}
|
|
638
|
-
/**
|
|
639
|
-
* Configure the log file path and enable/disable state.
|
|
640
|
-
* Call before initLogFile() to override defaults.
|
|
641
|
-
*/
|
|
642
668
|
function configureLogFile(opts) {
|
|
643
669
|
if (opts.path !== void 0) logFilePath = opts.path;
|
|
644
|
-
if (opts.enabled !== void 0)
|
|
670
|
+
if (opts.enabled !== void 0) fileLoggingEnabled = opts.enabled;
|
|
645
671
|
}
|
|
646
|
-
/**
|
|
647
|
-
* Configure log path from environment variables.
|
|
648
|
-
*
|
|
649
|
-
* Uses POSTHOG_WIZARD_LOG_DIR when set, joined with posthog-wizard.log.
|
|
650
|
-
*/
|
|
651
672
|
function configureLogFileFromEnvironment() {
|
|
652
|
-
const
|
|
653
|
-
if (
|
|
673
|
+
const dir = runtimeEnv("POSTHOG_WIZARD_LOG_DIR");
|
|
674
|
+
if (dir) configureLogFile({ path: path.join(dir, "posthog-wizard.log") });
|
|
654
675
|
}
|
|
655
|
-
/**
|
|
656
|
-
* Initialize the log file with a run header.
|
|
657
|
-
* Call this at the start of each wizard run.
|
|
658
|
-
* Fails silently to avoid crashing the wizard.
|
|
659
|
-
*/
|
|
660
676
|
function initLogFile() {
|
|
661
|
-
if (!
|
|
677
|
+
if (!fileLoggingEnabled) return;
|
|
662
678
|
try {
|
|
663
|
-
const
|
|
664
|
-
appendFileSync(logFilePath,
|
|
679
|
+
const divider = "=".repeat(60);
|
|
680
|
+
appendFileSync(logFilePath, `\n${divider}\nPostHog Wizard Run: ${(/* @__PURE__ */ new Date()).toISOString()}\n${divider}\n`);
|
|
665
681
|
} catch {}
|
|
666
682
|
}
|
|
667
|
-
/**
|
|
668
|
-
* Log a message to the log file.
|
|
669
|
-
* Always writes regardless of debug flag (when logging is enabled).
|
|
670
|
-
* Fails silently to avoid masking errors in catch blocks.
|
|
671
|
-
*/
|
|
672
683
|
function logToFile(...args) {
|
|
673
|
-
if (!
|
|
684
|
+
if (!fileLoggingEnabled) return;
|
|
674
685
|
try {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
appendFileSync(logFilePath, `[${timestamp}] ${msg}\n`);
|
|
686
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
687
|
+
appendFileSync(logFilePath, `[${ts}] ${renderLine(args)}\n`);
|
|
678
688
|
} catch {}
|
|
679
689
|
}
|
|
680
690
|
function debug(...args) {
|
|
681
|
-
if (!
|
|
682
|
-
|
|
683
|
-
getUI().log.info(msg);
|
|
691
|
+
if (!consoleLoggingEnabled) return;
|
|
692
|
+
getUI().log.info(renderLine(args));
|
|
684
693
|
}
|
|
685
694
|
function enableDebugLogs() {
|
|
686
|
-
|
|
695
|
+
consoleLoggingEnabled = true;
|
|
687
696
|
}
|
|
688
697
|
//#endregion
|
|
689
|
-
export {
|
|
698
|
+
export { OAUTH_TIMEOUT_MS as A, WIZARD_OAUTH_SCOPES as B, CONTEXT_MILL_URL as C, ISSUES_URL as D, DUMMY_PROJECT_API_KEY as E, POSTHOG_PROPERTY_HEADER_PREFIX as F, WIZARD_VARIANTS as G, WIZARD_REMARK_EVENT_NAME as H, POSTHOG_PROXY_CLIENT_ID as I, NODE_ENV as J, WIZARD_VARIANT_FLAG_KEY as K, POSTHOG_US_CLIENT_ID as L, POSTHOG_DOCS_URL as M, POSTHOG_FLAG_HEADER_PREFIX as N, Integration as O, POSTHOG_OAUTH_URL as P, REMOTE_SKILLS_BASE_URL as R, ANALYTICS_TEAM_TAG as S, DETECTION_TIMEOUT_MS as T, WIZARD_TOOLS_MENU_FLAG_KEY as U, WIZARD_PROVISIONING_SCOPES as V, WIZARD_USER_AGENT as W, VERSION as X, runtimeEnv as Y, SIGNUP_WIZARD_READINESS_CONFIG as _, getLogFilePath as a, ANALYTICS_HOST_URL as b, WIZARD_BENCHMARK_FILE as c, relativeToInstallDir as d, skillTmpPath as f, SERVICE_LABELS as g, LoggingUI as h, enableDebugLogs as i, POSTHOG_DEV_CLIENT_ID as j, OAUTH_PORTS as k, WIZARD_LOG_FILE as l, setUI as m, configureLogFileFromEnvironment as n, initLogFile as o, getUI as p, getSkillsBaseUrl as q, debug as r, logToFile as s, configureLogFile as t, WIZARD_YARA_REPORT_FILE as u, evaluateWizardReadiness as v, DEFAULT_HOST_URL as w, ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY as x, getBlockingServiceKeys as y, WIZARD_INTERACTION_EVENT_NAME as z };
|
|
690
699
|
|
|
691
|
-
//# sourceMappingURL=debug-
|
|
700
|
+
//# sourceMappingURL=debug-DRKLej5r.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-DRKLej5r.js","names":["errResult"],"sources":["../src/lib/version.ts","../src/env.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":["// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.15.0';\n","/**\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","/**\n * Shared constants for the PostHog wizard.\n */\n\nimport { VERSION } from './version';\n\n// ── Integration / CLI ───────────────────────────────────────────────\n\n/**\n * Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.\n */\nexport enum Integration {\n // Frameworks\n nextjs = 'nextjs',\n nuxt = 'nuxt',\n vue = 'vue',\n reactRouter = 'react-router',\n tanstackStart = 'tanstack-start',\n tanstackRouter = 'tanstack-router',\n reactNative = 'react-native',\n angular = 'angular',\n astro = 'astro',\n django = 'django',\n flask = 'flask',\n fastapi = 'fastapi',\n laravel = 'laravel',\n sveltekit = 'sveltekit',\n swift = 'swift',\n android = 'android',\n rails = 'rails',\n\n // Language fallbacks\n python = 'python',\n ruby = 'ruby',\n javascriptNode = 'javascript_node',\n javascript_web = 'javascript_web',\n}\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\n// ── Environment ──────────────────────────────────────────────────────\n\nimport { IS_DEV } from '@env';\nexport { IS_DEV };\nexport const DEBUG = false;\n\n// ── URLs ─────────────────────────────────────────────────────────────\n\nexport const DEFAULT_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.posthog.com';\nexport const DEFAULT_HOST_URL = IS_DEV\n ? 'http://localhost:8010'\n : 'https://us.i.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\nexport const CONTEXT_MILL_URL = 'https://github.com/PostHog/context-mill';\nexport const POSTHOG_DOCS_URL = 'https://posthog.com/docs';\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 *\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] 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 */\nexport const WIZARD_OAUTH_SCOPES = [\n ...WIZARD_PROVISIONING_SCOPES,\n 'health_issue:read',\n 'wizard_session:read',\n 'wizard_session:write',\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/** Timeout for the OAuth authorization flow (ms). */\nexport const OAUTH_TIMEOUT_MS = 360_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\nfunction errResult(error: string): BaseHealthResult {\n return { status: ServiceHealthStatus.Degraded, error };\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}`);\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');\n return { overall: err, components: err };\n }\n const err = errResult(e instanceof Error ? e.message : 'Unknown error');\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 { ServiceHealthStatus, type BaseHealthResult } from './types';\n\n// ---------------------------------------------------------------------------\n// Direct endpoint health checks\n//\n// These ping PostHog-owned services directly (no Statuspage intermediary).\n// A non-expected HTTP status or any network error is treated as Down.\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 / → 200 (HTML landing page)\n// ---------------------------------------------------------------------------\n\nfunction downResult(error: string): BaseHealthResult {\n return { status: ServiceHealthStatus.Down, error };\n}\n\nasync function fetchEndpointHealth(\n url: string,\n timeoutMs = 5000,\n expectedStatus = 200,\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.status === expectedStatus) {\n return {\n status: ServiceHealthStatus.Healthy,\n rawIndicator: `HTTP ${res.status}`,\n };\n }\n return downResult(`HTTP ${res.status}`);\n } catch (e) {\n if (e instanceof Error && e.name === 'AbortError')\n return downResult('Request timed out');\n return downResult(e instanceof Error ? e.message : 'Unknown error');\n }\n}\n\nexport const checkLlmGatewayHealth = (): Promise<BaseHealthResult> =>\n fetchEndpointHealth('https://gateway.us.posthog.com/_liveness');\n\nexport const checkMcpHealth = (): Promise<BaseHealthResult> =>\n fetchEndpointHealth('https://mcp.posthog.com/');\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 return {\n anthropic,\n posthogOverall,\n posthogComponents,\n github,\n npmOverall,\n npmComponents,\n cloudflareOverall,\n cloudflareComponents,\n llmGateway,\n mcp,\n githubReleases,\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\nconst READINESS_TIMEOUT_MS = 10_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 logToFile(`[health-checks] blocked by: ${blockingKeys.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 */\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 ) {\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/agent-interface';\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 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 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 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 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 { 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 ?? '';\n return JSON.stringify(value, null, 2);\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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"}
|
|
@@ -231,4 +231,4 @@ const getDefaultServerConfig = (apiKey, selectedFeatures, local) => {
|
|
|
231
231
|
//#endregion
|
|
232
232
|
export { getNativeHTTPServerConfig as i, AVAILABLE_FEATURES as n, getDefaultServerConfig as r, ALL_FEATURE_VALUES as t };
|
|
233
233
|
|
|
234
|
-
//# sourceMappingURL=defaults-
|
|
234
|
+
//# sourceMappingURL=defaults-CPH6eWhN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults-
|
|
1
|
+
{"version":3,"file":"defaults-CPH6eWhN.js","names":["z"],"sources":["../src/steps/add-mcp-server-to-clients/defaults.ts"],"sourcesContent":["import z from 'zod';\n\nexport const DefaultMCPClientConfig = z\n .object({\n mcpServers: z.record(\n z.string(),\n z.union([\n z.object({\n command: z.string().optional(),\n args: z.array(z.string()).optional(),\n env: z.record(z.string(), z.string()).optional(),\n }),\n z.object({\n url: z.string(),\n headers: z.record(z.string(), z.string()).optional(),\n }),\n ]),\n ),\n })\n .passthrough();\n\nexport const AVAILABLE_FEATURES = {\n 'Data & Analytics': [\n {\n value: 'dashboards',\n label: 'Dashboards',\n hint: 'Dashboard creation and management',\n },\n {\n value: 'insights',\n label: 'Insights',\n hint: 'Analytics insights',\n },\n {\n value: 'product_analytics',\n label: 'Product Analytics',\n hint: 'Insight CRUD management',\n },\n {\n value: 'experiments',\n label: 'Experiments',\n hint: 'A/B testing experiments',\n },\n {\n value: 'surveys',\n label: 'Surveys',\n hint: 'Survey management',\n },\n {\n value: 'annotations',\n label: 'Annotations',\n hint: 'Annotation management',\n },\n {\n value: 'replay',\n label: 'Session Replay',\n hint: 'Session recording management',\n },\n {\n value: 'sql',\n label: 'SQL',\n hint: 'SQL query execution',\n },\n ],\n 'AI Engineering': [\n {\n value: 'llm_analytics',\n label: 'LLM Analytics',\n hint: 'LLM usage and cost tracking',\n },\n {\n value: 'prompts',\n label: 'Prompts',\n hint: 'LLM prompt management',\n },\n ],\n 'Development Tools': [\n {\n value: 'error_tracking',\n label: 'Error Tracking',\n hint: 'Error monitoring and debugging',\n },\n {\n value: 'logs',\n label: 'Logs',\n hint: 'Log querying',\n },\n {\n value: 'flags',\n label: 'Feature Flags',\n hint: 'Feature flag management',\n },\n {\n value: 'early_access_features',\n label: 'Early Access Features',\n hint: 'Early access feature management',\n },\n {\n value: 'cohorts',\n label: 'Cohorts',\n hint: 'Cohort management',\n },\n ],\n 'Data Management': [\n {\n value: 'events',\n label: 'Events',\n hint: 'Event and property definitions',\n },\n {\n value: 'persons',\n label: 'Persons',\n hint: 'Person and group management',\n },\n {\n value: 'actions',\n label: 'Actions',\n hint: 'Action definitions',\n },\n {\n value: 'data_warehouse',\n label: 'Data Warehouse',\n hint: 'Data warehouse management',\n },\n {\n value: 'endpoints',\n label: 'Endpoints',\n hint: 'Data warehouse endpoint management',\n },\n {\n value: 'data_schema',\n label: 'Data Schema',\n hint: 'Data schema exploration',\n },\n ],\n 'CDP & Automation': [\n {\n value: 'hog_functions',\n label: 'Hog Functions',\n hint: 'CDP function management',\n },\n {\n value: 'hog_function_templates',\n label: 'Hog Function Templates',\n hint: 'CDP function template browsing',\n },\n {\n value: 'workflows',\n label: 'Workflows',\n hint: 'Workflow management',\n },\n ],\n 'Platform & Management': [\n {\n value: 'workspace',\n label: 'Workspace',\n hint: 'Organization and project management',\n },\n {\n value: 'docs',\n label: 'Documentation',\n hint: 'PostHog documentation search',\n },\n {\n value: 'notebooks',\n label: 'Notebooks',\n hint: 'Notebook management',\n },\n {\n value: 'alerts',\n label: 'Alerts',\n hint: 'Alert management',\n },\n {\n value: 'platform_features',\n label: 'Platform Features',\n hint: 'Activity logs, approvals, comments, and roles',\n },\n {\n value: 'integrations',\n label: 'Integrations',\n hint: 'Connected integration management',\n },\n {\n value: 'conversations',\n label: 'Conversations',\n hint: 'Support ticket management',\n },\n {\n value: 'core',\n label: 'Subscriptions',\n hint: 'Scheduled insight and dashboard deliveries',\n },\n {\n value: 'search',\n label: 'Search',\n hint: 'Entity search across the project',\n },\n {\n value: 'reverse_proxy',\n label: 'Reverse Proxy',\n hint: 'Reverse proxy record management',\n },\n {\n value: 'debug',\n label: 'Debug',\n hint: 'Debug and diagnostic tools',\n },\n ],\n};\n\nexport const ALL_FEATURE_VALUES = Object.values(AVAILABLE_FEATURES)\n .flat()\n .map((feature) => feature.value);\n\nexport const buildMCPUrl = (selectedFeatures?: string[], local?: boolean) => {\n const host = local ? 'http://localhost:8787' : 'https://mcp.posthog.com';\n const baseUrl = `${host}/mcp`;\n\n const isAllFeaturesSelected =\n selectedFeatures &&\n selectedFeatures.length === ALL_FEATURE_VALUES.length &&\n ALL_FEATURE_VALUES.every((feature) => selectedFeatures.includes(feature));\n\n const params: string[] = [];\n\n // Add features param if not all features selected\n if (\n selectedFeatures &&\n selectedFeatures.length > 0 &&\n !isAllFeaturesSelected\n ) {\n params.push(`features=${selectedFeatures.join(',')}`);\n }\n\n return params.length > 0 ? `${baseUrl}?${params.join('&')}` : baseUrl;\n};\n\nexport const getNativeHTTPServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const config: Record<string, unknown> = {\n url: buildMCPUrl(selectedFeatures, local),\n };\n\n // Only add auth header if API key is provided (not OAuth mode)\n if (apiKey) {\n config.headers = {\n Authorization: `Bearer ${apiKey}`,\n };\n }\n\n return config;\n};\n\nexport const getDefaultServerConfig = (\n apiKey: string | undefined,\n selectedFeatures?: string[],\n local?: boolean,\n) => {\n const urlWithFeatures = buildMCPUrl(selectedFeatures, local);\n\n // OAuth mode: no auth header, let MCP handle OAuth\n if (!apiKey) {\n return {\n command: 'npx',\n args: ['-y', 'mcp-remote@latest', urlWithFeatures],\n };\n }\n\n // API key mode: include auth header\n return {\n command: 'npx',\n args: [\n '-y',\n 'mcp-remote@latest',\n urlWithFeatures,\n '--header',\n `Authorization:\\${POSTHOG_AUTH_HEADER}`,\n ],\n env: {\n POSTHOG_AUTH_HEADER: `Bearer ${apiKey}`,\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import { t as FRAMEWORK_REGISTRY } from "./registry-
|
|
2
|
+
import { O as Integration, T as DETECTION_TIMEOUT_MS } from "./debug-DRKLej5r.js";
|
|
3
|
+
import { t as FRAMEWORK_REGISTRY } from "./registry-CofBzIdU.js";
|
|
4
4
|
import * as semver from "semver";
|
|
5
5
|
import { readFileSync } from "fs";
|
|
6
6
|
import { join } from "path";
|
|
@@ -203,4 +203,4 @@ var detection_exports = /* @__PURE__ */ __exportAll({
|
|
|
203
203
|
//#endregion
|
|
204
204
|
export { detectFramework as a, discoverFeatures as i, checkFrameworkVersion as n, gatherFrameworkContext as r, detection_exports as t };
|
|
205
205
|
|
|
206
|
-
//# sourceMappingURL=detection-
|
|
206
|
+
//# sourceMappingURL=detection-0Pz2NncX.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detection-OCF8fpfp.js","names":[],"sources":["../src/lib/detection/framework.ts","../src/lib/detection/features.ts","../src/lib/detection/context.ts","../src/lib/detection/index.ts"],"sourcesContent":["/**\n * Framework detection — identify which PostHog-supported framework\n * is present in the project directory.\n *\n * Pure function: takes an install dir, returns the detected integration\n * (or undefined). No store mutations, no UI calls.\n */\n\nimport { Integration, DETECTION_TIMEOUT_MS } from '@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 { WizardOptions } 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: WizardOptions,\n): Promise<Record<string, unknown>> {\n if (!config.metadata.gatherContext) return {};\n\n try {\n return await Promise.race([\n config.metadata.gatherContext(options),\n new Promise<Record<string, never>>((resolve) =>\n setTimeout(() => resolve({}), DETECTION_TIMEOUT_MS),\n ),\n ]);\n } catch {\n return {};\n }\n}\n\nexport interface VersionCheckResult {\n /** Whether the installed version is supported */\n supported:\n | true\n | {\n current: string;\n minimum: string;\n docsUrl: string;\n };\n}\n\n/**\n * Check whether the installed framework version meets the minimum requirement.\n *\n * Returns `{ supported: true }` if the version is fine (or no check is needed).\n * Returns the version details if unsupported.\n */\nexport async function checkFrameworkVersion(\n config: FrameworkConfig,\n options: WizardOptions,\n): Promise<VersionCheckResult> {\n if (\n !config.detection.minimumVersion ||\n !config.detection.getInstalledVersion\n ) {\n return { supported: true };\n }\n\n const version = await config.detection.getInstalledVersion(options);\n if (!version) return { supported: true };\n\n const coerced = semver.coerce(version);\n if (coerced && semver.lt(coerced, config.detection.minimumVersion)) {\n return {\n supported: {\n current: version,\n minimum: config.detection.minimumVersion,\n docsUrl:\n config.metadata.unsupportedVersionDocsUrl ?? config.metadata.docsUrl,\n },\n };\n }\n\n return { supported: true };\n}\n","export { detectFramework } from './framework.js';\nexport { discoverFeatures } from './features.js';\nexport {\n gatherFrameworkContext,\n checkFrameworkVersion,\n type VersionCheckResult,\n} from './context.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAgBA,eAAsB,gBACpB,YACkC;AAClC,MAAK,MAAM,eAAe,OAAO,OAAO,YAAY,EAAE;EACpD,MAAM,SAAS,mBAAmB;AAClC,MAAI;AAOF,OANiB,MAAM,QAAQ,KAAK,CAClC,OAAO,UAAU,OAAO,EAAE,YAAY,CAAC,EACvC,IAAI,SAAgB,YAClB,iBAAiB,QAAQ,MAAM,EAAA,IAAuB,CACvD,CACF,CAAC,CAEA,QAAO;UAEH;;;;;;;;;;;;ACnBZ,MAAM,kBAAkB,CAAC,UAAU,oBAAoB;AAEvD,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAGD,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAgB,iBAAiB,YAAyC;CACxE,MAAM,WAAgC,EAAE;AACxC,sBAAqB,YAAY,SAAS;AAC1C,wBAAuB,YAAY,SAAS;AAC5C,QAAO;;AAGT,SAAS,qBACP,YACA,UACM;CACN,MAAM,kBAAkB,SAAS,YAAY,eAAe;AAC5D,KAAI,CAAC,gBAAiB;CAEtB,IAAI;AAIJ,KAAI;AACF,gBAAc,KAAK,MAAM,gBAAgB;SACnC;AACN;;CAGF,MAAM,WAAW,OAAO,KAAK;EAC3B,GAAG,YAAY;EACf,GAAG,YAAY;EAChB,CAAC;AAEF,KAAI,SAAS,MAAM,YAAY,gBAAgB,SAAS,QAAQ,CAAC,CAC/D,UAAS,KAAA,SAA8B;AAEzC,KAAI,SAAS,MAAM,YAAY,aAAa,SAAS,QAAQ,CAAC,CAC5D,UAAS,KAAA,MAA2B;;AAIxC,SAAS,uBACP,YACA,UACM;AACN,KAAI,SAAS,SAAA,MAA+B,CAAE;CAE9C,MAAM,WAAqB,EAAE;CAE7B,MAAM,kBAAkB,SAAS,YAAY,mBAAmB;AAChE,KAAI,gBAAiB,UAAS,KAAK,GAAG,qBAAqB,gBAAgB,CAAC;CAE5E,MAAM,gBAAgB,SAAS,YAAY,iBAAiB;AAC5D,KAAI,cAAe,UAAS,KAAK,GAAG,mBAAmB,cAAc,CAAC;CAEtE,MAAM,UAAU,SAAS,YAAY,UAAU;AAC/C,KAAI,QAAS,UAAS,KAAK,GAAG,aAAa,QAAQ,CAAC;AAEpD,KAAI,SAAS,MAAM,YAAY,oBAAoB,SAAS,QAAQ,CAAC,CACnE,UAAS,KAAA,MAA2B;;AAIxC,SAAS,SAAS,YAAoB,MAA6B;AACjE,KAAI;AACF,SAAO,aAAa,KAAK,YAAY,KAAK,EAAE,QAAQ;SAC9C;AACN,SAAO;;;AAIX,SAAS,gBAAgB,MAAsB;AAC7C,QAAO,KAAK,aAAa,CAAC,QAAQ,MAAM,IAAI;;AAG9C,SAAgB,qBAAqB,SAA2B;AAC9D,QAAO,QACJ,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAS,QAAQ,CAAC,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,CACxE,KAAK,SAAS,KAAK,QAAQ,cAAc,GAAG,CAAC,CAC7C,KAAK,SAAS,KAAK,MAAM,aAAa,CAAC,GAAG,CAC1C,OAAO,QAAQ,CACf,IAAI,gBAAgB;;AAIzB,SAAgB,mBAAmB,SAA2B;CAC5D,MAAM,WAAqB,EAAE;AAE7B,MAAK,MAAM,cAAc,QAAQ,SAC/B,mCACD,EAAE;EACD,MAAM,YAAY,WAAW;AAC7B,OAAK,MAAM,eAAe,UAAU,SAAS,oBAAoB,EAAE;GAEjE,MAAM,OADU,YAAY,GACP,QAAQ,cAAc,GAAG,CAAC,MAAM,aAAa,CAAC;AACnE,OAAI,KAAM,UAAS,KAAK,gBAAgB,KAAK,CAAC;;;AAMlD,MAAK,MAAM,gBAAgB,QAAQ,SADjC,wGAC0D,EAAE;EAC5D,MAAM,cAAc,aAAa;AACjC,WAAS,KAAK,GAAG,uBAAuB,aAAa,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;;AAG7E,QAAO;;AAGT,SAAgB,aAAa,SAA2B;CACtD,MAAM,WAAqB,EAAE;AAE7B,MAAK,MAAM,gBAAgB,QAAQ,SADjB,mDACoC,EAAE;EACtD,MAAM,cAAc,aAAa;AACjC,WAAS,KAAK,GAAG,uBAAuB,YAAY,CAAC;;AAEvD,QAAO;;AAGT,SAAS,uBACP,aACA,OAA4B,EAAE,EACpB;CACV,MAAM,YAAY,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;CAC1C,MAAM,WAAqB,EAAE;AAC7B,MAAK,MAAM,QAAQ,YAAY,MAAM,KAAK,EAAE;EAC1C,MAAM,UAAU,KAAK,MAAM;AAC3B,MAAI,CAAC,WAAW,QAAQ,WAAW,IAAI,CAAE;EACzC,MAAM,cAAc,QAAQ,QAAQ,IAAI;AACxC,MAAI,eAAe,EAAG;EACtB,MAAM,OAAO,QAAQ,MAAM,GAAG,YAAY,CAAC,MAAM;AACjD,MAAI,CAAC,oBAAoB,KAAK,KAAK,CAAE;AACrC,MAAI,UAAU,IAAI,KAAK,aAAa,CAAC,CAAE;AACvC,WAAS,KAAK,gBAAgB,KAAK,CAAC;;AAEtC,QAAO;;;;;;;;;;;;;;;;;ACrKT,eAAsB,uBACpB,QACA,SACkC;AAClC,KAAI,CAAC,OAAO,SAAS,cAAe,QAAO,EAAE;AAE7C,KAAI;AACF,SAAO,MAAM,QAAQ,KAAK,CACxB,OAAO,SAAS,cAAc,QAAQ,EACtC,IAAI,SAAgC,YAClC,iBAAiB,QAAQ,EAAE,CAAC,EAAE,qBAAqB,CACpD,CACF,CAAC;SACI;AACN,SAAO,EAAE;;;;;;;;;AAqBb,eAAsB,sBACpB,QACA,SAC6B;AAC7B,KACE,CAAC,OAAO,UAAU,kBAClB,CAAC,OAAO,UAAU,oBAElB,QAAO,EAAE,WAAW,MAAM;CAG5B,MAAM,UAAU,MAAM,OAAO,UAAU,oBAAoB,QAAQ;AACnE,KAAI,CAAC,QAAS,QAAO,EAAE,WAAW,MAAM;CAExC,MAAM,UAAU,OAAO,OAAO,QAAQ;AACtC,KAAI,WAAW,OAAO,GAAG,SAAS,OAAO,UAAU,eAAe,CAChE,QAAO,EACL,WAAW;EACT,SAAS;EACT,SAAS,OAAO,UAAU;EAC1B,SACE,OAAO,SAAS,6BAA6B,OAAO,SAAS;EAChE,EACF;AAGH,QAAO,EAAE,WAAW,MAAM"}
|
|
1
|
+
{"version":3,"file":"detection-0Pz2NncX.js","names":[],"sources":["../src/lib/detection/framework.ts","../src/lib/detection/features.ts","../src/lib/detection/context.ts","../src/lib/detection/index.ts"],"sourcesContent":["/**\n * Framework detection — identify which PostHog-supported framework\n * is present in the project directory.\n *\n * Pure function: takes an install dir, returns the detected integration\n * (or undefined). No store mutations, no UI calls.\n */\n\nimport { Integration, DETECTION_TIMEOUT_MS } from '@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","export { detectFramework } from './framework.js';\nexport { discoverFeatures } from './features.js';\nexport {\n gatherFrameworkContext,\n checkFrameworkVersion,\n type VersionCheckResult,\n} from './context.js';\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-api-key-
|
|
1
|
+
{"version":3,"file":"env-api-key-HFqv1l-z.js","names":["path","fs"],"sources":["../src/utils/env-api-key.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\n/**\n * Read POSTHOG_PERSONAL_API_KEY from .env.local or .env in the current\n * working directory. Returns undefined when no key is found.\n */\nexport function readApiKeyFromEnv(): string | undefined {\n const envFiles = ['.env.local', '.env'];\n for (const envFile of envFiles) {\n const envPath = path.join(process.cwd(), envFile);\n if (fs.existsSync(envPath)) {\n const content = fs.readFileSync(envPath, 'utf8');\n const match = content.match(/^POSTHOG_PERSONAL_API_KEY=(.+)$/m);\n if (match) {\n return match[1].trim();\n }\n }\n }\n return undefined;\n}\n"],"mappings":";;;;;;;AAOA,SAAgB,oBAAwC;AAEtD,MAAK,MAAM,WADM,CAAC,cAAc,OAAO,EACP;EAC9B,MAAM,UAAUA,OAAK,KAAK,QAAQ,KAAK,EAAE,QAAQ;AACjD,MAAIC,KAAG,WAAW,QAAQ,EAAE;GAE1B,MAAM,QADUA,KAAG,aAAa,SAAS,OAAO,CAC1B,MAAM,mCAAmC;AAC/D,OAAI,MACF,QAAO,MAAM,GAAG,MAAM"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-utils-DnTSiTJw.js","names":[],"sources":["../src/utils/file-utils.ts"],"sourcesContent":["import path from 'path';\nimport fs from 'fs';\nimport type { WizardRunOptions } from './types';\n\nexport function getDotGitignore({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>) {\n const gitignorePath = path.join(installDir, '.gitignore');\n const gitignoreExists = fs.existsSync(gitignorePath);\n\n if (gitignoreExists) {\n return gitignorePath;\n }\n\n return undefined;\n}\n\n/**\n * Directory names to skip when recursively scanning a project tree.\n * Used by detection logic (e.g. finding all package.json files) to avoid\n * dependency directories, build output, virtual environments, etc.\n *\n * For fast-glob `ignore` patterns, map this to `**\\/<name>/**`.\n */\nexport const IGNORED_DIRS = new Set<string>([\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.turbo',\n '.cache',\n '.parcel-cache',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.coverage',\n 'venv',\n '.venv',\n '__pycache__',\n '.pytest_cache',\n 'vendor',\n 'target',\n '.gradle',\n '.idea',\n '.vscode',\n]);\n"],"mappings":";;;;;;;;;;AAwBA,MAAa,eAAe,IAAI,IAAY;CAC1C;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
//#region src/utils/package-json.ts
|
|
4
|
+
/**
|
|
5
|
+
* Returns the raw version spec for `packageName` as written in
|
|
6
|
+
* `package.json` (range, pinned version, workspace ref, URL, etc.).
|
|
7
|
+
* `dependencies` wins over `devDependencies`. An empty-string value in
|
|
8
|
+
* either slot falls through, matching the previous behaviour.
|
|
9
|
+
*/
|
|
10
|
+
function getDeclaredVersion(packageName, packageJson) {
|
|
11
|
+
const fromDeps = packageJson?.dependencies?.[packageName];
|
|
12
|
+
if (fromDeps) return fromDeps;
|
|
13
|
+
const fromDevDeps = packageJson?.devDependencies?.[packageName];
|
|
14
|
+
if (fromDevDeps) return fromDevDeps;
|
|
15
|
+
}
|
|
16
|
+
function hasDeclaredDependency(packageName, packageJson) {
|
|
17
|
+
return getDeclaredVersion(packageName, packageJson) !== void 0;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the resolved version from `node_modules/<pkg>/package.json`,
|
|
21
|
+
* not the range declared in the project's `package.json`. Use this when
|
|
22
|
+
* you need to know what npm actually installed.
|
|
23
|
+
*/
|
|
24
|
+
function getInstalledPackageVersion(packageName, installDir) {
|
|
25
|
+
try {
|
|
26
|
+
const manifestPath = path.join(installDir, "node_modules", packageName, "package.json");
|
|
27
|
+
return JSON.parse(readFileSync(manifestPath, "utf-8")).version;
|
|
28
|
+
} catch {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { getInstalledPackageVersion as n, hasDeclaredDependency as r, getDeclaredVersion as t };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=package-json-v_g2YlN1.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-json-v_g2YlN1.js","names":[],"sources":["../src/utils/package-json.ts"],"sourcesContent":["import { readFileSync } from 'fs';\nimport path from 'path';\n\nexport type PackageJson = {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n scripts?: Record<string, string | undefined>;\n version?: string;\n overrides?: Record<string, string>;\n resolutions?: Record<string, string>;\n pnpm?: {\n overrides?: Record<string, string>;\n };\n};\n\ntype InstalledPackage = {\n name: string;\n version: string;\n};\n\n/**\n * Returns the raw version spec for `packageName` as written in\n * `package.json` (range, pinned version, workspace ref, URL, etc.).\n * `dependencies` wins over `devDependencies`. An empty-string value in\n * either slot falls through, matching the previous behaviour.\n */\nexport function getDeclaredVersion(\n packageName: string,\n packageJson: PackageJson,\n): string | undefined {\n const fromDeps = packageJson?.dependencies?.[packageName];\n if (fromDeps) return fromDeps;\n const fromDevDeps = packageJson?.devDependencies?.[packageName];\n if (fromDevDeps) return fromDevDeps;\n return undefined;\n}\n\nexport function hasDeclaredDependency(\n packageName: string,\n packageJson: PackageJson,\n): boolean {\n return getDeclaredVersion(packageName, packageJson) !== undefined;\n}\n\nexport function findDeclaredPackage(\n packageNamesList: string[],\n packageJson: PackageJson,\n): InstalledPackage | undefined {\n for (const name of packageNamesList) {\n const version = getDeclaredVersion(name, packageJson);\n if (version) {\n return { name, version };\n }\n }\n return undefined;\n}\n\n/**\n * Returns the resolved version from `node_modules/<pkg>/package.json`,\n * not the range declared in the project's `package.json`. Use this when\n * you need to know what npm actually installed.\n */\nexport function getInstalledPackageVersion(\n packageName: string,\n installDir: string,\n): string | undefined {\n try {\n const manifestPath = path.join(\n installDir,\n 'node_modules',\n packageName,\n 'package.json',\n );\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf-8')) as {\n version?: string;\n };\n return manifest.version;\n } catch {\n return undefined;\n }\n}\n"],"mappings":";;;;;;;;;AA0BA,SAAgB,mBACd,aACA,aACoB;CACpB,MAAM,WAAW,aAAa,eAAe;AAC7C,KAAI,SAAU,QAAO;CACrB,MAAM,cAAc,aAAa,kBAAkB;AACnD,KAAI,YAAa,QAAO;;AAI1B,SAAgB,sBACd,aACA,aACS;AACT,QAAO,mBAAmB,aAAa,YAAY,KAAK,KAAA;;;;;;;AAqB1D,SAAgB,2BACd,aACA,YACoB;AACpB,KAAI;EACF,MAAM,eAAe,KAAK,KACxB,YACA,gBACA,aACA,eACD;AAID,SAHiB,KAAK,MAAM,aAAa,cAAc,QAAQ,CAAC,CAGhD;SACV;AACN"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as detectAllPackageManagers } from "./setup-utils-_P-or31U.js";
|
|
2
2
|
import { execSync } from "node:child_process";
|
|
3
3
|
//#region src/frameworks/python/utils.ts
|
|
4
4
|
/**
|
|
@@ -219,4 +219,4 @@ function gradlePackageManager() {
|
|
|
219
219
|
//#endregion
|
|
220
220
|
export { gradlePackageManager as a, getPackageManagerName as c, detectPythonPackageManagers as i, getPythonVersion as l, composerPackageManager as n, swiftPackageManager as o, detectNodePackageManagers as r, detectPackageManager as s, bundlerPackageManager as t, getPythonVersionBucket as u };
|
|
221
221
|
|
|
222
|
-
//# sourceMappingURL=package-manager-
|
|
222
|
+
//# sourceMappingURL=package-manager-DlTISyej.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-manager-DlTISyej.js","names":["detectPythonPM"],"sources":["../src/frameworks/python/utils.ts","../src/lib/detection/package-manager.ts"],"sourcesContent":["import { execSync } from 'node:child_process';\nimport type { WizardRunOptions } from '@utils/types';\n\nexport enum PythonPackageManager {\n UV = 'uv',\n POETRY = 'poetry',\n PDM = 'pdm',\n HATCH = 'hatch',\n RYE = 'rye',\n PIPENV = 'pipenv',\n CONDA = 'conda',\n PIP = 'pip',\n UNKNOWN = 'unknown',\n}\n\n/**\n * Get the installed Python version\n */\nexport function getPythonVersion(\n options: WizardRunOptions,\n): string | undefined {\n try {\n const version = execSync('python --version || python3 --version', {\n cwd: options.installDir,\n encoding: 'utf-8',\n })\n .trim()\n .replace('Python ', '');\n return version;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Bucket Python version for analytics (e.g., \"3.11.x\" -> \"3.11\")\n */\nexport function getPythonVersionBucket(version: string): string {\n const match = version.match(/^(\\d+\\.\\d+)/);\n return match ? match[1] : version;\n}\n\n/**\n * Detect which package manager the project uses\n */\nexport async function detectPackageManager(\n options: WizardRunOptions,\n): Promise<PythonPackageManager> {\n const { installDir } = options;\n const fs = await import('node:fs');\n const path = await import('node:path');\n\n // Check for uv (uv.lock)\n if (fs.existsSync(path.join(installDir, 'uv.lock'))) {\n return PythonPackageManager.UV;\n }\n\n // Check pyproject.toml for various tools\n if (fs.existsSync(path.join(installDir, 'pyproject.toml'))) {\n try {\n const content = fs.readFileSync(\n path.join(installDir, 'pyproject.toml'),\n 'utf-8',\n );\n\n // Check for Poetry\n if (content.includes('[tool.poetry]')) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM\n if (content.includes('[tool.pdm]')) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Hatch\n if (content.includes('[tool.hatch]')) {\n return PythonPackageManager.HATCH;\n }\n\n // Check for Rye\n if (content.includes('[tool.rye]')) {\n return PythonPackageManager.RYE;\n }\n } catch {\n // Continue checking\n }\n }\n\n // Check for Poetry lock file\n if (fs.existsSync(path.join(installDir, 'poetry.lock'))) {\n return PythonPackageManager.POETRY;\n }\n\n // Check for PDM lock file\n if (fs.existsSync(path.join(installDir, 'pdm.lock'))) {\n return PythonPackageManager.PDM;\n }\n\n // Check for Pipenv (Pipfile or Pipfile.lock)\n if (\n fs.existsSync(path.join(installDir, 'Pipfile')) ||\n fs.existsSync(path.join(installDir, 'Pipfile.lock'))\n ) {\n return PythonPackageManager.PIPENV;\n }\n\n // Check for Conda (environment.yml or environment.yaml)\n if (\n fs.existsSync(path.join(installDir, 'environment.yml')) ||\n fs.existsSync(path.join(installDir, 'environment.yaml'))\n ) {\n return PythonPackageManager.CONDA;\n }\n\n // Check for pip (requirements.txt, setup.py, setup.cfg, or pyproject.toml)\n if (\n fs.existsSync(path.join(installDir, 'requirements.txt')) ||\n fs.existsSync(path.join(installDir, 'setup.py')) ||\n fs.existsSync(path.join(installDir, 'setup.cfg')) ||\n fs.existsSync(path.join(installDir, 'pyproject.toml'))\n ) {\n return PythonPackageManager.PIP;\n }\n\n // Check for requirements directory\n try {\n const requirementsDir = path.join(installDir, 'requirements');\n if (\n fs.existsSync(requirementsDir) &&\n fs.statSync(requirementsDir).isDirectory()\n ) {\n const files = fs.readdirSync(requirementsDir);\n if (files.some((f) => f.endsWith('.txt'))) {\n return PythonPackageManager.PIP;\n }\n }\n } catch {\n // Continue\n }\n\n return PythonPackageManager.UNKNOWN;\n}\n\n/**\n * Get package manager display name\n */\nexport function getPackageManagerName(\n packageManager: PythonPackageManager,\n): string {\n switch (packageManager) {\n case PythonPackageManager.UV:\n return 'uv';\n case PythonPackageManager.POETRY:\n return 'Poetry';\n case PythonPackageManager.PDM:\n return 'PDM';\n case PythonPackageManager.HATCH:\n return 'Hatch';\n case PythonPackageManager.RYE:\n return 'Rye';\n case PythonPackageManager.PIPENV:\n return 'Pipenv';\n case PythonPackageManager.CONDA:\n return 'Conda';\n case PythonPackageManager.PIP:\n return 'pip';\n case PythonPackageManager.UNKNOWN:\n return 'unknown';\n }\n}\n","/**\n * Cross-ecosystem package manager detection.\n *\n * Provides a common interface (PackageManagerDetector) that each FrameworkConfig\n * implements, plus shared helpers for Node.js, Python, PHP, and Swift ecosystems.\n * The MCP tool in wizard-tools.ts delegates to whatever detector the\n * current framework supplies.\n */\n\nimport {\n detectAllPackageManagers,\n type PackageManager,\n} from '@utils/package-manager';\nimport {\n detectPackageManager as detectPythonPM,\n PythonPackageManager,\n} from '@frameworks/python/utils';\n\n// ---------------------------------------------------------------------------\n// Common types\n// ---------------------------------------------------------------------------\n\n/** Structured package manager info the agent can act on */\nexport interface DetectedPackageManager {\n name: string;\n label: string;\n installCommand: string;\n runCommand?: string;\n}\n\n/** Result returned by every detector */\nexport interface PackageManagerInfo {\n detected: DetectedPackageManager[];\n primary: DetectedPackageManager | null;\n recommendation: string;\n}\n\n/** Signature each framework implements */\nexport type PackageManagerDetector = (\n installDir: string,\n) => Promise<PackageManagerInfo>;\n\n// ---------------------------------------------------------------------------\n// Node.js helper\n// ---------------------------------------------------------------------------\n\nfunction serializeNodePM(pm: PackageManager): DetectedPackageManager {\n return {\n name: pm.name,\n label: pm.label,\n installCommand: pm.installCommand,\n runCommand: pm.runScriptCommand,\n };\n}\n\n/**\n * Detect Node.js package managers via lockfiles.\n * Wraps the existing detectAllPackageManagers() from utils/package-manager.ts.\n */\nexport function detectNodePackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const detected = detectAllPackageManagers({ installDir }).map(\n serializeNodePM,\n );\n\n if (detected.length === 0) {\n return Promise.resolve({\n detected: [],\n primary: null,\n recommendation: 'No lockfile found. Default to npm (npm add, npm run).',\n });\n }\n\n const primary = detected[0];\n return Promise.resolve({\n detected,\n primary,\n recommendation:\n detected.length === 1\n ? `Use ${primary.label} (${primary.installCommand}).`\n : `Multiple package managers detected. Prefer ${primary.label} (${primary.installCommand}).`,\n });\n}\n\n// ---------------------------------------------------------------------------\n// Python helper\n// ---------------------------------------------------------------------------\n\nconst PYTHON_PM_INFO: Record<PythonPackageManager, DetectedPackageManager> = {\n [PythonPackageManager.UV]: {\n name: 'uv',\n label: 'uv',\n installCommand: 'uv add',\n runCommand: 'uv run',\n },\n [PythonPackageManager.POETRY]: {\n name: 'poetry',\n label: 'Poetry',\n installCommand: 'poetry add',\n runCommand: 'poetry run',\n },\n [PythonPackageManager.PDM]: {\n name: 'pdm',\n label: 'PDM',\n installCommand: 'pdm add',\n runCommand: 'pdm run',\n },\n [PythonPackageManager.HATCH]: {\n name: 'hatch',\n label: 'Hatch',\n installCommand: 'hatch add',\n runCommand: 'hatch run',\n },\n [PythonPackageManager.RYE]: {\n name: 'rye',\n label: 'Rye',\n installCommand: 'rye add',\n runCommand: 'rye run',\n },\n [PythonPackageManager.PIPENV]: {\n name: 'pipenv',\n label: 'Pipenv',\n installCommand: 'pipenv install',\n runCommand: 'pipenv run',\n },\n [PythonPackageManager.CONDA]: {\n name: 'conda',\n label: 'Conda',\n installCommand: 'conda install',\n runCommand: 'conda run',\n },\n [PythonPackageManager.PIP]: {\n name: 'pip',\n label: 'pip',\n installCommand: 'pip install',\n },\n [PythonPackageManager.UNKNOWN]: {\n name: 'pip',\n label: 'pip (default)',\n installCommand: 'pip install',\n },\n};\n\n/**\n * Detect Python package managers via lockfiles and config files.\n * Wraps the existing detectPackageManager() from python/utils.ts.\n */\nexport async function detectPythonPackageManagers(\n installDir: string,\n): Promise<PackageManagerInfo> {\n const pm = await detectPythonPM({ installDir } as any);\n const info = PYTHON_PM_INFO[pm];\n\n return {\n detected: [info],\n primary: info,\n recommendation: `Use ${info.label} (${info.installCommand}).`,\n };\n}\n\n// ---------------------------------------------------------------------------\n// PHP (Composer) helper\n// ---------------------------------------------------------------------------\n\nconst COMPOSER: DetectedPackageManager = {\n name: 'composer',\n label: 'Composer',\n installCommand: 'composer require',\n};\n\nexport function composerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [COMPOSER],\n primary: COMPOSER,\n recommendation: 'Use Composer (composer require).',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Swift (SPM) helper\n// ---------------------------------------------------------------------------\n\nconst SPM: DetectedPackageManager = {\n name: 'spm',\n label: 'Swift Package Manager',\n installCommand: 'swift package add-dependency',\n};\n\nexport function swiftPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [SPM],\n primary: SPM,\n recommendation:\n 'Use Swift Package Manager. Add the dependency to Package.swift or via Xcode.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Ruby (Bundler) helper\n// ---------------------------------------------------------------------------\n\nconst BUNDLER: DetectedPackageManager = {\n name: 'bundler',\n label: 'Bundler',\n installCommand: 'bundle add',\n runCommand: 'bundle exec',\n};\n\nexport function bundlerPackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [BUNDLER],\n primary: BUNDLER,\n recommendation: 'Use Bundler (bundle add). Run commands with bundle exec.',\n });\n}\n\n// ---------------------------------------------------------------------------\n// Android (Gradle) helper\n// ---------------------------------------------------------------------------\n\nconst GRADLE: DetectedPackageManager = {\n name: 'gradle',\n label: 'Gradle',\n installCommand: 'implementation',\n};\n\nexport function gradlePackageManager(): Promise<PackageManagerInfo> {\n return Promise.resolve({\n detected: [GRADLE],\n primary: GRADLE,\n recommendation:\n 'Add dependencies to build.gradle(.kts) using implementation().',\n });\n}\n"],"mappings":";;;;;;AAkBA,SAAgB,iBACd,SACoB;AACpB,KAAI;AAOF,SANgB,SAAS,yCAAyC;GAChE,KAAK,QAAQ;GACb,UAAU;GACX,CAAC,CACC,MAAM,CACN,QAAQ,WAAW,GAAG;SAEnB;AACN;;;;;;AAOJ,SAAgB,uBAAuB,SAAyB;CAC9D,MAAM,QAAQ,QAAQ,MAAM,cAAc;AAC1C,QAAO,QAAQ,MAAM,KAAK;;;;;AAM5B,eAAsB,qBACpB,SAC+B;CAC/B,MAAM,EAAE,eAAe;CACvB,MAAM,KAAK,MAAM,OAAO;CACxB,MAAM,OAAO,MAAM,OAAO;AAG1B,KAAI,GAAG,WAAW,KAAK,KAAK,YAAY,UAAU,CAAC,CACjD,QAAA;AAIF,KAAI,GAAG,WAAW,KAAK,KAAK,YAAY,iBAAiB,CAAC,CACxD,KAAI;EACF,MAAM,UAAU,GAAG,aACjB,KAAK,KAAK,YAAY,iBAAiB,EACvC,QACD;AAGD,MAAI,QAAQ,SAAS,gBAAgB,CACnC,QAAA;AAIF,MAAI,QAAQ,SAAS,aAAa,CAChC,QAAA;AAIF,MAAI,QAAQ,SAAS,eAAe,CAClC,QAAA;AAIF,MAAI,QAAQ,SAAS,aAAa,CAChC,QAAA;SAEI;AAMV,KAAI,GAAG,WAAW,KAAK,KAAK,YAAY,cAAc,CAAC,CACrD,QAAA;AAIF,KAAI,GAAG,WAAW,KAAK,KAAK,YAAY,WAAW,CAAC,CAClD,QAAA;AAIF,KACE,GAAG,WAAW,KAAK,KAAK,YAAY,UAAU,CAAC,IAC/C,GAAG,WAAW,KAAK,KAAK,YAAY,eAAe,CAAC,CAEpD,QAAA;AAIF,KACE,GAAG,WAAW,KAAK,KAAK,YAAY,kBAAkB,CAAC,IACvD,GAAG,WAAW,KAAK,KAAK,YAAY,mBAAmB,CAAC,CAExD,QAAA;AAIF,KACE,GAAG,WAAW,KAAK,KAAK,YAAY,mBAAmB,CAAC,IACxD,GAAG,WAAW,KAAK,KAAK,YAAY,WAAW,CAAC,IAChD,GAAG,WAAW,KAAK,KAAK,YAAY,YAAY,CAAC,IACjD,GAAG,WAAW,KAAK,KAAK,YAAY,iBAAiB,CAAC,CAEtD,QAAA;AAIF,KAAI;EACF,MAAM,kBAAkB,KAAK,KAAK,YAAY,eAAe;AAC7D,MACE,GAAG,WAAW,gBAAgB,IAC9B,GAAG,SAAS,gBAAgB,CAAC,aAAa;OAE5B,GAAG,YAAY,gBAAgB,CACnC,MAAM,MAAM,EAAE,SAAS,OAAO,CAAC,CACvC,QAAA;;SAGE;AAIR,QAAA;;;;;AAMF,SAAgB,sBACd,gBACQ;AACR,SAAQ,gBAAR;EACE,KAAA,KACE,QAAO;EACT,KAAA,SACE,QAAO;EACT,KAAA,MACE,QAAO;EACT,KAAA,QACE,QAAO;EACT,KAAA,MACE,QAAO;EACT,KAAA,SACE,QAAO;EACT,KAAA,QACE,QAAO;EACT,KAAA,MACE,QAAO;EACT,KAAA,UACE,QAAO;;;;;;;;;;;;;AC1Hb,SAAS,gBAAgB,IAA4C;AACnE,QAAO;EACL,MAAM,GAAG;EACT,OAAO,GAAG;EACV,gBAAgB,GAAG;EACnB,YAAY,GAAG;EAChB;;;;;;AAOH,SAAgB,0BACd,YAC6B;CAC7B,MAAM,WAAW,yBAAyB,EAAE,YAAY,CAAC,CAAC,IACxD,gBACD;AAED,KAAI,SAAS,WAAW,EACtB,QAAO,QAAQ,QAAQ;EACrB,UAAU,EAAE;EACZ,SAAS;EACT,gBAAgB;EACjB,CAAC;CAGJ,MAAM,UAAU,SAAS;AACzB,QAAO,QAAQ,QAAQ;EACrB;EACA;EACA,gBACE,SAAS,WAAW,IAChB,OAAO,QAAQ,MAAM,IAAI,QAAQ,eAAe,MAChD,8CAA8C,QAAQ,MAAM,IAAI,QAAQ,eAAe;EAC9F,CAAC;;AAOJ,MAAM,iBAAuE;SAChD;EACzB,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;aAC8B;EAC7B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;UAC2B;EAC1B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;YAC6B;EAC5B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;UAC2B;EAC1B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;aAC8B;EAC7B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;YAC6B;EAC5B,MAAM;EACN,OAAO;EACP,gBAAgB;EAChB,YAAY;EACb;UAC2B;EAC1B,MAAM;EACN,OAAO;EACP,gBAAgB;EACjB;cAC+B;EAC9B,MAAM;EACN,OAAO;EACP,gBAAgB;EACjB;CACF;;;;;AAMD,eAAsB,4BACpB,YAC6B;CAE7B,MAAM,OAAO,eADF,MAAMA,qBAAe,EAAE,YAAY,CAAQ;AAGtD,QAAO;EACL,UAAU,CAAC,KAAK;EAChB,SAAS;EACT,gBAAgB,OAAO,KAAK,MAAM,IAAI,KAAK,eAAe;EAC3D;;AAOH,MAAM,WAAmC;CACvC,MAAM;CACN,OAAO;CACP,gBAAgB;CACjB;AAED,SAAgB,yBAAsD;AACpE,QAAO,QAAQ,QAAQ;EACrB,UAAU,CAAC,SAAS;EACpB,SAAS;EACT,gBAAgB;EACjB,CAAC;;AAOJ,MAAM,MAA8B;CAClC,MAAM;CACN,OAAO;CACP,gBAAgB;CACjB;AAED,SAAgB,sBAAmD;AACjE,QAAO,QAAQ,QAAQ;EACrB,UAAU,CAAC,IAAI;EACf,SAAS;EACT,gBACE;EACH,CAAC;;AAOJ,MAAM,UAAkC;CACtC,MAAM;CACN,OAAO;CACP,gBAAgB;CAChB,YAAY;CACb;AAED,SAAgB,wBAAqD;AACnE,QAAO,QAAQ,QAAQ;EACrB,UAAU,CAAC,QAAQ;EACnB,SAAS;EACT,gBAAgB;EACjB,CAAC;;AAOJ,MAAM,SAAiC;CACrC,MAAM;CACN,OAAO;CACP,gBAAgB;CACjB;AAED,SAAgB,uBAAoD;AAClE,QAAO,QAAQ,QAAQ;EACrB,UAAU,CAAC,OAAO;EAClB,SAAS;EACT,gBACE;EACH,CAAC"}
|