@posthog/wizard 2.21.0 → 2.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/{OutroScreen-CqF6SdBo.js → AiOptInRequiredScreen-B8mgZbe5.js} +482 -59
- package/dist/AiOptInRequiredScreen-B8mgZbe5.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-DQHGhzt6.js → add-mcp-server-to-clients-lCxOS1A1.js} +12 -10
- package/dist/add-mcp-server-to-clients-lCxOS1A1.js.map +1 -0
- package/dist/{agent-interface-DE7txTqh.js → agent-interface-BPCzPvK-.js} +6 -5
- package/dist/{agent-interface-DE7txTqh.js.map → agent-interface-BPCzPvK-.js.map} +1 -1
- package/dist/{agent-runner-DUZ5OD6e.js → agent-runner-DgzF2mga.js} +13 -9
- package/dist/{agent-runner-DUZ5OD6e.js.map → agent-runner-DgzF2mga.js.map} +1 -1
- package/dist/{analytics-Bl5DPj_0.js → analytics-BZv-cKyn.js} +28 -4
- package/dist/analytics-BZv-cKyn.js.map +1 -0
- package/dist/{api-DuA0_88V.js → api-BkLZ8BWm.js} +3 -3
- package/dist/{api-DuA0_88V.js.map → api-BkLZ8BWm.js.map} +1 -1
- package/dist/bin.js +160 -49
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-BnOYI4mZ.js → ci-install-DBARq5LX.js} +4 -4
- package/dist/{ci-install-BnOYI4mZ.js.map → ci-install-DBARq5LX.js.map} +1 -1
- package/dist/{debug-h7Z9zEbD.js → debug-Ckumcrye.js} +189 -40
- package/dist/debug-Ckumcrye.js.map +1 -0
- package/dist/{debug-BVC48wlb.js → debug-DLsuyfln.js} +1 -1
- package/dist/{environment-uaLmtlH_.js → environment-DUh_8hqW.js} +3 -3
- package/dist/{environment-uaLmtlH_.js.map → environment-DUh_8hqW.js.map} +1 -1
- package/dist/{interactive-CW5gjyDd.js → interactive-DeiHgviS.js} +2 -2
- package/dist/{interactive-CW5gjyDd.js.map → interactive-DeiHgviS.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-DMDwaark.js → mcp-prompt-streaming-kEJgmB30.js} +4 -4
- package/dist/{mcp-prompt-streaming-DMDwaark.js.map → mcp-prompt-streaming-kEJgmB30.js.map} +1 -1
- package/dist/{non-interactive-DJrVQ4nS.js → non-interactive-I4ifOSau.js} +2 -2
- package/dist/{non-interactive-DJrVQ4nS.js.map → non-interactive-I4ifOSau.js.map} +1 -1
- package/dist/{package-manager-DCUBRbr-.js → package-manager-fUeLORHg.js} +2 -2
- package/dist/{package-manager-DCUBRbr-.js.map → package-manager-fUeLORHg.js.map} +1 -1
- package/dist/{playground-DCVaVeVD.js → playground-DLLIz4Ql.js} +135 -19
- package/dist/playground-DLLIz4Ql.js.map +1 -0
- package/dist/{posthog-integration-ChdwFPMj.js → posthog-integration-COcPewVt.js} +48 -16
- package/dist/posthog-integration-COcPewVt.js.map +1 -0
- package/dist/{provisioning-GeMkBMSR.js → provisioning-7xU12_S9.js} +3 -3
- package/dist/{provisioning-GeMkBMSR.js.map → provisioning-7xU12_S9.js.map} +1 -1
- package/dist/{registry-VSSRH3sU.js → registry-YwaF-aD8.js} +7 -20
- package/dist/registry-YwaF-aD8.js.map +1 -0
- package/dist/{setup-utils-BfV4pydt.js → setup-utils-Cr4FxJDl.js} +114 -58
- package/dist/setup-utils-Cr4FxJDl.js.map +1 -0
- package/dist/{start-tui-BRvm5VP9.js → start-tui--E4PXdwG.js} +323 -134
- package/dist/start-tui--E4PXdwG.js.map +1 -0
- package/dist/{steps-DA4uvSbg.js → steps-CxUxdK4V.js} +6 -6
- package/dist/{steps-DA4uvSbg.js.map → steps-CxUxdK4V.js.map} +1 -1
- package/dist/telemetry-BS7yw3TP.js +68 -0
- package/dist/telemetry-BS7yw3TP.js.map +1 -0
- package/dist/{urls-B66Ib2jT.js → urls-BW23_XbC.js} +2 -2
- package/dist/{urls-B66Ib2jT.js.map → urls-BW23_XbC.js.map} +1 -1
- package/dist/{wizard-abort-gMB1eV6T.js → wizard-abort-BPsnXKY5.js} +1 -1
- package/dist/{wizard-abort-D1_DnFjm.js → wizard-abort-E66_R4S7.js} +3 -3
- package/dist/{wizard-abort-D1_DnFjm.js.map → wizard-abort-E66_R4S7.js.map} +1 -1
- package/dist/wizard-session-G3VWD6hv.js.map +1 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/package.json +1 -1
- package/dist/OutroScreen-CqF6SdBo.js.map +0 -1
- package/dist/add-mcp-server-to-clients-DQHGhzt6.js.map +0 -1
- package/dist/analytics-Bl5DPj_0.js.map +0 -1
- package/dist/debug-h7Z9zEbD.js.map +0 -1
- package/dist/playground-DCVaVeVD.js.map +0 -1
- package/dist/posthog-integration-ChdwFPMj.js.map +0 -1
- package/dist/registry-VSSRH3sU.js.map +0 -1
- package/dist/setup-utils-BfV4pydt.js.map +0 -1
- package/dist/start-tui-BRvm5VP9.js.map +0 -1
- package/dist/telemetry-BRAonUea.js +0 -13
- package/dist/telemetry-BRAonUea.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { p as getUI } from "./debug-
|
|
2
|
-
import { t as analytics } from "./analytics-
|
|
3
|
-
import { t as withProgress } from "./telemetry-
|
|
4
|
-
import "./setup-utils-
|
|
5
|
-
import "./add-mcp-server-to-clients-
|
|
1
|
+
import { p as getUI } from "./debug-Ckumcrye.js";
|
|
2
|
+
import { t as analytics } from "./analytics-BZv-cKyn.js";
|
|
3
|
+
import { t as withProgress } from "./telemetry-BS7yw3TP.js";
|
|
4
|
+
import "./setup-utils-Cr4FxJDl.js";
|
|
5
|
+
import "./add-mcp-server-to-clients-lCxOS1A1.js";
|
|
6
6
|
import * as fs$1 from "fs";
|
|
7
7
|
import * as path$1 from "path";
|
|
8
8
|
import "path";
|
|
@@ -143,4 +143,4 @@ const uploadEnvironmentVariablesStep = async (envVars, { integration, session })
|
|
|
143
143
|
//#endregion
|
|
144
144
|
export { uploadEnvironmentVariablesStep };
|
|
145
145
|
|
|
146
|
-
//# sourceMappingURL=steps-
|
|
146
|
+
//# sourceMappingURL=steps-CxUxdK4V.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps-
|
|
1
|
+
{"version":3,"file":"steps-CxUxdK4V.js","names":["path","fs","spawnSync","spawn"],"sources":["../src/steps/upload-environment-variables/EnvironmentProvider.ts","../src/steps/upload-environment-variables/providers/vercel.ts","../src/steps/upload-environment-variables/index.ts"],"sourcesContent":["export abstract class EnvironmentProvider {\n protected options: { installDir: string };\n\n name: string;\n\n constructor(options: { installDir: string }) {\n this.options = options;\n }\n\n abstract detect(): Promise<boolean>;\n\n abstract uploadEnvVars(\n vars: Record<string, string>,\n ): Promise<Record<string, boolean>>;\n}\n","import { execSync, spawn, spawnSync } from 'child_process';\nimport { EnvironmentProvider } from '@steps/upload-environment-variables/EnvironmentProvider';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getUI } from '@ui';\nimport { analytics } from '@utils/analytics';\n\nexport class VercelEnvironmentProvider extends EnvironmentProvider {\n name = 'Vercel';\n environments = ['production', 'preview', 'development'];\n\n constructor(options: { installDir: string }) {\n super(options);\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async detect(): Promise<boolean> {\n const vercelDetected =\n this.hasVercelCli() && this.isProjectLinked() && this.isAuthenticated();\n\n analytics.setTag('vercel-detected', vercelDetected);\n\n return vercelDetected;\n }\n\n hasDotVercelDir(): boolean {\n const dotVercelDir = path.join(this.options.installDir, '.vercel');\n return fs.existsSync(dotVercelDir);\n }\n\n hasVercelCli(): boolean {\n try {\n execSync('vercel --version', { stdio: 'ignore' });\n analytics.setTag('vercel-cli-installed', true);\n return true;\n } catch {\n analytics.setTag('vercel-cli-installed', false);\n return false;\n }\n }\n\n isProjectLinked(): boolean {\n const isProjectLinked = fs.existsSync(\n path.join(this.options.installDir, '.vercel', 'project.json'),\n );\n\n analytics.setTag('vercel-project-linked', isProjectLinked);\n\n return isProjectLinked;\n }\n\n isAuthenticated(): boolean {\n const result = spawnSync('vercel', ['whoami'], {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'], // suppress prompts\n env: {\n ...process.env,\n FORCE_COLOR: '0', // avoid ANSI formatting\n CI: '1', // hint to CLI that it's a non-interactive env\n },\n });\n\n const output = (\n String(result.stdout) + String(result.stderr)\n ).toLowerCase();\n\n if (\n output.includes('log in to vercel') ||\n output.includes('vercel login') ||\n result.status !== 0\n ) {\n analytics.setTag('vercel-authenticated', false);\n return false;\n }\n\n analytics.setTag('vercel-authenticated', true);\n\n return true;\n }\n\n async uploadEnvironmentVariable(\n key: string,\n value: string,\n environment: string,\n ): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const proc = spawn('vercel', ['env', 'add', key, environment], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let stderr = '';\n proc.stderr.on('data', (data) => {\n stderr += data.toString();\n });\n\n proc.stdin.write(value);\n proc.stdin.end();\n\n proc.on('close', (code) => {\n if (\n stderr.includes('already exists') ||\n stderr.includes('already been added') ||\n stderr.includes('vercel env rm')\n ) {\n reject(\n new Error(\n `❌ Environment variable ${key} already exists in ${this.name}. Please upload it manually.`,\n ),\n );\n } else if (code === 0) {\n resolve();\n } else {\n reject(\n new Error(\n `❌ Failed to upload environment variable ${key} to ${this.name}. Please upload it manually.`,\n ),\n );\n }\n });\n });\n }\n\n async uploadEnvVars(\n vars: Record<string, string>,\n ): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(vars)) {\n const spinner = getUI().spinner();\n\n spinner.start(`Uploading ${key} to ${this.name}...`);\n await Promise.all(\n this.environments.map((environment) =>\n this.uploadEnvironmentVariable(key, value, environment),\n ),\n )\n .then(() => {\n spinner.stop(`✅ Uploaded ${key} to ${this.name}`);\n results[key] = true;\n })\n .catch((err) => {\n spinner.stop(\n err instanceof Error\n ? err.message\n : `❌ Failed to upload environment variables to ${this.name}. Please upload it manually.`,\n );\n results[key] = false;\n });\n }\n\n return results;\n }\n}\n","import type { Integration } from '@lib/constants';\nimport { withProgress } from '../../telemetry';\nimport { analytics } from '@utils/analytics';\nimport { getUI } from '@ui';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { EnvironmentProvider } from './EnvironmentProvider';\nimport { VercelEnvironmentProvider } from './providers/vercel';\n\nexport const uploadEnvironmentVariablesStep = async (\n envVars: Record<string, string>,\n {\n integration,\n session,\n }: {\n integration: Integration;\n session: WizardSession;\n },\n): Promise<string[]> => {\n const providers: EnvironmentProvider[] = [\n new VercelEnvironmentProvider({ installDir: session.installDir }),\n ];\n\n let provider: EnvironmentProvider | null = null;\n\n for (const p of providers) {\n if (await p.detect()) {\n provider = p;\n break;\n }\n }\n\n if (!provider) {\n analytics.wizardCapture('env upload skipped', {\n reason: 'no environment provider found',\n integration,\n });\n return [];\n }\n\n // Auto-accept — the agent already wrote env vars via MCP tools\n getUI().log.info(`Uploading environment variables to ${provider.name}...`);\n\n const results = await withProgress(\n 'uploading environment variables',\n async () => {\n return await provider.uploadEnvVars(envVars);\n },\n );\n\n analytics.wizardCapture('env uploaded', {\n provider: provider.name,\n integration,\n });\n\n return Object.keys(results).filter((key) => results[key]);\n};\n"],"mappings":";;;;;;;;;;AAAA,IAAsB,sBAAtB,MAA0C;CACxC;CAEA;CAEA,YAAY,SAAiC;AAC3C,OAAK,UAAU;;;;;ACCnB,IAAa,4BAAb,cAA+C,oBAAoB;CACjE,OAAO;CACP,eAAe;EAAC;EAAc;EAAW;EAAc;CAEvD,YAAY,SAAiC;AAC3C,QAAM,QAAQ;;CAIhB,MAAM,SAA2B;EAC/B,MAAM,iBACJ,KAAK,cAAc,IAAI,KAAK,iBAAiB,IAAI,KAAK,iBAAiB;AAEzE,YAAU,OAAO,mBAAmB,eAAe;AAEnD,SAAO;;CAGT,kBAA2B;EACzB,MAAM,eAAeA,OAAK,KAAK,KAAK,QAAQ,YAAY,UAAU;AAClE,SAAOC,KAAG,WAAW,aAAa;;CAGpC,eAAwB;AACtB,MAAI;AACF,cAAS,oBAAoB,EAAE,OAAO,UAAU,CAAC;AACjD,aAAU,OAAO,wBAAwB,KAAK;AAC9C,UAAO;UACD;AACN,aAAU,OAAO,wBAAwB,MAAM;AAC/C,UAAO;;;CAIX,kBAA2B;EACzB,MAAM,kBAAkBA,KAAG,WACzBD,OAAK,KAAK,KAAK,QAAQ,YAAY,WAAW,eAAe,CAC9D;AAED,YAAU,OAAO,yBAAyB,gBAAgB;AAE1D,SAAO;;CAGT,kBAA2B;EACzB,MAAM,SAASE,YAAU,UAAU,CAAC,SAAS,EAAE;GAC7C,UAAU;GACV,OAAO;IAAC;IAAQ;IAAQ;IAAO;GAC/B,KAAK;IACH,GAAG,QAAQ;IACX,aAAa;IACb,IAAI;IACL;GACF,CAAC;EAEF,MAAM,UACJ,OAAO,OAAO,OAAO,GAAG,OAAO,OAAO,OAAO,EAC7C,aAAa;AAEf,MACE,OAAO,SAAS,mBAAmB,IACnC,OAAO,SAAS,eAAe,IAC/B,OAAO,WAAW,GAClB;AACA,aAAU,OAAO,wBAAwB,MAAM;AAC/C,UAAO;;AAGT,YAAU,OAAO,wBAAwB,KAAK;AAE9C,SAAO;;CAGT,MAAM,0BACJ,KACA,OACA,aACe;AACf,QAAM,IAAI,SAAe,SAAS,WAAW;GAC3C,MAAM,OAAOC,QAAM,UAAU;IAAC;IAAO;IAAO;IAAK;IAAY,EAAE,EAC7D,OAAO;IAAC;IAAQ;IAAQ;IAAO,EAChC,CAAC;GAEF,IAAI,SAAS;AACb,QAAK,OAAO,GAAG,SAAS,SAAS;AAC/B,cAAU,KAAK,UAAU;KACzB;AAEF,QAAK,MAAM,MAAM,MAAM;AACvB,QAAK,MAAM,KAAK;AAEhB,QAAK,GAAG,UAAU,SAAS;AACzB,QACE,OAAO,SAAS,iBAAiB,IACjC,OAAO,SAAS,qBAAqB,IACrC,OAAO,SAAS,gBAAgB,CAEhC,wBACE,IAAI,MACF,0BAA0B,IAAI,qBAAqB,KAAK,KAAK,8BAC9D,CACF;aACQ,SAAS,EAClB,UAAS;QAET,wBACE,IAAI,MACF,2CAA2C,IAAI,MAAM,KAAK,KAAK,8BAChE,CACF;KAEH;IACF;;CAGJ,MAAM,cACJ,MACkC;EAClC,MAAM,UAAmC,EAAE;AAE3C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,EAAE;GAC/C,MAAM,UAAU,OAAO,CAAC,SAAS;AAEjC,WAAQ,MAAM,aAAa,IAAI,MAAM,KAAK,KAAK,KAAK;AACpD,SAAM,QAAQ,IACZ,KAAK,aAAa,KAAK,gBACrB,KAAK,0BAA0B,KAAK,OAAO,YAAY,CACxD,CACF,CACE,WAAW;AACV,YAAQ,KAAK,cAAc,IAAI,MAAM,KAAK,OAAO;AACjD,YAAQ,OAAO;KACf,CACD,OAAO,QAAQ;AACd,YAAQ,KACN,eAAe,QACX,IAAI,UACJ,+CAA+C,KAAK,KAAK,8BAC9D;AACD,YAAQ,OAAO;KACf;;AAGN,SAAO;;;;;AC9IX,MAAa,iCAAiC,OAC5C,SACA,EACE,aACA,cAKoB;CACtB,MAAM,YAAmC,CACvC,IAAI,0BAA0B,EAAE,YAAY,QAAQ,YAAY,CAAC,CAClE;CAED,IAAI,WAAuC;AAE3C,MAAK,MAAM,KAAK,UACd,KAAI,MAAM,EAAE,QAAQ,EAAE;AACpB,aAAW;AACX;;AAIJ,KAAI,CAAC,UAAU;AACb,YAAU,cAAc,sBAAsB;GAC5C,QAAQ;GACR;GACD,CAAC;AACF,SAAO,EAAE;;AAIX,QAAO,CAAC,IAAI,KAAK,sCAAsC,SAAS,KAAK,KAAK;CAE1E,MAAM,UAAU,MAAM,aACpB,mCACA,YAAY;AACV,SAAO,MAAM,SAAS,cAAc,QAAQ;GAE/C;AAED,WAAU,cAAc,gBAAgB;EACtC,UAAU,SAAS;EACnB;EACD,CAAC;AAEF,QAAO,OAAO,KAAK,QAAQ,CAAC,QAAQ,QAAQ,QAAQ,KAAK"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import "./debug-Ckumcrye.js";
|
|
2
|
+
import { t as analytics } from "./analytics-BZv-cKyn.js";
|
|
3
|
+
import opn from "opn";
|
|
4
|
+
//#region src/utils/links.ts
|
|
5
|
+
/**
|
|
6
|
+
* Outbound links: UTM tagging and tracked opens.
|
|
7
|
+
*
|
|
8
|
+
* Every URL the wizard sends a user to — auto-opened or printed in the TUI —
|
|
9
|
+
* carries `utm_source=wizard`, `utm_medium=cli`, `utm_content=<which link>`.
|
|
10
|
+
* The command dimension rides on every wizard event as the `command` tag.
|
|
11
|
+
* Opening a link also captures a wizard event.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Record the CLI command this run was started with (e.g. `integrate`,
|
|
15
|
+
* `slack`, `mcp-add`). Set once at dispatch; tagged onto every wizard
|
|
16
|
+
* event so wizard-side events segment by command.
|
|
17
|
+
*/
|
|
18
|
+
function setEntryCommand(command) {
|
|
19
|
+
analytics.setTag("command", command);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Tag a URL with the wizard's UTM params. `content` names the specific link
|
|
23
|
+
* (e.g. `oauth-signup`, `slack-connect-setup`). URLs that already carry a
|
|
24
|
+
* utm_source — or don't parse — are returned untouched.
|
|
25
|
+
*/
|
|
26
|
+
function withUtm(url, content) {
|
|
27
|
+
let parsed;
|
|
28
|
+
try {
|
|
29
|
+
parsed = new URL(url);
|
|
30
|
+
} catch {
|
|
31
|
+
return url;
|
|
32
|
+
}
|
|
33
|
+
if (parsed.searchParams.has("utm_source")) return url;
|
|
34
|
+
parsed.searchParams.set("utm_source", "wizard");
|
|
35
|
+
parsed.searchParams.set("utm_medium", "cli");
|
|
36
|
+
parsed.searchParams.set("utm_content", content);
|
|
37
|
+
return parsed.toString();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Open a URL in the user's browser, UTM-tagged (pass `skipUtm` for
|
|
41
|
+
* destinations that aren't PostHog properties or are already final), and
|
|
42
|
+
* capture the interaction. `auto` marks opens the wizard initiated itself,
|
|
43
|
+
* as opposed to a user picking a link on screen. opn throws in headless
|
|
44
|
+
* environments — the URL is always also printed on screen, so the failure
|
|
45
|
+
* is swallowed.
|
|
46
|
+
*/
|
|
47
|
+
function openTrackedLink(url, content, opts) {
|
|
48
|
+
const finalUrl = opts?.skipUtm ? url : withUtm(url, content);
|
|
49
|
+
analytics.wizardCapture("link opened", {
|
|
50
|
+
content,
|
|
51
|
+
url: finalUrl,
|
|
52
|
+
auto: opts?.auto ?? false
|
|
53
|
+
});
|
|
54
|
+
opn(finalUrl, { wait: false }).catch(() => {});
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/telemetry.ts
|
|
58
|
+
function withProgress(step, callback) {
|
|
59
|
+
updateProgress(step);
|
|
60
|
+
return callback();
|
|
61
|
+
}
|
|
62
|
+
function updateProgress(step) {
|
|
63
|
+
analytics.setTag("progress", step);
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
export { withUtm as i, openTrackedLink as n, setEntryCommand as r, withProgress as t };
|
|
67
|
+
|
|
68
|
+
//# sourceMappingURL=telemetry-BS7yw3TP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-BS7yw3TP.js","names":[],"sources":["../src/utils/links.ts","../src/telemetry.ts"],"sourcesContent":["/**\n * Outbound links: UTM tagging and tracked opens.\n *\n * Every URL the wizard sends a user to — auto-opened or printed in the TUI —\n * carries `utm_source=wizard`, `utm_medium=cli`, `utm_content=<which link>`.\n * The command dimension rides on every wizard event as the `command` tag.\n * Opening a link also captures a wizard event.\n */\nimport opn from 'opn';\nimport { NODE_ENV } from '@env';\nimport { analytics } from './analytics';\n\n/**\n * Record the CLI command this run was started with (e.g. `integrate`,\n * `slack`, `mcp-add`). Set once at dispatch; tagged onto every wizard\n * event so wizard-side events segment by command.\n */\nexport function setEntryCommand(command: string): void {\n analytics.setTag('command', command);\n}\n\n/**\n * Tag a URL with the wizard's UTM params. `content` names the specific link\n * (e.g. `oauth-signup`, `slack-connect-setup`). URLs that already carry a\n * utm_source — or don't parse — are returned untouched.\n */\nexport function withUtm(url: string, content: string): string {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return url;\n }\n if (parsed.searchParams.has('utm_source')) return url;\n parsed.searchParams.set('utm_source', 'wizard');\n parsed.searchParams.set('utm_medium', 'cli');\n parsed.searchParams.set('utm_content', content);\n return parsed.toString();\n}\n\n/**\n * Open a URL in the user's browser, UTM-tagged (pass `skipUtm` for\n * destinations that aren't PostHog properties or are already final), and\n * capture the interaction. `auto` marks opens the wizard initiated itself,\n * as opposed to a user picking a link on screen. opn throws in headless\n * environments — the URL is always also printed on screen, so the failure\n * is swallowed.\n */\nexport function openTrackedLink(\n url: string,\n content: string,\n opts?: { auto?: boolean; skipUtm?: boolean },\n): void {\n const finalUrl = opts?.skipUtm ? url : withUtm(url, content);\n analytics.wizardCapture('link opened', {\n content,\n url: finalUrl,\n auto: opts?.auto ?? false,\n });\n if (NODE_ENV !== 'test') {\n opn(finalUrl, { wait: false }).catch(() => {\n // No browser available — the printed URL is the fallback.\n });\n }\n}\n","import { analytics } from '@utils/analytics';\n\nexport function withProgress<T>(step: string, callback: () => T): T {\n updateProgress(step);\n return callback();\n}\n\nexport function updateProgress(step: string) {\n analytics.setTag('progress', step);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,gBAAgB,SAAuB;AACrD,WAAU,OAAO,WAAW,QAAQ;;;;;;;AAQtC,SAAgB,QAAQ,KAAa,SAAyB;CAC5D,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,IAAI;SACf;AACN,SAAO;;AAET,KAAI,OAAO,aAAa,IAAI,aAAa,CAAE,QAAO;AAClD,QAAO,aAAa,IAAI,cAAc,SAAS;AAC/C,QAAO,aAAa,IAAI,cAAc,MAAM;AAC5C,QAAO,aAAa,IAAI,eAAe,QAAQ;AAC/C,QAAO,OAAO,UAAU;;;;;;;;;;AAW1B,SAAgB,gBACd,KACA,SACA,MACM;CACN,MAAM,WAAW,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ;AAC5D,WAAU,cAAc,eAAe;EACrC;EACA,KAAK;EACL,MAAM,MAAM,QAAQ;EACrB,CAAC;AAEA,KAAI,UAAU,EAAE,MAAM,OAAO,CAAC,CAAC,YAAY,GAEzC;;;;AC5DN,SAAgB,aAAgB,MAAc,UAAsB;AAClE,gBAAe,KAAK;AACpB,QAAO,UAAU;;AAGnB,SAAgB,eAAe,MAAc;AAC3C,WAAU,OAAO,YAAY,KAAK"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Y as WIZARD_USER_AGENT } from "./debug-Ckumcrye.js";
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
//#region src/utils/urls.ts
|
|
4
4
|
const getUiHostFromHost = (host) => {
|
|
@@ -32,4 +32,4 @@ const getLlmGatewayUrlFromHost = (host) => {
|
|
|
32
32
|
//#endregion
|
|
33
33
|
export { getUiHostFromHost as a, getLlmGatewayUrlFromHost as i, getCloudUrlFromRegion as n, getHostFromRegion as r, detectRegionFromToken as t };
|
|
34
34
|
|
|
35
|
-
//# sourceMappingURL=urls-
|
|
35
|
+
//# sourceMappingURL=urls-BW23_XbC.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urls-
|
|
1
|
+
{"version":3,"file":"urls-BW23_XbC.js","names":[],"sources":["../src/utils/urls.ts"],"sourcesContent":["import axios from 'axios';\nimport { IS_DEV, WIZARD_USER_AGENT } from '@lib/constants';\nimport type { CloudRegion } from './types';\n\nexport const getAssetHostFromHost = (host: string) => {\n if (host.includes('us.i.posthog.com')) {\n return 'https://us-assets.i.posthog.com';\n }\n\n if (host.includes('eu.i.posthog.com')) {\n return 'https://eu-assets.i.posthog.com';\n }\n\n return host;\n};\n\nexport const getUiHostFromHost = (host: string) => {\n if (host.includes('us.i.posthog.com')) {\n return 'https://us.posthog.com';\n }\n\n if (host.includes('eu.i.posthog.com')) {\n return 'https://eu.posthog.com';\n }\n\n return host;\n};\n\nexport const getHostFromRegion = (region: CloudRegion) => {\n if (IS_DEV) {\n return 'http://localhost:8010';\n }\n\n if (region === 'eu') {\n return 'https://eu.i.posthog.com';\n }\n\n return 'https://us.i.posthog.com';\n};\n\nexport const getCloudUrlFromRegion = (region: CloudRegion) => {\n if (IS_DEV) {\n return 'http://localhost:8010';\n }\n\n if (region === 'eu') {\n return 'https://eu.posthog.com';\n }\n\n return 'https://us.posthog.com';\n};\n\nexport async function detectRegionFromToken(\n accessToken: string,\n): Promise<CloudRegion> {\n if (IS_DEV) {\n return 'us';\n }\n\n const headers = {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n };\n\n const [usResult, euResult] = await Promise.allSettled([\n axios.get('https://us.posthog.com/api/users/@me/', { headers }),\n axios.get('https://eu.posthog.com/api/users/@me/', { headers }),\n ]);\n\n if (usResult.status === 'fulfilled') return 'us';\n if (euResult.status === 'fulfilled') return 'eu';\n\n throw new Error(\n 'Could not determine cloud region from access token. Please check your PostHog account.',\n );\n}\n\nexport const getLlmGatewayUrlFromHost = (host: string) => {\n if (host.includes('localhost')) {\n return 'http://localhost:3308/wizard';\n }\n\n if (host.includes('eu.posthog.com') || host.includes('eu.i.posthog.com')) {\n return 'https://gateway.eu.posthog.com/wizard';\n }\n\n return 'https://gateway.us.posthog.com/wizard';\n};\n"],"mappings":";;;AAgBA,MAAa,qBAAqB,SAAiB;AACjD,KAAI,KAAK,SAAS,mBAAmB,CACnC,QAAO;AAGT,KAAI,KAAK,SAAS,mBAAmB,CACnC,QAAO;AAGT,QAAO;;AAGT,MAAa,qBAAqB,WAAwB;AAKxD,KAAI,WAAW,KACb,QAAO;AAGT,QAAO;;AAGT,MAAa,yBAAyB,WAAwB;AAK5D,KAAI,WAAW,KACb,QAAO;AAGT,QAAO;;AAGT,eAAsB,sBACpB,aACsB;CAKtB,MAAM,UAAU;EACd,eAAe,UAAU;EACzB,cAAc;EACf;CAED,MAAM,CAAC,UAAU,YAAY,MAAM,QAAQ,WAAW,CACpD,MAAM,IAAI,yCAAyC,EAAE,SAAS,CAAC,EAC/D,MAAM,IAAI,yCAAyC,EAAE,SAAS,CAAC,CAChE,CAAC;AAEF,KAAI,SAAS,WAAW,YAAa,QAAO;AAC5C,KAAI,SAAS,WAAW,YAAa,QAAO;AAE5C,OAAM,IAAI,MACR,yFACD;;AAGH,MAAa,4BAA4B,SAAiB;AACxD,KAAI,KAAK,SAAS,YAAY,CAC5B,QAAO;AAGT,KAAI,KAAK,SAAS,iBAAiB,IAAI,KAAK,SAAS,mBAAmB,CACtE,QAAO;AAGT,QAAO"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as wizardAbort, t as WizardError } from "./wizard-abort-
|
|
1
|
+
import { i as wizardAbort, t as WizardError } from "./wizard-abort-E66_R4S7.js";
|
|
2
2
|
export { WizardError, wizardAbort };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as getUI, s as logToFile } from "./debug-
|
|
2
|
-
import { t as analytics } from "./analytics-
|
|
1
|
+
import { p as getUI, s as logToFile } from "./debug-Ckumcrye.js";
|
|
2
|
+
import { t as analytics } from "./analytics-BZv-cKyn.js";
|
|
3
3
|
//#region src/utils/wizard-abort.ts
|
|
4
4
|
/**
|
|
5
5
|
* Single exit point for the wizard. Use instead of process.exit() directly.
|
|
@@ -45,4 +45,4 @@ async function wizardAbort(options) {
|
|
|
45
45
|
//#endregion
|
|
46
46
|
export { wizardAbort as i, registerCleanup as n, runCleanups as r, WizardError as t };
|
|
47
47
|
|
|
48
|
-
//# sourceMappingURL=wizard-abort-
|
|
48
|
+
//# sourceMappingURL=wizard-abort-E66_R4S7.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard-abort-
|
|
1
|
+
{"version":3,"file":"wizard-abort-E66_R4S7.js","names":[],"sources":["../src/utils/wizard-abort.ts"],"sourcesContent":["/**\n * Single exit point for the wizard. Use instead of process.exit() directly.\n *\n * Sequence: cleanup -> error capture (optional) -> analytics shutdown -> outro -> process.exit\n *\n * WizardError is a data carrier passed to wizardAbort() for analytics context, never thrown.\n * The legacy abort() in setup-utils.ts delegates here.\n */\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport { getUI } from '@ui';\nimport { OutroKind, type OutroData } from '@lib/wizard-session';\n\nexport class WizardError extends Error {\n constructor(\n message: string,\n public readonly context?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'WizardError';\n }\n}\n\ninterface WizardAbortOptions {\n message?: string;\n /** Structured error data. Renders via `outroError` instead of `outro`. */\n outroData?: OutroData;\n error?: Error | WizardError;\n exitCode?: number;\n}\n\nconst cleanupFns: Array<() => void> = [];\n\nexport function registerCleanup(fn: () => void): void {\n cleanupFns.push(fn);\n}\n\nexport function clearCleanup(): void {\n cleanupFns.length = 0;\n}\n\n/** Runs all registered cleanup functions and drains the array. */\nexport function runCleanups(): void {\n const fns = cleanupFns.splice(0);\n for (const fn of fns) {\n try {\n fn();\n } catch {\n /* cleanup should not prevent exit */\n }\n }\n}\n\nexport async function wizardAbort(\n options?: WizardAbortOptions,\n): Promise<never> {\n const {\n message = 'Wizard setup cancelled.',\n outroData,\n error,\n exitCode = 1,\n } = options ?? {};\n\n logToFile(`[wizard-abort] exitCode=${exitCode}, message: ${message}`);\n if (error) {\n logToFile('[wizard-abort] error:', error);\n }\n\n // 1. Run registered cleanup functions\n runCleanups();\n\n // 2. Capture error in analytics (if provided)\n if (error) {\n analytics.captureException(error, {\n ...((error instanceof WizardError && error.context) || {}),\n });\n }\n\n // 3. Shutdown analytics\n await analytics.shutdown(error ? 'error' : 'cancelled');\n\n // 4. Render the error outro. Synthesize OutroData from `message`\n // when the caller didn't provide structured data.\n const ui = getUI();\n ui.outroError(outroData ?? { kind: OutroKind.Error, message });\n\n // 5. Wait for the user to dismiss the outro screen. In a TUI this gives\n // them time to read the error; in non-TUI environments it resolves\n // immediately.\n await ui.waitForOutroDismissed();\n\n // 6. Exit (fires 'exit' event so TUI cleanup runs)\n return process.exit(exitCode);\n}\n"],"mappings":";;;;;;;;;;;AAaA,IAAa,cAAb,cAAiC,MAAM;CACrC,YACE,SACA,SACA;AACA,QAAM,QAAQ;AAFE,OAAA,UAAA;AAGhB,OAAK,OAAO;;;AAYhB,MAAM,aAAgC,EAAE;AAExC,SAAgB,gBAAgB,IAAsB;AACpD,YAAW,KAAK,GAAG;;;AAQrB,SAAgB,cAAoB;CAClC,MAAM,MAAM,WAAW,OAAO,EAAE;AAChC,MAAK,MAAM,MAAM,IACf,KAAI;AACF,MAAI;SACE;;AAMZ,eAAsB,YACpB,SACgB;CAChB,MAAM,EACJ,UAAU,2BACV,WACA,OACA,WAAW,MACT,WAAW,EAAE;AAEjB,WAAU,2BAA2B,SAAS,aAAa,UAAU;AACrE,KAAI,MACF,WAAU,yBAAyB,MAAM;AAI3C,cAAa;AAGb,KAAI,MACF,WAAU,iBAAiB,OAAO,EAChC,GAAK,iBAAiB,eAAe,MAAM,WAAY,EAAE,EAC1D,CAAC;AAIJ,OAAM,UAAU,SAAS,QAAQ,UAAU,YAAY;CAIvD,MAAM,KAAK,OAAO;AAClB,IAAG,WAAW,aAAa;EAAE,MAAA;EAAuB;EAAS,CAAC;AAK9D,OAAM,GAAG,uBAAuB;AAGhC,QAAO,QAAQ,KAAK,SAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard-session-G3VWD6hv.js","names":[],"sources":["../src/lib/wizard-session.ts"],"sourcesContent":["/**\n * WizardSession — single source of truth for every decision the wizard needs.\n *\n * Populated in layers:\n * CLI args / env vars → populate fields directly\n * Auto-detection → framework, typescript, package manager\n * TUI screens → region, framework disambiguation, etc.\n * OAuth → credentials\n *\n * Business logic reads from the session. Never calls a prompt.\n */\n\nimport type { Integration } from './constants';\nimport type { FrameworkConfig } from './framework-config';\nimport type { WizardReadinessResult } from './health-checks/readiness';\nimport type { SettingsConflict } from './agent/claude-settings';\nimport type { ApiUser } from './api';\n\nexport interface Credentials {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n}\n\nfunction parseProjectIdArg(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const n = Number(value);\n return Number.isInteger(n) && n > 0 ? n : undefined;\n}\n\nexport type CloudRegion = 'us' | 'eu';\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Features discovered by the feature-discovery subagent */\nexport enum DiscoveredFeature {\n Stripe = 'stripe',\n LLM = 'llm',\n}\n\n/** Additional features the agent can integrate after the main setup */\nexport enum AdditionalFeature {\n LLM = 'llm',\n}\n\n/** Human-readable labels for additional features (used in TUI progress) */\nexport const ADDITIONAL_FEATURE_LABELS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: 'LLM analytics',\n};\n\n/** Agent prompts for each additional feature, injected via the stop hook */\nexport const ADDITIONAL_FEATURE_PROMPTS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: `Now integrate LLM analytics with PostHog. Use the PostHog MCP server to find the appropriate LLM analytics skill, install it, and follow its workflow. PostHog basics are already installed. Update the setup report markdown file when complete with additions from this task. `,\n};\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/** Outcome kind for the outro screen */\nexport enum OutroKind {\n Success = 'success',\n Error = 'error',\n Cancel = 'cancel',\n}\n\nexport interface OutroData {\n kind: OutroKind;\n /** Main headline (green check for Success, red X for Error, etc.) */\n message?: string;\n /** Free-form body text shown under the headline. Use \\n for paragraph breaks. */\n body?: string;\n /** Success-only: bulleted list of \"what the agent did\" */\n changes?: string[];\n docsUrl?: string;\n continueUrl?: string;\n /** Report file the agent wrote (e.g. \"posthog-setup-report.md\") */\n reportFile?: string;\n /** PostHog dashboard URL the program created on the user's behalf. */\n dashboardUrl?: string;\n /** PostHog notebook URL the program uploaded the report to. */\n notebookUrl?: string;\n}\n\n/** A single question rendered by the WizardAsk overlay. */\nexport interface AskQuestion {\n /** Key for the response map */\n id: string;\n prompt: string;\n /** text = single-line free input; single/multi = picker */\n kind: 'single' | 'multi' | 'text';\n /** Required for `single` and `multi`. Ignored for `text`. */\n options?: { label: string; value: string }[];\n /** Defaults to true */\n required?: boolean;\n /**\n * Only meaningful for kind='text'. When true, the wizard-tools `wizard_ask`\n * tool stores the user's answer in the session secret vault and returns\n * `{ secretRef }` to the agent instead of the plain string — so the value\n * never enters the LLM conversation. The TUI may also mask input\n * accordingly. See `secret-vault.ts`.\n */\n sensitive?: boolean;\n}\n\n/** Map of question id → answer (string for single/text, string[] for multi). */\nexport type AskAnswers = Record<string, string | string[]>;\n\n/** A pending wizard_ask request held by the store. */\nexport interface PendingQuestion {\n id: string;\n questions: AskQuestion[];\n /** Skill id of the caller. Set by the wizard from session.skillId. */\n source: string;\n}\n\n/**\n * PostHog dashboard URL emitted by the agent during a program run.\n * Populated via the `[DASHBOARD_URL]` text marker in agent assistant messages\n * — see `handleSDKMessage` in `agent/agent-interface.ts`. Read by programs\n * (e.g. events-audit) inside `buildOutroData` to surface a dashboard link\n * the agent actually created.\n */\n\nexport interface WizardSession {\n // From CLI args\n debug: boolean;\n installDir: string;\n ci: boolean;\n signup: boolean;\n localMcp: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n benchmark: boolean;\n yaraReport: boolean;\n projectId?: number;\n noTelemetry: boolean;\n\n // From detection + screens\n setupConfirmed: boolean;\n integration: Integration | null;\n frameworkContext: Record<string, unknown>;\n typescript: boolean;\n\n /** Human-readable label for the detected framework variant (e.g., \"Django with Wagtail CMS\") */\n detectedFrameworkLabel: string | null;\n\n /** True once framework detection has run (whether it found something or not) */\n detectionComplete: boolean;\n\n /** Set when the detected framework version is too old for the wizard */\n unsupportedVersion: {\n current: string;\n minimum: string;\n docsUrl: string;\n } | null;\n\n // From OAuth\n credentials: Credentials | null;\n\n /**\n * `role_at_organization` from `/api/users/@me/`. Null when the upstream\n * value is missing (older accounts, fresh signups before onboarding).\n * Drives role-tailored MCP prompt suggestions on the McpSuggestedPromptsScreen.\n *\n * Mirrors `apiUser?.role_at_organization` — kept as a top-level convenience\n * because it has dedicated UI semantics (role-tailored kits) and pre-dates\n * the broader `apiUser` plumbing.\n */\n roleAtOrganization: string | null;\n\n /**\n * Full user payload from `/api/users/@me/` — identifiers, profile,\n * current team + organization, preferences, etc. Null until OAuth /\n * CI-key auth populates it. Schema lives in `src/lib/api.ts` and\n * passes through unknown upstream fields so downstream features can\n * read account context (plan, org name, email, etc.) without\n * re-fetching.\n */\n apiUser: ApiUser | null;\n\n // Lifecycle\n runPhase: RunPhase;\n loginUrl: string | null;\n // Direct PostHog authorize URL, shown in the manual-paste modal for\n // headless/remote shells (the localhost loginUrl is unreachable there).\n authorizeUrl: string | null;\n\n // Feature discovery\n discoveredFeatures: DiscoveredFeature[];\n llmOptIn: boolean;\n\n // ScreenId completion\n mcpComplete: boolean;\n mcpOutcome: McpOutcome | null;\n mcpInstalledClients: string[];\n mcpSuggestedPromptsDismissed: boolean;\n /** True once the user has acted on (opened or skipped) the Connect-Slack step. */\n slackStepDismissed: boolean;\n /**\n * Whether the project already has a Slack integration connected.\n * `null` until detected. Prefetched by the tutorial screen as soon as\n * credentials exist so the Connect-Slack step renders the right\n * variant immediately instead of flashing the nudge first.\n */\n slackConnected: boolean | null;\n skillsComplete: boolean;\n outroDismissed: boolean;\n\n // Runtime\n readinessResult: WizardReadinessResult | null;\n outageDismissed: boolean;\n settingsOverrideKeys: string[] | null;\n settingsConflicts: SettingsConflict[] | null;\n authErrorDetail: {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n logFilePath: string;\n } | null;\n portConflictProcess: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null;\n outroData: OutroData | null;\n dashboardUrl: string | null;\n notebookUrl: string | null;\n\n // Additional features queue (drained via stop hook after main integration)\n additionalFeatureQueue: AdditionalFeature[];\n\n // Program metadata (set by runWizard in bin.ts)\n programLabel: string | null;\n skillId: string | null;\n\n // Resolved framework config (set after integration is known)\n frameworkConfig: FrameworkConfig | null;\n\n /** Active wizard_ask request, set by the bridge when the agent calls the tool. */\n pendingQuestion: PendingQuestion | null;\n}\n\n/**\n * Build a WizardSession from CLI args, pre-populating whatever is known.\n */\nexport function buildSession(args: {\n debug?: boolean;\n installDir?: string;\n ci?: boolean;\n signup?: boolean;\n localMcp?: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n integration?: Integration;\n benchmark?: boolean;\n yaraReport?: boolean;\n projectId?: string;\n noTelemetry?: boolean;\n}): WizardSession {\n return {\n debug: args.debug ?? false,\n installDir: args.installDir ?? process.cwd(),\n ci: args.ci ?? false,\n signup: args.signup ?? false,\n localMcp: args.localMcp ?? false,\n mcpFeatures: args.mcpFeatures,\n apiKey: args.apiKey,\n email: args.email,\n region: args.region,\n benchmark: args.benchmark ?? false,\n yaraReport: args.yaraReport ?? false,\n projectId: parseProjectIdArg(args.projectId),\n noTelemetry: args.noTelemetry ?? false,\n\n setupConfirmed: false,\n integration: args.integration ?? null,\n frameworkContext: {},\n typescript: false,\n detectedFrameworkLabel: null,\n detectionComplete: false,\n unsupportedVersion: null,\n\n runPhase: RunPhase.Idle,\n discoveredFeatures: [],\n llmOptIn: false,\n mcpComplete: false,\n mcpOutcome: null,\n mcpInstalledClients: [],\n mcpSuggestedPromptsDismissed: false,\n slackStepDismissed: false,\n slackConnected: null,\n skillsComplete: false,\n outroDismissed: false,\n loginUrl: null,\n authorizeUrl: null,\n credentials: null,\n roleAtOrganization: null,\n apiUser: null,\n readinessResult: null,\n outageDismissed: false,\n settingsOverrideKeys: null,\n settingsConflicts: null,\n authErrorDetail: null,\n portConflictProcess: null,\n outroData: null,\n dashboardUrl: null,\n notebookUrl: null,\n additionalFeatureQueue: [],\n programLabel: null,\n skillId: null,\n frameworkConfig: null,\n pendingQuestion: null,\n };\n}\n"],"mappings":";AAyBA,SAAS,kBAAkB,OAA+C;AACxE,KAAI,UAAU,KAAA,KAAa,UAAU,GAAI,QAAO,KAAA;CAChD,MAAM,IAAI,OAAO,MAAM;AACvB,QAAO,OAAO,UAAU,EAAE,IAAI,IAAI,IAAI,IAAI,KAAA;;;AAM5C,IAAY,WAAL,yBAAA,UAAA;;AAEL,UAAA,UAAA;;AAEA,UAAA,aAAA;;AAEA,UAAA,eAAA;;AAEA,UAAA,WAAA;;KACD;;AAcD,MAAa,4BAA+D,GAAA,QACjD,iBAC1B;;AAGD,MAAa,6BAAgE,GAAA,QAClD,oRAC1B;;;;AAuMD,SAAgB,aAAa,MAeX;AAChB,QAAO;EACL,OAAO,KAAK,SAAS;EACrB,YAAY,KAAK,cAAc,QAAQ,KAAK;EAC5C,IAAI,KAAK,MAAM;EACf,QAAQ,KAAK,UAAU;EACvB,UAAU,KAAK,YAAY;EAC3B,aAAa,KAAK;EAClB,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,WAAW,KAAK,aAAa;EAC7B,YAAY,KAAK,cAAc;EAC/B,WAAW,kBAAkB,KAAK,UAAU;EAC5C,aAAa,KAAK,eAAe;EAEjC,gBAAgB;EAChB,aAAa,KAAK,eAAe;EACjC,kBAAkB,EAAE;EACpB,YAAY;EACZ,wBAAwB;EACxB,mBAAmB;EACnB,oBAAoB;EAEpB,UAAA;EACA,oBAAoB,EAAE;EACtB,UAAU;EACV,aAAa;EACb,YAAY;EACZ,qBAAqB,EAAE;EACvB,8BAA8B;EAC9B,oBAAoB;EACpB,gBAAgB;EAChB,gBAAgB;EAChB,gBAAgB;EAChB,UAAU;EACV,cAAc;EACd,aAAa;EACb,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EACjB,sBAAsB;EACtB,mBAAmB;EACnB,iBAAiB;EACjB,qBAAqB;EACrB,WAAW;EACX,cAAc;EACd,aAAa;EACb,wBAAwB,EAAE;EAC1B,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EAClB"}
|
|
1
|
+
{"version":3,"file":"wizard-session-G3VWD6hv.js","names":[],"sources":["../src/lib/wizard-session.ts"],"sourcesContent":["/**\n * WizardSession — single source of truth for every decision the wizard needs.\n *\n * Populated in layers:\n * CLI args / env vars → populate fields directly\n * Auto-detection → framework, typescript, package manager\n * TUI screens → region, framework disambiguation, etc.\n * OAuth → credentials\n *\n * Business logic reads from the session. Never calls a prompt.\n */\n\nimport type { Integration } from './constants';\nimport type { FrameworkConfig } from './framework-config';\nimport type { WizardReadinessResult } from './health-checks/readiness';\nimport type { SettingsConflict } from './agent/claude-settings';\nimport type { ApiUser } from './api';\n\nexport interface Credentials {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n}\n\nfunction parseProjectIdArg(value: string | undefined): number | undefined {\n if (value === undefined || value === '') return undefined;\n const n = Number(value);\n return Number.isInteger(n) && n > 0 ? n : undefined;\n}\n\nexport type CloudRegion = 'us' | 'eu';\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Features discovered by the feature-discovery subagent */\nexport enum DiscoveredFeature {\n Stripe = 'stripe',\n LLM = 'llm',\n}\n\n/** Additional features the agent can integrate after the main setup */\nexport enum AdditionalFeature {\n LLM = 'llm',\n}\n\n/** Human-readable labels for additional features (used in TUI progress) */\nexport const ADDITIONAL_FEATURE_LABELS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: 'LLM analytics',\n};\n\n/** Agent prompts for each additional feature, injected via the stop hook */\nexport const ADDITIONAL_FEATURE_PROMPTS: Record<AdditionalFeature, string> = {\n [AdditionalFeature.LLM]: `Now integrate LLM analytics with PostHog. Use the PostHog MCP server to find the appropriate LLM analytics skill, install it, and follow its workflow. PostHog basics are already installed. Update the setup report markdown file when complete with additions from this task. `,\n};\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/** Outcome kind for the outro screen */\nexport enum OutroKind {\n Success = 'success',\n Error = 'error',\n Cancel = 'cancel',\n}\n\nexport interface OutroData {\n kind: OutroKind;\n /** Main headline (green check for Success, red X for Error, etc.) */\n message?: string;\n /** Free-form body text shown under the headline. Use \\n for paragraph breaks. */\n body?: string;\n /** Success-only: bulleted list of \"what the agent did\" */\n changes?: string[];\n docsUrl?: string;\n continueUrl?: string;\n /** Report file the agent wrote (e.g. \"posthog-setup-report.md\") */\n reportFile?: string;\n /** PostHog dashboard URL the program created on the user's behalf. */\n dashboardUrl?: string;\n /** PostHog notebook URL the program uploaded the report to. */\n notebookUrl?: string;\n /**\n * Copy-paste prompt the operator hands to their coding agent to finish the\n * job (work the report's checklist). Printed to the terminal's main buffer on\n * exit (see getExitLine in start-tui.ts) — the TUI's alternate screen is wiped\n * on exit, so the scrollback line is where it survives and can be\n * triple-click-selected. Set per-program in buildOutroData.\n */\n handoffPrompt?: string;\n}\n\n/** A single question rendered by the WizardAsk overlay. */\nexport interface AskQuestion {\n /** Key for the response map */\n id: string;\n prompt: string;\n /** text = single-line free input; single/multi = picker */\n kind: 'single' | 'multi' | 'text';\n /** Required for `single` and `multi`. Ignored for `text`. */\n options?: { label: string; value: string }[];\n /** Defaults to true */\n required?: boolean;\n /**\n * Only meaningful for kind='text'. When true, the wizard-tools `wizard_ask`\n * tool stores the user's answer in the session secret vault and returns\n * `{ secretRef }` to the agent instead of the plain string — so the value\n * never enters the LLM conversation. The TUI may also mask input\n * accordingly. See `secret-vault.ts`.\n */\n sensitive?: boolean;\n}\n\n/** Map of question id → answer (string for single/text, string[] for multi). */\nexport type AskAnswers = Record<string, string | string[]>;\n\n/** A pending wizard_ask request held by the store. */\nexport interface PendingQuestion {\n id: string;\n questions: AskQuestion[];\n /** Skill id of the caller. Set by the wizard from session.skillId. */\n source: string;\n}\n\n/**\n * PostHog dashboard URL emitted by the agent during a program run.\n * Populated via the `[DASHBOARD_URL]` text marker in agent assistant messages\n * — see `handleSDKMessage` in `agent/agent-interface.ts`. Read by programs\n * (e.g. events-audit) inside `buildOutroData` to surface a dashboard link\n * the agent actually created.\n */\n\nexport interface WizardSession {\n // From CLI args\n debug: boolean;\n installDir: string;\n ci: boolean;\n signup: boolean;\n localMcp: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n benchmark: boolean;\n yaraReport: boolean;\n projectId?: number;\n noTelemetry: boolean;\n\n // From detection + screens\n setupConfirmed: boolean;\n integration: Integration | null;\n frameworkContext: Record<string, unknown>;\n typescript: boolean;\n\n /** Human-readable label for the detected framework variant (e.g., \"Django with Wagtail CMS\") */\n detectedFrameworkLabel: string | null;\n\n /** True once framework detection has run (whether it found something or not) */\n detectionComplete: boolean;\n\n /** Set when the detected framework version is too old for the wizard */\n unsupportedVersion: {\n current: string;\n minimum: string;\n docsUrl: string;\n } | null;\n\n // From OAuth\n credentials: Credentials | null;\n\n /**\n * `role_at_organization` from `/api/users/@me/`. Null when the upstream\n * value is missing (older accounts, fresh signups before onboarding).\n * Drives role-tailored MCP prompt suggestions on the McpSuggestedPromptsScreen.\n *\n * Mirrors `apiUser?.role_at_organization` — kept as a top-level convenience\n * because it has dedicated UI semantics (role-tailored kits) and pre-dates\n * the broader `apiUser` plumbing.\n */\n roleAtOrganization: string | null;\n\n /**\n * Full user payload from `/api/users/@me/` — identifiers, profile,\n * current team + organization, preferences, etc. Null until OAuth /\n * CI-key auth populates it. Schema lives in `src/lib/api.ts` and\n * passes through unknown upstream fields so downstream features can\n * read account context (plan, org name, email, etc.) without\n * re-fetching.\n */\n apiUser: ApiUser | null;\n\n // Lifecycle\n runPhase: RunPhase;\n loginUrl: string | null;\n // Direct PostHog authorize URL, shown in the manual-paste modal for\n // headless/remote shells (the localhost loginUrl is unreachable there).\n authorizeUrl: string | null;\n\n // Feature discovery\n discoveredFeatures: DiscoveredFeature[];\n llmOptIn: boolean;\n\n // ScreenId completion\n mcpComplete: boolean;\n mcpOutcome: McpOutcome | null;\n mcpInstalledClients: string[];\n mcpSuggestedPromptsDismissed: boolean;\n /** True once the user has acted on (opened or skipped) the Connect-Slack step. */\n slackStepDismissed: boolean;\n /**\n * Whether the project already has a Slack integration connected.\n * `null` until detected. Prefetched by the tutorial screen as soon as\n * credentials exist so the Connect-Slack step renders the right\n * variant immediately instead of flashing the nudge first.\n */\n slackConnected: boolean | null;\n skillsComplete: boolean;\n outroDismissed: boolean;\n\n // Runtime\n readinessResult: WizardReadinessResult | null;\n outageDismissed: boolean;\n settingsOverrideKeys: string[] | null;\n settingsConflicts: SettingsConflict[] | null;\n authErrorDetail: {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n logFilePath: string;\n } | null;\n portConflictProcess: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null;\n outroData: OutroData | null;\n dashboardUrl: string | null;\n notebookUrl: string | null;\n\n // Additional features queue (drained via stop hook after main integration)\n additionalFeatureQueue: AdditionalFeature[];\n\n // Program metadata (set by runWizard in bin.ts)\n programLabel: string | null;\n skillId: string | null;\n\n // Resolved framework config (set after integration is known)\n frameworkConfig: FrameworkConfig | null;\n\n /** Active wizard_ask request, set by the bridge when the agent calls the tool. */\n pendingQuestion: PendingQuestion | null;\n}\n\n/**\n * Build a WizardSession from CLI args, pre-populating whatever is known.\n */\nexport function buildSession(args: {\n debug?: boolean;\n installDir?: string;\n ci?: boolean;\n signup?: boolean;\n localMcp?: boolean;\n mcpFeatures?: string[];\n apiKey?: string;\n email?: string;\n region?: CloudRegion;\n integration?: Integration;\n benchmark?: boolean;\n yaraReport?: boolean;\n projectId?: string;\n noTelemetry?: boolean;\n}): WizardSession {\n return {\n debug: args.debug ?? false,\n installDir: args.installDir ?? process.cwd(),\n ci: args.ci ?? false,\n signup: args.signup ?? false,\n localMcp: args.localMcp ?? false,\n mcpFeatures: args.mcpFeatures,\n apiKey: args.apiKey,\n email: args.email,\n region: args.region,\n benchmark: args.benchmark ?? false,\n yaraReport: args.yaraReport ?? false,\n projectId: parseProjectIdArg(args.projectId),\n noTelemetry: args.noTelemetry ?? false,\n\n setupConfirmed: false,\n integration: args.integration ?? null,\n frameworkContext: {},\n typescript: false,\n detectedFrameworkLabel: null,\n detectionComplete: false,\n unsupportedVersion: null,\n\n runPhase: RunPhase.Idle,\n discoveredFeatures: [],\n llmOptIn: false,\n mcpComplete: false,\n mcpOutcome: null,\n mcpInstalledClients: [],\n mcpSuggestedPromptsDismissed: false,\n slackStepDismissed: false,\n slackConnected: null,\n skillsComplete: false,\n outroDismissed: false,\n loginUrl: null,\n authorizeUrl: null,\n credentials: null,\n roleAtOrganization: null,\n apiUser: null,\n readinessResult: null,\n outageDismissed: false,\n settingsOverrideKeys: null,\n settingsConflicts: null,\n authErrorDetail: null,\n portConflictProcess: null,\n outroData: null,\n dashboardUrl: null,\n notebookUrl: null,\n additionalFeatureQueue: [],\n programLabel: null,\n skillId: null,\n frameworkConfig: null,\n pendingQuestion: null,\n };\n}\n"],"mappings":";AAyBA,SAAS,kBAAkB,OAA+C;AACxE,KAAI,UAAU,KAAA,KAAa,UAAU,GAAI,QAAO,KAAA;CAChD,MAAM,IAAI,OAAO,MAAM;AACvB,QAAO,OAAO,UAAU,EAAE,IAAI,IAAI,IAAI,IAAI,KAAA;;;AAM5C,IAAY,WAAL,yBAAA,UAAA;;AAEL,UAAA,UAAA;;AAEA,UAAA,aAAA;;AAEA,UAAA,eAAA;;AAEA,UAAA,WAAA;;KACD;;AAcD,MAAa,4BAA+D,GAAA,QACjD,iBAC1B;;AAGD,MAAa,6BAAgE,GAAA,QAClD,oRAC1B;;;;AA+MD,SAAgB,aAAa,MAeX;AAChB,QAAO;EACL,OAAO,KAAK,SAAS;EACrB,YAAY,KAAK,cAAc,QAAQ,KAAK;EAC5C,IAAI,KAAK,MAAM;EACf,QAAQ,KAAK,UAAU;EACvB,UAAU,KAAK,YAAY;EAC3B,aAAa,KAAK;EAClB,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,WAAW,KAAK,aAAa;EAC7B,YAAY,KAAK,cAAc;EAC/B,WAAW,kBAAkB,KAAK,UAAU;EAC5C,aAAa,KAAK,eAAe;EAEjC,gBAAgB;EAChB,aAAa,KAAK,eAAe;EACjC,kBAAkB,EAAE;EACpB,YAAY;EACZ,wBAAwB;EACxB,mBAAmB;EACnB,oBAAoB;EAEpB,UAAA;EACA,oBAAoB,EAAE;EACtB,UAAU;EACV,aAAa;EACb,YAAY;EACZ,qBAAqB,EAAE;EACvB,8BAA8B;EAC9B,oBAAoB;EACpB,gBAAgB;EAChB,gBAAgB;EAChB,gBAAgB;EAChB,UAAU;EACV,cAAc;EACd,aAAa;EACb,oBAAoB;EACpB,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EACjB,sBAAsB;EACtB,mBAAmB;EACnB,iBAAiB;EACjB,qBAAqB;EACrB,WAAW;EACX,cAAc;EACd,aAAa;EACb,wBAAwB,EAAE;EAC1B,cAAc;EACd,SAAS;EACT,iBAAiB;EACjB,iBAAiB;EAClB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard-ui-YdGFRyu_.js","names":[],"sources":["../src/ui/wizard-ui.ts"],"sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nimport type { SettingsConflict } from '@lib/agent/claude-settings';\nimport type { WizardReadinessResult } from '@lib/health-checks/readiness';\nimport type { ApiUser } from '@lib/api';\nimport type {\n AskAnswers,\n OutroData,\n PendingQuestion,\n} from '@lib/wizard-session';\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n}\n\nexport function isTaskStatus(value: string): value is TaskStatus {\n return (Object.values(TaskStatus) as string[]).includes(value);\n}\n\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\n/**\n * Context passed to `showAuthError` so the screen can pick the right copy.\n *\n * `hasSettingsConflict` is true when a Claude Code settings file (project,\n * project-local, the user's global config, or managed) actually overrides the\n * LLM Gateway auth. `conflicts` carries the exact files and keys so the screen\n * can name them. When there is no conflict, the 401 has a different cause (bad\n * PAT prefix, missing scope, expired key, region mismatch) and we should not\n * advise the user to log out of Claude Code.\n */\nexport interface AuthErrorDetail {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n logFilePath: string;\n}\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n /** Success outro with a plain text message. */\n outro(message: string): void;\n /**\n * Error outro. Sets structured outroData and transitions run phase so\n * the router advances to the outro screen. Use for abort/failure paths\n * that need a custom error render — do NOT build the outroData by\n * mutating session directly (nanostore holds a shallow copy).\n */\n outroError(data: OutroData): void;\n /** Resolves when the user dismisses the outro screen (presses any key).\n * Lets the abort path wait for the user to read the error before the\n * process exits. Resolves immediately in non-TUI environments. */\n waitForOutroDismissed(): Promise<void>;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n }): void;\n\n /**\n * Persist the user's `role_at_organization` once it's been fetched from\n * `/api/users/@me/`. Drives role-tailored prompt suggestions on the\n * McpSuggestedPromptsScreen. Pass `null` to clear / when unknown.\n */\n setRoleAtOrganization(role: string | null): void;\n\n /**\n * Persist the full user payload from `/api/users/@me/` so downstream\n * screens can read account context (current org, team, plan, email,\n * preferences, etc.) without re-fetching. Pass `null` to clear or\n * when the request failed.\n */\n setApiUser(user: ApiUser | null): void;\n\n /** Show blocking service outage (pushes outage overlay in TUI). Blocks until dismissed. */\n showBlockingOutage(result: WizardReadinessResult): Promise<void>;\n\n /** Store non-blocking readiness warnings (shown as Health tab in RunScreen). */\n setReadinessWarnings(result: WizardReadinessResult): void;\n\n /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void>;\n\n /**\n * Resolve with an OAuth authorization code the user enters by hand — the\n * fallback for headless/remote shells where the browser can't reach the\n * local callback server. The OAuth flow races this against the callback\n * server. Implementations that can't prompt (CI/logging) never resolve.\n */\n waitForManualAuthCode(): Promise<string>;\n\n showSettingsOverride(\n conflicts: SettingsConflict[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n /** Show auth error overlay when Anthropic API returns 401. */\n showAuthError(detail?: AuthErrorDetail): void;\n\n /**\n * Open the wizard_ask overlay and resolve with the user's answers.\n * Implementations that can't ask (CI/logging) reject so the bridge can\n * surface a clear \"not available\" error to the agent.\n */\n requestQuestion(question: PendingQuestion): Promise<AskAnswers>;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n /** Direct PostHog authorize URL, shown in the manual-paste modal. */\n setAuthorizeUrl(url: string | null): void;\n\n // ── Task tracking from SDK TaskCreate/TaskUpdate events ───────────\n // Receives the full materialised task list each call. The caller (agent\n // loop) maintains a Map<taskId, …> from incremental Task* events and\n // re-emits the snapshot here, preserving the existing store semantics.\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n\n // ── Dashboard URL emitted by the agent via [DASHBOARD_URL] marker ──\n setDashboardUrl(url: string): void;\n\n // ── Notebook URL emitted by the agent via [NOTEBOOK_URL] marker ──\n setNotebookUrl(url: string): void;\n\n // ── Outro payload built by agent-runner ──\n // Replaces the direct `session.outroData = X` mutation that breaks once\n // setKey-based store mutations have forked the session reference.\n setOutroData(data: OutroData): void;\n\n // ── Generic frameworkContext setter for program file watchers ─────\n setFrameworkContext(key: string, value: unknown): void;\n}\n"],"mappings":";AAmBA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,gBAAA;AACA,YAAA,eAAA;;KACD;AAED,SAAgB,aAAa,OAAoC;AAC/D,QAAQ,OAAO,OAAO,WAAW,CAAc,SAAS,MAAM"}
|
|
1
|
+
{"version":3,"file":"wizard-ui-YdGFRyu_.js","names":[],"sources":["../src/ui/wizard-ui.ts"],"sourcesContent":["/**\n * WizardUI — abstraction layer for all user-facing operations.\n *\n * Business logic calls `getUI()` instead of importing the store directly.\n * Implementations: InkUI (TUI), LoggingUI (CI).\n *\n * No prompt methods — the TUI screens own all user input.\n * Session-mutating methods trigger reactive screen resolution in the TUI.\n */\n\nimport type { SettingsConflict } from '@lib/agent/claude-settings';\nimport type { WizardReadinessResult } from '@lib/health-checks/readiness';\nimport type { ApiUser } from '@lib/api';\nimport type {\n AskAnswers,\n OutroData,\n PendingQuestion,\n} from '@lib/wizard-session';\n\nexport enum TaskStatus {\n Pending = 'pending',\n InProgress = 'in_progress',\n Completed = 'completed',\n}\n\nexport function isTaskStatus(value: string): value is TaskStatus {\n return (Object.values(TaskStatus) as string[]).includes(value);\n}\n\nexport interface SpinnerHandle {\n start(message?: string): void;\n stop(message?: string): void;\n message(msg?: string): void;\n}\n\n/**\n * Context passed to `showAuthError` so the screen can pick the right copy.\n *\n * `hasSettingsConflict` is true when a Claude Code settings file (project,\n * project-local, the user's global config, or managed) actually overrides the\n * LLM Gateway auth. `conflicts` carries the exact files and keys so the screen\n * can name them. When there is no conflict, the 401 has a different cause (bad\n * PAT prefix, missing scope, expired key, region mismatch) and we should not\n * advise the user to log out of Claude Code.\n */\nexport interface AuthErrorDetail {\n hasSettingsConflict: boolean;\n conflicts?: SettingsConflict[];\n logFilePath: string;\n}\n\nexport interface WizardUI {\n // ── Lifecycle messages ────────────────────────────────────────────\n intro(message: string): void;\n /** Success outro with a plain text message. */\n outro(message: string): void;\n /**\n * Error outro. Sets structured outroData and transitions run phase so\n * the router advances to the outro screen. Use for abort/failure paths\n * that need a custom error render — do NOT build the outroData by\n * mutating session directly (nanostore holds a shallow copy).\n */\n outroError(data: OutroData): void;\n /** Resolves when the user dismisses the outro screen (presses any key).\n * Lets the abort path wait for the user to read the error before the\n * process exits. Resolves immediately in non-TUI environments. */\n waitForOutroDismissed(): Promise<void>;\n cancel(message: string): void;\n\n // ── Logging ───────────────────────────────────────────────────────\n log: {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n };\n\n note(message: string): void;\n pushStatus(message: string): void;\n\n // ── Spinner ───────────────────────────────────────────────────────\n spinner(): SpinnerHandle;\n\n // ── Session state (triggers reactive screen resolution in TUI) ────\n /** Signal that the main work (agent run) has started. */\n startRun(): void;\n\n /** Store OAuth/API credentials. Resolves past AuthScreen in TUI. */\n setCredentials(credentials: {\n accessToken: string;\n projectApiKey: string;\n host: string;\n projectId: number;\n }): void;\n\n /**\n * Persist the user's `role_at_organization` once it's been fetched from\n * `/api/users/@me/`. Drives role-tailored prompt suggestions on the\n * McpSuggestedPromptsScreen. Pass `null` to clear / when unknown.\n */\n setRoleAtOrganization(role: string | null): void;\n\n /**\n * Persist the full user payload from `/api/users/@me/` so downstream\n * screens can read account context (current org, team, plan, email,\n * preferences, etc.) without re-fetching. Pass `null` to clear or\n * when the request failed.\n */\n setApiUser(user: ApiUser | null): void;\n\n /**\n * Park until the org's AI opt-in gate clears\n * (`organization.is_ai_data_processing_approved === true`, or the\n * program never registered the gate — requiresAi: false / no auth\n * step / CI session). The agent runner awaits this after setApiUser\n * and BEFORE skill install or agent start: this is the enforcement\n * point that keeps source on the machine while the TUI shows\n * AiOptInRequiredScreen. Resolves immediately in non-TUI\n * environments (CI auto-consents to AI usage).\n */\n waitForAiOptIn(): Promise<void>;\n\n /** Show blocking service outage (pushes outage overlay in TUI). Blocks until dismissed. */\n showBlockingOutage(result: WizardReadinessResult): Promise<void>;\n\n /** Store non-blocking readiness warnings (shown as Health tab in RunScreen). */\n setReadinessWarnings(result: WizardReadinessResult): void;\n\n /** Warn that another process is blocking the OAuth port (pushes overlay in TUI). */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void>;\n\n /**\n * Resolve with an OAuth authorization code the user enters by hand — the\n * fallback for headless/remote shells where the browser can't reach the\n * local callback server. The OAuth flow races this against the callback\n * server. Implementations that can't prompt (CI/logging) never resolve.\n */\n waitForManualAuthCode(): Promise<string>;\n\n showSettingsOverride(\n conflicts: SettingsConflict[],\n backupAndFix: () => boolean,\n ): Promise<void>;\n\n /** Show auth error overlay when Anthropic API returns 401. */\n showAuthError(detail?: AuthErrorDetail): void;\n\n /** Show the session-timeout overlay when the OAuth login window expires. */\n showSessionTimeout(): void;\n\n /**\n * Open the wizard_ask overlay and resolve with the user's answers.\n * Implementations that can't ask (CI/logging) reject so the bridge can\n * surface a clear \"not available\" error to the agent.\n */\n requestQuestion(question: PendingQuestion): Promise<AskAnswers>;\n\n // ── Display state ──────────────────────────────────────────────────\n /** Set the detected framework label (e.g., \"Django with Wagtail CMS\") */\n setDetectedFramework(label: string): void;\n\n /** Register a callback to run when the TUI transitions onto the given screen. */\n onEnterScreen(screen: string, fn: () => void): void;\n\n setLoginUrl(url: string | null): void;\n\n /** Direct PostHog authorize URL, shown in the manual-paste modal. */\n setAuthorizeUrl(url: string | null): void;\n\n // ── Task tracking from SDK TaskCreate/TaskUpdate events ───────────\n // Receives the full materialised task list each call. The caller (agent\n // loop) maintains a Map<taskId, …> from incremental Task* events and\n // re-emits the snapshot here, preserving the existing store semantics.\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void;\n\n // ── Event plan from .posthog-events.json ────────────────────\n setEventPlan(events: Array<{ name: string; description: string }>): void;\n\n // ── Dashboard URL emitted by the agent via [DASHBOARD_URL] marker ──\n setDashboardUrl(url: string): void;\n\n // ── Notebook URL emitted by the agent via [NOTEBOOK_URL] marker ──\n setNotebookUrl(url: string): void;\n\n // ── Outro payload built by agent-runner ──\n // Replaces the direct `session.outroData = X` mutation that breaks once\n // setKey-based store mutations have forked the session reference.\n setOutroData(data: OutroData): void;\n\n // ── Generic frameworkContext setter for program file watchers ─────\n setFrameworkContext(key: string, value: unknown): void;\n}\n"],"mappings":";AAmBA,IAAY,aAAL,yBAAA,YAAA;AACL,YAAA,aAAA;AACA,YAAA,gBAAA;AACA,YAAA,eAAA;;KACD;AAED,SAAgB,aAAa,OAAoC;AAC/D,QAAQ,OAAO,OAAO,WAAW,CAAc,SAAS,MAAM"}
|
package/package.json
CHANGED