@posthog/wizard 2.23.0 → 2.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -2
- package/dist/{AiOptInRequiredScreen-BOMyYFep.js → AiOptInRequiredScreen-_33FOcVo.js} +148 -685
- package/dist/AiOptInRequiredScreen-_33FOcVo.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-BEziI3z9.js → add-mcp-server-to-clients-CfwEQT_z.js} +4 -4
- package/dist/{add-mcp-server-to-clients-BEziI3z9.js.map → add-mcp-server-to-clients-CfwEQT_z.js.map} +1 -1
- package/dist/{agent-interface-DjMPlXl0.js → agent-interface-D1vtN6Wn.js} +6 -7
- package/dist/agent-interface-D1vtN6Wn.js.map +1 -0
- package/dist/{agent-runner-Bv-7z-pQ.js → agent-runner-CBbkS0Ro.js} +8 -8
- package/dist/{agent-runner-Bv-7z-pQ.js.map → agent-runner-CBbkS0Ro.js.map} +1 -1
- package/dist/{analytics-9D4eGgmT.js → analytics-CUr82BDl.js} +11 -2
- package/dist/{analytics-9D4eGgmT.js.map → analytics-CUr82BDl.js.map} +1 -1
- package/dist/{api-Dwd0B-E9.js → api-CI3Z74NG.js} +3 -3
- package/dist/{api-Dwd0B-E9.js.map → api-CI3Z74NG.js.map} +1 -1
- package/dist/bin.js +887 -465
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-DGXCpvKh.js → ci-install-D_kxNmbJ.js} +5 -5
- package/dist/{ci-install-DGXCpvKh.js.map → ci-install-D_kxNmbJ.js.map} +1 -1
- package/dist/{debug-CgT5MmVB.js → debug-DxA_f5QT.js} +2 -2
- package/dist/{debug-CgT5MmVB.js.map → debug-DxA_f5QT.js.map} +1 -1
- package/dist/{debug-DayHBBST.js → debug-zMvpNYb2.js} +1 -1
- package/dist/{environment-CI2pTYTG.js → environment-CyS37cmM.js} +3 -3
- package/dist/{environment-CI2pTYTG.js.map → environment-CyS37cmM.js.map} +1 -1
- package/dist/{interactive-D52p_opJ.js → interactive-CG6FFqSw.js} +3 -3
- package/dist/{interactive-D52p_opJ.js.map → interactive-CG6FFqSw.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-tdoy9UJ2.js → mcp-prompt-streaming-DQz4FSb1.js} +4 -4
- package/dist/{mcp-prompt-streaming-tdoy9UJ2.js.map → mcp-prompt-streaming-DQz4FSb1.js.map} +1 -1
- package/dist/{non-interactive-6hadW20x.js → non-interactive-DWtHX3ZR.js} +2 -2
- package/dist/{non-interactive-6hadW20x.js.map → non-interactive-DWtHX3ZR.js.map} +1 -1
- package/dist/{package-manager-BI0J5E7t.js → package-manager-BWUS4CP0.js} +2 -2
- package/dist/{package-manager-BI0J5E7t.js.map → package-manager-BWUS4CP0.js.map} +1 -1
- package/dist/{playground-z4A5dHPv.js → playground-D7AhMMF5.js} +9 -20
- package/dist/playground-D7AhMMF5.js.map +1 -0
- package/dist/{posthog-integration-BWbZU9Xq.js → posthog-integration-DexZ2uHU.js} +18 -18
- package/dist/{posthog-integration-BWbZU9Xq.js.map → posthog-integration-DexZ2uHU.js.map} +1 -1
- package/dist/{provisioning-B30Be2NA.js → provisioning-9c-AQbsa.js} +3 -3
- package/dist/{provisioning-B30Be2NA.js.map → provisioning-9c-AQbsa.js.map} +1 -1
- package/dist/{registry-CD_DplSQ.js → registry-CO7JVZyE.js} +4 -4
- package/dist/{registry-CD_DplSQ.js.map → registry-CO7JVZyE.js.map} +1 -1
- package/dist/{setup-utils-Dwgkk8AQ.js → setup-utils-0U-_Md2G.js} +8 -8
- package/dist/{setup-utils-Dwgkk8AQ.js.map → setup-utils-0U-_Md2G.js.map} +1 -1
- package/dist/{start-tui-SLeEzlJs.js → start-tui-WNb3ET14.js} +206 -1205
- package/dist/start-tui-WNb3ET14.js.map +1 -0
- package/dist/{steps-B1gzyRkC.js → steps-BAUXDCC4.js} +6 -6
- package/dist/{steps-B1gzyRkC.js.map → steps-BAUXDCC4.js.map} +1 -1
- package/dist/{telemetry-5rkeTd2_.js → telemetry-ycqCpNPr.js} +3 -3
- package/dist/{telemetry-5rkeTd2_.js.map → telemetry-ycqCpNPr.js.map} +1 -1
- package/dist/{urls-Cb4SI9kf.js → urls-C8aJWvgh.js} +2 -2
- package/dist/{urls-Cb4SI9kf.js.map → urls-C8aJWvgh.js.map} +1 -1
- package/dist/{wizard-abort-DovHQa-j.js → wizard-abort-C6gRLxUE.js} +3 -3
- package/dist/{wizard-abort-DovHQa-j.js.map → wizard-abort-C6gRLxUE.js.map} +1 -1
- package/dist/{wizard-abort-DW2-ZjiS.js → wizard-abort-DWXyJdws.js} +1 -1
- package/package.json +1 -1
- package/dist/AiOptInRequiredScreen-BOMyYFep.js.map +0 -1
- package/dist/agent-interface-DjMPlXl0.js.map +0 -1
- package/dist/playground-z4A5dHPv.js.map +0 -1
- package/dist/start-tui-SLeEzlJs.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as VERSION, P as POSTHOG_DOCS_URL, Y as WIZARD_USER_AGENT, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, h as LoggingUI, m as setUI, p as getUI, s as logToFile, v as evaluateWizardReadiness, y as getBlockingServiceKeys } from "./debug-
|
|
3
|
-
import { t as analytics } from "./analytics-
|
|
4
|
-
import { r as setEntryCommand } from "./telemetry-
|
|
5
|
-
import { n as isUsingTypeScript
|
|
6
|
-
import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-
|
|
7
|
-
import { o as handleApiError } from "./api-
|
|
2
|
+
import { $ as VERSION, P as POSTHOG_DOCS_URL, Q as getSkillsBaseUrl, Y as WIZARD_USER_AGENT, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, h as LoggingUI, m as setUI, p as getUI, s as logToFile, v as evaluateWizardReadiness, y as getBlockingServiceKeys } from "./debug-DxA_f5QT.js";
|
|
3
|
+
import { t as analytics } from "./analytics-CUr82BDl.js";
|
|
4
|
+
import { r as setEntryCommand } from "./telemetry-ycqCpNPr.js";
|
|
5
|
+
import { n as isUsingTypeScript } from "./setup-utils-0U-_Md2G.js";
|
|
6
|
+
import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-C8aJWvgh.js";
|
|
7
|
+
import { o as handleApiError } from "./api-CI3Z74NG.js";
|
|
8
8
|
import "./wizard-session-G3VWD6hv.js";
|
|
9
|
-
import { r as runCleanups } from "./wizard-abort-
|
|
10
|
-
import { n as isNonInteractiveEnvironment } from "./environment-
|
|
11
|
-
import { _ as AUDIT_CHECKS_KEY, f as WIZARD_TOOL_NAMES, g as AUDIT_CHECKS_FILE, l as AgentSignals, s as recoverOrphanedSettingsBackups, v as AUDIT_REPORT_FILE } from "./agent-interface-
|
|
12
|
-
import { i as SPINNER_MESSAGE } from "./registry-
|
|
13
|
-
import { a as PRODUCT_SUITE_BLOCK, f as Colors, i as LINE_CHART_BLOCK, l as isClearBlock, m as HEALTH_CHECK_STEP, n as posthogIntegrationConfig, o as StatusPeekTrigger, r as FUNNEL_BLOCK } from "./posthog-integration-
|
|
9
|
+
import { r as runCleanups } from "./wizard-abort-C6gRLxUE.js";
|
|
10
|
+
import { n as isNonInteractiveEnvironment } from "./environment-CyS37cmM.js";
|
|
11
|
+
import { _ as AUDIT_CHECKS_KEY, f as WIZARD_TOOL_NAMES, g as AUDIT_CHECKS_FILE, l as AgentSignals, m as fetchSkillMenu, s as recoverOrphanedSettingsBackups, v as AUDIT_REPORT_FILE } from "./agent-interface-D1vtN6Wn.js";
|
|
12
|
+
import { i as SPINNER_MESSAGE } from "./registry-CO7JVZyE.js";
|
|
13
|
+
import { a as PRODUCT_SUITE_BLOCK, f as Colors, i as LINE_CHART_BLOCK, l as isClearBlock, m as HEALTH_CHECK_STEP, n as posthogIntegrationConfig, o as StatusPeekTrigger, p as Icons, r as FUNNEL_BLOCK } from "./posthog-integration-DexZ2uHU.js";
|
|
14
14
|
import { t as IGNORED_DIRS } from "./file-utils-VAXoyXVA.js";
|
|
15
15
|
import { n as readApiKeyFromEnv } from "./env-api-key-MlzJYAvt.js";
|
|
16
16
|
import { satisfies } from "semver";
|
|
@@ -20,7 +20,8 @@ import fs, { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
|
20
20
|
import path, { join, relative } from "path";
|
|
21
21
|
import axios from "axios";
|
|
22
22
|
import { z } from "zod";
|
|
23
|
-
import { Text } from "ink";
|
|
23
|
+
import { Box, Text, render, useInput } from "ink";
|
|
24
|
+
import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
24
25
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
25
26
|
//#region src/commands/command.ts
|
|
26
27
|
/** Extract the bare command word(s) from a yargs name spec, dropping positionals and aliases' arg syntax. */
|
|
@@ -34,16 +35,17 @@ function toCommandModule(cmd, parentPath) {
|
|
|
34
35
|
describe: cmd.description,
|
|
35
36
|
builder: (y) => {
|
|
36
37
|
let next = cmd.options ? y.options(cmd.options) : y;
|
|
38
|
+
for (const [key, opts] of Object.entries(cmd.positionals ?? {})) next = next.positional(key, opts);
|
|
37
39
|
if (cmd.check) next = next.check(cmd.check);
|
|
38
40
|
for (const [usage, description] of cmd.examples ?? []) next = next.example(usage, description);
|
|
39
41
|
const ownPath = [...parentPath, commandKeys(cmd.name)[0]];
|
|
40
42
|
for (const child of cmd.children ?? []) next = next.command(toCommandModule(child, ownPath));
|
|
41
|
-
if (cmd.children?.length && !cmd.handler) next = next.demandCommand(1);
|
|
43
|
+
if (cmd.children?.length && !cmd.handler && !cmd.interactiveDefault) next = next.demandCommand(1);
|
|
42
44
|
return next;
|
|
43
45
|
},
|
|
44
46
|
handler: (argv) => {
|
|
45
47
|
if (entryCommand) setEntryCommand(entryCommand);
|
|
46
|
-
cmd.handler
|
|
48
|
+
(cmd.handler ?? cmd.interactiveDefault ?? (() => void 0))(argv);
|
|
47
49
|
}
|
|
48
50
|
};
|
|
49
51
|
}
|
|
@@ -52,6 +54,10 @@ function toCommandModule(cmd, parentPath) {
|
|
|
52
54
|
/**
|
|
53
55
|
* Global yargs options applied to every command. These are read from the
|
|
54
56
|
* `POSTHOG_WIZARD` env prefix as well as flags.
|
|
57
|
+
*
|
|
58
|
+
* Options with `hidden: true` are "internal modes" — they don't show up in
|
|
59
|
+
* `--help` but are still accepted on every command. The catalog of internal
|
|
60
|
+
* flags and what each one does lives in CONTRIBUTING.md.
|
|
55
61
|
*/
|
|
56
62
|
const GLOBAL_OPTIONS = {
|
|
57
63
|
debug: {
|
|
@@ -69,11 +75,6 @@ const GLOBAL_OPTIONS = {
|
|
|
69
75
|
describe: "Create a new PostHog account during setup\nenv: POSTHOG_WIZARD_SIGNUP",
|
|
70
76
|
type: "boolean"
|
|
71
77
|
},
|
|
72
|
-
"local-mcp": {
|
|
73
|
-
default: false,
|
|
74
|
-
describe: "Use local MCP server at http://localhost:8787/mcp\nenv: POSTHOG_WIZARD_LOCAL_MCP",
|
|
75
|
-
type: "boolean"
|
|
76
|
-
},
|
|
77
78
|
telemetry: {
|
|
78
79
|
default: true,
|
|
79
80
|
describe: "Send wizard run state to PostHog (pass --no-telemetry to disable)\nenv: POSTHOG_WIZARD_TELEMETRY",
|
|
@@ -90,16 +91,33 @@ const GLOBAL_OPTIONS = {
|
|
|
90
91
|
email: {
|
|
91
92
|
describe: "Email address for signup (used with --signup)\nenv: POSTHOG_WIZARD_EMAIL",
|
|
92
93
|
type: "string"
|
|
94
|
+
},
|
|
95
|
+
"local-mcp": {
|
|
96
|
+
default: false,
|
|
97
|
+
describe: "Use local MCP server at http://localhost:8787/mcp\nenv: POSTHOG_WIZARD_LOCAL_MCP",
|
|
98
|
+
type: "boolean",
|
|
99
|
+
hidden: true
|
|
100
|
+
},
|
|
101
|
+
benchmark: {
|
|
102
|
+
default: false,
|
|
103
|
+
describe: "Run in benchmark mode with per-phase token tracking\nenv: POSTHOG_WIZARD_BENCHMARK",
|
|
104
|
+
type: "boolean",
|
|
105
|
+
hidden: true
|
|
106
|
+
},
|
|
107
|
+
"yara-report": {
|
|
108
|
+
default: false,
|
|
109
|
+
describe: "Print YARA scanner summary after the agent run\nenv: POSTHOG_WIZARD_YARA_REPORT",
|
|
110
|
+
type: "boolean",
|
|
111
|
+
hidden: true
|
|
93
112
|
}
|
|
94
113
|
};
|
|
95
114
|
var Wizard = class Wizard {
|
|
96
115
|
cli;
|
|
97
116
|
constructor() {
|
|
98
117
|
let cli = yargs(hideBin(process.argv)).env("POSTHOG_WIZARD").options(GLOBAL_OPTIONS);
|
|
99
|
-
this.cli = cli.strictOptions().fail((msg, err
|
|
118
|
+
this.cli = cli.strictOptions().strictCommands().fail((msg, err) => {
|
|
100
119
|
const text = msg || err && err.message || "Invalid arguments";
|
|
101
|
-
process.stderr.write(`\n\x1b[1;91m✖ ${text}\x1b[0m\n\n`);
|
|
102
|
-
parser.showHelp();
|
|
120
|
+
process.stderr.write(`\n\x1b[1;91m✖ ${text}\x1b[0m\n Run \`wizard --help\` to see available commands and options.\n\n`);
|
|
103
121
|
process.exit(1);
|
|
104
122
|
}).help().alias("help", "h").version().alias("version", "v");
|
|
105
123
|
}
|
|
@@ -166,7 +184,7 @@ function runProvision(argv) {
|
|
|
166
184
|
}
|
|
167
185
|
async function provision({ email, region, name, jsonMode }) {
|
|
168
186
|
try {
|
|
169
|
-
const { provisionNewAccount } = await import("./provisioning-
|
|
187
|
+
const { provisionNewAccount } = await import("./provisioning-9c-AQbsa.js").then((n) => n.n);
|
|
170
188
|
if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
|
|
171
189
|
emitResult(await provisionNewAccount(email, name, region), jsonMode);
|
|
172
190
|
process.exit(0);
|
|
@@ -212,25 +230,15 @@ const basicIntegrationCommand = {
|
|
|
212
230
|
describe: "Directory to install PostHog in\nenv: POSTHOG_WIZARD_INSTALL_DIR",
|
|
213
231
|
type: "string"
|
|
214
232
|
},
|
|
233
|
+
name: {
|
|
234
|
+
describe: "Name for account creation with --ci --signup\nenv: POSTHOG_WIZARD_NAME",
|
|
235
|
+
type: "string"
|
|
236
|
+
},
|
|
215
237
|
playground: {
|
|
216
238
|
default: false,
|
|
217
239
|
describe: "Launch the TUI primitives playground",
|
|
218
|
-
type: "boolean"
|
|
219
|
-
},
|
|
220
|
-
benchmark: {
|
|
221
|
-
default: false,
|
|
222
|
-
describe: "Run in benchmark mode with per-phase token tracking\nenv: POSTHOG_WIZARD_BENCHMARK",
|
|
223
|
-
type: "boolean"
|
|
224
|
-
},
|
|
225
|
-
"yara-report": {
|
|
226
|
-
default: false,
|
|
227
|
-
describe: "Print YARA scanner summary after the agent run\nenv: POSTHOG_WIZARD_YARA_REPORT",
|
|
228
240
|
type: "boolean",
|
|
229
241
|
hidden: true
|
|
230
|
-
},
|
|
231
|
-
name: {
|
|
232
|
-
describe: "Name for account creation with --ci --signup\nenv: POSTHOG_WIZARD_NAME",
|
|
233
|
-
type: "string"
|
|
234
242
|
}
|
|
235
243
|
},
|
|
236
244
|
check: (argv) => {
|
|
@@ -241,18 +249,18 @@ const basicIntegrationCommand = {
|
|
|
241
249
|
setEntryCommand("integrate");
|
|
242
250
|
(async () => {
|
|
243
251
|
if (argv.ci) {
|
|
244
|
-
const { runCIInstall } = await import("./ci-install-
|
|
252
|
+
const { runCIInstall } = await import("./ci-install-D_kxNmbJ.js");
|
|
245
253
|
return runCIInstall(argv);
|
|
246
254
|
}
|
|
247
255
|
if (isNonInteractiveEnvironment()) {
|
|
248
|
-
const { failNonInteractive } = await import("./non-interactive-
|
|
256
|
+
const { failNonInteractive } = await import("./non-interactive-DWtHX3ZR.js");
|
|
249
257
|
return failNonInteractive();
|
|
250
258
|
}
|
|
251
259
|
if (argv.playground) {
|
|
252
|
-
const { runPlayground } = await import("./playground-
|
|
260
|
+
const { runPlayground } = await import("./playground-D7AhMMF5.js");
|
|
253
261
|
return runPlayground();
|
|
254
262
|
}
|
|
255
|
-
const { runInteractive } = await import("./interactive-
|
|
263
|
+
const { runInteractive } = await import("./interactive-CG6FFqSw.js");
|
|
256
264
|
runInteractive(argv);
|
|
257
265
|
})();
|
|
258
266
|
}
|
|
@@ -473,9 +481,10 @@ const getContentBlocks$2 = (store) => {
|
|
|
473
481
|
//#endregion
|
|
474
482
|
//#region src/lib/programs/revenue-analytics/index.ts
|
|
475
483
|
const revenueAnalyticsConfig = {
|
|
476
|
-
command: "revenue",
|
|
484
|
+
command: "revenue-analytics",
|
|
477
485
|
description: "Set up PostHog revenue analytics (e.g. Stripe integration)",
|
|
478
486
|
id: "revenue-analytics-setup",
|
|
487
|
+
skillId: "revenue-analytics-setup",
|
|
479
488
|
steps: REVENUE_ANALYTICS_PROGRAM,
|
|
480
489
|
getContentBlocks: getContentBlocks$2,
|
|
481
490
|
allowedTools: ["Agent"],
|
|
@@ -678,7 +687,7 @@ const withAuditScreens = (steps) => steps.map((step) => {
|
|
|
678
687
|
} : step;
|
|
679
688
|
});
|
|
680
689
|
const auditSteps = withAuditScreens(AGENT_SKILL_STEPS);
|
|
681
|
-
const baseConfig
|
|
690
|
+
const baseConfig = createSkillProgram({
|
|
682
691
|
skillId: "audit",
|
|
683
692
|
command: "audit",
|
|
684
693
|
id: "audit",
|
|
@@ -695,8 +704,8 @@ const baseConfig$1 = createSkillProgram({
|
|
|
695
704
|
});
|
|
696
705
|
const auditRun = async (session) => {
|
|
697
706
|
seedBeforeAuditRun(session);
|
|
698
|
-
if (!baseConfig
|
|
699
|
-
const baseRun = typeof baseConfig
|
|
707
|
+
if (!baseConfig.run) throw new Error("Audit program has no run configuration.");
|
|
708
|
+
const baseRun = typeof baseConfig.run === "function" ? await baseConfig.run(session) : baseConfig.run;
|
|
700
709
|
return {
|
|
701
710
|
...baseRun,
|
|
702
711
|
buildOutroData: (sess, _credentials, cloudRegion) => {
|
|
@@ -715,7 +724,7 @@ const auditRun = async (session) => {
|
|
|
715
724
|
};
|
|
716
725
|
};
|
|
717
726
|
const auditConfig = {
|
|
718
|
-
...baseConfig
|
|
727
|
+
...baseConfig,
|
|
719
728
|
steps: auditSteps,
|
|
720
729
|
run: auditRun,
|
|
721
730
|
allowedTools: ["Agent"],
|
|
@@ -882,207 +891,6 @@ Project context:
|
|
|
882
891
|
}
|
|
883
892
|
};
|
|
884
893
|
//#endregion
|
|
885
|
-
//#region src/lib/programs/audit-3000/index.ts
|
|
886
|
-
const AUDIT3000_REPORT_FILE = "posthog-audit-3000-report.md";
|
|
887
|
-
const AUDIT3000_EXTRA_CHECKS = [
|
|
888
|
-
{
|
|
889
|
-
id: "event-naming-standardization",
|
|
890
|
-
area: "Event Quality",
|
|
891
|
-
label: "Event naming convention is consistent",
|
|
892
|
-
status: "pending"
|
|
893
|
-
},
|
|
894
|
-
{
|
|
895
|
-
id: "event-duplicates-and-bloat",
|
|
896
|
-
area: "Event Quality",
|
|
897
|
-
label: "No duplicate or bloated event capture",
|
|
898
|
-
status: "pending"
|
|
899
|
-
},
|
|
900
|
-
{
|
|
901
|
-
id: "event-quality-context-review",
|
|
902
|
-
area: "Event Quality",
|
|
903
|
-
label: "Event property context reviewed",
|
|
904
|
-
status: "pending"
|
|
905
|
-
},
|
|
906
|
-
{
|
|
907
|
-
id: "event-usage-coverage",
|
|
908
|
-
area: "Event Quality",
|
|
909
|
-
label: "Captured events match insights / dashboards usage",
|
|
910
|
-
status: "pending"
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
id: "stale-feature-flags-reviewed",
|
|
914
|
-
area: "Feature Flags",
|
|
915
|
-
label: "Stale feature flags reviewed",
|
|
916
|
-
status: "pending"
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
id: "replay-minimum-duration-set",
|
|
920
|
-
area: "Session Replay",
|
|
921
|
-
label: "Minimum duration set on init",
|
|
922
|
-
status: "pending"
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
id: "replay-mask-config",
|
|
926
|
-
area: "Session Replay",
|
|
927
|
-
label: "Mask config covers sensitive surfaces",
|
|
928
|
-
status: "pending"
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
id: "replay-disabled-in-test-envs",
|
|
932
|
-
area: "Session Replay",
|
|
933
|
-
label: "Disabled in test / CI environments",
|
|
934
|
-
status: "pending"
|
|
935
|
-
},
|
|
936
|
-
{
|
|
937
|
-
id: "replay-strict-minimum-duration",
|
|
938
|
-
area: "Session Replay",
|
|
939
|
-
label: "Strict minimum duration enforced",
|
|
940
|
-
status: "pending"
|
|
941
|
-
},
|
|
942
|
-
{
|
|
943
|
-
id: "replay-sampling-rate",
|
|
944
|
-
area: "Session Replay — Optimize",
|
|
945
|
-
label: "Sampling rate tuned for cost",
|
|
946
|
-
status: "pending"
|
|
947
|
-
},
|
|
948
|
-
{
|
|
949
|
-
id: "replay-triggers-configured",
|
|
950
|
-
area: "Session Replay — Optimize",
|
|
951
|
-
label: "Triggers configured (event / URL / flag)",
|
|
952
|
-
status: "pending"
|
|
953
|
-
},
|
|
954
|
-
{
|
|
955
|
-
id: "replay-network-recording-filtered",
|
|
956
|
-
area: "Session Replay — Optimize",
|
|
957
|
-
label: "Network recording filtered",
|
|
958
|
-
status: "pending"
|
|
959
|
-
},
|
|
960
|
-
{
|
|
961
|
-
id: "replay-mobile-sampling",
|
|
962
|
-
area: "Session Replay — Optimize",
|
|
963
|
-
label: "Mobile sampling configured",
|
|
964
|
-
status: "pending"
|
|
965
|
-
},
|
|
966
|
-
{
|
|
967
|
-
id: "expansion-product-analytics",
|
|
968
|
-
area: "Use Case: Expansion",
|
|
969
|
-
label: "Product analytics coverage",
|
|
970
|
-
status: "pending"
|
|
971
|
-
},
|
|
972
|
-
{
|
|
973
|
-
id: "expansion-error-tracking",
|
|
974
|
-
area: "Use Case: Expansion",
|
|
975
|
-
label: "Error tracking coverage",
|
|
976
|
-
status: "pending"
|
|
977
|
-
},
|
|
978
|
-
{
|
|
979
|
-
id: "expansion-llm-observability",
|
|
980
|
-
area: "Use Case: Expansion",
|
|
981
|
-
label: "LLM observability coverage",
|
|
982
|
-
status: "pending"
|
|
983
|
-
},
|
|
984
|
-
{
|
|
985
|
-
id: "expansion-session-replay",
|
|
986
|
-
area: "Use Case: Expansion",
|
|
987
|
-
label: "Session replay coverage",
|
|
988
|
-
status: "pending"
|
|
989
|
-
},
|
|
990
|
-
{
|
|
991
|
-
id: "expansion-feature-flags",
|
|
992
|
-
area: "Use Case: Expansion",
|
|
993
|
-
label: "Feature flags coverage",
|
|
994
|
-
status: "pending"
|
|
995
|
-
},
|
|
996
|
-
{
|
|
997
|
-
id: "expansion-surveys",
|
|
998
|
-
area: "Use Case: Expansion",
|
|
999
|
-
label: "Surveys coverage",
|
|
1000
|
-
status: "pending"
|
|
1001
|
-
},
|
|
1002
|
-
{
|
|
1003
|
-
id: "expansion-logs",
|
|
1004
|
-
area: "Use Case: Expansion",
|
|
1005
|
-
label: "Logs coverage",
|
|
1006
|
-
status: "pending"
|
|
1007
|
-
},
|
|
1008
|
-
{
|
|
1009
|
-
id: "expansion-web-analytics",
|
|
1010
|
-
area: "Use Case: Expansion",
|
|
1011
|
-
label: "Web analytics coverage",
|
|
1012
|
-
status: "pending"
|
|
1013
|
-
},
|
|
1014
|
-
{
|
|
1015
|
-
id: "customer-enrichment",
|
|
1016
|
-
area: "Additional Sections",
|
|
1017
|
-
label: "Customer enrichment (Harmonic + PDL)",
|
|
1018
|
-
status: "pending"
|
|
1019
|
-
},
|
|
1020
|
-
{
|
|
1021
|
-
id: "use-case-match",
|
|
1022
|
-
area: "Additional Sections",
|
|
1023
|
-
label: "Use-case match",
|
|
1024
|
-
status: "pending"
|
|
1025
|
-
},
|
|
1026
|
-
{
|
|
1027
|
-
id: "final-report",
|
|
1028
|
-
area: "Additional Sections",
|
|
1029
|
-
label: "Final audit report written",
|
|
1030
|
-
status: "pending"
|
|
1031
|
-
}
|
|
1032
|
-
];
|
|
1033
|
-
const AUDIT3000_SEED_CHECKS = [...AUDIT_SEED_CHECKS, ...AUDIT3000_EXTRA_CHECKS];
|
|
1034
|
-
const AUDIT3000_SCREEN_BY_STEP = {
|
|
1035
|
-
intro: "audit-3000-intro",
|
|
1036
|
-
run: "audit-3000-run",
|
|
1037
|
-
outro: "audit-3000-outro"
|
|
1038
|
-
};
|
|
1039
|
-
const seedAudit3000Ledger = (installDir) => {
|
|
1040
|
-
const target = path.join(installDir, AUDIT_CHECKS_FILE);
|
|
1041
|
-
const tmp = `${target}.tmp`;
|
|
1042
|
-
fs.writeFileSync(tmp, JSON.stringify(AUDIT3000_SEED_CHECKS, null, 2), "utf8");
|
|
1043
|
-
fs.renameSync(tmp, target);
|
|
1044
|
-
logToFile(`seedAudit3000Ledger: wrote ${AUDIT3000_SEED_CHECKS.length} entries to ${target}`);
|
|
1045
|
-
};
|
|
1046
|
-
const seedBeforeAudit3000Run = (session) => {
|
|
1047
|
-
seedAudit3000Ledger(session.installDir);
|
|
1048
|
-
session.frameworkContext[AUDIT_CHECKS_KEY] = AUDIT3000_SEED_CHECKS;
|
|
1049
|
-
};
|
|
1050
|
-
const withAudit3000Screens = (steps) => steps.map((step) => {
|
|
1051
|
-
const override = AUDIT3000_SCREEN_BY_STEP[step.id];
|
|
1052
|
-
return override ? {
|
|
1053
|
-
...step,
|
|
1054
|
-
screenId: override
|
|
1055
|
-
} : step;
|
|
1056
|
-
});
|
|
1057
|
-
const audit3000Steps = withAudit3000Screens(AGENT_SKILL_STEPS);
|
|
1058
|
-
const baseConfig = createSkillProgram({
|
|
1059
|
-
skillId: "audit-3000",
|
|
1060
|
-
command: "audit-3000",
|
|
1061
|
-
id: "audit-3000",
|
|
1062
|
-
description: "Audit an existing PostHog integration (v3000 — adds event quality, stale-flag hygiene, customer enrichment, use-case match)",
|
|
1063
|
-
integrationLabel: "audit-3000",
|
|
1064
|
-
customPrompt: "Run the audit-3000 skill end-to-end. Follow the step chain starting at references/1-version.md. Do not modify any project files — only create the final audit report and (when enrichment is enabled) the enrichment report.",
|
|
1065
|
-
successMessage: `Audit complete! View the report at ./${AUDIT3000_REPORT_FILE}`,
|
|
1066
|
-
reportFile: AUDIT3000_REPORT_FILE,
|
|
1067
|
-
docsUrl: "https://posthog.com/docs/product-analytics/best-practices",
|
|
1068
|
-
spinnerMessage: "Running PostHog Audit 3000...",
|
|
1069
|
-
estimatedDurationMinutes: 6,
|
|
1070
|
-
requires: ["posthog-integration"],
|
|
1071
|
-
abortCases: AUDIT_ABORT_CASES
|
|
1072
|
-
});
|
|
1073
|
-
const audit3000Run = async (session) => {
|
|
1074
|
-
seedBeforeAudit3000Run(session);
|
|
1075
|
-
if (!baseConfig.run) throw new Error("audit-3000 program has no run configuration.");
|
|
1076
|
-
return typeof baseConfig.run === "function" ? baseConfig.run(session) : baseConfig.run;
|
|
1077
|
-
};
|
|
1078
|
-
const audit3000Config = {
|
|
1079
|
-
...baseConfig,
|
|
1080
|
-
steps: audit3000Steps,
|
|
1081
|
-
run: audit3000Run,
|
|
1082
|
-
allowedTools: ["Agent"],
|
|
1083
|
-
disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk]
|
|
1084
|
-
};
|
|
1085
|
-
//#endregion
|
|
1086
894
|
//#region src/lib/programs/posthog-doctor/steps.ts
|
|
1087
895
|
const POSTHOG_DOCTOR_PROGRAM = [
|
|
1088
896
|
{
|
|
@@ -1845,32 +1653,19 @@ const MIGRATION_ABORT_CASES = [{
|
|
|
1845
1653
|
message: "No source-SDK calls found",
|
|
1846
1654
|
body: "The migration needs an existing third-party SDK to migrate from. No calls to the source SDK appear anywhere in this project. If you haven't installed PostHog yet, you don't need this command — run `npx @posthog/wizard@latest` to add PostHog from scratch."
|
|
1847
1655
|
}];
|
|
1848
|
-
|
|
1849
|
-
* Map each `--product=<id>` choice to the context-mill skill ID that handles
|
|
1850
|
-
* it. Adding a variant: drop a new row here. The CLI `choices` and the
|
|
1851
|
-
* runtime lookup both read from this map, so the two stay in sync.
|
|
1852
|
-
*/
|
|
1853
|
-
const PRODUCT_TO_SKILL_ID = { statsig: "migrate-statsig" };
|
|
1854
|
-
const MIGRATE_PRODUCTS = Object.keys(PRODUCT_TO_SKILL_ID);
|
|
1656
|
+
const DEFAULT_MIGRATE_SKILL_ID = "migrate-statsig";
|
|
1855
1657
|
const migrationConfig = {
|
|
1856
1658
|
command: "migrate",
|
|
1857
1659
|
description: "Migrate to PostHog from another analytics provider",
|
|
1858
1660
|
id: "migration",
|
|
1859
|
-
skillId:
|
|
1661
|
+
skillId: DEFAULT_MIGRATE_SKILL_ID,
|
|
1860
1662
|
steps: MIGRATION_PROGRAM,
|
|
1861
1663
|
reportFile: MIGRATION_REPORT_FILE,
|
|
1862
1664
|
getContentBlocks: getContentBlocks$1,
|
|
1863
1665
|
allowedTools: ["Agent"],
|
|
1864
1666
|
disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],
|
|
1865
|
-
cliOptions: { product: {
|
|
1866
|
-
describe: "Source SDK to migrate from",
|
|
1867
|
-
type: "string",
|
|
1868
|
-
choices: MIGRATE_PRODUCTS,
|
|
1869
|
-
demandOption: true
|
|
1870
|
-
} },
|
|
1871
|
-
mapCliOptions: (argv) => ({ skillId: PRODUCT_TO_SKILL_ID[argv.product] }),
|
|
1872
1667
|
run: {
|
|
1873
|
-
skillId:
|
|
1668
|
+
skillId: DEFAULT_MIGRATE_SKILL_ID,
|
|
1874
1669
|
integrationLabel: "migration",
|
|
1875
1670
|
customPrompt: () => `Migrate this project from its existing third-party analytics, feature-flag, and observability tools to PostHog. Run the \`migrate\` skill end-to-end: follow the step chain starting at references/1-presence.md. Only replace existing source-SDK call sites with PostHog equivalents — make zero unrelated changes and no net-new instrumentation. The final report is written to ./${MIGRATION_REPORT_FILE}.`,
|
|
1876
1671
|
successMessage: `Migration complete! View the report at ./${MIGRATION_REPORT_FILE}`,
|
|
@@ -2680,19 +2475,19 @@ const mcpAddConfig = {
|
|
|
2680
2475
|
screenId: "mcp-add",
|
|
2681
2476
|
isComplete: (s) => s.mcpComplete
|
|
2682
2477
|
},
|
|
2683
|
-
{
|
|
2684
|
-
id: "mcp-suggested-prompts",
|
|
2685
|
-
label: "Suggested prompts",
|
|
2686
|
-
screenId: "mcp-suggested-prompts",
|
|
2687
|
-
show: (s) => s.mcpOutcome === "installed",
|
|
2688
|
-
isComplete: (s) => s.mcpSuggestedPromptsDismissed
|
|
2689
|
-
},
|
|
2690
2478
|
{
|
|
2691
2479
|
id: "slack-connect",
|
|
2692
2480
|
label: "Connect Slack",
|
|
2693
2481
|
screenId: "slack-connect",
|
|
2694
2482
|
show: (s) => s.mcpOutcome === "installed",
|
|
2695
2483
|
isComplete: (s) => s.slackStepDismissed
|
|
2484
|
+
},
|
|
2485
|
+
{
|
|
2486
|
+
id: "mcp-suggested-prompts",
|
|
2487
|
+
label: "Suggested prompts",
|
|
2488
|
+
screenId: "mcp-suggested-prompts",
|
|
2489
|
+
show: (s) => s.mcpOutcome === "installed",
|
|
2490
|
+
isComplete: (s) => s.mcpSuggestedPromptsDismissed
|
|
2696
2491
|
}
|
|
2697
2492
|
]
|
|
2698
2493
|
};
|
|
@@ -2700,10 +2495,10 @@ const mcpAddConfig = {
|
|
|
2700
2495
|
* `wizard mcp remove` — single-step uninstall flow.
|
|
2701
2496
|
*
|
|
2702
2497
|
* DO NOT append `mcp-suggested-prompts` (or any other tutorial-shaped
|
|
2703
|
-
* step) here. A user who just removed MCP is opting OUT of the agent
|
|
2704
|
-
*
|
|
2705
|
-
*
|
|
2706
|
-
*
|
|
2498
|
+
* step) here. A user who just removed MCP is opting OUT of the agent having
|
|
2499
|
+
* access to PostHog; immediately pivoting into a tutorial that asks
|
|
2500
|
+
* them to log in and try prompts is wrong on intent and confusing on
|
|
2501
|
+
* UX. The screen also reads `session.mcpInstalledClients` for its
|
|
2707
2502
|
* Choose-phase copy ("MCP is installed for X") — that array is empty
|
|
2708
2503
|
* post-remove, so the copy would be a lie.
|
|
2709
2504
|
*
|
|
@@ -2756,39 +2551,9 @@ const slackConnectConfig = {
|
|
|
2756
2551
|
id: "slack-connect",
|
|
2757
2552
|
label: "Connect Slack",
|
|
2758
2553
|
screenId: "slack-connect",
|
|
2759
|
-
isComplete: (s) => s.slackStepDismissed
|
|
2760
|
-
onInit: loginForSlackConnect
|
|
2554
|
+
isComplete: (s) => s.slackStepDismissed
|
|
2761
2555
|
}]
|
|
2762
2556
|
};
|
|
2763
|
-
/** OAuth for the standalone flow. The screen shows the auth-wait state
|
|
2764
|
-
* (and the login URL) until the credentials land in the store. */
|
|
2765
|
-
function loginForSlackConnect() {
|
|
2766
|
-
(async () => {
|
|
2767
|
-
try {
|
|
2768
|
-
const data = await getOrAskForProjectData({
|
|
2769
|
-
signup: false,
|
|
2770
|
-
ci: false,
|
|
2771
|
-
apiKey: void 0,
|
|
2772
|
-
projectId: void 0,
|
|
2773
|
-
programId: "slack"
|
|
2774
|
-
});
|
|
2775
|
-
const ui = getUI();
|
|
2776
|
-
ui.setCredentials({
|
|
2777
|
-
accessToken: data.accessToken,
|
|
2778
|
-
projectApiKey: data.projectApiKey,
|
|
2779
|
-
host: data.host,
|
|
2780
|
-
projectId: data.projectId
|
|
2781
|
-
});
|
|
2782
|
-
ui.setRoleAtOrganization(data.roleAtOrganization);
|
|
2783
|
-
ui.setApiUser(data.user);
|
|
2784
|
-
ui.setLoginUrl(null);
|
|
2785
|
-
} catch (err) {
|
|
2786
|
-
analytics.captureException(err instanceof Error ? err : new Error(String(err)), { step: "slack_connect_login" });
|
|
2787
|
-
getUI().log.error(`Login failed. ${err instanceof Error ? err.message : String(err)}`);
|
|
2788
|
-
process.exit(1);
|
|
2789
|
-
}
|
|
2790
|
-
})();
|
|
2791
|
-
}
|
|
2792
2557
|
//#endregion
|
|
2793
2558
|
//#region src/lib/programs/program-registry.ts
|
|
2794
2559
|
const agentSkillConfig = {
|
|
@@ -2796,7 +2561,19 @@ const agentSkillConfig = {
|
|
|
2796
2561
|
description: "Run an arbitrary context-mill skill",
|
|
2797
2562
|
steps: AGENT_SKILL_STEPS,
|
|
2798
2563
|
getContentBlocks: getContentBlocks$2,
|
|
2799
|
-
allowedTools: ["Agent"]
|
|
2564
|
+
allowedTools: ["Agent"],
|
|
2565
|
+
run: (session) => {
|
|
2566
|
+
const skillId = session.skillId ?? "agent-skill";
|
|
2567
|
+
return Promise.resolve({
|
|
2568
|
+
skillId,
|
|
2569
|
+
integrationLabel: skillId,
|
|
2570
|
+
spinnerMessage: `Running ${skillId}...`,
|
|
2571
|
+
successMessage: `${skillId} complete!`,
|
|
2572
|
+
estimatedDurationMinutes: 5,
|
|
2573
|
+
reportFile: `posthog-${skillId}-report.md`,
|
|
2574
|
+
docsUrl: POSTHOG_DOCS_URL
|
|
2575
|
+
});
|
|
2576
|
+
}
|
|
2800
2577
|
};
|
|
2801
2578
|
const PROGRAM_REGISTRY = [
|
|
2802
2579
|
posthogIntegrationConfig,
|
|
@@ -2804,7 +2581,6 @@ const PROGRAM_REGISTRY = [
|
|
|
2804
2581
|
errorTrackingUploadSourceMapsConfig,
|
|
2805
2582
|
auditConfig,
|
|
2806
2583
|
eventsAuditConfig,
|
|
2807
|
-
audit3000Config,
|
|
2808
2584
|
posthogDoctorConfig,
|
|
2809
2585
|
webAnalyticsDoctorConfig,
|
|
2810
2586
|
migrationConfig,
|
|
@@ -2826,7 +2602,6 @@ const Program = {
|
|
|
2826
2602
|
Migration: migrationConfig.id,
|
|
2827
2603
|
Audit: auditConfig.id,
|
|
2828
2604
|
EventsAudit: eventsAuditConfig.id,
|
|
2829
|
-
Audit3000: audit3000Config.id,
|
|
2830
2605
|
PosthogDoctor: posthogDoctorConfig.id,
|
|
2831
2606
|
WebAnalyticsDoctor: webAnalyticsDoctorConfig.id,
|
|
2832
2607
|
AgentSkill: agentSkillConfig.id,
|
|
@@ -2873,7 +2648,7 @@ function runMcpAdd(argv) {
|
|
|
2873
2648
|
const debug = argv.debug;
|
|
2874
2649
|
const localMcp = argv.local;
|
|
2875
2650
|
try {
|
|
2876
|
-
const { startTUI } = await import("./start-tui-
|
|
2651
|
+
const { startTUI } = await import("./start-tui-WNb3ET14.js");
|
|
2877
2652
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2878
2653
|
const tui = startTUI(VERSION, Program.McpAdd);
|
|
2879
2654
|
tui.store.session = buildSession({
|
|
@@ -2885,7 +2660,7 @@ function runMcpAdd(argv) {
|
|
|
2885
2660
|
} catch (error) {
|
|
2886
2661
|
if (!isTUIUnavailable(error)) throw error;
|
|
2887
2662
|
setUI(new LoggingUI());
|
|
2888
|
-
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-
|
|
2663
|
+
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-CfwEQT_z.js").then((n) => n.r);
|
|
2889
2664
|
await addMCPServerToClientsStep({
|
|
2890
2665
|
local: localMcp,
|
|
2891
2666
|
features,
|
|
@@ -2924,7 +2699,7 @@ function runMcpRemove(argv) {
|
|
|
2924
2699
|
const debug = argv.debug;
|
|
2925
2700
|
const localMcp = argv.local;
|
|
2926
2701
|
try {
|
|
2927
|
-
const { startTUI } = await import("./start-tui-
|
|
2702
|
+
const { startTUI } = await import("./start-tui-WNb3ET14.js");
|
|
2928
2703
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2929
2704
|
const tui = startTUI(VERSION, Program.McpRemove);
|
|
2930
2705
|
tui.store.session = buildSession({
|
|
@@ -2933,7 +2708,7 @@ function runMcpRemove(argv) {
|
|
|
2933
2708
|
});
|
|
2934
2709
|
} catch {
|
|
2935
2710
|
setUI(new LoggingUI());
|
|
2936
|
-
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-
|
|
2711
|
+
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-CfwEQT_z.js").then((n) => n.r);
|
|
2937
2712
|
await removeMCPServerFromClientsStep({ local: localMcp });
|
|
2938
2713
|
}
|
|
2939
2714
|
})();
|
|
@@ -2955,7 +2730,7 @@ function runMcpTutorial(argv) {
|
|
|
2955
2730
|
const debug = argv.debug;
|
|
2956
2731
|
const localMcp = argv.local;
|
|
2957
2732
|
try {
|
|
2958
|
-
const { startTUI } = await import("./start-tui-
|
|
2733
|
+
const { startTUI } = await import("./start-tui-WNb3ET14.js");
|
|
2959
2734
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2960
2735
|
const tui = startTUI(VERSION, Program.McpTutorial);
|
|
2961
2736
|
tui.store.session = buildSession({
|
|
@@ -3010,7 +2785,7 @@ function runWizard(config, options) {
|
|
|
3010
2785
|
(async () => {
|
|
3011
2786
|
try {
|
|
3012
2787
|
const installDir = options.installDir || process.cwd();
|
|
3013
|
-
const { startTUI } = await import("./start-tui-
|
|
2788
|
+
const { startTUI } = await import("./start-tui-WNb3ET14.js");
|
|
3014
2789
|
const { buildSession, RunPhase } = await import("./wizard-session-wPJtNl4c.js");
|
|
3015
2790
|
const { TaskStreamPush } = await import("./task-stream-CZawuzlz.js");
|
|
3016
2791
|
const { PostHogDestination } = await import("./posthog-Cr37rnla.js");
|
|
@@ -3066,7 +2841,7 @@ function runWizard(config, options) {
|
|
|
3066
2841
|
await activeTui.store.getGate("health-check");
|
|
3067
2842
|
const skipAgent = config.run == null;
|
|
3068
2843
|
if (skipAgent) {
|
|
3069
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
2844
|
+
const { getOrAskForProjectData } = await import("./setup-utils-0U-_Md2G.js").then((n) => n.r);
|
|
3070
2845
|
const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
|
|
3071
2846
|
signup: session.signup,
|
|
3072
2847
|
ci: session.ci,
|
|
@@ -3081,7 +2856,7 @@ function runWizard(config, options) {
|
|
|
3081
2856
|
projectId
|
|
3082
2857
|
});
|
|
3083
2858
|
} else {
|
|
3084
|
-
const { runAgent } = await import("./agent-runner-
|
|
2859
|
+
const { runAgent } = await import("./agent-runner-CBbkS0Ro.js");
|
|
3085
2860
|
await runAgent(config, activeTui.store.session);
|
|
3086
2861
|
}
|
|
3087
2862
|
const isDone = () => skipAgent ? activeTui.store.session.outroDismissed : activeTui.store.session.skillsComplete;
|
|
@@ -3158,10 +2933,10 @@ function runWizardCI(config, options) {
|
|
|
3158
2933
|
(async () => {
|
|
3159
2934
|
const path = await import("path");
|
|
3160
2935
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
3161
|
-
const { readEnvironment } = await import("./environment-
|
|
2936
|
+
const { readEnvironment } = await import("./environment-CyS37cmM.js").then((n) => n.t);
|
|
3162
2937
|
const { readApiKeyFromEnv } = await import("./env-api-key-MlzJYAvt.js").then((n) => n.t);
|
|
3163
|
-
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-
|
|
3164
|
-
const { wizardAbort, WizardError } = await import("./wizard-abort-
|
|
2938
|
+
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-zMvpNYb2.js");
|
|
2939
|
+
const { wizardAbort, WizardError } = await import("./wizard-abort-DWXyJdws.js");
|
|
3165
2940
|
configureLogFileFromEnvironment();
|
|
3166
2941
|
const env = readEnvironment();
|
|
3167
2942
|
const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
|
|
@@ -3212,7 +2987,7 @@ function runWizardCI(config, options) {
|
|
|
3212
2987
|
})
|
|
3213
2988
|
});
|
|
3214
2989
|
}
|
|
3215
|
-
const { runAgent } = await import("./agent-runner-
|
|
2990
|
+
const { runAgent } = await import("./agent-runner-CBbkS0Ro.js");
|
|
3216
2991
|
await runAgent(config, session);
|
|
3217
2992
|
} catch (error) {
|
|
3218
2993
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -3231,106 +3006,731 @@ function runWizardCI(config, options) {
|
|
|
3231
3006
|
}
|
|
3232
3007
|
//#endregion
|
|
3233
3008
|
//#region src/commands/skill-program-options.ts
|
|
3234
|
-
/**
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
"
|
|
3246
|
-
|
|
3247
|
-
describe: "Use local MCP server",
|
|
3248
|
-
type: "boolean"
|
|
3249
|
-
},
|
|
3250
|
-
benchmark: {
|
|
3251
|
-
default: false,
|
|
3252
|
-
describe: "Run in benchmark mode",
|
|
3253
|
-
type: "boolean"
|
|
3254
|
-
},
|
|
3255
|
-
"yara-report": {
|
|
3256
|
-
default: false,
|
|
3257
|
-
describe: "Print YARA scanner summary",
|
|
3258
|
-
type: "boolean",
|
|
3259
|
-
hidden: true
|
|
3260
|
-
}
|
|
3261
|
-
};
|
|
3262
|
-
//#endregion
|
|
3263
|
-
//#region src/commands/integrate.ts
|
|
3264
|
-
const integrateCommand = {
|
|
3265
|
-
name: "integrate",
|
|
3266
|
-
description: posthogIntegrationConfig.description,
|
|
3267
|
-
options: {
|
|
3268
|
-
...skillProgramOptions,
|
|
3269
|
-
...posthogIntegrationConfig.cliOptions ?? {}
|
|
3270
|
-
},
|
|
3271
|
-
handler: (argv) => {
|
|
3272
|
-
const extras = posthogIntegrationConfig.mapCliOptions?.(argv) ?? {};
|
|
3273
|
-
const options = {
|
|
3274
|
-
...argv,
|
|
3275
|
-
...extras
|
|
3276
|
-
};
|
|
3277
|
-
if (options.ci) runWizardCI(posthogIntegrationConfig, options);
|
|
3278
|
-
else runWizard(posthogIntegrationConfig, options);
|
|
3279
|
-
}
|
|
3280
|
-
};
|
|
3009
|
+
/**
|
|
3010
|
+
* Per-command options shared by every skill-based program command
|
|
3011
|
+
* (`audit events`, `migrate statsig`, `revenue`, `source-maps`, …).
|
|
3012
|
+
*
|
|
3013
|
+
* Only flags that are unique to skill commands live here. Global flags
|
|
3014
|
+
* (`--debug`, `--local-mcp`, `--benchmark`, `--yara-report`, `--ci`) are
|
|
3015
|
+
* declared once in `wizard.ts::GLOBAL_OPTIONS` and apply automatically
|
|
3016
|
+
* across every command — no need to repeat them per subcommand.
|
|
3017
|
+
*/
|
|
3018
|
+
const skillProgramOptions = { "install-dir": {
|
|
3019
|
+
describe: "Directory to install in",
|
|
3020
|
+
type: "string"
|
|
3021
|
+
} };
|
|
3281
3022
|
//#endregion
|
|
3282
|
-
//#region src/commands/
|
|
3283
|
-
|
|
3284
|
-
|
|
3023
|
+
//#region src/commands/factories/shared.ts
|
|
3024
|
+
/**
|
|
3025
|
+
* Dispatch a parsed yargs invocation to the wizard runner. Applies the
|
|
3026
|
+
* program's `mapCliOptions` transform, then routes to `runWizard` or
|
|
3027
|
+
* `runWizardCI` based on the `--ci` flag.
|
|
3028
|
+
*
|
|
3029
|
+
* Every command file used to inline this; the factories call it instead.
|
|
3030
|
+
*/
|
|
3031
|
+
/**
|
|
3032
|
+
* Run a command's async body as fire-and-forget while still surfacing failures.
|
|
3033
|
+
* yargs handlers are synchronous, so async work kicks off a detached promise —
|
|
3034
|
+
* without this, a rejection becomes an unhandled promise rejection (no message,
|
|
3035
|
+
* wrong exit code). This awaits the work and turns any error into a clean
|
|
3036
|
+
* message + non-zero exit.
|
|
3037
|
+
*/
|
|
3038
|
+
function runCommandHandler(work) {
|
|
3039
|
+
(async () => {
|
|
3040
|
+
try {
|
|
3041
|
+
await work();
|
|
3042
|
+
} catch (err) {
|
|
3043
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3044
|
+
process.stderr.write(`\n\x1b[1;91m✖ ${msg}\x1b[0m\n\n`);
|
|
3045
|
+
process.exit(1);
|
|
3046
|
+
}
|
|
3047
|
+
})();
|
|
3048
|
+
}
|
|
3049
|
+
function dispatchProgram(config, argv) {
|
|
3050
|
+
const argvRecord = argv;
|
|
3051
|
+
const extras = config.mapCliOptions?.(argvRecord) ?? {};
|
|
3285
3052
|
const options = {
|
|
3286
|
-
...
|
|
3053
|
+
...argvRecord,
|
|
3287
3054
|
...extras
|
|
3288
3055
|
};
|
|
3289
3056
|
if (options.ci) runWizardCI(config, options);
|
|
3290
3057
|
else runWizard(config, options);
|
|
3291
|
-
}
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3058
|
+
}
|
|
3059
|
+
/**
|
|
3060
|
+
* Merge the standard skill-program flags (`--debug`, `--install-dir`, etc.)
|
|
3061
|
+
* with any program-specific options declared on `cliOptions`.
|
|
3062
|
+
*
|
|
3063
|
+
* Program-specific options shadow the standard ones — that's intentional, so
|
|
3064
|
+
* a program can override a default flag if it ever needs to.
|
|
3065
|
+
*/
|
|
3066
|
+
function mergeCommandOptions(config) {
|
|
3067
|
+
return {
|
|
3296
3068
|
...skillProgramOptions,
|
|
3297
|
-
...
|
|
3298
|
-
}
|
|
3299
|
-
|
|
3300
|
-
|
|
3069
|
+
...config.cliOptions ?? {}
|
|
3070
|
+
};
|
|
3071
|
+
}
|
|
3072
|
+
//#endregion
|
|
3073
|
+
//#region src/lib/programs/dispatch-family.ts
|
|
3074
|
+
/**
|
|
3075
|
+
* Capture a CLI dispatch error, flush analytics, and exit. The wizard never
|
|
3076
|
+
* starts a run from these paths — use flush() (not shutdown()) so we don't
|
|
3077
|
+
* fire a "setup wizard finished" event for a parse error that didn't run.
|
|
3078
|
+
*/
|
|
3079
|
+
async function exitDispatchError(reason, properties, message, code = 1) {
|
|
3080
|
+
analytics.wizardCapture("cli dispatch error", {
|
|
3081
|
+
reason,
|
|
3082
|
+
...properties
|
|
3083
|
+
});
|
|
3084
|
+
try {
|
|
3085
|
+
await analytics.flush();
|
|
3086
|
+
} catch {}
|
|
3087
|
+
process.stderr.write(message);
|
|
3088
|
+
return process.exit(code);
|
|
3089
|
+
}
|
|
3090
|
+
/**
|
|
3091
|
+
* Family commands (`wizard audit`, `wizard migrate`, ...) resolve their
|
|
3092
|
+
* subcommands at runtime against the published `cliEntries` inside
|
|
3093
|
+
* `skill-menu.json`. Adding a subcommand is a context-mill release — no
|
|
3094
|
+
* wizard release needed.
|
|
3095
|
+
*
|
|
3096
|
+
* Wizard-native subcommands (programs that aren't backed by a single skill,
|
|
3097
|
+
* e.g. `wizard audit web-analytics`) live here in code, dispatched directly
|
|
3098
|
+
* without touching the registry. Adding a native is a wizard PR.
|
|
3099
|
+
*/
|
|
3100
|
+
/** Wizard-native subcommands keyed by family. */
|
|
3101
|
+
const NATIVE_HANDLERS = { audit: { "web-analytics": webAnalyticsDoctorConfig } };
|
|
3102
|
+
/**
|
|
3103
|
+
* Resolve a fetched CliEntry to the ProgramConfig that actually runs it.
|
|
3104
|
+
* Most entries run via the generic agent-skill program with the entry's
|
|
3105
|
+
* `skillId` injected. The comprehensive `audit all` is the one exception —
|
|
3106
|
+
* skillId 'audit' triggers the specialized auditConfig (custom hooks,
|
|
3107
|
+
* content blocks, screens).
|
|
3108
|
+
*/
|
|
3109
|
+
function configForCliEntry(entry) {
|
|
3110
|
+
if (entry.skillId === "audit") return auditConfig;
|
|
3111
|
+
return {
|
|
3112
|
+
...agentSkillConfig,
|
|
3113
|
+
skillId: entry.skillId
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
function familyEntries(family, entries) {
|
|
3117
|
+
return entries.filter((e) => e.role === "command" && e.parentCommand === family && Boolean(e.command));
|
|
3118
|
+
}
|
|
3119
|
+
/**
|
|
3120
|
+
* Dispatch `wizard <family> <sub>` to the right program.
|
|
3121
|
+
*
|
|
3122
|
+
* Order:
|
|
3123
|
+
* 1. Native handler for (family, sub) — runs immediately, no network.
|
|
3124
|
+
* 2. Fetched CliEntry — runs the resolved skill.
|
|
3125
|
+
* 3. Unknown — prints the available list and exits non-zero.
|
|
3126
|
+
*/
|
|
3127
|
+
async function dispatchFamily(family, argv) {
|
|
3128
|
+
const sub = argv.skill?.trim();
|
|
3129
|
+
if (!sub) return exitDispatchError("missing subcommand", { family }, `\n\x1b[1;91m✖ \`wizard ${family}\` requires a subcommand.\x1b[0m\n Pass one (e.g. \`wizard ${family} <subcommand>\`), or run it in an interactive terminal to pick from a menu.\n\n`);
|
|
3130
|
+
const native = NATIVE_HANDLERS[family]?.[sub];
|
|
3131
|
+
if (native) {
|
|
3132
|
+
dispatchProgram(native, argv);
|
|
3133
|
+
return;
|
|
3301
3134
|
}
|
|
3135
|
+
const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv["local-mcp"]));
|
|
3136
|
+
const menu = await fetchSkillMenu(skillsBaseUrl);
|
|
3137
|
+
if (!menu) return exitDispatchError("registry unreachable", {
|
|
3138
|
+
family,
|
|
3139
|
+
sub,
|
|
3140
|
+
skillsBaseUrl
|
|
3141
|
+
}, `\n\x1b[1;91m✖ Couldn't reach the skill registry at ${skillsBaseUrl}.\x1b[0m\n Check your network connection and try again.\n\n`);
|
|
3142
|
+
const entries = menu.cliEntries ?? [];
|
|
3143
|
+
const entry = familyEntries(family, entries).find((e) => e.command === sub);
|
|
3144
|
+
if (entry) {
|
|
3145
|
+
dispatchProgram(configForCliEntry(entry), argv);
|
|
3146
|
+
return;
|
|
3147
|
+
}
|
|
3148
|
+
const available = [...Object.keys(NATIVE_HANDLERS[family] ?? {}), ...familyEntries(family, entries).map((e) => e.command)].sort();
|
|
3149
|
+
return exitDispatchError("unknown subcommand", {
|
|
3150
|
+
family,
|
|
3151
|
+
sub,
|
|
3152
|
+
available
|
|
3153
|
+
}, `\n\x1b[1;91m✖ Unknown subcommand "${sub}" under \`${family}\`.\x1b[0m\n` + (available.length ? ` Available: ${available.join(", ")}\n\n` : ` No subcommands published for "${family}" yet.\n\n`));
|
|
3154
|
+
}
|
|
3155
|
+
/**
|
|
3156
|
+
* Build the children list shown in the family's interactive picker.
|
|
3157
|
+
* Combines native handlers with skill-backed entries from the live registry.
|
|
3158
|
+
* Used by `familyCommandFactory`'s `interactiveDefault`.
|
|
3159
|
+
*/
|
|
3160
|
+
function buildFamilyPickerChildren(family, entries) {
|
|
3161
|
+
const natives = Object.entries(NATIVE_HANDLERS[family] ?? {}).map(([cmd, program]) => ({
|
|
3162
|
+
name: cmd,
|
|
3163
|
+
description: program.description,
|
|
3164
|
+
handler: (argv) => dispatchProgram(program, argv)
|
|
3165
|
+
}));
|
|
3166
|
+
const live = familyEntries(family, entries).map((entry) => ({
|
|
3167
|
+
name: entry.command,
|
|
3168
|
+
description: entry.description,
|
|
3169
|
+
handler: (argv) => {
|
|
3170
|
+
dispatchFamily(family, {
|
|
3171
|
+
...argv,
|
|
3172
|
+
skill: entry.command
|
|
3173
|
+
});
|
|
3174
|
+
},
|
|
3175
|
+
default: entry.default
|
|
3176
|
+
}));
|
|
3177
|
+
return [...natives, ...live];
|
|
3178
|
+
}
|
|
3179
|
+
/**
|
|
3180
|
+
* The children the family picker shows **today**: only the leaf marked
|
|
3181
|
+
* `default` (e.g. `audit events`). Every other subcommand stays runnable
|
|
3182
|
+
* directly (`wizard audit <name>`) — they just aren't listed in the picker yet.
|
|
3183
|
+
* Falls back to all children when nothing is marked `default`.
|
|
3184
|
+
*
|
|
3185
|
+
* Temporary: when we're ready to surface the full menu, return `children`
|
|
3186
|
+
* unchanged (and delete this note).
|
|
3187
|
+
*/
|
|
3188
|
+
function pickerChildrenToShow(children) {
|
|
3189
|
+
const defaults = children.filter((c) => c.default);
|
|
3190
|
+
return defaults.length > 0 ? [...defaults] : [...children];
|
|
3191
|
+
}
|
|
3192
|
+
//#endregion
|
|
3193
|
+
//#region src/ui/tui/primitives/PromptLabel.tsx
|
|
3194
|
+
/**
|
|
3195
|
+
* PromptLabel — Compact inline label for input prompts.
|
|
3196
|
+
*
|
|
3197
|
+
* Renders: [!] message
|
|
3198
|
+
* where [!] is black text on accent background.
|
|
3199
|
+
*/
|
|
3200
|
+
const PromptLabel = ({ message }) => {
|
|
3201
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, {
|
|
3202
|
+
bold: true,
|
|
3203
|
+
color: Colors.accent,
|
|
3204
|
+
children: [" ", message]
|
|
3205
|
+
}) });
|
|
3302
3206
|
};
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3207
|
+
//#endregion
|
|
3208
|
+
//#region src/ui/tui/hooks/keyboard-hints-utils.ts
|
|
3209
|
+
/** Default priorities by key type. */
|
|
3210
|
+
const DEFAULT_PRIORITY = {
|
|
3211
|
+
["upArrow"]: 0,
|
|
3212
|
+
["downArrow"]: 0,
|
|
3213
|
+
["leftArrow"]: 1,
|
|
3214
|
+
["rightArrow"]: 1,
|
|
3215
|
+
["space"]: 10,
|
|
3216
|
+
["escape"]: 20,
|
|
3217
|
+
["return"]: 21
|
|
3218
|
+
};
|
|
3219
|
+
/** Get the default display priority for a key match. */
|
|
3220
|
+
function getDefaultPriority(match) {
|
|
3221
|
+
return DEFAULT_PRIORITY[Array.isArray(match) ? match[0] : match] ?? 15;
|
|
3222
|
+
}
|
|
3223
|
+
/** Check if a KeyMatchOrChar matches the given input string and key flags. */
|
|
3224
|
+
function matchesKey(m, input, key) {
|
|
3225
|
+
switch (m) {
|
|
3226
|
+
case "upArrow": return !!key.upArrow;
|
|
3227
|
+
case "downArrow": return !!key.downArrow;
|
|
3228
|
+
case "leftArrow": return !!key.leftArrow;
|
|
3229
|
+
case "rightArrow": return !!key.rightArrow;
|
|
3230
|
+
case "return": return !!key.return;
|
|
3231
|
+
case "escape": return !!key.escape;
|
|
3232
|
+
case "space": return input === " ";
|
|
3233
|
+
default: return input === m;
|
|
3313
3234
|
}
|
|
3235
|
+
}
|
|
3236
|
+
/** Serialize hints for comparison. */
|
|
3237
|
+
function hintsKey(hints) {
|
|
3238
|
+
return hints.map((h) => `${h.label}:${h.action}`).join("|");
|
|
3239
|
+
}
|
|
3240
|
+
/** Deduplicate hints by label+action and sort by priority. */
|
|
3241
|
+
function deduplicateAndSort(hints) {
|
|
3242
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3243
|
+
const deduped = [];
|
|
3244
|
+
for (const hint of hints) {
|
|
3245
|
+
const k = `${hint.label}:${hint.action}`;
|
|
3246
|
+
if (!seen.has(k)) {
|
|
3247
|
+
seen.add(k);
|
|
3248
|
+
deduped.push(hint);
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
deduped.sort((a, b) => a.priority - b.priority);
|
|
3252
|
+
return deduped;
|
|
3253
|
+
}
|
|
3254
|
+
//#endregion
|
|
3255
|
+
//#region src/ui/tui/hooks/useKeyboardHints.tsx
|
|
3256
|
+
/**
|
|
3257
|
+
* KeyboardHintsProvider — Context for collecting and displaying keyboard hints.
|
|
3258
|
+
*
|
|
3259
|
+
* Input components register their hints via useKeyBindings. The provider
|
|
3260
|
+
* flattens, deduplicates, and sorts them. The hints bar stays visible for as
|
|
3261
|
+
* long as a screen has registered hints — it never auto-dismisses.
|
|
3262
|
+
*/
|
|
3263
|
+
const KeyboardHintsContext = createContext({
|
|
3264
|
+
register: () => void 0,
|
|
3265
|
+
unregister: () => void 0,
|
|
3266
|
+
hints: []
|
|
3267
|
+
});
|
|
3268
|
+
const useKeyboardHintsContext = () => useContext(KeyboardHintsContext);
|
|
3269
|
+
const KeyboardHintsProvider = ({ children }) => {
|
|
3270
|
+
const registrationsRef = useRef(/* @__PURE__ */ new Map());
|
|
3271
|
+
const [hints, setHints] = useState([]);
|
|
3272
|
+
const prevHintsKeyRef = useRef("");
|
|
3273
|
+
const recompute = useCallback(() => {
|
|
3274
|
+
const all = [];
|
|
3275
|
+
for (const h of registrationsRef.current.values()) all.push(...h);
|
|
3276
|
+
const deduped = deduplicateAndSort(all);
|
|
3277
|
+
const newKey = hintsKey(deduped);
|
|
3278
|
+
if (newKey !== prevHintsKeyRef.current) {
|
|
3279
|
+
prevHintsKeyRef.current = newKey;
|
|
3280
|
+
setHints(deduped);
|
|
3281
|
+
}
|
|
3282
|
+
}, []);
|
|
3283
|
+
const register = useCallback((id, h) => {
|
|
3284
|
+
registrationsRef.current.set(id, h);
|
|
3285
|
+
recompute();
|
|
3286
|
+
}, [recompute]);
|
|
3287
|
+
const unregister = useCallback((id) => {
|
|
3288
|
+
registrationsRef.current.delete(id);
|
|
3289
|
+
recompute();
|
|
3290
|
+
}, [recompute]);
|
|
3291
|
+
return /* @__PURE__ */ jsx(KeyboardHintsContext.Provider, {
|
|
3292
|
+
value: {
|
|
3293
|
+
register,
|
|
3294
|
+
unregister,
|
|
3295
|
+
hints
|
|
3296
|
+
},
|
|
3297
|
+
children
|
|
3298
|
+
});
|
|
3314
3299
|
};
|
|
3315
3300
|
//#endregion
|
|
3316
|
-
//#region src/
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3301
|
+
//#region src/ui/tui/hooks/useKeyBindings.ts
|
|
3302
|
+
/**
|
|
3303
|
+
* useKeyBindings — Declarative keyboard input + automatic hint registration.
|
|
3304
|
+
*
|
|
3305
|
+
* Replaces raw `useInput` in input components. Define bindings as data;
|
|
3306
|
+
* the hook wires up the Ink input handler AND registers hints in the
|
|
3307
|
+
* KeyboardHintsProvider. One source of truth for keys and their labels.
|
|
3308
|
+
*/
|
|
3309
|
+
/**
|
|
3310
|
+
* Declarative key bindings hook. Replaces `useInput` in input components.
|
|
3311
|
+
* Registers hints automatically with the KeyboardHintsProvider.
|
|
3312
|
+
*
|
|
3313
|
+
* @param id Unique identifier for this component's hints registration
|
|
3314
|
+
* @param bindings Array of key binding definitions
|
|
3315
|
+
*/
|
|
3316
|
+
function useKeyBindings(id, bindings) {
|
|
3317
|
+
const ctx = useKeyboardHintsContext();
|
|
3318
|
+
const hintsRef = useRef("");
|
|
3319
|
+
const hints = bindings.map((b) => ({
|
|
3320
|
+
label: b.label,
|
|
3321
|
+
action: b.action,
|
|
3322
|
+
priority: b.priority ?? getDefaultPriority(b.match)
|
|
3323
|
+
}));
|
|
3324
|
+
const serialized = hints.map((h) => `${h.label}:${h.action}:${h.priority}`).join("|");
|
|
3325
|
+
useEffect(() => {
|
|
3326
|
+
if (serialized !== hintsRef.current) {
|
|
3327
|
+
hintsRef.current = serialized;
|
|
3328
|
+
ctx.register(id, hints);
|
|
3329
|
+
}
|
|
3330
|
+
return () => ctx.unregister(id);
|
|
3331
|
+
}, [id, serialized]);
|
|
3332
|
+
useInput((input, key) => {
|
|
3333
|
+
for (const binding of bindings) if ((Array.isArray(binding.match) ? binding.match : [binding.match]).some((m) => matchesKey(m, input, key))) {
|
|
3334
|
+
binding.handler(input, key);
|
|
3335
|
+
return;
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3338
|
+
}
|
|
3339
|
+
//#endregion
|
|
3340
|
+
//#region src/ui/tui/primitives/PickerMenu.tsx
|
|
3341
|
+
/**
|
|
3342
|
+
* PickerMenu — Single and multi select.
|
|
3343
|
+
* Single mode: custom renderer with small triangle indicator.
|
|
3344
|
+
* Multi mode: checkbox glyphs with space to toggle.
|
|
3345
|
+
*
|
|
3346
|
+
* Key bindings are declared via useKeyBindings, which auto-registers
|
|
3347
|
+
* hints in the KeyboardHintsBar.
|
|
3348
|
+
*/
|
|
3349
|
+
/**
|
|
3350
|
+
* Step through a column's options in `dir`, wrapping, until an enabled
|
|
3351
|
+
* option is found. Returns `from` unchanged if the column is entirely
|
|
3352
|
+
* disabled.
|
|
3353
|
+
*/
|
|
3354
|
+
function stepEnabled(options, rows, from, dir) {
|
|
3355
|
+
const colStart = Math.floor(from / rows) * rows;
|
|
3356
|
+
const colLen = Math.min(rows, options.length - colStart);
|
|
3357
|
+
let row = from % rows;
|
|
3358
|
+
for (let i = 0; i < colLen; i++) {
|
|
3359
|
+
row = (row + dir + colLen) % colLen;
|
|
3360
|
+
const idx = colStart + row;
|
|
3361
|
+
if (!options[idx]?.disabled) return idx;
|
|
3332
3362
|
}
|
|
3363
|
+
return from;
|
|
3364
|
+
}
|
|
3365
|
+
/** Index of the first enabled option, for the initial focus. */
|
|
3366
|
+
function firstEnabled(options) {
|
|
3367
|
+
const idx = options.findIndex((o) => !o.disabled);
|
|
3368
|
+
return idx === -1 ? 0 : idx;
|
|
3369
|
+
}
|
|
3370
|
+
const PickerMenu = ({ message, options, mode = "single", centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
|
|
3371
|
+
if (mode === "multi") return /* @__PURE__ */ jsx(MultiPickerMenu, {
|
|
3372
|
+
message,
|
|
3373
|
+
options,
|
|
3374
|
+
centered,
|
|
3375
|
+
columns,
|
|
3376
|
+
optionMarginBottom,
|
|
3377
|
+
onSelect
|
|
3378
|
+
});
|
|
3379
|
+
return /* @__PURE__ */ jsx(SinglePickerMenu, {
|
|
3380
|
+
message,
|
|
3381
|
+
options,
|
|
3382
|
+
centered,
|
|
3383
|
+
columns,
|
|
3384
|
+
optionMarginBottom,
|
|
3385
|
+
onSelect
|
|
3386
|
+
});
|
|
3333
3387
|
};
|
|
3388
|
+
/** Custom single-select with triangle indicator and accent highlight. */
|
|
3389
|
+
const SinglePickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
|
|
3390
|
+
const [focused, setFocused] = useState(() => firstEnabled(options));
|
|
3391
|
+
const rows = Math.ceil(options.length / columns);
|
|
3392
|
+
useEffect(() => {
|
|
3393
|
+
if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
|
|
3394
|
+
}, [options, focused]);
|
|
3395
|
+
const bindings = [{
|
|
3396
|
+
match: ["upArrow", "downArrow"],
|
|
3397
|
+
label: "↑↓",
|
|
3398
|
+
action: "navigate",
|
|
3399
|
+
handler: (_input, key) => {
|
|
3400
|
+
if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
|
|
3401
|
+
if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
|
|
3402
|
+
}
|
|
3403
|
+
}, {
|
|
3404
|
+
match: "return",
|
|
3405
|
+
label: "enter",
|
|
3406
|
+
action: "select",
|
|
3407
|
+
handler: () => {
|
|
3408
|
+
const selected = options[focused];
|
|
3409
|
+
if (selected && !selected.disabled) onSelect(selected.value);
|
|
3410
|
+
}
|
|
3411
|
+
}];
|
|
3412
|
+
if (columns > 1) bindings.splice(1, 0, {
|
|
3413
|
+
match: ["leftArrow", "rightArrow"],
|
|
3414
|
+
label: "←→",
|
|
3415
|
+
action: "navigate",
|
|
3416
|
+
handler: (_input, key) => {
|
|
3417
|
+
const col = Math.floor(focused / rows);
|
|
3418
|
+
const row = focused % rows;
|
|
3419
|
+
let next = focused;
|
|
3420
|
+
if (key.leftArrow) {
|
|
3421
|
+
const prevCol = col > 0 ? col - 1 : columns - 1;
|
|
3422
|
+
next = Math.min(prevCol * rows + row, options.length - 1);
|
|
3423
|
+
}
|
|
3424
|
+
if (key.rightArrow) {
|
|
3425
|
+
const nextCol = col < columns - 1 ? col + 1 : 0;
|
|
3426
|
+
next = Math.min(nextCol * rows + row, options.length - 1);
|
|
3427
|
+
}
|
|
3428
|
+
if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
|
|
3429
|
+
setFocused(next);
|
|
3430
|
+
}
|
|
3431
|
+
});
|
|
3432
|
+
useKeyBindings("single-picker", bindings);
|
|
3433
|
+
const columnArrays = [];
|
|
3434
|
+
for (let c = 0; c < columns; c++) columnArrays.push(options.slice(c * rows, c * rows + rows));
|
|
3435
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3436
|
+
flexDirection: "column",
|
|
3437
|
+
alignItems: centered ? "center" : void 0,
|
|
3438
|
+
children: [/* @__PURE__ */ jsx(PromptLabel, { message }), /* @__PURE__ */ jsx(Box, {
|
|
3439
|
+
flexDirection: "row",
|
|
3440
|
+
gap: 4,
|
|
3441
|
+
children: columnArrays.map((colOpts, colIdx) => /* @__PURE__ */ jsx(Box, {
|
|
3442
|
+
flexDirection: "column",
|
|
3443
|
+
children: colOpts.map((opt, rowIdx) => {
|
|
3444
|
+
const flatIdx = colIdx * rows + rowIdx;
|
|
3445
|
+
const isFocused = flatIdx === focused;
|
|
3446
|
+
const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;
|
|
3447
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3448
|
+
gap: 1,
|
|
3449
|
+
marginBottom: optionMarginBottom,
|
|
3450
|
+
children: [
|
|
3451
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3452
|
+
color: isFocused ? Colors.accent : void 0,
|
|
3453
|
+
dimColor: !isFocused,
|
|
3454
|
+
children: isFocused ? Icons.triangleSmallRight : " "
|
|
3455
|
+
}),
|
|
3456
|
+
opt.icon && /* @__PURE__ */ jsx(Text, {
|
|
3457
|
+
color: opt.icon.color,
|
|
3458
|
+
children: opt.icon.glyph
|
|
3459
|
+
}),
|
|
3460
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3461
|
+
color: opt.disabled ? Colors.muted : isFocused ? Colors.accent : void 0,
|
|
3462
|
+
bold: isFocused && !opt.disabled,
|
|
3463
|
+
dimColor: !isFocused || opt.disabled,
|
|
3464
|
+
children: label
|
|
3465
|
+
})
|
|
3466
|
+
]
|
|
3467
|
+
}, flatIdx);
|
|
3468
|
+
})
|
|
3469
|
+
}, colIdx))
|
|
3470
|
+
})]
|
|
3471
|
+
});
|
|
3472
|
+
};
|
|
3473
|
+
/** Custom multi-select with checkbox glyphs and accent highlight. */
|
|
3474
|
+
const MultiPickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
|
|
3475
|
+
const [focused, setFocused] = useState(() => firstEnabled(options));
|
|
3476
|
+
const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
|
|
3477
|
+
const rows = Math.ceil(options.length / columns);
|
|
3478
|
+
useEffect(() => {
|
|
3479
|
+
if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
|
|
3480
|
+
}, [options, focused]);
|
|
3481
|
+
const bindings = [
|
|
3482
|
+
{
|
|
3483
|
+
match: ["upArrow", "downArrow"],
|
|
3484
|
+
label: "↑↓",
|
|
3485
|
+
action: "navigate",
|
|
3486
|
+
handler: (_input, key) => {
|
|
3487
|
+
if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
|
|
3488
|
+
if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
|
|
3489
|
+
}
|
|
3490
|
+
},
|
|
3491
|
+
{
|
|
3492
|
+
match: "space",
|
|
3493
|
+
label: "space",
|
|
3494
|
+
action: "toggle",
|
|
3495
|
+
handler: () => {
|
|
3496
|
+
if (options[focused]?.disabled) return;
|
|
3497
|
+
setSelected((prev) => {
|
|
3498
|
+
const next = new Set(prev);
|
|
3499
|
+
if (next.has(focused)) {
|
|
3500
|
+
next.delete(focused);
|
|
3501
|
+
return next;
|
|
3502
|
+
}
|
|
3503
|
+
if (options[focused]?.exclusive) return new Set([focused]);
|
|
3504
|
+
for (const i of next) if (options[i]?.exclusive) next.delete(i);
|
|
3505
|
+
next.add(focused);
|
|
3506
|
+
return next;
|
|
3507
|
+
});
|
|
3508
|
+
}
|
|
3509
|
+
},
|
|
3510
|
+
{
|
|
3511
|
+
match: "return",
|
|
3512
|
+
label: "enter",
|
|
3513
|
+
action: "confirm",
|
|
3514
|
+
handler: () => {
|
|
3515
|
+
if (selected.size === 0) {
|
|
3516
|
+
const hovered = options[focused];
|
|
3517
|
+
if (hovered && !hovered.disabled) onSelect(hovered.value);
|
|
3518
|
+
} else onSelect([...selected].sort().map((i) => options[i].value));
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
];
|
|
3522
|
+
if (columns > 1) bindings.splice(1, 0, {
|
|
3523
|
+
match: ["leftArrow", "rightArrow"],
|
|
3524
|
+
label: "←→",
|
|
3525
|
+
action: "navigate",
|
|
3526
|
+
handler: (_input, key) => {
|
|
3527
|
+
const col = Math.floor(focused / rows);
|
|
3528
|
+
const row = focused % rows;
|
|
3529
|
+
let next = focused;
|
|
3530
|
+
if (key.leftArrow) {
|
|
3531
|
+
const prevCol = col > 0 ? col - 1 : columns - 1;
|
|
3532
|
+
next = Math.min(prevCol * rows + row, options.length - 1);
|
|
3533
|
+
}
|
|
3534
|
+
if (key.rightArrow) {
|
|
3535
|
+
const nextCol = col < columns - 1 ? col + 1 : 0;
|
|
3536
|
+
next = Math.min(nextCol * rows + row, options.length - 1);
|
|
3537
|
+
}
|
|
3538
|
+
if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
|
|
3539
|
+
setFocused(next);
|
|
3540
|
+
}
|
|
3541
|
+
});
|
|
3542
|
+
useKeyBindings("multi-picker", bindings);
|
|
3543
|
+
const columnArrays = [];
|
|
3544
|
+
for (let c = 0; c < columns; c++) columnArrays.push(options.slice(c * rows, c * rows + rows));
|
|
3545
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3546
|
+
flexDirection: "column",
|
|
3547
|
+
alignItems: centered ? "center" : void 0,
|
|
3548
|
+
children: [/* @__PURE__ */ jsx(PromptLabel, { message }), /* @__PURE__ */ jsx(Box, {
|
|
3549
|
+
flexDirection: "row",
|
|
3550
|
+
gap: 4,
|
|
3551
|
+
marginLeft: centered ? 0 : 2,
|
|
3552
|
+
marginTop: 1,
|
|
3553
|
+
children: columnArrays.map((colOpts, colIdx) => /* @__PURE__ */ jsx(Box, {
|
|
3554
|
+
flexDirection: "column",
|
|
3555
|
+
children: colOpts.map((opt, rowIdx) => {
|
|
3556
|
+
const flatIdx = colIdx * rows + rowIdx;
|
|
3557
|
+
const isFocused = flatIdx === focused;
|
|
3558
|
+
const isSelected = selected.has(flatIdx);
|
|
3559
|
+
const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;
|
|
3560
|
+
const checkbox = isSelected ? Icons.squareFilled : Icons.squareOpen;
|
|
3561
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3562
|
+
gap: 1,
|
|
3563
|
+
marginBottom: optionMarginBottom,
|
|
3564
|
+
children: [
|
|
3565
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3566
|
+
color: isSelected ? "white" : Colors.muted,
|
|
3567
|
+
dimColor: !isFocused && !isSelected,
|
|
3568
|
+
children: checkbox
|
|
3569
|
+
}),
|
|
3570
|
+
opt.icon && /* @__PURE__ */ jsx(Text, {
|
|
3571
|
+
color: opt.icon.color,
|
|
3572
|
+
children: opt.icon.glyph
|
|
3573
|
+
}),
|
|
3574
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3575
|
+
color: opt.disabled ? Colors.muted : isFocused ? Colors.accent : void 0,
|
|
3576
|
+
bold: isFocused && !opt.disabled,
|
|
3577
|
+
dimColor: !isFocused || opt.disabled,
|
|
3578
|
+
children: label
|
|
3579
|
+
})
|
|
3580
|
+
]
|
|
3581
|
+
}, flatIdx);
|
|
3582
|
+
})
|
|
3583
|
+
}, colIdx))
|
|
3584
|
+
})]
|
|
3585
|
+
});
|
|
3586
|
+
};
|
|
3587
|
+
//#endregion
|
|
3588
|
+
//#region src/commands/factories/family-picker.tsx
|
|
3589
|
+
function FamilyPickerApp(props) {
|
|
3590
|
+
return createElement(Box, {
|
|
3591
|
+
flexDirection: "column",
|
|
3592
|
+
paddingX: 1,
|
|
3593
|
+
paddingY: 1
|
|
3594
|
+
}, createElement(Text, {
|
|
3595
|
+
bold: true,
|
|
3596
|
+
color: Colors.accent
|
|
3597
|
+
}, props.parentLabel), createElement(Box, { height: 1 }), createElement(PickerMenu, {
|
|
3598
|
+
message: "Pick a subcommand",
|
|
3599
|
+
options: props.options,
|
|
3600
|
+
optionMarginBottom: 1,
|
|
3601
|
+
onSelect: (value) => {
|
|
3602
|
+
const cmd = Array.isArray(value) ? value[0] : value;
|
|
3603
|
+
if (cmd) props.onSelect(cmd);
|
|
3604
|
+
}
|
|
3605
|
+
}));
|
|
3606
|
+
}
|
|
3607
|
+
function describe(child) {
|
|
3608
|
+
return commandKeys(child.name)[0] ?? "";
|
|
3609
|
+
}
|
|
3610
|
+
/**
|
|
3611
|
+
* Reorder children so the `default`-marked entry is first, while
|
|
3612
|
+
* preserving the relative order of the rest. The picker's initial
|
|
3613
|
+
* focus is index 0, so this is what makes "press Enter on
|
|
3614
|
+
* `wizard audit`" run the default leaf (today `audit events`).
|
|
3615
|
+
*
|
|
3616
|
+
* Exported for testability — the ordering logic stays pure and
|
|
3617
|
+
* inspectable without mounting Ink.
|
|
3618
|
+
*/
|
|
3619
|
+
function orderFamilyChildren(children) {
|
|
3620
|
+
const selectable = children.filter((c) => c.handler || c.children?.length);
|
|
3621
|
+
const defaults = selectable.filter((c) => c.default);
|
|
3622
|
+
const rest = selectable.filter((c) => !c.default);
|
|
3623
|
+
return [...defaults, ...rest];
|
|
3624
|
+
}
|
|
3625
|
+
/**
|
|
3626
|
+
* Render the picker. Resolves once the user has selected a child;
|
|
3627
|
+
* dispatching the child's handler is the caller's responsibility (so this
|
|
3628
|
+
* function stays pure-UI and easy to test by stubbing `render`).
|
|
3629
|
+
*/
|
|
3630
|
+
function chooseFamilyChild(parentLabel, children) {
|
|
3631
|
+
const ordered = orderFamilyChildren(children);
|
|
3632
|
+
if (ordered.length === 0) return Promise.resolve(null);
|
|
3633
|
+
const options = ordered.map((child) => ({
|
|
3634
|
+
label: describe(child),
|
|
3635
|
+
value: child,
|
|
3636
|
+
hint: child.description
|
|
3637
|
+
}));
|
|
3638
|
+
return new Promise((resolve) => {
|
|
3639
|
+
let app = null;
|
|
3640
|
+
const handleSelect = (cmd) => {
|
|
3641
|
+
app?.unmount();
|
|
3642
|
+
resolve(cmd);
|
|
3643
|
+
};
|
|
3644
|
+
app = render(createElement(FamilyPickerApp, {
|
|
3645
|
+
parentLabel,
|
|
3646
|
+
options,
|
|
3647
|
+
onSelect: handleSelect
|
|
3648
|
+
}));
|
|
3649
|
+
});
|
|
3650
|
+
}
|
|
3651
|
+
/**
|
|
3652
|
+
* Returns an `interactiveDefault` handler for a family parent's no-leaf
|
|
3653
|
+
* invocation. Always opens the picker; the `default`-marked child is
|
|
3654
|
+
* shown first (pre-highlighted), so a single Enter keystroke runs it.
|
|
3655
|
+
*
|
|
3656
|
+
* Discovery + consent in one extra keystroke vs. auto-running silently.
|
|
3657
|
+
*
|
|
3658
|
+
* Wire onto a family parent:
|
|
3659
|
+
* export const auditCommand: Command = {
|
|
3660
|
+
* name: 'audit',
|
|
3661
|
+
* description: '...',
|
|
3662
|
+
* children: [...],
|
|
3663
|
+
* interactiveDefault: createFamilyPickerDefault('audit', auditChildren),
|
|
3664
|
+
* };
|
|
3665
|
+
*/
|
|
3666
|
+
function createFamilyPickerDefault(parentLabel, children, chooser = chooseFamilyChild) {
|
|
3667
|
+
return async (argv) => {
|
|
3668
|
+
const chosen = await chooser(parentLabel, children);
|
|
3669
|
+
if (!chosen) return;
|
|
3670
|
+
await Promise.resolve(chosen.handler?.(argv));
|
|
3671
|
+
};
|
|
3672
|
+
}
|
|
3673
|
+
//#endregion
|
|
3674
|
+
//#region src/commands/factories/family-command-factory.ts
|
|
3675
|
+
/**
|
|
3676
|
+
* Build a yargs `Command` for a family parent (`wizard audit`, etc.).
|
|
3677
|
+
*
|
|
3678
|
+
* - `wizard <family> <sub>` — `dispatchFamily` resolves `<sub>` against
|
|
3679
|
+
* native handlers first, then the live `cliEntries` from
|
|
3680
|
+
* `skill-menu.json`. Unknown subs error with the available list.
|
|
3681
|
+
* - `wizard <family>` (no positional) — in an interactive terminal, runs the
|
|
3682
|
+
* family's single shown entry directly (today `audit events`, so the user
|
|
3683
|
+
* lands on its intro screen); opens the picker once a family shows more than
|
|
3684
|
+
* one. In non-TTY/CI, falls through to `dispatchFamily`, which prints
|
|
3685
|
+
* "requires a subcommand" rather than running something unprompted.
|
|
3686
|
+
*
|
|
3687
|
+
* No static yargs children. New skill-backed subcommands appear after a
|
|
3688
|
+
* context-mill release without a wizard release. New *native* subcommands
|
|
3689
|
+
* (rare) are added by updating `NATIVE_HANDLERS` in `dispatch-family.ts`.
|
|
3690
|
+
*/
|
|
3691
|
+
function familyCommandFactory({ family, description, optionsFrom }) {
|
|
3692
|
+
const openFamilyEntry = async (argv) => {
|
|
3693
|
+
const toShow = pickerChildrenToShow(buildFamilyPickerChildren(family, (await fetchSkillMenu(getSkillsBaseUrl(Boolean(argv["local-mcp"]))))?.cliEntries ?? []));
|
|
3694
|
+
if (toShow.length === 1 && toShow[0]?.handler) {
|
|
3695
|
+
await Promise.resolve(toShow[0].handler(argv));
|
|
3696
|
+
return;
|
|
3697
|
+
}
|
|
3698
|
+
await createFamilyPickerDefault(`wizard ${family}`, toShow)(argv);
|
|
3699
|
+
};
|
|
3700
|
+
return {
|
|
3701
|
+
name: `${family} [skill]`,
|
|
3702
|
+
description,
|
|
3703
|
+
options: mergeCommandOptions(optionsFrom),
|
|
3704
|
+
positionals: { skill: {
|
|
3705
|
+
type: "string",
|
|
3706
|
+
describe: "Subcommand to run (omit to run the default)"
|
|
3707
|
+
} },
|
|
3708
|
+
handler: (argv) => {
|
|
3709
|
+
const sub = argv.skill?.trim();
|
|
3710
|
+
runCommandHandler(() => sub || !process.stdout.isTTY ? dispatchFamily(family, argv) : openFamilyEntry(argv));
|
|
3711
|
+
},
|
|
3712
|
+
interactiveDefault: openFamilyEntry
|
|
3713
|
+
};
|
|
3714
|
+
}
|
|
3715
|
+
//#endregion
|
|
3716
|
+
//#region src/commands/audit.ts
|
|
3717
|
+
/**
|
|
3718
|
+
* The `wizard audit` family.
|
|
3719
|
+
*
|
|
3720
|
+
* Subcommands are resolved at runtime: the wizard fetches `cliEntries` from
|
|
3721
|
+
* `skill-menu.json` and dispatches based on `parentCommand: 'audit'`. The
|
|
3722
|
+
* wizard-native handler for `web-analytics` lives in `NATIVE_HANDLERS` over
|
|
3723
|
+
* in `dispatch-family.ts`. `wizard audit` with no positional opens the
|
|
3724
|
+
* family picker, which combines native + live entries.
|
|
3725
|
+
*
|
|
3726
|
+
* Adding a new skill-backed audit subcommand is a context-mill release —
|
|
3727
|
+
* no wizard release needed.
|
|
3728
|
+
*/
|
|
3729
|
+
const auditCommand = familyCommandFactory({
|
|
3730
|
+
family: "audit",
|
|
3731
|
+
description: auditConfig.description,
|
|
3732
|
+
optionsFrom: auditConfig
|
|
3733
|
+
});
|
|
3334
3734
|
//#endregion
|
|
3335
3735
|
//#region src/commands/doctor.ts
|
|
3336
3736
|
const doctorCommand = {
|
|
@@ -3366,7 +3766,7 @@ async function runDoctorCI(options) {
|
|
|
3366
3766
|
getUI().intro("Welcome to the PostHog setup wizard");
|
|
3367
3767
|
getUI().log.info("Running posthog-doctor in CI mode");
|
|
3368
3768
|
try {
|
|
3369
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
3769
|
+
const { getOrAskForProjectData } = await import("./setup-utils-0U-_Md2G.js").then((n) => n.r);
|
|
3370
3770
|
const { host, accessToken, projectId } = await getOrAskForProjectData({
|
|
3371
3771
|
signup: false,
|
|
3372
3772
|
ci: true,
|
|
@@ -3383,69 +3783,53 @@ async function runDoctorCI(options) {
|
|
|
3383
3783
|
for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
|
|
3384
3784
|
process.exit(1);
|
|
3385
3785
|
} catch (error) {
|
|
3386
|
-
const { ApiError } = await import("./api-
|
|
3786
|
+
const { ApiError } = await import("./api-CI3Z74NG.js").then((n) => n.n);
|
|
3387
3787
|
const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
|
|
3388
3788
|
getUI().log.error(`Doctor failed: ${message}`);
|
|
3389
3789
|
process.exit(1);
|
|
3390
3790
|
}
|
|
3391
3791
|
}
|
|
3392
3792
|
//#endregion
|
|
3393
|
-
//#region src/commands/
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
}
|
|
3410
|
-
}
|
|
3793
|
+
//#region src/commands/factories/native-command-factory.ts
|
|
3794
|
+
/**
|
|
3795
|
+
* Build a yargs `Command` from a wizard-native `ProgramConfig`.
|
|
3796
|
+
*
|
|
3797
|
+
* Collapses the previously duplicated boilerplate (read `config.command`,
|
|
3798
|
+
* merge skill-program flags with program-specific options, dispatch via
|
|
3799
|
+
* `runWizard` / `runWizardCI`) into a single call.
|
|
3800
|
+
*/
|
|
3801
|
+
function nativeCommandFactory(config, opts = {}) {
|
|
3802
|
+
if (!config.command) throw new Error(`nativeCommandFactory: program "${config.id}" has no \`command\` — wizard-native programs must declare a CLI name`);
|
|
3803
|
+
return {
|
|
3804
|
+
name: config.command,
|
|
3805
|
+
description: config.description,
|
|
3806
|
+
options: mergeCommandOptions(config),
|
|
3807
|
+
children: opts.children,
|
|
3808
|
+
handler: (argv) => dispatchProgram(config, argv)
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3411
3811
|
//#endregion
|
|
3412
|
-
//#region src/commands/
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
...extras
|
|
3425
|
-
};
|
|
3426
|
-
if (options.ci) runWizardCI(eventsAuditConfig, options);
|
|
3427
|
-
else runWizard(eventsAuditConfig, options);
|
|
3428
|
-
}
|
|
3429
|
-
};
|
|
3812
|
+
//#region src/commands/migrate.ts
|
|
3813
|
+
/**
|
|
3814
|
+
* `wizard migrate` — flat skill command, Statsig today.
|
|
3815
|
+
*
|
|
3816
|
+
* Stays flat while there's only one vendor. When a second vendor lands,
|
|
3817
|
+
* restructure into a family with `familyCommandFactory` and publish each
|
|
3818
|
+
* vendor as a `cliEntries` entry with `parentCommand: 'migrate'` from
|
|
3819
|
+
* context-mill. That move is a deliberate breaking change for users
|
|
3820
|
+
* (`wizard migrate` stops running Statsig directly), so do it explicitly
|
|
3821
|
+
* when the second vendor arrives, not pre-emptively.
|
|
3822
|
+
*/
|
|
3823
|
+
const migrateCommand = nativeCommandFactory(migrationConfig);
|
|
3430
3824
|
//#endregion
|
|
3431
3825
|
//#region src/commands/revenue.ts
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
handler: (argv) => {
|
|
3440
|
-
const extras = revenueAnalyticsConfig.mapCliOptions?.(argv) ?? {};
|
|
3441
|
-
const options = {
|
|
3442
|
-
...argv,
|
|
3443
|
-
...extras
|
|
3444
|
-
};
|
|
3445
|
-
if (options.ci) runWizardCI(revenueAnalyticsConfig, options);
|
|
3446
|
-
else runWizard(revenueAnalyticsConfig, options);
|
|
3447
|
-
}
|
|
3448
|
-
};
|
|
3826
|
+
/**
|
|
3827
|
+
* `wizard revenue-analytics` — flat skill command, Stripe today.
|
|
3828
|
+
*
|
|
3829
|
+
* Stays flat while there's only one provider. Restructure into a family
|
|
3830
|
+
* if/when a second provider lands.
|
|
3831
|
+
*/
|
|
3832
|
+
const revenueCommand = nativeCommandFactory(revenueAnalyticsConfig);
|
|
3449
3833
|
//#endregion
|
|
3450
3834
|
//#region src/commands/slack.ts
|
|
3451
3835
|
const slackCommand = {
|
|
@@ -3462,7 +3846,7 @@ function runSlackConnect(argv) {
|
|
|
3462
3846
|
(async () => {
|
|
3463
3847
|
const debug = argv.debug;
|
|
3464
3848
|
try {
|
|
3465
|
-
const { startTUI } = await import("./start-tui-
|
|
3849
|
+
const { startTUI } = await import("./start-tui-WNb3ET14.js");
|
|
3466
3850
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
3467
3851
|
const tui = startTUI(VERSION, Program.SlackConnect);
|
|
3468
3852
|
tui.store.session = buildSession({ debug });
|
|
@@ -3522,8 +3906,14 @@ function runSkillMode(argv) {
|
|
|
3522
3906
|
function readSkillName(argv) {
|
|
3523
3907
|
return String(argv.skillName ?? argv["skill-name"] ?? "").trim();
|
|
3524
3908
|
}
|
|
3909
|
+
const BROWSABLE_ROLES = new Set(["command", "skill"]);
|
|
3910
|
+
function formatEntry(entry) {
|
|
3911
|
+
const path = entry.parentCommand ? `wizard ${entry.parentCommand} ${entry.command}` : entry.command ? `wizard ${entry.command}` : `wizard skill ${entry.skillId}`;
|
|
3912
|
+
return ` ${entry.skillId.padEnd(38)} ${path.padEnd(36)} ${entry.description}`;
|
|
3913
|
+
}
|
|
3525
3914
|
/**
|
|
3526
3915
|
* `wizard skill <skill-name>` — run a single context-mill skill by id.
|
|
3916
|
+
* `wizard skill list` — list every browsable skill in the catalog.
|
|
3527
3917
|
*
|
|
3528
3918
|
* Replaces the old `--skill=<id>` flag on the default command. The skill id
|
|
3529
3919
|
* is fetched from context-mill's release at runtime (same mechanism the flag
|
|
@@ -3531,9 +3921,41 @@ function readSkillName(argv) {
|
|
|
3531
3921
|
*/
|
|
3532
3922
|
const skillCommand = {
|
|
3533
3923
|
name: "skill <skill-name>",
|
|
3534
|
-
description: "Run a specific context-mill skill by name",
|
|
3924
|
+
description: "Run a specific context-mill skill by name (or `list` them)",
|
|
3925
|
+
children: [{
|
|
3926
|
+
name: "list",
|
|
3927
|
+
description: "List every browsable skill in the catalog",
|
|
3928
|
+
handler: (argv) => {
|
|
3929
|
+
runCommandHandler(async () => {
|
|
3930
|
+
const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv["local-mcp"]));
|
|
3931
|
+
const menu = await fetchSkillMenu(skillsBaseUrl);
|
|
3932
|
+
if (!menu) {
|
|
3933
|
+
analytics.wizardCapture("cli dispatch error", {
|
|
3934
|
+
reason: "registry unreachable",
|
|
3935
|
+
family: "skill",
|
|
3936
|
+
sub: "list",
|
|
3937
|
+
skillsBaseUrl
|
|
3938
|
+
});
|
|
3939
|
+
try {
|
|
3940
|
+
await analytics.flush();
|
|
3941
|
+
} catch {}
|
|
3942
|
+
process.stderr.write("\n\x1B[1;91m✖ Couldn't reach the skill registry.\x1B[0m\n Check your network connection and try again.\n\n");
|
|
3943
|
+
process.exit(1);
|
|
3944
|
+
}
|
|
3945
|
+
const entries = (menu.cliEntries ?? []).filter((e) => BROWSABLE_ROLES.has(e.role));
|
|
3946
|
+
if (entries.length === 0) {
|
|
3947
|
+
process.stdout.write("No skills found.\n");
|
|
3948
|
+
return;
|
|
3949
|
+
}
|
|
3950
|
+
process.stdout.write(`${entries.length} skill${entries.length === 1 ? "" : "s"}:\n`);
|
|
3951
|
+
process.stdout.write(` ${"SKILL ID".padEnd(38)} ${"COMMAND".padEnd(36)} DESCRIPTION\n`);
|
|
3952
|
+
for (const entry of entries) process.stdout.write(`${formatEntry(entry)}\n`);
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3955
|
+
}],
|
|
3535
3956
|
options: { ...skillProgramOptions },
|
|
3536
3957
|
check: (argv) => {
|
|
3958
|
+
if (argv.skillName == null && argv["skill-name"] == null) return true;
|
|
3537
3959
|
if (!readSkillName(argv)) throw new Error("skill needs a skill name, e.g. `wizard skill audit-events`");
|
|
3538
3960
|
return true;
|
|
3539
3961
|
},
|
|
@@ -3560,8 +3982,8 @@ function resolveInstallDir() {
|
|
|
3560
3982
|
if (inline) return inline.slice(14);
|
|
3561
3983
|
return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd();
|
|
3562
3984
|
}
|
|
3563
|
-
Wizard.use(basicIntegrationCommand).use(mcpCommand).use(
|
|
3985
|
+
Wizard.use(basicIntegrationCommand).use(mcpCommand).use(auditCommand).use(doctorCommand).use(migrateCommand).use(revenueCommand).use(slackCommand).use(uploadSourcemapsCommand).use(skillCommand).init();
|
|
3564
3986
|
//#endregion
|
|
3565
|
-
export {
|
|
3987
|
+
export { POSTHOG_SDKS$1 as _, PromptLabel as a, PROGRAM_REGISTRY as c, DISPLAY_NAME as d, SOURCE_MAPS_CONTEXT_KEYS as f, getContentBlocks$2 as g, fetchHealthIssues as h, useKeyboardHintsContext as i, Program as l, getKindMeta as m, useKeyBindings as n, runWizardCI as o, getContentBlocks$1 as p, KeyboardHintsProvider as r, runWizard as s, PickerMenu as t, getProgramConfig as u, STRIPE_SDKS as v };
|
|
3566
3988
|
|
|
3567
3989
|
//# sourceMappingURL=bin.js.map
|