@posthog/wizard 2.10.4 → 2.12.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.
Files changed (90) hide show
  1. package/README.md +48 -7
  2. package/dist/{McpScreen-LqnNwEfV.js → AuditChecksViewer-DsfXIO9e.js} +475 -36
  3. package/dist/AuditChecksViewer-DsfXIO9e.js.map +1 -0
  4. package/dist/{add-mcp-server-to-clients-lfUH2pdU.js → add-mcp-server-to-clients-BKoew3aT.js} +157 -125
  5. package/dist/add-mcp-server-to-clients-BKoew3aT.js.map +1 -0
  6. package/dist/{readiness-Cep84RsR.js → agent-interface-D5W9BAB2.js} +329 -464
  7. package/dist/agent-interface-D5W9BAB2.js.map +1 -0
  8. package/dist/{agent-runner-DHtcWn15.js → agent-runner-B8Cx6X6x.js} +22 -31
  9. package/dist/agent-runner-B8Cx6X6x.js.map +1 -0
  10. package/dist/analytics-DmD31Ssc.js +123 -0
  11. package/dist/analytics-DmD31Ssc.js.map +1 -0
  12. package/dist/analytics-JDitS2JI.js +2 -0
  13. package/dist/bin.js +521 -46
  14. package/dist/bin.js.map +1 -1
  15. package/dist/debug-Bkaqv1ab.js +686 -0
  16. package/dist/debug-Bkaqv1ab.js.map +1 -0
  17. package/dist/{debug-CIyf0ZGx.js → debug-I5sRZubJ.js} +1 -1
  18. package/dist/{defaults-DoVkE0gW.js → defaults-GbLPuHxj.js} +8 -8
  19. package/dist/defaults-GbLPuHxj.js.map +1 -0
  20. package/dist/detection-C_RfYYDe.js +206 -0
  21. package/dist/detection-C_RfYYDe.js.map +1 -0
  22. package/dist/{env-api-key-K8TdTDII.js → env-api-key-D5G2PrXW.js} +1 -1
  23. package/dist/{env-api-key-K8TdTDII.js.map → env-api-key-D5G2PrXW.js.map} +1 -1
  24. package/dist/file-8iNrXHkG.js +16 -0
  25. package/dist/file-8iNrXHkG.js.map +1 -0
  26. package/dist/{file-utils-BWneZy6p.js → file-utils-DnTSiTJw.js} +1 -1
  27. package/dist/{file-utils-BWneZy6p.js.map → file-utils-DnTSiTJw.js.map} +1 -1
  28. package/dist/package-json-BzVey4Bd.js +2 -0
  29. package/dist/{package-json-Ctq6LSl8.js → package-json-F_7oktsp.js} +1 -1
  30. package/dist/{package-json-Ctq6LSl8.js.map → package-json-F_7oktsp.js.map} +1 -1
  31. package/dist/{package-manager-CwU26DwX.js → package-manager-qxP2PpM_.js} +2 -2
  32. package/dist/{package-manager-CwU26DwX.js.map → package-manager-qxP2PpM_.js.map} +1 -1
  33. package/dist/paths-DJS47p5x.js +26 -0
  34. package/dist/paths-DJS47p5x.js.map +1 -0
  35. package/dist/{posthog-integration-HBDZrREG.js → posthog-integration-DX77Msto.js} +43 -14
  36. package/dist/posthog-integration-DX77Msto.js.map +1 -0
  37. package/dist/posthog-vm0k9PKS.js +11 -0
  38. package/dist/posthog-vm0k9PKS.js.map +1 -0
  39. package/dist/provisioning-CHfTOEvg.js +2 -0
  40. package/dist/provisioning-DUj285NO.js +166 -0
  41. package/dist/provisioning-DUj285NO.js.map +1 -0
  42. package/dist/{registry-BIV1wRpo.js → registry-CCtIsqb8.js} +5 -6
  43. package/dist/{registry-BIV1wRpo.js.map → registry-CCtIsqb8.js.map} +1 -1
  44. package/dist/{router-CXjdWNh2.js → router-BTfmEDDJ.js} +4 -3
  45. package/dist/router-BTfmEDDJ.js.map +1 -0
  46. package/dist/{setup-utils-CHojnr4N.js → setup-utils-Bv8z6HMb.js} +17 -150
  47. package/dist/setup-utils-Bv8z6HMb.js.map +1 -0
  48. package/dist/setup-utils-CoX-vLgw.js +2 -0
  49. package/dist/{start-playground-D1iLBvqF.js → start-playground-DYNQ8rOz.js} +181 -9
  50. package/dist/start-playground-DYNQ8rOz.js.map +1 -0
  51. package/dist/{start-tui-DkT_H5zx.js → start-tui-DleQG3La.js} +1290 -163
  52. package/dist/start-tui-DleQG3La.js.map +1 -0
  53. package/dist/{steps-zpqG7W08.js → steps-C-syS8if.js} +8 -8
  54. package/dist/steps-C-syS8if.js.map +1 -0
  55. package/dist/task-stream-CX7Uf6EM.js +61 -0
  56. package/dist/task-stream-CX7Uf6EM.js.map +1 -0
  57. package/dist/{telemetry-CPoSyK0a.js → telemetry-DHZfjgqx.js} +2 -2
  58. package/dist/{telemetry-CPoSyK0a.js.map → telemetry-DHZfjgqx.js.map} +1 -1
  59. package/dist/{wizard-abort-BcEPhAxY.js → wizard-abort-DIhFXJ5N.js} +1 -1
  60. package/dist/{wizard-abort-DKctLd33.js → wizard-abort-DfhWuzaw.js} +6 -4
  61. package/dist/{wizard-abort-DKctLd33.js.map → wizard-abort-DfhWuzaw.js.map} +1 -1
  62. package/dist/wizard-session-BQC9vy9Z.js +2 -0
  63. package/dist/{wizard-session-Db6R023m.js → wizard-session-BcNJTl2I.js} +1 -1
  64. package/dist/{wizard-session-Db6R023m.js.map → wizard-session-BcNJTl2I.js.map} +1 -1
  65. package/dist/wizard-ui-YdGFRyu_.js +14 -0
  66. package/dist/wizard-ui-YdGFRyu_.js.map +1 -0
  67. package/npm-shrinkwrap.json +2 -2
  68. package/package.json +1 -1
  69. package/dist/McpScreen-LqnNwEfV.js.map +0 -1
  70. package/dist/add-mcp-server-to-clients-lfUH2pdU.js.map +0 -1
  71. package/dist/agent-runner-DHtcWn15.js.map +0 -1
  72. package/dist/agent-skill-BVjJqol6.js +0 -59
  73. package/dist/agent-skill-BVjJqol6.js.map +0 -1
  74. package/dist/analytics-Cm6i5_gc.js +0 -207
  75. package/dist/analytics-Cm6i5_gc.js.map +0 -1
  76. package/dist/analytics-CviQ_A9M.js +0 -2
  77. package/dist/debug-CyJ_3dTP.js +0 -201
  78. package/dist/debug-CyJ_3dTP.js.map +0 -1
  79. package/dist/defaults-DoVkE0gW.js.map +0 -1
  80. package/dist/detection-gcQwPKPu.js +0 -122
  81. package/dist/detection-gcQwPKPu.js.map +0 -1
  82. package/dist/package-json-BQgl5C3Z.js +0 -2
  83. package/dist/posthog-integration-HBDZrREG.js.map +0 -1
  84. package/dist/readiness-Cep84RsR.js.map +0 -1
  85. package/dist/router-CXjdWNh2.js.map +0 -1
  86. package/dist/setup-utils-CHojnr4N.js.map +0 -1
  87. package/dist/start-playground-D1iLBvqF.js.map +0 -1
  88. package/dist/start-tui-DkT_H5zx.js.map +0 -1
  89. package/dist/steps-zpqG7W08.js.map +0 -1
  90. package/dist/wizard-session-y7nf6aKH.js +0 -2
@@ -1,19 +1,25 @@
1
- import { l as setUI, s as logToFile } from "./debug-CyJ_3dTP.js";
2
- import { i as CONTEXT_MILL_URL, l as Integration, u as OAUTH_PORTS, v as REMOTE_SKILLS_BASE_URL, w as getSkillsBaseUrl } from "./analytics-Cm6i5_gc.js";
3
- import { t as ADDITIONAL_FEATURE_LABELS } from "./wizard-session-Db6R023m.js";
4
- import { r as wizardAbort } from "./wizard-abort-DKctLd33.js";
5
- import { m as fetchSkillMenu, p as downloadSkill, r as getBlockingServiceKeys } from "./readiness-Cep84RsR.js";
6
- import { n as POSTHOG_SDKS, r as STRIPE_SDKS } from "./bin.js";
7
- import { t as ALL_FEATURE_VALUES } from "./defaults-DoVkE0gW.js";
8
- import { a as getSupportedClients, i as getInstalledClients, o as removeMCPServer } from "./add-mcp-server-to-clients-lfUH2pdU.js";
9
- import "./router-CXjdWNh2.js";
10
- import { _ as SplitView, a as HNViewer, b as Icons, c as EventPlanViewer, d as ConfirmationInput, g as LoadingBox, h as ProgressList, i as LearnCard, l as LogViewer, m as PickerMenu, n as ServiceHealthList, o as TabContainer, p as useStdoutDimensions, r as TipsCard, s as ScreenContainer, t as McpScreen, u as ModalOverlay, x as WizardStore, y as Colors } from "./McpScreen-LqnNwEfV.js";
1
+ import { C as Integration, D as POSTHOG_DOCS_URL, H as getSkillsBaseUrl, N as REMOTE_SKILLS_BASE_URL, R as WIZARD_TOOLS_MENU_FLAG_KEY, f as SIGNUP_WIZARD_READINESS_CONFIG, l as setUI, m as getBlockingServiceKeys, s as logToFile, w as OAUTH_PORTS } from "./debug-Bkaqv1ab.js";
2
+ import { a as relativeToInstallDir, n as WIZARD_LOG_FILE } from "./paths-DJS47p5x.js";
3
+ import { n as analytics } from "./analytics-DmD31Ssc.js";
4
+ import { l as ApiError, p as getUiHostFromHost } from "./setup-utils-Bv8z6HMb.js";
5
+ import { t as ADDITIONAL_FEATURE_LABELS } from "./wizard-session-BcNJTl2I.js";
6
+ import { r as wizardAbort } from "./wizard-abort-DfhWuzaw.js";
7
+ import { _ as coerceAuditChecks, d as fetchSkillMenu, g as AUDIT_SEVERITY_STYLE, h as AUDIT_REPORT_FILE, m as AUDIT_CHECKS_KEY, p as AUDIT_CHECKS_FILE, u as downloadSkill, v as getAuditChecks } from "./agent-interface-D5W9BAB2.js";
8
+ import { t as EVENT_PLAN_FILE } from "./posthog-integration-DX77Msto.js";
9
+ import { a as POSTHOG_SDKS, o as STRIPE_SDKS, r as fetchHealthIssues } from "./bin.js";
10
+ import { t as ALL_FEATURE_VALUES } from "./defaults-GbLPuHxj.js";
11
+ import { a as getSupportedClients, c as removeMCPServer, i as getInstalledClients, o as getSupportedPluginClients, s as installPlugins, u as isPluginCapable } from "./add-mcp-server-to-clients-BKoew3aT.js";
12
+ import "./router-BTfmEDDJ.js";
13
+ import { C as Colors, T as WizardStore, _ as useStdoutDimensions, a as SEVERITY_ORDER, b as LoadingBox, c as LearnCard, d as ScreenContainer, f as EventPlanViewer, h as ConfirmationInput, i as SEVERITY_LABEL, l as HNViewer, m as ModalOverlay, n as McpScreen, o as ServiceHealthList, p as LogViewer, r as IssueTable, s as TipsCard, t as AuditChecksViewer, u as TabContainer, v as PickerMenu, w as Icons, x as SplitView, y as ProgressList } from "./AuditChecksViewer-DsfXIO9e.js";
14
+ import { spawn, spawnSync } from "node:child_process";
11
15
  import { join } from "node:path";
16
+ import * as fs$1 from "fs";
12
17
  import path from "path";
13
18
  import { Box, Text, render, useInput } from "ink";
14
- import { createElement, useEffect, useMemo, useState, useSyncExternalStore } from "react";
15
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
16
- import { readdir, rm } from "node:fs/promises";
19
+ import { Fragment, createElement, useEffect, useMemo, useState, useSyncExternalStore } from "react";
20
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
+ import { Spinner } from "@inkjs/ui";
22
+ import { access, readdir, rm } from "node:fs/promises";
17
23
  //#region src/ui/tui/ink-ui.ts
18
24
  const ANSI_RE = /\x1b\[[0-9;]*m/g;
19
25
  function stripAnsi(s) {
@@ -28,7 +34,8 @@ var InkUI = class {
28
34
  }
29
35
  outro(message) {
30
36
  this.store.pushStatus(stripAnsi(message));
31
- if (!this.store.session.outroData) this.store.setOutroData({
37
+ const existing = this.store.session.outroData;
38
+ this.store.setOutroData(existing ?? {
32
39
  kind: "success",
33
40
  message: stripAnsi(message)
34
41
  });
@@ -38,6 +45,20 @@ var InkUI = class {
38
45
  this.store.setOutroData(data);
39
46
  if (this.store.session.runPhase !== "error") this.store.setRunPhase("error");
40
47
  }
48
+ waitForOutroDismissed() {
49
+ return new Promise((resolve) => {
50
+ if (this.store.session.outroDismissed) {
51
+ resolve();
52
+ return;
53
+ }
54
+ const unsub = this.store.subscribe(() => {
55
+ if (this.store.session.outroDismissed) {
56
+ unsub();
57
+ resolve();
58
+ }
59
+ });
60
+ });
61
+ }
41
62
  setCredentials(credentials) {
42
63
  this.store.setCredentials(credentials);
43
64
  }
@@ -114,6 +135,9 @@ var InkUI = class {
114
135
  setEventPlan(events) {
115
136
  this.store.setEventPlan(events);
116
137
  }
138
+ setFrameworkContext(key, value) {
139
+ this.store.setFrameworkContext(key, value);
140
+ }
117
141
  };
118
142
  //#endregion
119
143
  //#region src/ui/tui/screens/health/HealthCheckScreen.tsx
@@ -174,14 +198,18 @@ const HealthCheckScreen = ({ store }) => {
174
198
  justifyContent: "center",
175
199
  children: /* @__PURE__ */ jsx(LoadingBox, { message: "Checking service status..." })
176
200
  });
177
- const blockingKeys = getBlockingServiceKeys(result.health);
178
- if (blockingKeys.length === 0) return null;
179
- const isGithubReleasesDown = blockingKeys.includes("githubReleases");
201
+ const isSignup = store.session.signup;
202
+ const blockingKeys = getBlockingServiceKeys(result.health, isSignup ? SIGNUP_WIZARD_READINESS_CONFIG : void 0);
203
+ const warningKeys = isSignup ? getBlockingServiceKeys(result.health).filter((k) => !blockingKeys.includes(k)) : [];
204
+ const hasHardBlock = blockingKeys.length > 0;
205
+ const displayKeys = hasHardBlock ? blockingKeys : warningKeys;
206
+ if (displayKeys.length === 0) return null;
207
+ const isGithubReleasesDown = hasHardBlock && blockingKeys.includes("githubReleases");
180
208
  const canDownloadSkills = result.health.githubReleases.status === "healthy";
181
209
  const integration = store.session.integration;
182
- const title = `Ongoing service disruptions`;
210
+ const title = hasHardBlock ? "Ongoing service disruptions" : "Service disruption detected";
183
211
  const docsUrl = store.session.frameworkConfig?.metadata.docsUrl;
184
- const description = isGithubReleasesDown ? "The Wizard can't download necessary skills from GitHub Releases right now." : "The Wizard may not work reliably while services are affected.";
212
+ const description = isGithubReleasesDown ? "The Wizard can't download necessary skills from GitHub Releases right now." : hasHardBlock ? "The Wizard cannot start while these services are down." : "Some services are degraded. You can continue, but parts of the wizard may not work reliably.";
185
213
  const handleDownloadAndExit = async () => {
186
214
  if (downloading) return;
187
215
  setDownloading(true);
@@ -194,7 +222,7 @@ const HealthCheckScreen = ({ store }) => {
194
222
  setDownloaded(true);
195
223
  };
196
224
  return /* @__PURE__ */ jsxs(ModalOverlay, {
197
- borderColor: "red",
225
+ borderColor: hasHardBlock ? "red" : "yellow",
198
226
  title,
199
227
  width: 72,
200
228
  footer: isGithubReleasesDown ? /* @__PURE__ */ jsx(ConfirmationInput, {
@@ -236,7 +264,7 @@ const HealthCheckScreen = ({ store }) => {
236
264
  ] })
237
265
  }), /* @__PURE__ */ jsx(ServiceHealthList, {
238
266
  health: result.health,
239
- filterKeys: blockingKeys,
267
+ filterKeys: displayKeys,
240
268
  showHealthy: false
241
269
  })]
242
270
  }),
@@ -259,6 +287,225 @@ const HealthCheckScreen = ({ store }) => {
259
287
  });
260
288
  };
261
289
  //#endregion
290
+ //#region src/ui/tui/screens/doctor/DoctorIntroScreen.tsx
291
+ const DoctorIntroScreen = ({ store }) => {
292
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
293
+ return /* @__PURE__ */ jsxs(Box, {
294
+ flexDirection: "column",
295
+ children: [
296
+ /* @__PURE__ */ jsxs(Box, {
297
+ flexDirection: "column",
298
+ marginBottom: 1,
299
+ children: [/* @__PURE__ */ jsx(Text, {
300
+ bold: true,
301
+ color: Colors.accent,
302
+ children: "PostHog Doctor"
303
+ }), /* @__PURE__ */ jsx(Text, {
304
+ dimColor: true,
305
+ children: "Scan your project configuration for issues that may need attention."
306
+ })]
307
+ }),
308
+ /* @__PURE__ */ jsxs(Box, {
309
+ flexDirection: "column",
310
+ marginBottom: 1,
311
+ children: [/* @__PURE__ */ jsx(Text, { children: "The wizard will:" }), /* @__PURE__ */ jsxs(Box, {
312
+ paddingLeft: 2,
313
+ flexDirection: "column",
314
+ children: [
315
+ /* @__PURE__ */ jsxs(Text, { children: [Icons.bullet, " Sign you in to PostHog"] }),
316
+ /* @__PURE__ */ jsxs(Text, { children: [Icons.bullet, " Fetch active health issues for your project"] }),
317
+ /* @__PURE__ */ jsxs(Text, { children: [Icons.bullet, " Show you what needs to be resolved, with docs links"] })
318
+ ]
319
+ })]
320
+ }),
321
+ /* @__PURE__ */ jsx(PickerMenu, {
322
+ options: [{
323
+ label: "Continue",
324
+ value: "continue"
325
+ }, {
326
+ label: "Cancel",
327
+ value: "cancel"
328
+ }],
329
+ onSelect: (value) => {
330
+ if (value === "cancel") process.exit(0);
331
+ else store.completeSetup();
332
+ }
333
+ })
334
+ ]
335
+ });
336
+ };
337
+ //#endregion
338
+ //#region src/ui/tui/screens/doctor/DoctorReportScreen.tsx
339
+ const DoctorReportScreen = ({ store }) => {
340
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
341
+ const { credentials } = store.session;
342
+ const accessToken = credentials?.accessToken;
343
+ const host = credentials?.host;
344
+ const projectId = credentials?.projectId;
345
+ const [state, setState] = useState({ kind: "loading" });
346
+ useEffect(() => {
347
+ if (!accessToken || !host || projectId == null) return;
348
+ let cancelled = false;
349
+ (async () => {
350
+ try {
351
+ const issues = await fetchHealthIssues(accessToken, host, projectId);
352
+ if (!cancelled) setState({
353
+ kind: "ready",
354
+ issues
355
+ });
356
+ } catch (err) {
357
+ if (!cancelled) setState({
358
+ kind: "error",
359
+ message: err instanceof ApiError && err.statusCode === 401 ? "Your PostHog session has expired. Re-run the wizard to sign in again." : err instanceof Error ? err.message : String(err)
360
+ });
361
+ }
362
+ })();
363
+ return () => {
364
+ cancelled = true;
365
+ };
366
+ }, [
367
+ accessToken,
368
+ host,
369
+ projectId
370
+ ]);
371
+ if (!credentials) return /* @__PURE__ */ jsx(LoadingBox, { message: "Waiting for authentication..." });
372
+ if (state.kind === "loading") return /* @__PURE__ */ jsxs(Box, {
373
+ flexDirection: "column",
374
+ children: [/* @__PURE__ */ jsx(Header, {
375
+ host: credentials.host,
376
+ projectId: credentials.projectId
377
+ }), /* @__PURE__ */ jsx(LoadingBox, { message: "Fetching health issues..." })]
378
+ });
379
+ const healthUrl = `${getUiHostFromHost(credentials.host)}/project/${credentials.projectId}/health`;
380
+ if (state.kind === "error") return /* @__PURE__ */ jsxs(Box, {
381
+ flexDirection: "column",
382
+ children: [
383
+ /* @__PURE__ */ jsx(Header, {
384
+ host: credentials.host,
385
+ projectId: credentials.projectId
386
+ }),
387
+ /* @__PURE__ */ jsxs(Box, {
388
+ flexDirection: "column",
389
+ marginY: 1,
390
+ children: [/* @__PURE__ */ jsxs(Text, {
391
+ color: Colors.error,
392
+ bold: true,
393
+ children: [Icons.squareFilled, " Failed to fetch health issues"]
394
+ }), /* @__PURE__ */ jsx(Text, {
395
+ dimColor: true,
396
+ children: state.message
397
+ })]
398
+ }),
399
+ /* @__PURE__ */ jsx(PickerMenu, {
400
+ options: [{
401
+ label: "Continue",
402
+ value: "continue"
403
+ }],
404
+ onSelect: () => {
405
+ store.setOutroData({
406
+ kind: "error",
407
+ message: "Failed to fetch health issues",
408
+ body: state.message,
409
+ docsUrl: POSTHOG_DOCS_URL
410
+ });
411
+ }
412
+ })
413
+ ]
414
+ });
415
+ const { issues } = state;
416
+ if (issues.length === 0) return /* @__PURE__ */ jsxs(Box, {
417
+ flexDirection: "column",
418
+ children: [
419
+ /* @__PURE__ */ jsx(Header, {
420
+ host: credentials.host,
421
+ projectId: credentials.projectId
422
+ }),
423
+ /* @__PURE__ */ jsx(Box, {
424
+ marginY: 1,
425
+ children: /* @__PURE__ */ jsxs(Text, {
426
+ color: Colors.success,
427
+ bold: true,
428
+ children: [Icons.check, " No active issues — you're all set!"]
429
+ })
430
+ }),
431
+ /* @__PURE__ */ jsx(PickerMenu, {
432
+ options: [{
433
+ label: "Continue",
434
+ value: "continue"
435
+ }],
436
+ onSelect: () => {
437
+ store.setOutroData({
438
+ kind: "success",
439
+ message: "No active issues — your project looks healthy.",
440
+ docsUrl: POSTHOG_DOCS_URL,
441
+ continueUrl: healthUrl
442
+ });
443
+ }
444
+ })
445
+ ]
446
+ });
447
+ return /* @__PURE__ */ jsxs(Box, {
448
+ flexDirection: "column",
449
+ children: [
450
+ /* @__PURE__ */ jsx(Header, {
451
+ host: credentials.host,
452
+ projectId: credentials.projectId
453
+ }),
454
+ /* @__PURE__ */ jsx(Box, {
455
+ marginTop: 1,
456
+ children: /* @__PURE__ */ jsx(Text, { children: formatSummaryLine(issues) })
457
+ }),
458
+ /* @__PURE__ */ jsx(Box, {
459
+ flexDirection: "column",
460
+ marginBottom: 1,
461
+ children: /* @__PURE__ */ jsx(IssueTable, { issues })
462
+ }),
463
+ /* @__PURE__ */ jsx(PickerMenu, {
464
+ options: [{
465
+ label: "Continue",
466
+ value: "continue"
467
+ }],
468
+ onSelect: () => {
469
+ store.setOutroData({
470
+ kind: "success",
471
+ message: `Found ${issues.length} active issue${issues.length === 1 ? "" : "s"}.`,
472
+ body: "Open the dashboard in PostHog to dismiss or resolve issues.",
473
+ docsUrl: POSTHOG_DOCS_URL,
474
+ continueUrl: healthUrl
475
+ });
476
+ }
477
+ })
478
+ ]
479
+ });
480
+ };
481
+ const Header = ({ host, projectId }) => /* @__PURE__ */ jsxs(Box, {
482
+ flexDirection: "column",
483
+ children: [/* @__PURE__ */ jsx(Text, {
484
+ bold: true,
485
+ color: Colors.accent,
486
+ children: "PostHog Doctor Report"
487
+ }), /* @__PURE__ */ jsxs(Text, {
488
+ dimColor: true,
489
+ children: [
490
+ "Project ",
491
+ projectId,
492
+ " ",
493
+ Icons.bullet,
494
+ " ",
495
+ host
496
+ ]
497
+ })]
498
+ });
499
+ function formatSummaryLine(issues) {
500
+ const parts = [];
501
+ for (const sev of SEVERITY_ORDER) {
502
+ const n = issues.filter((i) => i.severity === sev).length;
503
+ if (n > 0) parts.push(`${n} ${SEVERITY_LABEL[sev].toLowerCase()}`);
504
+ }
505
+ const suffix = parts.length > 0 ? `: ${parts.join(", ")}` : "";
506
+ return `${issues.length} active issue${issues.length === 1 ? "" : "s"}${suffix}`;
507
+ }
508
+ //#endregion
262
509
  //#region src/ui/tui/screens/SettingsOverrideScreen.tsx
263
510
  function sourcePath(source) {
264
511
  switch (source) {
@@ -477,7 +724,7 @@ const IntroScreenLayout = ({ installDir, title = "PostHog Wizard 🦔", showSubt
477
724
  children: /* @__PURE__ */ jsx(WizardTitle, { title })
478
725
  }), errorView]
479
726
  });
480
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, {
727
+ return /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsxs(Box, {
481
728
  flexDirection: "column",
482
729
  flexGrow: 1,
483
730
  alignItems: "center",
@@ -568,6 +815,69 @@ const IntroScreenLayout = ({ installDir, title = "PostHog Wizard 🦔", showSubt
568
815
  }) });
569
816
  };
570
817
  //#endregion
818
+ //#region src/ui/tui/screens/SkillSourceInfo.tsx
819
+ /**
820
+ * Shared "Skill: <id> / URL: <downloadUrl>" block for intro screens.
821
+ *
822
+ * `useSkillEntry` fetches the entry from the skill menu and re-runs when
823
+ * `skillId` or `local` change. The previous fetch is cancelled (its result
824
+ * is ignored) so a session that flips `local=false → true` mid-mount picks
825
+ * up the right base URL.
826
+ *
827
+ * `<SkillSourceInfo>` renders the block, taking the entry as a prop so the
828
+ * caller can reuse the same hook result for additional UI (e.g. showing
829
+ * `skillEntry.name`) without invoking the hook twice.
830
+ */
831
+ function useSkillEntry(skillId, local) {
832
+ const [skillEntry, setSkillEntry] = useState(null);
833
+ const [fetchFailed, setFetchFailed] = useState(false);
834
+ useEffect(() => {
835
+ if (!skillId) {
836
+ setFetchFailed(true);
837
+ return;
838
+ }
839
+ let cancelled = false;
840
+ setSkillEntry(null);
841
+ setFetchFailed(false);
842
+ fetchSkillMenu(getSkillsBaseUrl(local)).then((menu) => {
843
+ if (cancelled) return;
844
+ if (!menu) {
845
+ setFetchFailed(true);
846
+ return;
847
+ }
848
+ const match = Object.values(menu.categories).flat().find((s) => s.id === skillId);
849
+ if (match) setSkillEntry(match);
850
+ else setFetchFailed(true);
851
+ });
852
+ return () => {
853
+ cancelled = true;
854
+ };
855
+ }, [skillId, local]);
856
+ return {
857
+ skillEntry,
858
+ fetchFailed
859
+ };
860
+ }
861
+ const SkillSourceInfo = ({ skillId, skillEntry, fetchFailed }) => /* @__PURE__ */ jsxs(Box, {
862
+ flexDirection: "column",
863
+ children: [/* @__PURE__ */ jsxs(Text, { children: [
864
+ "Skill:",
865
+ " ",
866
+ /* @__PURE__ */ jsx(Text, {
867
+ italic: true,
868
+ color: "cyan",
869
+ children: skillId ?? "unknown"
870
+ })
871
+ ] }), /* @__PURE__ */ jsxs(Text, { children: [
872
+ "URL:",
873
+ " ",
874
+ /* @__PURE__ */ jsx(Text, {
875
+ color: "cyan",
876
+ children: skillEntry?.downloadUrl ?? (fetchFailed ? "unavailable" : "Loading...")
877
+ })
878
+ ] })]
879
+ });
880
+ //#endregion
571
881
  //#region src/ui/tui/screens/PostHogIntegrationIntroScreen.tsx
572
882
  /**
573
883
  * PostHogIntegrationIntroScreen — Intro screen for the core PostHog integration.
@@ -578,6 +888,19 @@ const IntroScreenLayout = ({ installDir, title = "PostHog Wizard 🦔", showSubt
578
888
  * 3. Unsupported version: upgrade prompt
579
889
  * 4. Detection succeeded: continue/change-framework/cancel
580
890
  */
891
+ const TOOLS = [{
892
+ label: "Troubleshoot Integration",
893
+ command: "doctor"
894
+ }];
895
+ function launchTool(command, installDir) {
896
+ releaseTerminal();
897
+ const result = spawnSync(process.execPath, [
898
+ process.argv[1],
899
+ command,
900
+ `--install-dir=${installDir}`
901
+ ], { stdio: "inherit" });
902
+ process.exit(result.status ?? 0);
903
+ }
581
904
  /** Framework picker shown when auto-detection fails. */
582
905
  const FrameworkPicker = ({ store, onComplete }) => {
583
906
  return /* @__PURE__ */ jsx(PickerMenu, {
@@ -590,7 +913,7 @@ const FrameworkPicker = ({ store, onComplete }) => {
590
913
  })),
591
914
  onSelect: (value) => {
592
915
  const integration = Array.isArray(value) ? value[0] : value;
593
- import("./registry-BIV1wRpo.js").then((n) => n.n).then(({ FRAMEWORK_REGISTRY }) => {
916
+ import("./registry-CCtIsqb8.js").then((n) => n.n).then(({ FRAMEWORK_REGISTRY }) => {
594
917
  const config = FRAMEWORK_REGISTRY[integration];
595
918
  store.setFrameworkConfig(integration, config);
596
919
  store.setDetectedFramework(config.metadata.name);
@@ -603,21 +926,33 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
603
926
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
604
927
  const [pickingFramework, setPickingFramework] = useState(false);
605
928
  const [manuallySelected, setManuallySelected] = useState(false);
606
- const [showingMoreInfo, setShowingMoreInfo] = useState(false);
929
+ const [view, setView] = useState("default");
930
+ const [toolsEnabled, setToolsEnabled] = useState(false);
931
+ useEffect(() => {
932
+ let cancelled = false;
933
+ analytics.getAllFlagsForWizard().then((flags) => {
934
+ const value = flags[WIZARD_TOOLS_MENU_FLAG_KEY];
935
+ if (!cancelled && value && value !== "false") setToolsEnabled(true);
936
+ });
937
+ return () => {
938
+ cancelled = true;
939
+ };
940
+ }, []);
607
941
  const { session } = store;
608
942
  const config = session.frameworkConfig;
609
943
  const frameworkLabel = session.detectedFrameworkLabel ?? config?.metadata.name;
944
+ const { skillEntry, fetchFailed } = useSkillEntry(session.skillId, session.localMcp);
610
945
  const detecting = !session.detectionComplete;
611
946
  const needsFrameworkPick = session.detectionComplete && !session.frameworkConfig;
612
947
  const unsupported = session.unsupportedVersion;
613
- const showContinue = session.frameworkConfig !== null && !detecting && !pickingFramework && !showingMoreInfo && !unsupported;
948
+ const showContinue = session.frameworkConfig !== null && !detecting && !pickingFramework && view === "default" && !unsupported;
614
949
  const title = detecting ? "PostHog Wizard starting up" : "PostHog Wizard 🦔";
615
950
  let body = null;
616
951
  if (detecting) body = /* @__PURE__ */ jsx(Box, {
617
952
  marginY: 1,
618
953
  children: /* @__PURE__ */ jsx(LoadingBox, { message: "Detecting project framework..." })
619
954
  });
620
- else if (needsFrameworkPick && !pickingFramework) body = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Box, {
955
+ else if (needsFrameworkPick && !pickingFramework) body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
621
956
  marginY: 1,
622
957
  children: /* @__PURE__ */ jsx(Text, {
623
958
  dimColor: true,
@@ -631,9 +966,10 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
631
966
  store,
632
967
  onComplete: () => setPickingFramework(false)
633
968
  });
634
- else if (showingMoreInfo) body = /* @__PURE__ */ jsxs(Box, {
969
+ else if (view === "more-info") body = /* @__PURE__ */ jsxs(Box, {
635
970
  flexDirection: "column",
636
971
  width: 56,
972
+ flexShrink: 0,
637
973
  children: [
638
974
  /* @__PURE__ */ jsxs(Text, { children: ["The wizard is an agent that executes PostHog tasks. Its code is open source: ", /* @__PURE__ */ jsx(Text, {
639
975
  color: "cyan",
@@ -665,21 +1001,21 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
665
1001
  /* @__PURE__ */ jsxs(Text, { children: [`\u2022`, " Error Tracking"] })
666
1002
  ]
667
1003
  }),
668
- /* @__PURE__ */ jsx(Box, {
1004
+ /* @__PURE__ */ jsxs(Box, {
669
1005
  flexDirection: "column",
670
1006
  marginTop: 1,
671
- children: /* @__PURE__ */ jsxs(Text, { children: [
672
- "If you prefer your own AI setup, download the skill:",
673
- " ",
674
- /* @__PURE__ */ jsxs(Text, {
675
- color: "cyan",
676
- children: [CONTEXT_MILL_URL, "/releases"]
1007
+ children: [/* @__PURE__ */ jsx(Text, { children: "If you prefer your own AI setup, download the skill:" }), /* @__PURE__ */ jsx(Box, {
1008
+ marginTop: 1,
1009
+ children: /* @__PURE__ */ jsx(SkillSourceInfo, {
1010
+ skillId: session.skillId,
1011
+ skillEntry,
1012
+ fetchFailed
677
1013
  })
678
- ] })
1014
+ })]
679
1015
  })
680
1016
  ]
681
1017
  });
682
- else if (showContinue) body = /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "Let's do two hours of work in eight minutes." }) }) });
1018
+ else if (showContinue) body = /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, { children: "Let's do two hours of work in eight minutes." }) }) });
683
1019
  const detectionRows = [];
684
1020
  if (frameworkLabel) {
685
1021
  const suffixParts = [];
@@ -739,7 +1075,14 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
739
1075
  ]
740
1076
  });
741
1077
  let menuOptions = null;
742
- if (showingMoreInfo) menuOptions = [{
1078
+ if (view === "tools") menuOptions = [...TOOLS.map((t) => ({
1079
+ label: t.label,
1080
+ value: t.command
1081
+ })), {
1082
+ label: "Back",
1083
+ value: "back"
1084
+ }];
1085
+ else if (view === "more-info") menuOptions = [{
743
1086
  label: "Back",
744
1087
  value: "back"
745
1088
  }];
@@ -752,6 +1095,10 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
752
1095
  label: "Change framework",
753
1096
  value: "framework"
754
1097
  },
1098
+ ...toolsEnabled ? [{
1099
+ label: "Tools",
1100
+ value: "tools"
1101
+ }] : [],
755
1102
  {
756
1103
  label: "More info",
757
1104
  value: "more-info"
@@ -762,18 +1109,24 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
762
1109
  }
763
1110
  ];
764
1111
  const handleSelect = (value) => {
1112
+ if (view === "tools") {
1113
+ if (value === "back") setView("default");
1114
+ else launchTool(value, session.installDir);
1115
+ return;
1116
+ }
765
1117
  if (value === "cancel") process.exit(0);
766
1118
  else if (value === "framework") {
767
1119
  setPickingFramework(true);
768
1120
  setManuallySelected(true);
769
- } else if (value === "more-info") setShowingMoreInfo(true);
770
- else if (value === "back") setShowingMoreInfo(false);
1121
+ } else if (value === "more-info") setView("more-info");
1122
+ else if (value === "tools") setView("tools");
1123
+ else if (value === "back") setView("default");
771
1124
  else store.completeSetup();
772
1125
  };
773
1126
  return /* @__PURE__ */ jsx(IntroScreenLayout, {
774
1127
  installDir: session.installDir,
775
1128
  title,
776
- showSubtitle: !showingMoreInfo,
1129
+ showSubtitle: view === "default",
777
1130
  body,
778
1131
  showDetection: showContinue,
779
1132
  detectionRows,
@@ -816,6 +1169,7 @@ const RevenueIntroScreen = ({ store }) => {
816
1169
  const body = showingMoreInfo ? /* @__PURE__ */ jsxs(Box, {
817
1170
  flexDirection: "column",
818
1171
  width: 56,
1172
+ flexShrink: 0,
819
1173
  children: [
820
1174
  /* @__PURE__ */ jsxs(Text, { children: [
821
1175
  "The wizard is an agent that executes PostHog tasks. Its code is open source: ",
@@ -851,7 +1205,7 @@ const RevenueIntroScreen = ({ store }) => {
851
1205
  ]
852
1206
  })
853
1207
  ]
854
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Box, {
1208
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
855
1209
  flexDirection: "column",
856
1210
  alignItems: "center",
857
1211
  children: [/* @__PURE__ */ jsx(Text, { children: "Let's create revenue analytics with Stripe and PostHog." }), /* @__PURE__ */ jsx(Box, {
@@ -879,7 +1233,7 @@ const RevenueIntroScreen = ({ store }) => {
879
1233
  ]
880
1234
  }, p))]
881
1235
  })] });
882
- const errorView = detectError ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Box, {
1236
+ const errorView = detectError ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
883
1237
  flexDirection: "column",
884
1238
  marginBottom: 1,
885
1239
  children: [/* @__PURE__ */ jsxs(Text, {
@@ -941,7 +1295,7 @@ const DetectErrorBody = ({ error }) => {
941
1295
  "not-dir": "is not a directory",
942
1296
  unreadable: "could not be accessed"
943
1297
  }[error.reason];
944
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, { children: [
1298
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, { children: [
945
1299
  "This path ",
946
1300
  reasonText,
947
1301
  ":"
@@ -950,7 +1304,7 @@ const DetectErrorBody = ({ error }) => {
950
1304
  children: [" ", error.path]
951
1305
  })] });
952
1306
  }
953
- case "no-package-json": return /* @__PURE__ */ jsxs(Fragment, { children: [
1307
+ case "no-package-json": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
954
1308
  /* @__PURE__ */ jsx(Text, { children: "No package.json found in this directory." }),
955
1309
  /* @__PURE__ */ jsx(Text, {
956
1310
  dimColor: true,
@@ -961,7 +1315,7 @@ const DetectErrorBody = ({ error }) => {
961
1315
  children: "Run this command from your project root."
962
1316
  })
963
1317
  ] });
964
- case "no-sdks": return /* @__PURE__ */ jsxs(Fragment, { children: [
1318
+ case "no-sdks": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
965
1319
  /* @__PURE__ */ jsxs(Text, { children: [
966
1320
  "Neither PostHog nor Stripe SDKs detected (scanned",
967
1321
  " ",
@@ -1010,7 +1364,7 @@ const DetectErrorBody = ({ error }) => {
1010
1364
  })
1011
1365
  })
1012
1366
  ] });
1013
- case "missing-posthog": return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, { children: [
1367
+ case "missing-posthog": return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, { children: [
1014
1368
  "Found Stripe (",
1015
1369
  error.foundStripe.join(", "),
1016
1370
  ") but no PostHog SDK."
@@ -1028,7 +1382,7 @@ const DetectErrorBody = ({ error }) => {
1028
1382
  ]
1029
1383
  })
1030
1384
  })] });
1031
- case "missing-stripe": return /* @__PURE__ */ jsxs(Fragment, { children: [
1385
+ case "missing-stripe": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1032
1386
  /* @__PURE__ */ jsxs(Text, { children: [
1033
1387
  "Found PostHog (",
1034
1388
  error.foundPosthog.join(", "),
@@ -1059,41 +1413,22 @@ const DetectErrorBody = ({ error }) => {
1059
1413
  //#endregion
1060
1414
  //#region src/ui/tui/screens/AgentSkillIntroScreen.tsx
1061
1415
  /**
1062
- * AgentSkillIntroScreen — Intro screen for the generic agent-skill workflow.
1416
+ * AgentSkillIntroScreen — Default intro for generic agent-skill workflows.
1063
1417
  *
1064
- * Main menu: one-liner body, detection rows, continue/cancel.
1065
- * More info: skill name, download URL fetched from the skill menu.
1418
+ * Workflows that need a different intro ship their own screen component
1419
+ * (see audit/AuditIntroScreen.tsx).
1066
1420
  */
1067
1421
  const AgentSkillIntroScreen = ({ store }) => {
1068
1422
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
1069
1423
  const [showingMoreInfo, setShowingMoreInfo] = useState(false);
1070
- const [skillEntry, setSkillEntry] = useState(null);
1071
- const [fetchFailed, setFetchFailed] = useState(false);
1072
1424
  const { session } = store;
1073
1425
  const skillId = session.skillId ?? "unknown";
1074
- const isMainMenu = !showingMoreInfo;
1075
- useEffect(() => {
1076
- if (!showingMoreInfo || skillEntry || fetchFailed) return;
1077
- fetchSkillMenu(getSkillsBaseUrl(session.localMcp)).then((menu) => {
1078
- if (!menu) {
1079
- setFetchFailed(true);
1080
- return;
1081
- }
1082
- const match = Object.values(menu.categories).flat().find((s) => s.id === skillId);
1083
- if (match) setSkillEntry(match);
1084
- else setFetchFailed(true);
1085
- });
1086
- }, [
1087
- showingMoreInfo,
1088
- skillEntry,
1089
- fetchFailed,
1090
- skillId,
1091
- session.localMcp
1092
- ]);
1426
+ const { skillEntry, fetchFailed } = useSkillEntry(skillId, session.localMcp);
1093
1427
  let body;
1094
1428
  if (showingMoreInfo) body = /* @__PURE__ */ jsxs(Box, {
1095
1429
  flexDirection: "column",
1096
1430
  width: 56,
1431
+ flexShrink: 0,
1097
1432
  children: [
1098
1433
  /* @__PURE__ */ jsx(Box, {
1099
1434
  flexDirection: "column",
@@ -1103,23 +1438,11 @@ const AgentSkillIntroScreen = ({ store }) => {
1103
1438
  children: "https://github.com/PostHog/wizard"
1104
1439
  })] })
1105
1440
  }),
1106
- /* @__PURE__ */ jsxs(Text, { children: [
1107
- "Skill:",
1108
- " ",
1109
- /* @__PURE__ */ jsx(Text, {
1110
- italic: true,
1111
- color: "cyan",
1112
- children: skillEntry?.id ?? skillId
1113
- })
1114
- ] }),
1115
- /* @__PURE__ */ jsxs(Text, { children: [
1116
- "URL:",
1117
- " ",
1118
- /* @__PURE__ */ jsx(Text, {
1119
- color: "cyan",
1120
- children: skillEntry?.downloadUrl ?? (fetchFailed ? "unavailable" : "Loading...")
1121
- })
1122
- ] }),
1441
+ /* @__PURE__ */ jsx(SkillSourceInfo, {
1442
+ skillId,
1443
+ skillEntry,
1444
+ fetchFailed
1445
+ }),
1123
1446
  /* @__PURE__ */ jsx(Box, {
1124
1447
  marginTop: 1,
1125
1448
  children: /* @__PURE__ */ jsx(Text, {
@@ -1167,7 +1490,7 @@ const AgentSkillIntroScreen = ({ store }) => {
1167
1490
  installDir: session.installDir,
1168
1491
  showSubtitle: !showingMoreInfo,
1169
1492
  body,
1170
- showDetection: isMainMenu,
1493
+ showDetection: !showingMoreInfo,
1171
1494
  workflowLabel: session.workflowLabel,
1172
1495
  skillId: session.skillId,
1173
1496
  menuOptions,
@@ -1175,39 +1498,813 @@ const AgentSkillIntroScreen = ({ store }) => {
1175
1498
  });
1176
1499
  };
1177
1500
  //#endregion
1178
- //#region src/ui/tui/screens/SetupScreen.tsx
1179
- /**
1180
- * SetupScreen Generic framework disambiguation.
1181
- *
1182
- * Iterates unresolved setup questions from the FrameworkConfig
1183
- * and renders a PickerMenu for each. If all questions are auto-resolved,
1184
- * this screen is skipped entirely (the router skips it via its show() predicate).
1185
- */
1186
- const SetupScreen = ({ store }) => {
1501
+ //#region src/ui/tui/screens/audit/AuditIntroScreen.tsx
1502
+ const AUDIT_SKILL_ID = "audit";
1503
+ const AuditIntroScreen = ({ store }) => {
1187
1504
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
1188
- const config = store.session.frameworkConfig;
1189
- const questions = config?.metadata.setup?.questions ?? [];
1190
- const [currentIndex, setCurrentIndex] = useState(0);
1191
- const [resolving, setResolving] = useState(true);
1192
- useEffect(() => {
1193
- (async () => {
1194
- for (const q of questions) {
1195
- if (q.key in store.session.frameworkContext) continue;
1196
- try {
1197
- const detected = await q.detect({ installDir: store.session.installDir });
1198
- if (detected !== null) store.setFrameworkContext(q.key, detected);
1199
- } catch {}
1200
- }
1201
- setResolving(false);
1202
- })();
1203
- }, []);
1204
- if (resolving) return /* @__PURE__ */ jsx(Box, {
1505
+ const [showingMoreInfo, setShowingMoreInfo] = useState(false);
1506
+ const { session } = store;
1507
+ const { skillEntry, fetchFailed } = useSkillEntry(AUDIT_SKILL_ID, session.localMcp);
1508
+ const body = showingMoreInfo ? /* @__PURE__ */ jsxs(Box, {
1205
1509
  flexDirection: "column",
1206
- flexGrow: 1,
1207
- children: /* @__PURE__ */ jsx(Text, {
1208
- dimColor: true,
1209
- children: "Detecting project configuration..."
1210
- })
1510
+ width: 56,
1511
+ children: [
1512
+ /* @__PURE__ */ jsx(Box, {
1513
+ marginBottom: 1,
1514
+ children: /* @__PURE__ */ jsxs(Text, { children: ["The wizard is an agent that executes PostHog tasks. Its code is open source: ", /* @__PURE__ */ jsx(Text, {
1515
+ color: "cyan",
1516
+ children: "https://github.com/PostHog/wizard"
1517
+ })] })
1518
+ }),
1519
+ /* @__PURE__ */ jsxs(Text, { children: [
1520
+ "The",
1521
+ " ",
1522
+ /* @__PURE__ */ jsx(Text, {
1523
+ color: "cyan",
1524
+ italic: true,
1525
+ children: AUDIT_SKILL_ID
1526
+ }),
1527
+ " ",
1528
+ "workflow reviews your project's PostHog integration against best practices to help you capture high-quality events and writes a report for suggested actions. Nothing in your project will be modified."
1529
+ ] }),
1530
+ /* @__PURE__ */ jsx(Box, {
1531
+ marginTop: 1,
1532
+ children: /* @__PURE__ */ jsx(SkillSourceInfo, {
1533
+ skillId: AUDIT_SKILL_ID,
1534
+ skillEntry,
1535
+ fetchFailed
1536
+ })
1537
+ })
1538
+ ]
1539
+ }) : /* @__PURE__ */ jsx(Box, {
1540
+ flexDirection: "column",
1541
+ alignItems: "center",
1542
+ children: /* @__PURE__ */ jsx(Text, { children: "Let's review your existing PostHog setup for best practices." })
1543
+ });
1544
+ const menuOptions = showingMoreInfo ? [{
1545
+ label: "Back",
1546
+ value: "back"
1547
+ }] : [
1548
+ {
1549
+ label: "Continue",
1550
+ value: "continue"
1551
+ },
1552
+ {
1553
+ label: "More info",
1554
+ value: "more-info"
1555
+ },
1556
+ {
1557
+ label: "Cancel",
1558
+ value: "cancel"
1559
+ }
1560
+ ];
1561
+ const handleSelect = (value) => {
1562
+ if (value === "cancel") process.exit(0);
1563
+ else if (value === "more-info") setShowingMoreInfo(true);
1564
+ else if (value === "back") setShowingMoreInfo(false);
1565
+ else store.completeSetup();
1566
+ };
1567
+ return /* @__PURE__ */ jsx(IntroScreenLayout, {
1568
+ installDir: session.installDir,
1569
+ body,
1570
+ showDetection: !showingMoreInfo,
1571
+ workflowLabel: session.workflowLabel,
1572
+ skillId: session.skillId,
1573
+ menuOptions,
1574
+ onSelect: handleSelect
1575
+ });
1576
+ };
1577
+ //#endregion
1578
+ //#region src/ui/tui/hooks/file-watcher.ts
1579
+ /**
1580
+ * File watcher (UI concern).
1581
+ *
1582
+ * `fs.watch` alone is unreliable for atomic-rename writes (which is how Claude
1583
+ * rewrites JSON files), so the watcher pairs `fs.watch` with a continuous
1584
+ * mtime-polled re-read. The poll catches missed events; the watch keeps
1585
+ * latency low when it does fire. We dedupe with `mtimeMs` so steady-state
1586
+ * polls cost a single `stat`.
1587
+ *
1588
+ * Screens that need to mirror an agent-emitted JSON file into the store call
1589
+ * `useFileWatcher(absolutePath, onUpdate)`; the watcher starts on mount and
1590
+ * tears down on unmount.
1591
+ */
1592
+ const DEFAULT_POLL_INTERVAL_MS = 5e3;
1593
+ const DEFAULT_ATTACH_RETRY_INTERVAL_MS = 1e3;
1594
+ /** Watch `path` for JSON updates and call `onUpdate(parsed)` whenever the
1595
+ * file's mtime changes and the contents are valid JSON. Caller must invoke
1596
+ * `handle.stop()` to release the watcher. */
1597
+ function startFileWatcher(path, onUpdate, options = {}) {
1598
+ const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
1599
+ const attachRetryIntervalMs = options.attachRetryIntervalMs ?? DEFAULT_ATTACH_RETRY_INTERVAL_MS;
1600
+ const watchers = [];
1601
+ const intervals = [];
1602
+ let lastMtimeMs = 0;
1603
+ const read = (force = false) => {
1604
+ try {
1605
+ const stat = fs$1.statSync(path);
1606
+ if (!force && stat.mtimeMs === lastMtimeMs) return;
1607
+ lastMtimeMs = stat.mtimeMs;
1608
+ onUpdate(JSON.parse(fs$1.readFileSync(path, "utf-8")));
1609
+ } catch {}
1610
+ };
1611
+ intervals.push(setInterval(() => read(), pollIntervalMs));
1612
+ try {
1613
+ watchers.push(fs$1.watch(path, () => read(true)));
1614
+ read(true);
1615
+ } catch {
1616
+ const attachInterval = setInterval(() => {
1617
+ try {
1618
+ fs$1.accessSync(path);
1619
+ clearInterval(attachInterval);
1620
+ const idx = intervals.indexOf(attachInterval);
1621
+ if (idx >= 0) intervals.splice(idx, 1);
1622
+ watchers.push(fs$1.watch(path, () => read(true)));
1623
+ } catch {}
1624
+ }, attachRetryIntervalMs);
1625
+ intervals.push(attachInterval);
1626
+ }
1627
+ return { stop() {
1628
+ for (const w of watchers) w.close();
1629
+ for (const i of intervals) clearInterval(i);
1630
+ } };
1631
+ }
1632
+ /** React hook wrapping `startFileWatcher`. Starts on mount, stops on unmount
1633
+ * or when `path` changes. `onUpdate` and `options` are captured at mount
1634
+ * time — change `path` to restart with a new callback. */
1635
+ function useFileWatcher(path, onUpdate, options = {}) {
1636
+ useEffect(() => {
1637
+ const handle = startFileWatcher(path, onUpdate, options);
1638
+ return () => handle.stop();
1639
+ }, [path]);
1640
+ }
1641
+ //#endregion
1642
+ //#region src/ui/tui/screens/audit/slides/shared.tsx
1643
+ /** Narrow bordered box for the small ASCII illustrations in baseline slides. */
1644
+ const VisualBox = ({ children }) => /* @__PURE__ */ jsx(Box, {
1645
+ borderStyle: "single",
1646
+ borderColor: Colors.muted,
1647
+ paddingX: 1,
1648
+ flexDirection: "column",
1649
+ marginBottom: 1,
1650
+ children
1651
+ });
1652
+ //#endregion
1653
+ //#region src/ui/tui/screens/audit/slides/installation.tsx
1654
+ const InstallationVisual = () => /* @__PURE__ */ jsxs(VisualBox, { children: [
1655
+ /* @__PURE__ */ jsx(Text, {
1656
+ dimColor: true,
1657
+ children: "app boot"
1658
+ }),
1659
+ /* @__PURE__ */ jsxs(Text, { children: [
1660
+ /* @__PURE__ */ jsx(Text, {
1661
+ dimColor: true,
1662
+ children: " ▼ "
1663
+ }),
1664
+ /* @__PURE__ */ jsx(Text, {
1665
+ color: "green",
1666
+ children: "posthog.init(...)"
1667
+ }),
1668
+ /* @__PURE__ */ jsx(Text, {
1669
+ dimColor: true,
1670
+ children: " once"
1671
+ })
1672
+ ] }),
1673
+ /* @__PURE__ */ jsx(Text, {
1674
+ dimColor: true,
1675
+ children: " │"
1676
+ }),
1677
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
1678
+ dimColor: true,
1679
+ children: " ▼ "
1680
+ }), /* @__PURE__ */ jsx(Text, {
1681
+ color: "cyan",
1682
+ children: "posthog.capture('pageview')"
1683
+ })] }),
1684
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
1685
+ dimColor: true,
1686
+ children: " "
1687
+ }), /* @__PURE__ */ jsx(Text, {
1688
+ color: "cyan",
1689
+ children: "posthog.capture('signup')"
1690
+ })] }),
1691
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
1692
+ dimColor: true,
1693
+ children: " "
1694
+ }), /* @__PURE__ */ jsx(Text, {
1695
+ color: "cyan",
1696
+ children: "posthog.capture('purchase')"
1697
+ })] })
1698
+ ] });
1699
+ const InstallationSlide = {
1700
+ area: "Installation",
1701
+ intro: [
1702
+ "PostHog releases frequent SDK updates to fix bugs and add new features. We're checking your project's SDK version and making sure it's up to date.",
1703
+ "We're also checking that your SDK is initialized correctly and in the right part of your app's lifecycle.",
1704
+ "This ensures you won't miss any autocaptured events."
1705
+ ],
1706
+ visual: /* @__PURE__ */ jsx(InstallationVisual, {}),
1707
+ docsUrl: "https://posthog.com/docs/getting-started/install"
1708
+ };
1709
+ //#endregion
1710
+ //#region src/ui/tui/screens/audit/slides/identification.tsx
1711
+ const IdentificationVisual = () => /* @__PURE__ */ jsxs(VisualBox, { children: [
1712
+ /* @__PURE__ */ jsxs(Text, { children: [
1713
+ /* @__PURE__ */ jsx(Text, {
1714
+ bold: true,
1715
+ children: "browser "
1716
+ }),
1717
+ /* @__PURE__ */ jsx(Text, {
1718
+ dimColor: true,
1719
+ children: "capture"
1720
+ }),
1721
+ /* @__PURE__ */ jsx(Text, { children: " (" }),
1722
+ /* @__PURE__ */ jsx(Text, {
1723
+ color: "cyan",
1724
+ children: "u_42"
1725
+ }),
1726
+ /* @__PURE__ */ jsx(Text, { children: ", \"click\")" })
1727
+ ] }),
1728
+ /* @__PURE__ */ jsx(Text, {
1729
+ dimColor: true,
1730
+ children: " │"
1731
+ }),
1732
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
1733
+ dimColor: true,
1734
+ children: " ▼ "
1735
+ }), /* @__PURE__ */ jsx(Text, {
1736
+ color: "green",
1737
+ children: "same distinct_id"
1738
+ })] }),
1739
+ /* @__PURE__ */ jsx(Text, {
1740
+ dimColor: true,
1741
+ children: " │"
1742
+ }),
1743
+ /* @__PURE__ */ jsxs(Text, { children: [
1744
+ /* @__PURE__ */ jsx(Text, {
1745
+ bold: true,
1746
+ children: "server "
1747
+ }),
1748
+ /* @__PURE__ */ jsx(Text, {
1749
+ dimColor: true,
1750
+ children: "capture"
1751
+ }),
1752
+ /* @__PURE__ */ jsx(Text, { children: " (" }),
1753
+ /* @__PURE__ */ jsx(Text, {
1754
+ color: "cyan",
1755
+ children: "u_42"
1756
+ }),
1757
+ /* @__PURE__ */ jsx(Text, { children: ", \"charged\")" })
1758
+ ] })
1759
+ ] });
1760
+ const IdentificationSlide = {
1761
+ area: "Identification",
1762
+ intro: [
1763
+ "For events to be useful, they need to be reliably attributed to a user.",
1764
+ "We're checking your project's `identify()` calls to make sure they're correctly and consistently implemented.",
1765
+ "We're also checking that your `distinct_id`s are correctly passed between your client and server runtimes if applicable."
1766
+ ],
1767
+ visual: /* @__PURE__ */ jsx(IdentificationVisual, {}),
1768
+ docsUrl: "https://posthog.com/docs/product-analytics/identify"
1769
+ };
1770
+ //#endregion
1771
+ //#region src/ui/tui/screens/audit/slides/eventCapture.tsx
1772
+ const CaptureVisual = () => /* @__PURE__ */ jsxs(VisualBox, { children: [
1773
+ /* @__PURE__ */ jsxs(Text, { children: [
1774
+ /* @__PURE__ */ jsx(Text, {
1775
+ color: "cyan",
1776
+ children: "pageview "
1777
+ }),
1778
+ /* @__PURE__ */ jsx(Text, {
1779
+ color: "green",
1780
+ children: "████████████"
1781
+ }),
1782
+ /* @__PURE__ */ jsx(Text, {
1783
+ dimColor: true,
1784
+ children: " 1000"
1785
+ })
1786
+ ] }),
1787
+ /* @__PURE__ */ jsxs(Text, { children: [
1788
+ /* @__PURE__ */ jsx(Text, {
1789
+ color: "cyan",
1790
+ children: "signup "
1791
+ }),
1792
+ /* @__PURE__ */ jsx(Text, {
1793
+ color: "green",
1794
+ children: "████████"
1795
+ }),
1796
+ /* @__PURE__ */ jsx(Text, {
1797
+ dimColor: true,
1798
+ children: " 640"
1799
+ })
1800
+ ] }),
1801
+ /* @__PURE__ */ jsxs(Text, { children: [
1802
+ /* @__PURE__ */ jsx(Text, {
1803
+ color: "cyan",
1804
+ children: "activated "
1805
+ }),
1806
+ /* @__PURE__ */ jsx(Text, {
1807
+ color: "green",
1808
+ children: "█████"
1809
+ }),
1810
+ /* @__PURE__ */ jsx(Text, {
1811
+ dimColor: true,
1812
+ children: " 410"
1813
+ })
1814
+ ] }),
1815
+ /* @__PURE__ */ jsxs(Text, { children: [
1816
+ /* @__PURE__ */ jsx(Text, {
1817
+ color: "cyan",
1818
+ children: "purchased "
1819
+ }),
1820
+ /* @__PURE__ */ jsx(Text, {
1821
+ color: "green",
1822
+ children: "██"
1823
+ }),
1824
+ /* @__PURE__ */ jsx(Text, {
1825
+ dimColor: true,
1826
+ children: " 120"
1827
+ })
1828
+ ] })
1829
+ ] });
1830
+ //#endregion
1831
+ //#region src/ui/tui/screens/audit/slides/index.ts
1832
+ const AUDIT_AREA_SLIDES = [
1833
+ InstallationSlide,
1834
+ IdentificationSlide,
1835
+ {
1836
+ area: "Event Capture",
1837
+ intro: [
1838
+ "Everything you do in PostHog starts with event captures. Every dashboard, insight, funnel, cohort, and replay is built on top of events.",
1839
+ "We're checking that your project's event capture calls cover key user actions and use sensible event names, so you can build high-quality insights and reports.",
1840
+ "We're also checking that you use a reverse proxy so your events are not blocked by ad blockers or tracking blockers."
1841
+ ],
1842
+ visual: /* @__PURE__ */ jsx(CaptureVisual, {}),
1843
+ docsUrl: "https://posthog.com/docs/product-analytics/capture-events"
1844
+ }
1845
+ ];
1846
+ //#endregion
1847
+ //#region src/ui/tui/screens/audit/AuditAreaPane.tsx
1848
+ /**
1849
+ * AuditAreaPane — left-pane slide that follows whatever area the agent is
1850
+ * currently checking, plus a wrap-up state once every check is resolved
1851
+ * and the agent has moved on to writing the report.
1852
+ *
1853
+ * Three states, gated top-down on the ledger:
1854
+ * 1. firstPending defined → render the slide for that area
1855
+ * 2. checks empty → blank (the seed hook fires before
1856
+ * this screen mounts in practice;
1857
+ * this is just defensive)
1858
+ * 3. all checks non-pending → "writing report" wrap-up
1859
+ *
1860
+ * Pressing `O` opens the active slide's docs URL.
1861
+ */
1862
+ const FINDING_STATUSES = [
1863
+ "error",
1864
+ "warning",
1865
+ "suggestion"
1866
+ ];
1867
+ const isFinding = (c) => FINDING_STATUSES.includes(c.status);
1868
+ const fallbackSlide = (area) => ({
1869
+ area,
1870
+ intro: [`Verifying ${area.toLowerCase()}…`],
1871
+ docsUrl: ""
1872
+ });
1873
+ const openLink = (url) => {
1874
+ spawn(process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open", process.platform === "win32" ? [
1875
+ "/c",
1876
+ "start",
1877
+ "",
1878
+ url
1879
+ ] : [url], {
1880
+ detached: true,
1881
+ stdio: "ignore"
1882
+ }).unref();
1883
+ };
1884
+ const AuditAreaPane = ({ checks, reportPath }) => {
1885
+ const activeArea = checks.filter((c) => c.status === "pending")[0]?.area;
1886
+ const slide = activeArea ? AUDIT_AREA_SLIDES.find((s) => s.area === activeArea) ?? fallbackSlide(activeArea) : null;
1887
+ useInput((input) => {
1888
+ if (input.toLowerCase() === "o" && slide?.docsUrl) openLink(slide.docsUrl);
1889
+ });
1890
+ if (slide) return /* @__PURE__ */ jsx(ActiveSlide, {
1891
+ slide,
1892
+ hasFindings: checks.some(isFinding)
1893
+ });
1894
+ if (checks.length === 0) return null;
1895
+ return /* @__PURE__ */ jsx(WritingReport, { reportPath });
1896
+ };
1897
+ const ActiveSlide = ({ slide, hasFindings }) => /* @__PURE__ */ jsxs(Box, {
1898
+ flexDirection: "column",
1899
+ paddingX: 1,
1900
+ children: [
1901
+ /* @__PURE__ */ jsxs(Text, {
1902
+ bold: true,
1903
+ color: Colors.accent,
1904
+ children: ["Verifying ", slide.area.toLowerCase()]
1905
+ }),
1906
+ /* @__PURE__ */ jsx(Box, { height: 1 }),
1907
+ slide.visual,
1908
+ slide.intro.map((paragraph, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx(Box, { height: 1 }), /* @__PURE__ */ jsx(Text, { children: paragraph })] }, i)),
1909
+ /* @__PURE__ */ jsx(Box, {
1910
+ marginTop: 1,
1911
+ children: /* @__PURE__ */ jsxs(Text, {
1912
+ dimColor: true,
1913
+ children: [slide.docsUrl && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1914
+ "[",
1915
+ /* @__PURE__ */ jsx(Text, {
1916
+ color: Colors.accent,
1917
+ children: "O"
1918
+ }),
1919
+ "] Learn more"
1920
+ ] }), hasFindings && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1921
+ slide.docsUrl && " ",
1922
+ "[",
1923
+ /* @__PURE__ */ jsx(Text, {
1924
+ color: Colors.accent,
1925
+ children: "→"
1926
+ }),
1927
+ "] View issues"
1928
+ ] })]
1929
+ })
1930
+ })
1931
+ ]
1932
+ });
1933
+ const WritingReport = ({ reportPath }) => /* @__PURE__ */ jsxs(Box, {
1934
+ flexDirection: "column",
1935
+ paddingX: 1,
1936
+ children: [
1937
+ /* @__PURE__ */ jsx(Text, {
1938
+ bold: true,
1939
+ color: Colors.accent,
1940
+ children: "We've wrapped up the review."
1941
+ }),
1942
+ /* @__PURE__ */ jsx(Box, { height: 1 }),
1943
+ /* @__PURE__ */ jsxs(Text, { children: [
1944
+ "To help you get the most out of your PostHog integration, we're preparing a report for you at ",
1945
+ /* @__PURE__ */ jsx(Text, {
1946
+ color: "cyan",
1947
+ children: reportPath
1948
+ }),
1949
+ "."
1950
+ ] }),
1951
+ /* @__PURE__ */ jsx(Box, { height: 1 }),
1952
+ /* @__PURE__ */ jsx(Text, { children: "We'll cover what we checked and suggest where we can improve the existing integration." }),
1953
+ /* @__PURE__ */ jsx(Box, { height: 1 }),
1954
+ /* @__PURE__ */ jsx(Text, {
1955
+ dimColor: true,
1956
+ children: "Hang tight!"
1957
+ })
1958
+ ]
1959
+ });
1960
+ //#endregion
1961
+ //#region src/ui/tui/screens/audit/PendingChecksList.tsx
1962
+ function groupByArea(checks) {
1963
+ const order = [];
1964
+ const map = /* @__PURE__ */ new Map();
1965
+ for (const c of checks) {
1966
+ if (!map.has(c.area)) {
1967
+ map.set(c.area, []);
1968
+ order.push(c.area);
1969
+ }
1970
+ map.get(c.area).push(c);
1971
+ }
1972
+ return order.map((area) => ({
1973
+ area,
1974
+ checks: map.get(area)
1975
+ }));
1976
+ }
1977
+ function groupIcon(group) {
1978
+ const total = group.checks.length;
1979
+ const complete = group.checks.filter((c) => c.status !== "pending").length;
1980
+ if (complete === 0) return {
1981
+ icon: Icons.squareOpen,
1982
+ color: Colors.muted
1983
+ };
1984
+ if (complete === total) return {
1985
+ icon: Icons.squareFilled,
1986
+ color: Colors.success
1987
+ };
1988
+ return {
1989
+ icon: Icons.triangleRight,
1990
+ color: Colors.primary
1991
+ };
1992
+ }
1993
+ const GroupHeader = ({ group, showIcon, isActive }) => {
1994
+ const complete = group.checks.filter((c) => c.status !== "pending").length;
1995
+ const total = group.checks.length;
1996
+ const { icon, color } = groupIcon(group);
1997
+ return /* @__PURE__ */ jsxs(Box, { children: [isActive ? /* @__PURE__ */ jsx(Box, {
1998
+ marginRight: 1,
1999
+ children: /* @__PURE__ */ jsx(Spinner, {})
2000
+ }) : showIcon ? /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
2001
+ color,
2002
+ children: icon
2003
+ }), " "] }) : null, /* @__PURE__ */ jsxs(Text, { children: [
2004
+ /* @__PURE__ */ jsx(Text, {
2005
+ bold: true,
2006
+ children: group.area
2007
+ }),
2008
+ " ",
2009
+ /* @__PURE__ */ jsxs(Text, {
2010
+ dimColor: true,
2011
+ children: [
2012
+ "(",
2013
+ complete,
2014
+ "/",
2015
+ total,
2016
+ ")"
2017
+ ]
2018
+ })
2019
+ ] })] });
2020
+ };
2021
+ const CheckRow = ({ check }) => {
2022
+ const { glyph, color } = AUDIT_SEVERITY_STYLE[check.status];
2023
+ return /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
2024
+ color,
2025
+ children: glyph
2026
+ }), /* @__PURE__ */ jsxs(Text, {
2027
+ dimColor: check.status === "pending",
2028
+ children: [" ", check.label]
2029
+ })] });
2030
+ };
2031
+ const COLLAPSE_BELOW_ROWS = 24;
2032
+ const PendingChecksList = ({ checks }) => {
2033
+ const [, termRows] = useStdoutDimensions();
2034
+ if (checks.length === 0) return /* @__PURE__ */ jsxs(Box, {
2035
+ flexDirection: "column",
2036
+ children: [
2037
+ /* @__PURE__ */ jsx(Text, {
2038
+ bold: true,
2039
+ children: "Checks"
2040
+ }),
2041
+ /* @__PURE__ */ jsx(Text, { children: " " }),
2042
+ /* @__PURE__ */ jsx(LoadingBox, { message: "Seeding audit checklist..." })
2043
+ ]
2044
+ });
2045
+ const groups = groupByArea(checks);
2046
+ const activeIndex = groups.findIndex((g) => g.checks.some((c) => c.status === "pending"));
2047
+ return /* @__PURE__ */ jsxs(Box, {
2048
+ flexDirection: "column",
2049
+ children: [
2050
+ /* @__PURE__ */ jsx(Text, {
2051
+ bold: true,
2052
+ children: "Checks"
2053
+ }),
2054
+ /* @__PURE__ */ jsx(Text, { children: " " }),
2055
+ termRows < COLLAPSE_BELOW_ROWS ? groups.map((group, i) => /* @__PURE__ */ jsx(GroupHeader, {
2056
+ group,
2057
+ showIcon: true,
2058
+ isActive: i === activeIndex
2059
+ }, group.area)) : groups.map((group, i) => /* @__PURE__ */ jsxs(Box, {
2060
+ flexDirection: "column",
2061
+ marginTop: i === 0 ? 0 : 1,
2062
+ children: [/* @__PURE__ */ jsx(GroupHeader, {
2063
+ group,
2064
+ showIcon: false,
2065
+ isActive: i === activeIndex
2066
+ }), group.checks.map((c) => /* @__PURE__ */ jsx(CheckRow, { check: c }, c.id))]
2067
+ }, group.area))
2068
+ ]
2069
+ });
2070
+ };
2071
+ //#endregion
2072
+ //#region src/ui/tui/screens/audit/AuditRunScreen.tsx
2073
+ const AuditRunScreen = ({ store }) => {
2074
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
2075
+ useFileWatcher(join(store.session.installDir, AUDIT_CHECKS_FILE), (parsed) => store.setFrameworkContext(AUDIT_CHECKS_KEY, coerceAuditChecks(parsed)));
2076
+ const statuses = store.statusMessages.length > 0 ? store.statusMessages : void 0;
2077
+ const [columns] = useStdoutDimensions();
2078
+ const checks = getAuditChecks(store.session);
2079
+ const reportPath = `./${AUDIT_REPORT_FILE}`;
2080
+ const pendingChecksList = /* @__PURE__ */ jsx(PendingChecksList, { checks });
2081
+ return /* @__PURE__ */ jsx(TabContainer, {
2082
+ tabs: [
2083
+ {
2084
+ id: "status",
2085
+ label: "Status",
2086
+ component: columns < 80 ? /* @__PURE__ */ jsx(Box, {
2087
+ flexDirection: "column",
2088
+ flexGrow: 1,
2089
+ children: pendingChecksList
2090
+ }) : /* @__PURE__ */ jsx(SplitView, {
2091
+ left: /* @__PURE__ */ jsx(AuditAreaPane, {
2092
+ checks,
2093
+ reportPath
2094
+ }),
2095
+ right: pendingChecksList
2096
+ })
2097
+ },
2098
+ {
2099
+ id: "audit-checks",
2100
+ label: "Audit plan",
2101
+ component: /* @__PURE__ */ jsx(AuditChecksViewer, { checks })
2102
+ },
2103
+ {
2104
+ id: "logs",
2105
+ label: "Tail logs",
2106
+ component: /* @__PURE__ */ jsx(LogViewer, { filePath: WIZARD_LOG_FILE })
2107
+ },
2108
+ {
2109
+ id: "hn",
2110
+ label: "HN",
2111
+ component: /* @__PURE__ */ jsx(HNViewer, {})
2112
+ }
2113
+ ],
2114
+ statusMessage: statuses,
2115
+ expandableStatus: true,
2116
+ store
2117
+ });
2118
+ };
2119
+ //#endregion
2120
+ //#region src/ui/tui/screens/audit/AuditChecksOutroSection.tsx
2121
+ const MAX_VISIBLE = 6;
2122
+ const AuditChecksOutroSection = ({ checks, installDir }) => {
2123
+ if (checks.length === 0) return null;
2124
+ const errors = checks.filter((c) => c.status === "error");
2125
+ const warnings = checks.filter((c) => c.status === "warning");
2126
+ const suggestions = checks.filter((c) => c.status === "suggestion");
2127
+ const problematic = [
2128
+ ...errors,
2129
+ ...warnings,
2130
+ ...suggestions
2131
+ ];
2132
+ const visible = problematic.slice(0, MAX_VISIBLE);
2133
+ const hidden = problematic.length - visible.length;
2134
+ return /* @__PURE__ */ jsxs(Box, {
2135
+ flexDirection: "column",
2136
+ marginTop: 1,
2137
+ children: [
2138
+ /* @__PURE__ */ jsx(Text, {
2139
+ color: "cyan",
2140
+ bold: true,
2141
+ children: "Items audited:"
2142
+ }),
2143
+ /* @__PURE__ */ jsxs(Text, {
2144
+ dimColor: true,
2145
+ children: [
2146
+ checks.length,
2147
+ " checks · ",
2148
+ errors.length,
2149
+ " errors · ",
2150
+ warnings.length,
2151
+ " ",
2152
+ "warnings · ",
2153
+ suggestions.length,
2154
+ " suggestions"
2155
+ ]
2156
+ }),
2157
+ problematic.length === 0 ? /* @__PURE__ */ jsxs(Text, {
2158
+ color: "green",
2159
+ children: ["•", " No issues found."]
2160
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [visible.map((item) => {
2161
+ const style = AUDIT_SEVERITY_STYLE[item.status];
2162
+ return /* @__PURE__ */ jsxs(Box, {
2163
+ flexDirection: "column",
2164
+ marginTop: 1,
2165
+ children: [/* @__PURE__ */ jsxs(Text, { children: [
2166
+ /* @__PURE__ */ jsx(Text, {
2167
+ color: style.color,
2168
+ children: style.glyph
2169
+ }),
2170
+ " ",
2171
+ /* @__PURE__ */ jsx(Text, {
2172
+ bold: true,
2173
+ children: item.label
2174
+ }),
2175
+ " ",
2176
+ /* @__PURE__ */ jsxs(Text, {
2177
+ dimColor: true,
2178
+ children: [
2179
+ "(",
2180
+ item.area,
2181
+ ")"
2182
+ ]
2183
+ })
2184
+ ] }), item.file && /* @__PURE__ */ jsxs(Text, {
2185
+ dimColor: true,
2186
+ children: [" ", relativeToInstallDir(item.file, installDir)]
2187
+ })]
2188
+ }, item.id);
2189
+ }), hidden > 0 && /* @__PURE__ */ jsxs(Text, {
2190
+ dimColor: true,
2191
+ children: [
2192
+ "… and ",
2193
+ hidden,
2194
+ " more — see the report."
2195
+ ]
2196
+ })] })
2197
+ ]
2198
+ });
2199
+ };
2200
+ //#endregion
2201
+ //#region src/ui/tui/screens/audit/AuditOutroScreen.tsx
2202
+ /**
2203
+ * AuditOutroScreen — Audit-specific post-run summary. Renders the standard
2204
+ * success / error / cancel views with the audit checks summary inlined into
2205
+ * the success body. The report path is hardcoded to AUDIT_REPORT_FILE.
2206
+ */
2207
+ const AuditOutroScreen = ({ store }) => {
2208
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
2209
+ useInput(() => {
2210
+ store.setOutroDismissed();
2211
+ });
2212
+ const outroData = store.session.outroData;
2213
+ if (!outroData) return /* @__PURE__ */ jsx(Box, {
2214
+ flexDirection: "column",
2215
+ flexGrow: 1,
2216
+ children: /* @__PURE__ */ jsx(Text, {
2217
+ dimColor: true,
2218
+ children: "Finishing up..."
2219
+ })
2220
+ });
2221
+ return /* @__PURE__ */ jsxs(Box, {
2222
+ flexDirection: "column",
2223
+ flexGrow: 1,
2224
+ children: [
2225
+ outroData.kind === "success" && /* @__PURE__ */ jsxs(Box, {
2226
+ flexDirection: "column",
2227
+ children: [
2228
+ /* @__PURE__ */ jsxs(Text, {
2229
+ color: "green",
2230
+ bold: true,
2231
+ children: ["✔ ", outroData.message || "Audit complete!"]
2232
+ }),
2233
+ /* @__PURE__ */ jsx(AuditChecksOutroSection, {
2234
+ checks: getAuditChecks(store.session),
2235
+ installDir: store.session.installDir
2236
+ }),
2237
+ outroData.docsUrl && /* @__PURE__ */ jsx(Box, {
2238
+ marginTop: 1,
2239
+ children: /* @__PURE__ */ jsxs(Text, { children: ["Learn more: ", /* @__PURE__ */ jsx(Text, {
2240
+ color: "cyan",
2241
+ children: outroData.docsUrl
2242
+ })] })
2243
+ })
2244
+ ]
2245
+ }),
2246
+ outroData.kind === "error" && /* @__PURE__ */ jsxs(Box, {
2247
+ flexDirection: "column",
2248
+ children: [/* @__PURE__ */ jsxs(Text, {
2249
+ color: "red",
2250
+ bold: true,
2251
+ children: ["✘ ", outroData.message || "An error occurred"]
2252
+ }), outroData.body && /* @__PURE__ */ jsx(Box, {
2253
+ marginTop: 1,
2254
+ children: /* @__PURE__ */ jsx(Text, {
2255
+ dimColor: true,
2256
+ children: outroData.body
2257
+ })
2258
+ })]
2259
+ }),
2260
+ outroData.kind === "cancel" && /* @__PURE__ */ jsxs(Text, {
2261
+ color: "yellow",
2262
+ children: ["■ ", outroData.message || "Cancelled"]
2263
+ }),
2264
+ /* @__PURE__ */ jsx(Box, {
2265
+ marginTop: 1,
2266
+ children: /* @__PURE__ */ jsx(Text, {
2267
+ color: Colors.muted,
2268
+ children: "Press any key to continue"
2269
+ })
2270
+ })
2271
+ ]
2272
+ });
2273
+ };
2274
+ //#endregion
2275
+ //#region src/ui/tui/screens/SetupScreen.tsx
2276
+ /**
2277
+ * SetupScreen — Generic framework disambiguation.
2278
+ *
2279
+ * Iterates unresolved setup questions from the FrameworkConfig
2280
+ * and renders a PickerMenu for each. If all questions are auto-resolved,
2281
+ * this screen is skipped entirely (the router skips it via its show() predicate).
2282
+ */
2283
+ const SetupScreen = ({ store }) => {
2284
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
2285
+ const config = store.session.frameworkConfig;
2286
+ const questions = config?.metadata.setup?.questions ?? [];
2287
+ const [currentIndex, setCurrentIndex] = useState(0);
2288
+ const [resolving, setResolving] = useState(true);
2289
+ useEffect(() => {
2290
+ (async () => {
2291
+ for (const q of questions) {
2292
+ if (q.key in store.session.frameworkContext) continue;
2293
+ try {
2294
+ const detected = await q.detect({ installDir: store.session.installDir });
2295
+ if (detected !== null) store.setFrameworkContext(q.key, detected);
2296
+ } catch {}
2297
+ }
2298
+ setResolving(false);
2299
+ })();
2300
+ }, []);
2301
+ if (resolving) return /* @__PURE__ */ jsx(Box, {
2302
+ flexDirection: "column",
2303
+ flexGrow: 1,
2304
+ children: /* @__PURE__ */ jsx(Text, {
2305
+ dimColor: true,
2306
+ children: "Detecting project configuration..."
2307
+ })
1211
2308
  });
1212
2309
  const unresolved = questions.filter((q) => !(q.key in store.session.frameworkContext));
1213
2310
  if (unresolved.length === 0) return null;
@@ -1309,18 +2406,21 @@ const AuthScreen = ({ store }) => {
1309
2406
  //#endregion
1310
2407
  //#region src/ui/tui/screens/RunScreen.tsx
1311
2408
  /**
1312
- * RunScreen — Tabbed observational view of the agent run.
1313
- *
1314
- * Two tabs:
1315
- * - Status: SplitView with LearnCard (left) + ProgressList (right)
1316
- * - Logs: LogViewer tailing the wizard log file
2409
+ * RunScreen — Default observational view of the agent run.
1317
2410
  *
1318
- * No prompts the agent runs headlessly.
1319
- * LearnCard shows animated educational content and reacts to discovered features.
2411
+ * Tabs: Status (LearnCard + ProgressList), Event plan (when present),
2412
+ * Tail logs, HN. Workflows that need a different tab list ship their own
2413
+ * screen component (see audit/AuditRunScreen.tsx).
1320
2414
  */
1321
- const LOG_FILE = "/tmp/posthog-wizard.log";
1322
2415
  const RunScreen = ({ store }) => {
1323
2416
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
2417
+ useFileWatcher(join(store.session.installDir, EVENT_PLAN_FILE), (parsed) => {
2418
+ if (!Array.isArray(parsed)) return;
2419
+ store.setEventPlan(parsed.map((e) => ({
2420
+ name: e.name ?? e.event ?? "",
2421
+ description: e.description ?? ""
2422
+ })));
2423
+ });
1324
2424
  const [columns] = useStdoutDimensions();
1325
2425
  const progressItems = store.tasks.map((t) => ({
1326
2426
  label: t.label,
@@ -1367,7 +2467,7 @@ const RunScreen = ({ store }) => {
1367
2467
  {
1368
2468
  id: "logs",
1369
2469
  label: "Tail logs",
1370
- component: /* @__PURE__ */ jsx(LogViewer, { filePath: LOG_FILE })
2470
+ component: /* @__PURE__ */ jsx(LogViewer, { filePath: WIZARD_LOG_FILE })
1371
2471
  },
1372
2472
  {
1373
2473
  id: "hn",
@@ -1390,6 +2490,7 @@ const RunScreen = ({ store }) => {
1390
2490
  *
1391
2491
  * When done, calls store.setSkillsComplete() and exits the process.
1392
2492
  */
2493
+ const WIZARD_MARKER = ".posthog-wizard";
1393
2494
  const KeepSkillsScreen = ({ store }) => {
1394
2495
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
1395
2496
  const [phase, setPhase] = useState("loading");
@@ -1401,7 +2502,12 @@ const KeepSkillsScreen = ({ store }) => {
1401
2502
  const dirs = (await readdir(skillsDir, { withFileTypes: true })).filter((e) => e.isDirectory());
1402
2503
  const result = [];
1403
2504
  for (const dir of dirs) {
1404
- const children = await readdir(join(skillsDir, dir.name));
2505
+ try {
2506
+ await access(join(skillsDir, dir.name, WIZARD_MARKER));
2507
+ } catch {
2508
+ continue;
2509
+ }
2510
+ const children = (await readdir(join(skillsDir, dir.name))).filter((c) => c !== WIZARD_MARKER);
1405
2511
  result.push({
1406
2512
  name: dir.name,
1407
2513
  children
@@ -1425,8 +2531,14 @@ const KeepSkillsScreen = ({ store }) => {
1425
2531
  };
1426
2532
  const handleRemove = async () => {
1427
2533
  setPhase("removing");
2534
+ for (const skill of skills) try {
2535
+ await rm(join(skillsDir, skill.name), {
2536
+ recursive: true,
2537
+ force: true
2538
+ });
2539
+ } catch {}
1428
2540
  try {
1429
- await rm(skillsDir, {
2541
+ if ((await readdir(skillsDir)).length === 0) await rm(skillsDir, {
1430
2542
  recursive: true,
1431
2543
  force: true
1432
2544
  });
@@ -1452,7 +2564,7 @@ const KeepSkillsScreen = ({ store }) => {
1452
2564
  dimColor: true,
1453
2565
  children: "Checking installed skills..."
1454
2566
  }),
1455
- phase === "ask" && /* @__PURE__ */ jsxs(Fragment, { children: [
2567
+ phase === "ask" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1456
2568
  /* @__PURE__ */ jsx(Text, {
1457
2569
  dimColor: true,
1458
2570
  children: "The wizard installed open-source skills that help AI coding agents integrate PostHog into your project:"
@@ -1522,9 +2634,11 @@ const KeepSkillsScreen = ({ store }) => {
1522
2634
  //#endregion
1523
2635
  //#region src/ui/tui/screens/OutroScreen.tsx
1524
2636
  /**
1525
- * OutroScreen — Summary after the agent run.
1526
- * Reads store.session.outroData to render success, error, or cancel view.
1527
- * Keeps the process alive until the user presses a key to exit.
2637
+ * OutroScreen — Default post-run summary.
2638
+ *
2639
+ * Renders the success / error / cancel views from `outroData`. Workflows
2640
+ * that need a different success view (e.g. with extra summary content)
2641
+ * ship their own screen component (see audit/AuditOutroScreen.tsx).
1528
2642
  */
1529
2643
  const OutroScreen = ({ store }) => {
1530
2644
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
@@ -1550,11 +2664,14 @@ const OutroScreen = ({ store }) => {
1550
2664
  /* @__PURE__ */ jsxs(Text, {
1551
2665
  color: "green",
1552
2666
  bold: true,
1553
- children: [
1554
- "✔",
1555
- " ",
1556
- outroData.message || "Done!"
1557
- ]
2667
+ children: ["✔ ", outroData.message || "Done!"]
2668
+ }),
2669
+ outroData.body && /* @__PURE__ */ jsx(Box, {
2670
+ marginTop: 1,
2671
+ children: /* @__PURE__ */ jsx(Text, {
2672
+ dimColor: true,
2673
+ children: outroData.body
2674
+ })
1558
2675
  }),
1559
2676
  outroData.reportFile && /* @__PURE__ */ jsx(Box, {
1560
2677
  marginTop: 1,
@@ -1574,11 +2691,7 @@ const OutroScreen = ({ store }) => {
1574
2691
  color: "cyan",
1575
2692
  bold: true,
1576
2693
  children: "What the agent did:"
1577
- }), outroData.changes.map((change, i) => /* @__PURE__ */ jsxs(Text, { children: [
1578
- "•",
1579
- " ",
1580
- change
1581
- ] }, i))]
2694
+ }), outroData.changes.map((change, i) => /* @__PURE__ */ jsxs(Text, { children: ["• ", change] }, i))]
1582
2695
  }),
1583
2696
  store.eventPlan.length > 0 && /* @__PURE__ */ jsxs(Box, {
1584
2697
  flexDirection: "column",
@@ -1588,8 +2701,7 @@ const OutroScreen = ({ store }) => {
1588
2701
  bold: true,
1589
2702
  children: "Events added:"
1590
2703
  }), store.eventPlan.map((event) => /* @__PURE__ */ jsxs(Text, { children: [
1591
- "•",
1592
- " ",
2704
+ "• ",
1593
2705
  /* @__PURE__ */ jsx(Text, {
1594
2706
  bold: true,
1595
2707
  children: event.name
@@ -1622,10 +2734,10 @@ const OutroScreen = ({ store }) => {
1622
2734
  children: "Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made."
1623
2735
  })
1624
2736
  }),
1625
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, {
2737
+ /* @__PURE__ */ jsx(Text, {
1626
2738
  dimColor: true,
1627
2739
  children: "How did this work for you? Drop us a line: wizard@posthog.com"
1628
- }) })
2740
+ })
1629
2741
  ]
1630
2742
  }),
1631
2743
  outroData.kind === "error" && /* @__PURE__ */ jsxs(Box, {
@@ -1634,11 +2746,7 @@ const OutroScreen = ({ store }) => {
1634
2746
  /* @__PURE__ */ jsxs(Text, {
1635
2747
  color: "red",
1636
2748
  bold: true,
1637
- children: [
1638
- "✘",
1639
- " ",
1640
- outroData.message || "An error occurred"
1641
- ]
2749
+ children: ["✘ ", outroData.message || "An error occurred"]
1642
2750
  }),
1643
2751
  outroData.body && /* @__PURE__ */ jsx(Box, {
1644
2752
  marginTop: 1,
@@ -1660,11 +2768,7 @@ const OutroScreen = ({ store }) => {
1660
2768
  flexDirection: "column",
1661
2769
  children: /* @__PURE__ */ jsxs(Text, {
1662
2770
  color: "yellow",
1663
- children: [
1664
- "■",
1665
- " ",
1666
- outroData.message || "Cancelled"
1667
- ]
2771
+ children: ["■ ", outroData.message || "Cancelled"]
1668
2772
  })
1669
2773
  }),
1670
2774
  /* @__PURE__ */ jsx(Box, {
@@ -1763,7 +2867,10 @@ function createMcpInstaller() {
1763
2867
  name: c.name,
1764
2868
  raw: c
1765
2869
  }));
1766
- return supported.map((c) => ({ name: c.name }));
2870
+ return supported.map((c) => ({
2871
+ name: c.name,
2872
+ supportsPlugin: isPluginCapable(c) && c.supportsPlugin()
2873
+ }));
1767
2874
  },
1768
2875
  async install(clientNames, features, apiKey) {
1769
2876
  const resolvedFeatures = features ?? [...ALL_FEATURE_VALUES];
@@ -1786,6 +2893,15 @@ function createMcpInstaller() {
1786
2893
  if (installed.length === 0) return [];
1787
2894
  await removeMCPServer(installed);
1788
2895
  return installed.map((c) => c.name);
2896
+ },
2897
+ async installPlugins(clientNames) {
2898
+ const pluginClients = getSupportedPluginClients(cachedClients.filter((c) => clientNames.includes(c.name)).map((c) => c.raw));
2899
+ const installed = await installPlugins(pluginClients);
2900
+ analytics.wizardCapture("mcp plugins installed", {
2901
+ clients: installed,
2902
+ attempted: pluginClients.map((c) => c.name)
2903
+ });
2904
+ return installed;
1789
2905
  }
1790
2906
  };
1791
2907
  }
@@ -1803,7 +2919,12 @@ function createScreens(store, services) {
1803
2919
  ["intro"]: /* @__PURE__ */ jsx(PostHogIntegrationIntroScreen, { store }),
1804
2920
  ["revenue-intro"]: /* @__PURE__ */ jsx(RevenueIntroScreen, { store }),
1805
2921
  ["agent-skill-intro"]: /* @__PURE__ */ jsx(AgentSkillIntroScreen, { store }),
2922
+ ["audit-intro"]: /* @__PURE__ */ jsx(AuditIntroScreen, { store }),
2923
+ ["audit-run"]: /* @__PURE__ */ jsx(AuditRunScreen, { store }),
2924
+ ["audit-outro"]: /* @__PURE__ */ jsx(AuditOutroScreen, { store }),
1806
2925
  ["health-check"]: /* @__PURE__ */ jsx(HealthCheckScreen, { store }),
2926
+ ["doctor-intro"]: /* @__PURE__ */ jsx(DoctorIntroScreen, { store }),
2927
+ ["doctor-report"]: /* @__PURE__ */ jsx(DoctorReportScreen, { store }),
1807
2928
  ["setup"]: /* @__PURE__ */ jsx(SetupScreen, { store }),
1808
2929
  ["auth"]: /* @__PURE__ */ jsx(AuthScreen, { store }),
1809
2930
  ["run"]: /* @__PURE__ */ jsx(RunScreen, { store }),
@@ -1852,10 +2973,16 @@ const LEAVE_ALT_SCREEN = "\x1B[?1049l";
1852
2973
  const GREEN = "\x1B[32m";
1853
2974
  const BOLD = "\x1B[1m";
1854
2975
  const DIM = "\x1B[2m";
2976
+ function releaseTerminal() {
2977
+ process.stdout.write(RESET_ATTRS + LEAVE_ALT_SCREEN);
2978
+ }
1855
2979
  function getExitLine(store) {
1856
2980
  const outro = store.session.outroData;
1857
2981
  const label = store.session.workflowLabel ?? "Wizard";
1858
- if (outro?.kind === "success") return `${GREEN}${BOLD}\u2714${RESET_ATTRS} ${outro.message ?? `${label} completed successfully.`}`;
2982
+ if (outro?.kind === "success") {
2983
+ const message = outro.message ?? `${label} completed successfully.`;
2984
+ return `${GREEN}${BOLD}\u2714${RESET_ATTRS} ${message}${outro.reportFile && !message.includes(outro.reportFile) ? ` Check ./${outro.reportFile} for details.` : ""}`;
2985
+ }
1859
2986
  return `${DIM}${label} exited.${RESET_ATTRS}`;
1860
2987
  }
1861
2988
  function startTUI(version, flow = "posthog-integration") {
@@ -1869,7 +2996,7 @@ function startTUI(version, flow = "posthog-integration") {
1869
2996
  if (cleaned) return;
1870
2997
  cleaned = true;
1871
2998
  inkUnmount();
1872
- process.stdout.write(RESET_ATTRS + LEAVE_ALT_SCREEN);
2999
+ releaseTerminal();
1873
3000
  process.stdout.write(getExitLine(store) + "\n");
1874
3001
  };
1875
3002
  process.on("exit", cleanup);
@@ -1882,4 +3009,4 @@ function startTUI(version, flow = "posthog-integration") {
1882
3009
  //#endregion
1883
3010
  export { startTUI };
1884
3011
 
1885
- //# sourceMappingURL=start-tui-DkT_H5zx.js.map
3012
+ //# sourceMappingURL=start-tui-DleQG3La.js.map