@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.
- package/README.md +48 -7
- package/dist/{McpScreen-LqnNwEfV.js → AuditChecksViewer-DsfXIO9e.js} +475 -36
- package/dist/AuditChecksViewer-DsfXIO9e.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-lfUH2pdU.js → add-mcp-server-to-clients-BKoew3aT.js} +157 -125
- package/dist/add-mcp-server-to-clients-BKoew3aT.js.map +1 -0
- package/dist/{readiness-Cep84RsR.js → agent-interface-D5W9BAB2.js} +329 -464
- package/dist/agent-interface-D5W9BAB2.js.map +1 -0
- package/dist/{agent-runner-DHtcWn15.js → agent-runner-B8Cx6X6x.js} +22 -31
- package/dist/agent-runner-B8Cx6X6x.js.map +1 -0
- package/dist/analytics-DmD31Ssc.js +123 -0
- package/dist/analytics-DmD31Ssc.js.map +1 -0
- package/dist/analytics-JDitS2JI.js +2 -0
- package/dist/bin.js +521 -46
- package/dist/bin.js.map +1 -1
- package/dist/debug-Bkaqv1ab.js +686 -0
- package/dist/debug-Bkaqv1ab.js.map +1 -0
- package/dist/{debug-CIyf0ZGx.js → debug-I5sRZubJ.js} +1 -1
- package/dist/{defaults-DoVkE0gW.js → defaults-GbLPuHxj.js} +8 -8
- package/dist/defaults-GbLPuHxj.js.map +1 -0
- package/dist/detection-C_RfYYDe.js +206 -0
- package/dist/detection-C_RfYYDe.js.map +1 -0
- package/dist/{env-api-key-K8TdTDII.js → env-api-key-D5G2PrXW.js} +1 -1
- package/dist/{env-api-key-K8TdTDII.js.map → env-api-key-D5G2PrXW.js.map} +1 -1
- package/dist/file-8iNrXHkG.js +16 -0
- package/dist/file-8iNrXHkG.js.map +1 -0
- package/dist/{file-utils-BWneZy6p.js → file-utils-DnTSiTJw.js} +1 -1
- package/dist/{file-utils-BWneZy6p.js.map → file-utils-DnTSiTJw.js.map} +1 -1
- package/dist/package-json-BzVey4Bd.js +2 -0
- package/dist/{package-json-Ctq6LSl8.js → package-json-F_7oktsp.js} +1 -1
- package/dist/{package-json-Ctq6LSl8.js.map → package-json-F_7oktsp.js.map} +1 -1
- package/dist/{package-manager-CwU26DwX.js → package-manager-qxP2PpM_.js} +2 -2
- package/dist/{package-manager-CwU26DwX.js.map → package-manager-qxP2PpM_.js.map} +1 -1
- package/dist/paths-DJS47p5x.js +26 -0
- package/dist/paths-DJS47p5x.js.map +1 -0
- package/dist/{posthog-integration-HBDZrREG.js → posthog-integration-DX77Msto.js} +43 -14
- package/dist/posthog-integration-DX77Msto.js.map +1 -0
- package/dist/posthog-vm0k9PKS.js +11 -0
- package/dist/posthog-vm0k9PKS.js.map +1 -0
- package/dist/provisioning-CHfTOEvg.js +2 -0
- package/dist/provisioning-DUj285NO.js +166 -0
- package/dist/provisioning-DUj285NO.js.map +1 -0
- package/dist/{registry-BIV1wRpo.js → registry-CCtIsqb8.js} +5 -6
- package/dist/{registry-BIV1wRpo.js.map → registry-CCtIsqb8.js.map} +1 -1
- package/dist/{router-CXjdWNh2.js → router-BTfmEDDJ.js} +4 -3
- package/dist/router-BTfmEDDJ.js.map +1 -0
- package/dist/{setup-utils-CHojnr4N.js → setup-utils-Bv8z6HMb.js} +17 -150
- package/dist/setup-utils-Bv8z6HMb.js.map +1 -0
- package/dist/setup-utils-CoX-vLgw.js +2 -0
- package/dist/{start-playground-D1iLBvqF.js → start-playground-DYNQ8rOz.js} +181 -9
- package/dist/start-playground-DYNQ8rOz.js.map +1 -0
- package/dist/{start-tui-DkT_H5zx.js → start-tui-DleQG3La.js} +1290 -163
- package/dist/start-tui-DleQG3La.js.map +1 -0
- package/dist/{steps-zpqG7W08.js → steps-C-syS8if.js} +8 -8
- package/dist/steps-C-syS8if.js.map +1 -0
- package/dist/task-stream-CX7Uf6EM.js +61 -0
- package/dist/task-stream-CX7Uf6EM.js.map +1 -0
- package/dist/{telemetry-CPoSyK0a.js → telemetry-DHZfjgqx.js} +2 -2
- package/dist/{telemetry-CPoSyK0a.js.map → telemetry-DHZfjgqx.js.map} +1 -1
- package/dist/{wizard-abort-BcEPhAxY.js → wizard-abort-DIhFXJ5N.js} +1 -1
- package/dist/{wizard-abort-DKctLd33.js → wizard-abort-DfhWuzaw.js} +6 -4
- package/dist/{wizard-abort-DKctLd33.js.map → wizard-abort-DfhWuzaw.js.map} +1 -1
- package/dist/wizard-session-BQC9vy9Z.js +2 -0
- package/dist/{wizard-session-Db6R023m.js → wizard-session-BcNJTl2I.js} +1 -1
- package/dist/{wizard-session-Db6R023m.js.map → wizard-session-BcNJTl2I.js.map} +1 -1
- package/dist/wizard-ui-YdGFRyu_.js +14 -0
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/McpScreen-LqnNwEfV.js.map +0 -1
- package/dist/add-mcp-server-to-clients-lfUH2pdU.js.map +0 -1
- package/dist/agent-runner-DHtcWn15.js.map +0 -1
- package/dist/agent-skill-BVjJqol6.js +0 -59
- package/dist/agent-skill-BVjJqol6.js.map +0 -1
- package/dist/analytics-Cm6i5_gc.js +0 -207
- package/dist/analytics-Cm6i5_gc.js.map +0 -1
- package/dist/analytics-CviQ_A9M.js +0 -2
- package/dist/debug-CyJ_3dTP.js +0 -201
- package/dist/debug-CyJ_3dTP.js.map +0 -1
- package/dist/defaults-DoVkE0gW.js.map +0 -1
- package/dist/detection-gcQwPKPu.js +0 -122
- package/dist/detection-gcQwPKPu.js.map +0 -1
- package/dist/package-json-BQgl5C3Z.js +0 -2
- package/dist/posthog-integration-HBDZrREG.js.map +0 -1
- package/dist/readiness-Cep84RsR.js.map +0 -1
- package/dist/router-CXjdWNh2.js.map +0 -1
- package/dist/setup-utils-CHojnr4N.js.map +0 -1
- package/dist/start-playground-D1iLBvqF.js.map +0 -1
- package/dist/start-tui-DkT_H5zx.js.map +0 -1
- package/dist/steps-zpqG7W08.js.map +0 -1
- package/dist/wizard-session-y7nf6aKH.js +0 -2
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import { l as setUI, s as logToFile } from "./debug-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import "./
|
|
10
|
-
import {
|
|
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 {
|
|
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
|
-
|
|
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
|
|
178
|
-
|
|
179
|
-
const
|
|
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 =
|
|
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
|
|
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:
|
|
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-
|
|
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 [
|
|
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 &&
|
|
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 (
|
|
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__ */
|
|
1004
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
669
1005
|
flexDirection: "column",
|
|
670
1006
|
marginTop: 1,
|
|
671
|
-
children: /* @__PURE__ */
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
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 (
|
|
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")
|
|
770
|
-
else if (value === "
|
|
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:
|
|
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 —
|
|
1416
|
+
* AgentSkillIntroScreen — Default intro for generic agent-skill workflows.
|
|
1063
1417
|
*
|
|
1064
|
-
*
|
|
1065
|
-
*
|
|
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
|
|
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__ */
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
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:
|
|
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/
|
|
1179
|
-
|
|
1180
|
-
|
|
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
|
|
1189
|
-
const
|
|
1190
|
-
const
|
|
1191
|
-
const
|
|
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
|
-
|
|
1207
|
-
children:
|
|
1208
|
-
|
|
1209
|
-
|
|
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 —
|
|
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
|
-
*
|
|
1319
|
-
*
|
|
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:
|
|
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
|
-
|
|
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 —
|
|
1526
|
-
*
|
|
1527
|
-
*
|
|
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
|
-
|
|
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(
|
|
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) => ({
|
|
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")
|
|
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
|
-
|
|
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-
|
|
3012
|
+
//# sourceMappingURL=start-tui-DleQG3La.js.map
|