@posthog/wizard 2.11.0 → 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 (85) hide show
  1. package/README.md +48 -7
  2. package/dist/{McpScreen-DvUncZBi.js → AuditChecksViewer-DsfXIO9e.js} +330 -21
  3. package/dist/AuditChecksViewer-DsfXIO9e.js.map +1 -0
  4. package/dist/{add-mcp-server-to-clients-Br1hDRiB.js → add-mcp-server-to-clients-BKoew3aT.js} +5 -5
  5. package/dist/{add-mcp-server-to-clients-Br1hDRiB.js.map → add-mcp-server-to-clients-BKoew3aT.js.map} +1 -1
  6. package/dist/{readiness-gQvQNCeL.js → agent-interface-D5W9BAB2.js} +326 -461
  7. package/dist/agent-interface-D5W9BAB2.js.map +1 -0
  8. package/dist/{agent-runner-fWYFO4H0.js → agent-runner-B8Cx6X6x.js} +19 -30
  9. package/dist/{agent-runner-fWYFO4H0.js.map → agent-runner-B8Cx6X6x.js.map} +1 -1
  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 +324 -42
  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-D-0xueVl.js → debug-I5sRZubJ.js} +1 -1
  18. package/dist/{defaults-CPH6eWhN.js → defaults-GbLPuHxj.js} +1 -1
  19. package/dist/{defaults-CPH6eWhN.js.map → defaults-GbLPuHxj.js.map} +1 -1
  20. package/dist/{detection-B7GNzve-.js → detection-C_RfYYDe.js} +3 -3
  21. package/dist/{detection-B7GNzve-.js.map → detection-C_RfYYDe.js.map} +1 -1
  22. package/dist/{env-api-key-DU8uIEvo.js → env-api-key-D5G2PrXW.js} +1 -1
  23. package/dist/{env-api-key-DU8uIEvo.js.map → env-api-key-D5G2PrXW.js.map} +1 -1
  24. package/dist/{file-DhSBlq-x.js → file-8iNrXHkG.js} +2 -2
  25. package/dist/{file-DhSBlq-x.js.map → file-8iNrXHkG.js.map} +1 -1
  26. package/dist/{file-utils-Dy9JncCo.js → file-utils-DnTSiTJw.js} +1 -1
  27. package/dist/{file-utils-Dy9JncCo.js.map → file-utils-DnTSiTJw.js.map} +1 -1
  28. package/dist/{package-manager-D3Lo6nXf.js → package-manager-qxP2PpM_.js} +2 -2
  29. package/dist/{package-manager-D3Lo6nXf.js.map → package-manager-qxP2PpM_.js.map} +1 -1
  30. package/dist/paths-DJS47p5x.js +26 -0
  31. package/dist/paths-DJS47p5x.js.map +1 -0
  32. package/dist/{posthog-integration-D4SRhJIQ.js → posthog-integration-DX77Msto.js} +41 -13
  33. package/dist/posthog-integration-DX77Msto.js.map +1 -0
  34. package/dist/{posthog-ByrpqEjN.js → posthog-vm0k9PKS.js} +1 -1
  35. package/dist/{posthog-ByrpqEjN.js.map → posthog-vm0k9PKS.js.map} +1 -1
  36. package/dist/provisioning-CHfTOEvg.js +2 -0
  37. package/dist/provisioning-DUj285NO.js +166 -0
  38. package/dist/provisioning-DUj285NO.js.map +1 -0
  39. package/dist/{registry-DaPKstG3.js → registry-CCtIsqb8.js} +4 -5
  40. package/dist/{registry-DaPKstG3.js.map → registry-CCtIsqb8.js.map} +1 -1
  41. package/dist/{router-SgzmfLGi.js → router-BTfmEDDJ.js} +3 -3
  42. package/dist/router-BTfmEDDJ.js.map +1 -0
  43. package/dist/{setup-utils-y4s-3uKT.js → setup-utils-Bv8z6HMb.js} +11 -150
  44. package/dist/setup-utils-Bv8z6HMb.js.map +1 -0
  45. package/dist/setup-utils-CoX-vLgw.js +2 -0
  46. package/dist/{start-playground-g1TxpCZ5.js → start-playground-DYNQ8rOz.js} +102 -7
  47. package/dist/start-playground-DYNQ8rOz.js.map +1 -0
  48. package/dist/{start-tui-CQef69NR.js → start-tui-DleQG3La.js} +969 -124
  49. package/dist/start-tui-DleQG3La.js.map +1 -0
  50. package/dist/{steps-D1zKDqAo.js → steps-C-syS8if.js} +8 -8
  51. package/dist/steps-C-syS8if.js.map +1 -0
  52. package/dist/{task-stream-DX_jKDQu.js → task-stream-CX7Uf6EM.js} +4 -4
  53. package/dist/{task-stream-DX_jKDQu.js.map → task-stream-CX7Uf6EM.js.map} +1 -1
  54. package/dist/{telemetry-CyUUSAYy.js → telemetry-DHZfjgqx.js} +2 -2
  55. package/dist/{telemetry-CyUUSAYy.js.map → telemetry-DHZfjgqx.js.map} +1 -1
  56. package/dist/{wizard-abort-DZmO_sIZ.js → wizard-abort-DIhFXJ5N.js} +1 -1
  57. package/dist/{wizard-abort-Buodno3f.js → wizard-abort-DfhWuzaw.js} +6 -4
  58. package/dist/{wizard-abort-Buodno3f.js.map → wizard-abort-DfhWuzaw.js.map} +1 -1
  59. package/dist/wizard-session-BQC9vy9Z.js +2 -0
  60. package/dist/{wizard-session-D5bggSsu.js → wizard-session-BcNJTl2I.js} +1 -1
  61. package/dist/{wizard-session-D5bggSsu.js.map → wizard-session-BcNJTl2I.js.map} +1 -1
  62. package/dist/{wizard-ui-BExOjdjA.js → wizard-ui-YdGFRyu_.js} +1 -1
  63. package/dist/wizard-ui-YdGFRyu_.js.map +1 -0
  64. package/npm-shrinkwrap.json +2 -2
  65. package/package.json +1 -1
  66. package/dist/McpScreen-DvUncZBi.js.map +0 -1
  67. package/dist/agent-skill-DJOzDaQV.js +0 -59
  68. package/dist/agent-skill-DJOzDaQV.js.map +0 -1
  69. package/dist/analytics-CfAUlt6-.js +0 -2
  70. package/dist/analytics-D3rY3TaN.js +0 -210
  71. package/dist/analytics-D3rY3TaN.js.map +0 -1
  72. package/dist/debug-gWEjmYVV.js +0 -203
  73. package/dist/debug-gWEjmYVV.js.map +0 -1
  74. package/dist/paths-BL-x2rFy.js +0 -16
  75. package/dist/paths-BL-x2rFy.js.map +0 -1
  76. package/dist/posthog-integration-D4SRhJIQ.js.map +0 -1
  77. package/dist/readiness-gQvQNCeL.js.map +0 -1
  78. package/dist/router-SgzmfLGi.js.map +0 -1
  79. package/dist/setup-utils-_ONxN-TT.js +0 -2
  80. package/dist/setup-utils-y4s-3uKT.js.map +0 -1
  81. package/dist/start-playground-g1TxpCZ5.js.map +0 -1
  82. package/dist/start-tui-CQef69NR.js.map +0 -1
  83. package/dist/steps-D1zKDqAo.js.map +0 -1
  84. package/dist/wizard-session-COhklXAF.js +0 -2
  85. package/dist/wizard-ui-BExOjdjA.js.map +0 -1
@@ -1,22 +1,25 @@
1
- import { l as setUI, s as logToFile } from "./debug-gWEjmYVV.js";
2
- import { E as getSkillsBaseUrl, S as WIZARD_TOOLS_MENU_FLAG_KEY, i as CONTEXT_MILL_URL, l as Integration, n as analytics, p as POSTHOG_DOCS_URL, u as OAUTH_PORTS, y as REMOTE_SKILLS_BASE_URL } from "./analytics-D3rY3TaN.js";
3
- import { n as WIZARD_LOG_FILE } from "./paths-BL-x2rFy.js";
4
- import { l as ApiError, p as getUiHostFromHost } from "./setup-utils-y4s-3uKT.js";
5
- import { t as ADDITIONAL_FEATURE_LABELS } from "./wizard-session-D5bggSsu.js";
6
- import { r as wizardAbort } from "./wizard-abort-Buodno3f.js";
7
- import { m as fetchSkillMenu, p as downloadSkill, r as getBlockingServiceKeys } from "./readiness-gQvQNCeL.js";
8
- import { a as STRIPE_SDKS, i as POSTHOG_SDKS, r as fetchHealthIssues } from "./bin.js";
9
- import { t as ALL_FEATURE_VALUES } from "./defaults-CPH6eWhN.js";
10
- 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-Br1hDRiB.js";
11
- import "./router-SgzmfLGi.js";
12
- import { C as Icons, S as Colors, _ as PickerMenu, a as ServiceHealthList, b as SplitView, c as HNViewer, d as EventPlanViewer, f as LogViewer, g as useStdoutDimensions, i as SEVERITY_ORDER, l as TabContainer, m as ConfirmationInput, n as IssueTable, o as TipsCard, p as ModalOverlay, r as SEVERITY_LABEL, s as LearnCard, t as McpScreen, u as ScreenContainer, v as ProgressList, w as WizardStore, y as LoadingBox } from "./McpScreen-DvUncZBi.js";
13
- import { spawnSync } from "node:child_process";
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";
14
15
  import { join } from "node:path";
16
+ import * as fs$1 from "fs";
15
17
  import path from "path";
16
18
  import { Box, Text, render, useInput } from "ink";
17
- import { createElement, useEffect, useMemo, useState, useSyncExternalStore } from "react";
18
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
19
- 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";
20
23
  //#region src/ui/tui/ink-ui.ts
21
24
  const ANSI_RE = /\x1b\[[0-9;]*m/g;
22
25
  function stripAnsi(s) {
@@ -31,7 +34,8 @@ var InkUI = class {
31
34
  }
32
35
  outro(message) {
33
36
  this.store.pushStatus(stripAnsi(message));
34
- if (!this.store.session.outroData) this.store.setOutroData({
37
+ const existing = this.store.session.outroData;
38
+ this.store.setOutroData(existing ?? {
35
39
  kind: "success",
36
40
  message: stripAnsi(message)
37
41
  });
@@ -41,6 +45,20 @@ var InkUI = class {
41
45
  this.store.setOutroData(data);
42
46
  if (this.store.session.runPhase !== "error") this.store.setRunPhase("error");
43
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
+ }
44
62
  setCredentials(credentials) {
45
63
  this.store.setCredentials(credentials);
46
64
  }
@@ -117,6 +135,9 @@ var InkUI = class {
117
135
  setEventPlan(events) {
118
136
  this.store.setEventPlan(events);
119
137
  }
138
+ setFrameworkContext(key, value) {
139
+ this.store.setFrameworkContext(key, value);
140
+ }
120
141
  };
121
142
  //#endregion
122
143
  //#region src/ui/tui/screens/health/HealthCheckScreen.tsx
@@ -177,14 +198,18 @@ const HealthCheckScreen = ({ store }) => {
177
198
  justifyContent: "center",
178
199
  children: /* @__PURE__ */ jsx(LoadingBox, { message: "Checking service status..." })
179
200
  });
180
- const blockingKeys = getBlockingServiceKeys(result.health);
181
- if (blockingKeys.length === 0) return null;
182
- 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");
183
208
  const canDownloadSkills = result.health.githubReleases.status === "healthy";
184
209
  const integration = store.session.integration;
185
- const title = `Ongoing service disruptions`;
210
+ const title = hasHardBlock ? "Ongoing service disruptions" : "Service disruption detected";
186
211
  const docsUrl = store.session.frameworkConfig?.metadata.docsUrl;
187
- 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.";
188
213
  const handleDownloadAndExit = async () => {
189
214
  if (downloading) return;
190
215
  setDownloading(true);
@@ -197,7 +222,7 @@ const HealthCheckScreen = ({ store }) => {
197
222
  setDownloaded(true);
198
223
  };
199
224
  return /* @__PURE__ */ jsxs(ModalOverlay, {
200
- borderColor: "red",
225
+ borderColor: hasHardBlock ? "red" : "yellow",
201
226
  title,
202
227
  width: 72,
203
228
  footer: isGithubReleasesDown ? /* @__PURE__ */ jsx(ConfirmationInput, {
@@ -239,7 +264,7 @@ const HealthCheckScreen = ({ store }) => {
239
264
  ] })
240
265
  }), /* @__PURE__ */ jsx(ServiceHealthList, {
241
266
  health: result.health,
242
- filterKeys: blockingKeys,
267
+ filterKeys: displayKeys,
243
268
  showHealthy: false
244
269
  })]
245
270
  }),
@@ -699,7 +724,7 @@ const IntroScreenLayout = ({ installDir, title = "PostHog Wizard 🦔", showSubt
699
724
  children: /* @__PURE__ */ jsx(WizardTitle, { title })
700
725
  }), errorView]
701
726
  });
702
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Box, {
727
+ return /* @__PURE__ */ jsx(Fragment$1, { children: /* @__PURE__ */ jsxs(Box, {
703
728
  flexDirection: "column",
704
729
  flexGrow: 1,
705
730
  alignItems: "center",
@@ -790,6 +815,69 @@ const IntroScreenLayout = ({ installDir, title = "PostHog Wizard 🦔", showSubt
790
815
  }) });
791
816
  };
792
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
793
881
  //#region src/ui/tui/screens/PostHogIntegrationIntroScreen.tsx
794
882
  /**
795
883
  * PostHogIntegrationIntroScreen — Intro screen for the core PostHog integration.
@@ -825,7 +913,7 @@ const FrameworkPicker = ({ store, onComplete }) => {
825
913
  })),
826
914
  onSelect: (value) => {
827
915
  const integration = Array.isArray(value) ? value[0] : value;
828
- import("./registry-DaPKstG3.js").then((n) => n.n).then(({ FRAMEWORK_REGISTRY }) => {
916
+ import("./registry-CCtIsqb8.js").then((n) => n.n).then(({ FRAMEWORK_REGISTRY }) => {
829
917
  const config = FRAMEWORK_REGISTRY[integration];
830
918
  store.setFrameworkConfig(integration, config);
831
919
  store.setDetectedFramework(config.metadata.name);
@@ -853,6 +941,7 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
853
941
  const { session } = store;
854
942
  const config = session.frameworkConfig;
855
943
  const frameworkLabel = session.detectedFrameworkLabel ?? config?.metadata.name;
944
+ const { skillEntry, fetchFailed } = useSkillEntry(session.skillId, session.localMcp);
856
945
  const detecting = !session.detectionComplete;
857
946
  const needsFrameworkPick = session.detectionComplete && !session.frameworkConfig;
858
947
  const unsupported = session.unsupportedVersion;
@@ -863,7 +952,7 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
863
952
  marginY: 1,
864
953
  children: /* @__PURE__ */ jsx(LoadingBox, { message: "Detecting project framework..." })
865
954
  });
866
- 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, {
867
956
  marginY: 1,
868
957
  children: /* @__PURE__ */ jsx(Text, {
869
958
  dimColor: true,
@@ -912,21 +1001,21 @@ const PostHogIntegrationIntroScreen = ({ store }) => {
912
1001
  /* @__PURE__ */ jsxs(Text, { children: [`\u2022`, " Error Tracking"] })
913
1002
  ]
914
1003
  }),
915
- /* @__PURE__ */ jsx(Box, {
1004
+ /* @__PURE__ */ jsxs(Box, {
916
1005
  flexDirection: "column",
917
1006
  marginTop: 1,
918
- children: /* @__PURE__ */ jsxs(Text, { children: [
919
- "If you prefer your own AI setup, download the skill:",
920
- " ",
921
- /* @__PURE__ */ jsxs(Text, {
922
- color: "cyan",
923
- 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
924
1013
  })
925
- ] })
1014
+ })]
926
1015
  })
927
1016
  ]
928
1017
  });
929
- 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." }) }) });
930
1019
  const detectionRows = [];
931
1020
  if (frameworkLabel) {
932
1021
  const suffixParts = [];
@@ -1116,7 +1205,7 @@ const RevenueIntroScreen = ({ store }) => {
1116
1205
  ]
1117
1206
  })
1118
1207
  ]
1119
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Box, {
1208
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
1120
1209
  flexDirection: "column",
1121
1210
  alignItems: "center",
1122
1211
  children: [/* @__PURE__ */ jsx(Text, { children: "Let's create revenue analytics with Stripe and PostHog." }), /* @__PURE__ */ jsx(Box, {
@@ -1144,7 +1233,7 @@ const RevenueIntroScreen = ({ store }) => {
1144
1233
  ]
1145
1234
  }, p))]
1146
1235
  })] });
1147
- const errorView = detectError ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Box, {
1236
+ const errorView = detectError ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Box, {
1148
1237
  flexDirection: "column",
1149
1238
  marginBottom: 1,
1150
1239
  children: [/* @__PURE__ */ jsxs(Text, {
@@ -1206,7 +1295,7 @@ const DetectErrorBody = ({ error }) => {
1206
1295
  "not-dir": "is not a directory",
1207
1296
  unreadable: "could not be accessed"
1208
1297
  }[error.reason];
1209
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Text, { children: [
1298
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, { children: [
1210
1299
  "This path ",
1211
1300
  reasonText,
1212
1301
  ":"
@@ -1215,7 +1304,7 @@ const DetectErrorBody = ({ error }) => {
1215
1304
  children: [" ", error.path]
1216
1305
  })] });
1217
1306
  }
1218
- case "no-package-json": return /* @__PURE__ */ jsxs(Fragment, { children: [
1307
+ case "no-package-json": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1219
1308
  /* @__PURE__ */ jsx(Text, { children: "No package.json found in this directory." }),
1220
1309
  /* @__PURE__ */ jsx(Text, {
1221
1310
  dimColor: true,
@@ -1226,7 +1315,7 @@ const DetectErrorBody = ({ error }) => {
1226
1315
  children: "Run this command from your project root."
1227
1316
  })
1228
1317
  ] });
1229
- case "no-sdks": return /* @__PURE__ */ jsxs(Fragment, { children: [
1318
+ case "no-sdks": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1230
1319
  /* @__PURE__ */ jsxs(Text, { children: [
1231
1320
  "Neither PostHog nor Stripe SDKs detected (scanned",
1232
1321
  " ",
@@ -1275,7 +1364,7 @@ const DetectErrorBody = ({ error }) => {
1275
1364
  })
1276
1365
  })
1277
1366
  ] });
1278
- 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: [
1279
1368
  "Found Stripe (",
1280
1369
  error.foundStripe.join(", "),
1281
1370
  ") but no PostHog SDK."
@@ -1293,7 +1382,7 @@ const DetectErrorBody = ({ error }) => {
1293
1382
  ]
1294
1383
  })
1295
1384
  })] });
1296
- case "missing-stripe": return /* @__PURE__ */ jsxs(Fragment, { children: [
1385
+ case "missing-stripe": return /* @__PURE__ */ jsxs(Fragment$1, { children: [
1297
1386
  /* @__PURE__ */ jsxs(Text, { children: [
1298
1387
  "Found PostHog (",
1299
1388
  error.foundPosthog.join(", "),
@@ -1324,37 +1413,17 @@ const DetectErrorBody = ({ error }) => {
1324
1413
  //#endregion
1325
1414
  //#region src/ui/tui/screens/AgentSkillIntroScreen.tsx
1326
1415
  /**
1327
- * AgentSkillIntroScreen — Intro screen for the generic agent-skill workflow.
1416
+ * AgentSkillIntroScreen — Default intro for generic agent-skill workflows.
1328
1417
  *
1329
- * Main menu: one-liner body, detection rows, continue/cancel.
1330
- * 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).
1331
1420
  */
1332
1421
  const AgentSkillIntroScreen = ({ store }) => {
1333
1422
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
1334
1423
  const [showingMoreInfo, setShowingMoreInfo] = useState(false);
1335
- const [skillEntry, setSkillEntry] = useState(null);
1336
- const [fetchFailed, setFetchFailed] = useState(false);
1337
1424
  const { session } = store;
1338
1425
  const skillId = session.skillId ?? "unknown";
1339
- const isMainMenu = !showingMoreInfo;
1340
- useEffect(() => {
1341
- if (!showingMoreInfo || skillEntry || fetchFailed) return;
1342
- fetchSkillMenu(getSkillsBaseUrl(session.localMcp)).then((menu) => {
1343
- if (!menu) {
1344
- setFetchFailed(true);
1345
- return;
1346
- }
1347
- const match = Object.values(menu.categories).flat().find((s) => s.id === skillId);
1348
- if (match) setSkillEntry(match);
1349
- else setFetchFailed(true);
1350
- });
1351
- }, [
1352
- showingMoreInfo,
1353
- skillEntry,
1354
- fetchFailed,
1355
- skillId,
1356
- session.localMcp
1357
- ]);
1426
+ const { skillEntry, fetchFailed } = useSkillEntry(skillId, session.localMcp);
1358
1427
  let body;
1359
1428
  if (showingMoreInfo) body = /* @__PURE__ */ jsxs(Box, {
1360
1429
  flexDirection: "column",
@@ -1369,23 +1438,11 @@ const AgentSkillIntroScreen = ({ store }) => {
1369
1438
  children: "https://github.com/PostHog/wizard"
1370
1439
  })] })
1371
1440
  }),
1372
- /* @__PURE__ */ jsxs(Text, { children: [
1373
- "Skill:",
1374
- " ",
1375
- /* @__PURE__ */ jsx(Text, {
1376
- italic: true,
1377
- color: "cyan",
1378
- children: skillEntry?.id ?? skillId
1379
- })
1380
- ] }),
1381
- /* @__PURE__ */ jsxs(Text, { children: [
1382
- "URL:",
1383
- " ",
1384
- /* @__PURE__ */ jsx(Text, {
1385
- color: "cyan",
1386
- children: skillEntry?.downloadUrl ?? (fetchFailed ? "unavailable" : "Loading...")
1387
- })
1388
- ] }),
1441
+ /* @__PURE__ */ jsx(SkillSourceInfo, {
1442
+ skillId,
1443
+ skillEntry,
1444
+ fetchFailed
1445
+ }),
1389
1446
  /* @__PURE__ */ jsx(Box, {
1390
1447
  marginTop: 1,
1391
1448
  children: /* @__PURE__ */ jsx(Text, {
@@ -1433,7 +1490,7 @@ const AgentSkillIntroScreen = ({ store }) => {
1433
1490
  installDir: session.installDir,
1434
1491
  showSubtitle: !showingMoreInfo,
1435
1492
  body,
1436
- showDetection: isMainMenu,
1493
+ showDetection: !showingMoreInfo,
1437
1494
  workflowLabel: session.workflowLabel,
1438
1495
  skillId: session.skillId,
1439
1496
  menuOptions,
@@ -1441,6 +1498,780 @@ const AgentSkillIntroScreen = ({ store }) => {
1441
1498
  });
1442
1499
  };
1443
1500
  //#endregion
1501
+ //#region src/ui/tui/screens/audit/AuditIntroScreen.tsx
1502
+ const AUDIT_SKILL_ID = "audit";
1503
+ const AuditIntroScreen = ({ store }) => {
1504
+ useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
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, {
1509
+ flexDirection: "column",
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
1444
2275
  //#region src/ui/tui/screens/SetupScreen.tsx
1445
2276
  /**
1446
2277
  * SetupScreen — Generic framework disambiguation.
@@ -1575,17 +2406,21 @@ const AuthScreen = ({ store }) => {
1575
2406
  //#endregion
1576
2407
  //#region src/ui/tui/screens/RunScreen.tsx
1577
2408
  /**
1578
- * RunScreen — Tabbed observational view of the agent run.
1579
- *
1580
- * Two tabs:
1581
- * - Status: SplitView with LearnCard (left) + ProgressList (right)
1582
- * - Logs: LogViewer tailing the wizard log file
2409
+ * RunScreen — Default observational view of the agent run.
1583
2410
  *
1584
- * No prompts the agent runs headlessly.
1585
- * 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).
1586
2414
  */
1587
2415
  const RunScreen = ({ store }) => {
1588
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
+ });
1589
2424
  const [columns] = useStdoutDimensions();
1590
2425
  const progressItems = store.tasks.map((t) => ({
1591
2426
  label: t.label,
@@ -1655,6 +2490,7 @@ const RunScreen = ({ store }) => {
1655
2490
  *
1656
2491
  * When done, calls store.setSkillsComplete() and exits the process.
1657
2492
  */
2493
+ const WIZARD_MARKER = ".posthog-wizard";
1658
2494
  const KeepSkillsScreen = ({ store }) => {
1659
2495
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
1660
2496
  const [phase, setPhase] = useState("loading");
@@ -1666,7 +2502,12 @@ const KeepSkillsScreen = ({ store }) => {
1666
2502
  const dirs = (await readdir(skillsDir, { withFileTypes: true })).filter((e) => e.isDirectory());
1667
2503
  const result = [];
1668
2504
  for (const dir of dirs) {
1669
- 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);
1670
2511
  result.push({
1671
2512
  name: dir.name,
1672
2513
  children
@@ -1690,8 +2531,14 @@ const KeepSkillsScreen = ({ store }) => {
1690
2531
  };
1691
2532
  const handleRemove = async () => {
1692
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 {}
1693
2540
  try {
1694
- await rm(skillsDir, {
2541
+ if ((await readdir(skillsDir)).length === 0) await rm(skillsDir, {
1695
2542
  recursive: true,
1696
2543
  force: true
1697
2544
  });
@@ -1717,7 +2564,7 @@ const KeepSkillsScreen = ({ store }) => {
1717
2564
  dimColor: true,
1718
2565
  children: "Checking installed skills..."
1719
2566
  }),
1720
- phase === "ask" && /* @__PURE__ */ jsxs(Fragment, { children: [
2567
+ phase === "ask" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1721
2568
  /* @__PURE__ */ jsx(Text, {
1722
2569
  dimColor: true,
1723
2570
  children: "The wizard installed open-source skills that help AI coding agents integrate PostHog into your project:"
@@ -1787,9 +2634,11 @@ const KeepSkillsScreen = ({ store }) => {
1787
2634
  //#endregion
1788
2635
  //#region src/ui/tui/screens/OutroScreen.tsx
1789
2636
  /**
1790
- * OutroScreen — Summary after the agent run.
1791
- * Reads store.session.outroData to render success, error, or cancel view.
1792
- * 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).
1793
2642
  */
1794
2643
  const OutroScreen = ({ store }) => {
1795
2644
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
@@ -1815,11 +2664,14 @@ const OutroScreen = ({ store }) => {
1815
2664
  /* @__PURE__ */ jsxs(Text, {
1816
2665
  color: "green",
1817
2666
  bold: true,
1818
- children: [
1819
- "✔",
1820
- " ",
1821
- outroData.message || "Done!"
1822
- ]
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
+ })
1823
2675
  }),
1824
2676
  outroData.reportFile && /* @__PURE__ */ jsx(Box, {
1825
2677
  marginTop: 1,
@@ -1839,11 +2691,7 @@ const OutroScreen = ({ store }) => {
1839
2691
  color: "cyan",
1840
2692
  bold: true,
1841
2693
  children: "What the agent did:"
1842
- }), outroData.changes.map((change, i) => /* @__PURE__ */ jsxs(Text, { children: [
1843
- "•",
1844
- " ",
1845
- change
1846
- ] }, i))]
2694
+ }), outroData.changes.map((change, i) => /* @__PURE__ */ jsxs(Text, { children: ["• ", change] }, i))]
1847
2695
  }),
1848
2696
  store.eventPlan.length > 0 && /* @__PURE__ */ jsxs(Box, {
1849
2697
  flexDirection: "column",
@@ -1853,8 +2701,7 @@ const OutroScreen = ({ store }) => {
1853
2701
  bold: true,
1854
2702
  children: "Events added:"
1855
2703
  }), store.eventPlan.map((event) => /* @__PURE__ */ jsxs(Text, { children: [
1856
- "•",
1857
- " ",
2704
+ "• ",
1858
2705
  /* @__PURE__ */ jsx(Text, {
1859
2706
  bold: true,
1860
2707
  children: event.name
@@ -1887,10 +2734,10 @@ const OutroScreen = ({ store }) => {
1887
2734
  children: "Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made."
1888
2735
  })
1889
2736
  }),
1890
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, {
2737
+ /* @__PURE__ */ jsx(Text, {
1891
2738
  dimColor: true,
1892
2739
  children: "How did this work for you? Drop us a line: wizard@posthog.com"
1893
- }) })
2740
+ })
1894
2741
  ]
1895
2742
  }),
1896
2743
  outroData.kind === "error" && /* @__PURE__ */ jsxs(Box, {
@@ -1899,11 +2746,7 @@ const OutroScreen = ({ store }) => {
1899
2746
  /* @__PURE__ */ jsxs(Text, {
1900
2747
  color: "red",
1901
2748
  bold: true,
1902
- children: [
1903
- "✘",
1904
- " ",
1905
- outroData.message || "An error occurred"
1906
- ]
2749
+ children: ["✘ ", outroData.message || "An error occurred"]
1907
2750
  }),
1908
2751
  outroData.body && /* @__PURE__ */ jsx(Box, {
1909
2752
  marginTop: 1,
@@ -1925,11 +2768,7 @@ const OutroScreen = ({ store }) => {
1925
2768
  flexDirection: "column",
1926
2769
  children: /* @__PURE__ */ jsxs(Text, {
1927
2770
  color: "yellow",
1928
- children: [
1929
- "■",
1930
- " ",
1931
- outroData.message || "Cancelled"
1932
- ]
2771
+ children: ["■ ", outroData.message || "Cancelled"]
1933
2772
  })
1934
2773
  }),
1935
2774
  /* @__PURE__ */ jsx(Box, {
@@ -2080,6 +2919,9 @@ function createScreens(store, services) {
2080
2919
  ["intro"]: /* @__PURE__ */ jsx(PostHogIntegrationIntroScreen, { store }),
2081
2920
  ["revenue-intro"]: /* @__PURE__ */ jsx(RevenueIntroScreen, { store }),
2082
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 }),
2083
2925
  ["health-check"]: /* @__PURE__ */ jsx(HealthCheckScreen, { store }),
2084
2926
  ["doctor-intro"]: /* @__PURE__ */ jsx(DoctorIntroScreen, { store }),
2085
2927
  ["doctor-report"]: /* @__PURE__ */ jsx(DoctorReportScreen, { store }),
@@ -2137,7 +2979,10 @@ function releaseTerminal() {
2137
2979
  function getExitLine(store) {
2138
2980
  const outro = store.session.outroData;
2139
2981
  const label = store.session.workflowLabel ?? "Wizard";
2140
- 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
+ }
2141
2986
  return `${DIM}${label} exited.${RESET_ATTRS}`;
2142
2987
  }
2143
2988
  function startTUI(version, flow = "posthog-integration") {
@@ -2164,4 +3009,4 @@ function startTUI(version, flow = "posthog-integration") {
2164
3009
  //#endregion
2165
3010
  export { startTUI };
2166
3011
 
2167
- //# sourceMappingURL=start-tui-CQef69NR.js.map
3012
+ //# sourceMappingURL=start-tui-DleQG3La.js.map