@posthog/wizard 2.24.1 → 2.26.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/dist/{add-mcp-server-to-clients-CfwEQT_z.js → add-mcp-server-to-clients-C58l_KpV.js} +4 -4
- package/dist/{add-mcp-server-to-clients-CfwEQT_z.js.map → add-mcp-server-to-clients-C58l_KpV.js.map} +1 -1
- package/dist/{agent-interface-D1vtN6Wn.js → agent-interface-Dq_4h2eN.js} +435 -45
- package/dist/agent-interface-Dq_4h2eN.js.map +1 -0
- package/dist/{agent-runner-CBbkS0Ro.js → agent-runner-BNGW3osc.js} +748 -132
- package/dist/agent-runner-BNGW3osc.js.map +1 -0
- package/dist/{analytics-CUr82BDl.js → analytics-BX3LKPch.js} +51 -17
- package/dist/analytics-BX3LKPch.js.map +1 -0
- package/dist/{api-CI3Z74NG.js → api-DCHci5SD.js} +9 -5
- package/dist/api-DCHci5SD.js.map +1 -0
- package/dist/bin.js +830 -120
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-D_kxNmbJ.js → ci-install-CHIbwXio.js} +5 -5
- package/dist/{ci-install-D_kxNmbJ.js.map → ci-install-CHIbwXio.js.map} +1 -1
- package/dist/{debug-DxA_f5QT.js → debug-BizeRFR0.js} +17 -8
- package/dist/debug-BizeRFR0.js.map +1 -0
- package/dist/{debug-zMvpNYb2.js → debug-fg4BAKKA.js} +1 -1
- package/dist/{environment-CyS37cmM.js → environment-DS5Pq9Wm.js} +3 -3
- package/dist/{environment-CyS37cmM.js.map → environment-DS5Pq9Wm.js.map} +1 -1
- package/dist/{interactive-CG6FFqSw.js → interactive-DE3WDjk7.js} +3 -3
- package/dist/{interactive-CG6FFqSw.js.map → interactive-DE3WDjk7.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-DQz4FSb1.js → mcp-prompt-streaming-zsYd1zJx.js} +7 -26
- package/dist/mcp-prompt-streaming-zsYd1zJx.js.map +1 -0
- package/dist/{non-interactive-DWtHX3ZR.js → non-interactive-DNah9u3t.js} +2 -2
- package/dist/{non-interactive-DWtHX3ZR.js.map → non-interactive-DNah9u3t.js.map} +1 -1
- package/dist/{package-manager-BWUS4CP0.js → package-manager-Dma9-zGs.js} +2 -2
- package/dist/{package-manager-BWUS4CP0.js.map → package-manager-Dma9-zGs.js.map} +1 -1
- package/dist/{playground-D7AhMMF5.js → playground-Cwe0Q9HW.js} +146 -49
- package/dist/playground-Cwe0Q9HW.js.map +1 -0
- package/dist/{posthog-integration-DexZ2uHU.js → posthog-integration-CAYZdk0r.js} +11 -11
- package/dist/{posthog-integration-DexZ2uHU.js.map → posthog-integration-CAYZdk0r.js.map} +1 -1
- package/dist/{provisioning-9c-AQbsa.js → provisioning-BmL4ro-o.js} +10 -6
- package/dist/{provisioning-9c-AQbsa.js.map → provisioning-BmL4ro-o.js.map} +1 -1
- package/dist/{registry-CO7JVZyE.js → registry-C3wcDM3X.js} +4 -4
- package/dist/{registry-CO7JVZyE.js.map → registry-C3wcDM3X.js.map} +1 -1
- package/dist/{setup-utils-0U-_Md2G.js → setup-utils-CNWIMZ-d.js} +71 -16
- package/dist/setup-utils-CNWIMZ-d.js.map +1 -0
- package/dist/smoke-test.sh +36 -1
- package/dist/{start-tui-WNb3ET14.js → start-tui-CS802Ww9.js} +311 -54
- package/dist/start-tui-CS802Ww9.js.map +1 -0
- package/dist/{steps-BAUXDCC4.js → steps-BX44xr30.js} +6 -6
- package/dist/{steps-BAUXDCC4.js.map → steps-BX44xr30.js.map} +1 -1
- package/dist/{task-stream-CZawuzlz.js → task-stream-BQNSp0qR.js} +4 -3
- package/dist/task-stream-BQNSp0qR.js.map +1 -0
- package/dist/{telemetry-ycqCpNPr.js → telemetry-BH-MgWPT.js} +3 -3
- package/dist/{telemetry-ycqCpNPr.js.map → telemetry-BH-MgWPT.js.map} +1 -1
- package/dist/{AiOptInRequiredScreen-_33FOcVo.js → terminal-BSiupnOQ.js} +1058 -92
- package/dist/terminal-BSiupnOQ.js.map +1 -0
- package/dist/{urls-C8aJWvgh.js → urls-BuEABcmF.js} +2 -2
- package/dist/{urls-C8aJWvgh.js.map → urls-BuEABcmF.js.map} +1 -1
- package/dist/{wizard-abort-DWXyJdws.js → wizard-abort-CR3w2Efg.js} +1 -1
- package/dist/{wizard-abort-C6gRLxUE.js → wizard-abort-Dl2MJOP9.js} +3 -3
- package/dist/{wizard-abort-C6gRLxUE.js.map → wizard-abort-Dl2MJOP9.js.map} +1 -1
- package/dist/wizard-session-G3VWD6hv.js.map +1 -1
- package/dist/{wizard-ui-YdGFRyu_.js → wizard-ui-WZ48rUgr.js} +2 -1
- package/dist/wizard-ui-WZ48rUgr.js.map +1 -0
- package/package.json +1 -1
- package/dist/AiOptInRequiredScreen-_33FOcVo.js.map +0 -1
- package/dist/agent-interface-D1vtN6Wn.js.map +0 -1
- package/dist/agent-runner-CBbkS0Ro.js.map +0 -1
- package/dist/analytics-CUr82BDl.js.map +0 -1
- package/dist/api-CI3Z74NG.js.map +0 -1
- package/dist/debug-DxA_f5QT.js.map +0 -1
- package/dist/mcp-prompt-streaming-DQz4FSb1.js.map +0 -1
- package/dist/playground-D7AhMMF5.js.map +0 -1
- package/dist/setup-utils-0U-_Md2G.js.map +0 -1
- package/dist/start-tui-WNb3ET14.js.map +0 -1
- package/dist/task-stream-CZawuzlz.js.map +0 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +0 -1
package/dist/bin.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { $ as
|
|
3
|
-
import { t as analytics } from "./analytics-
|
|
4
|
-
import { r as setEntryCommand } from "./telemetry-
|
|
5
|
-
import { n as isUsingTypeScript } from "./setup-utils-
|
|
6
|
-
import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-
|
|
7
|
-
import { o as handleApiError } from "./api-
|
|
2
|
+
import { $ as getSkillsBaseUrl, P as POSTHOG_DOCS_URL, X as WIZARD_USER_AGENT, _ as SIGNUP_WIZARD_READINESS_CONFIG, a as getLogFilePath, et as VERSION, h as LoggingUI, m as setUI, p as getUI, r as debug, s as logToFile, v as evaluateWizardReadiness, y as getBlockingServiceKeys } from "./debug-BizeRFR0.js";
|
|
3
|
+
import { t as analytics } from "./analytics-BX3LKPch.js";
|
|
4
|
+
import { r as setEntryCommand } from "./telemetry-BH-MgWPT.js";
|
|
5
|
+
import { n as isUsingTypeScript } from "./setup-utils-CNWIMZ-d.js";
|
|
6
|
+
import { a as getUiHostFromHost, n as getCloudUrlFromRegion } from "./urls-BuEABcmF.js";
|
|
7
|
+
import { o as handleApiError } from "./api-DCHci5SD.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 {
|
|
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, p as Icons, r as FUNNEL_BLOCK } from "./posthog-integration-
|
|
9
|
+
import { r as runCleanups } from "./wizard-abort-Dl2MJOP9.js";
|
|
10
|
+
import { n as isNonInteractiveEnvironment } from "./environment-DS5Pq9Wm.js";
|
|
11
|
+
import { S as AUDIT_REPORT_FILE, b as AUDIT_CHECKS_FILE, c as recoverOrphanedSettingsBackups, h as fetchSkillMenu, p as WIZARD_TOOL_NAMES, u as AgentSignals, x as AUDIT_CHECKS_KEY } from "./agent-interface-Dq_4h2eN.js";
|
|
12
|
+
import { i as SPINNER_MESSAGE } from "./registry-C3wcDM3X.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-CAYZdk0r.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";
|
|
@@ -18,11 +18,17 @@ import yargs from "yargs";
|
|
|
18
18
|
import { hideBin } from "yargs/helpers";
|
|
19
19
|
import fs, { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
20
20
|
import path, { join, relative } from "path";
|
|
21
|
+
import * as os from "node:os";
|
|
22
|
+
import * as path$1 from "node:path";
|
|
23
|
+
import { spawnSync } from "node:child_process";
|
|
24
|
+
import * as fs$1 from "node:fs";
|
|
21
25
|
import axios from "axios";
|
|
22
26
|
import { z } from "zod";
|
|
23
27
|
import { Box, Text, render, useInput } from "ink";
|
|
24
28
|
import { createContext, createElement, useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
25
29
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
30
|
+
import { access, rm } from "node:fs/promises";
|
|
31
|
+
import * as readline from "node:readline/promises";
|
|
26
32
|
//#region src/commands/command.ts
|
|
27
33
|
/** Extract the bare command word(s) from a yargs name spec, dropping positionals and aliases' arg syntax. */
|
|
28
34
|
function commandKeys(name) {
|
|
@@ -184,7 +190,7 @@ function runProvision(argv) {
|
|
|
184
190
|
}
|
|
185
191
|
async function provision({ email, region, name, jsonMode }) {
|
|
186
192
|
try {
|
|
187
|
-
const { provisionNewAccount } = await import("./provisioning-
|
|
193
|
+
const { provisionNewAccount } = await import("./provisioning-BmL4ro-o.js").then((n) => n.n);
|
|
188
194
|
if (!jsonMode) getUI().log.info(`Provisioning account for ${email} in ${region}...`);
|
|
189
195
|
emitResult(await provisionNewAccount(email, name, region), jsonMode);
|
|
190
196
|
process.exit(0);
|
|
@@ -249,18 +255,18 @@ const basicIntegrationCommand = {
|
|
|
249
255
|
setEntryCommand("integrate");
|
|
250
256
|
(async () => {
|
|
251
257
|
if (argv.ci) {
|
|
252
|
-
const { runCIInstall } = await import("./ci-install-
|
|
258
|
+
const { runCIInstall } = await import("./ci-install-CHIbwXio.js");
|
|
253
259
|
return runCIInstall(argv);
|
|
254
260
|
}
|
|
255
261
|
if (isNonInteractiveEnvironment()) {
|
|
256
|
-
const { failNonInteractive } = await import("./non-interactive-
|
|
262
|
+
const { failNonInteractive } = await import("./non-interactive-DNah9u3t.js");
|
|
257
263
|
return failNonInteractive();
|
|
258
264
|
}
|
|
259
265
|
if (argv.playground) {
|
|
260
|
-
const { runPlayground } = await import("./playground-
|
|
266
|
+
const { runPlayground } = await import("./playground-Cwe0Q9HW.js");
|
|
261
267
|
return runPlayground();
|
|
262
268
|
}
|
|
263
|
-
const { runInteractive } = await import("./interactive-
|
|
269
|
+
const { runInteractive } = await import("./interactive-DE3WDjk7.js");
|
|
264
270
|
runInteractive(argv);
|
|
265
271
|
})();
|
|
266
272
|
}
|
|
@@ -841,7 +847,7 @@ const EVENTS_AUDIT_SEED_CHECKS = [
|
|
|
841
847
|
//#endregion
|
|
842
848
|
//#region src/lib/programs/events-audit/index.ts
|
|
843
849
|
const SETUP_REPORT_FILE = "posthog-events-audit-report.md";
|
|
844
|
-
const DOCS_URL$
|
|
850
|
+
const DOCS_URL$3 = "https://posthog.com/docs/product-analytics/best-practices";
|
|
845
851
|
const eventsAuditConfig = {
|
|
846
852
|
command: "events-audit",
|
|
847
853
|
description: "Audit PostHog event tracking in this project",
|
|
@@ -863,7 +869,7 @@ const eventsAuditConfig = {
|
|
|
863
869
|
successMessage: "Events audit complete! You can view the report at ./posthog-events-audit-report.md",
|
|
864
870
|
estimatedDurationMinutes: 5,
|
|
865
871
|
reportFile: SETUP_REPORT_FILE,
|
|
866
|
-
docsUrl: DOCS_URL$
|
|
872
|
+
docsUrl: DOCS_URL$3,
|
|
867
873
|
errorMessage: "Events audit failed",
|
|
868
874
|
additionalFeatureQueue: session.additionalFeatureQueue,
|
|
869
875
|
customPrompt: (ctx) => `Audit PostHog event capture in this project. Do not modify any project files — produce a read-only report only.
|
|
@@ -881,7 +887,7 @@ Project context:
|
|
|
881
887
|
message: "Your events audit was successful",
|
|
882
888
|
reportFile: SETUP_REPORT_FILE,
|
|
883
889
|
changes: [],
|
|
884
|
-
docsUrl: DOCS_URL$
|
|
890
|
+
docsUrl: DOCS_URL$3,
|
|
885
891
|
continueUrl: sess.signup && cloudUrl ? `${cloudUrl}/products?source=wizard` : void 0,
|
|
886
892
|
dashboardUrl: sess.dashboardUrl ?? (cloudUrl ? `${cloudUrl}/dashboard` : void 0),
|
|
887
893
|
notebookUrl: sess.notebookUrl ?? void 0
|
|
@@ -2410,15 +2416,15 @@ const getContentBlocks = (store) => pace([
|
|
|
2410
2416
|
]);
|
|
2411
2417
|
//#endregion
|
|
2412
2418
|
//#region src/lib/programs/error-tracking-upload-source-maps/index.ts
|
|
2413
|
-
const REPORT_FILE = "posthog-source-maps-report.md";
|
|
2414
|
-
const DOCS_URL = "https://posthog.com/docs/error-tracking/upload-source-maps";
|
|
2419
|
+
const REPORT_FILE$1 = "posthog-source-maps-report.md";
|
|
2420
|
+
const DOCS_URL$1 = "https://posthog.com/docs/error-tracking/upload-source-maps";
|
|
2415
2421
|
const errorTrackingUploadSourceMapsConfig = {
|
|
2416
2422
|
command: "upload-source-maps",
|
|
2417
2423
|
description: "Upload source maps to PostHog Error Tracking",
|
|
2418
2424
|
id: "error-tracking-upload-source-maps",
|
|
2419
2425
|
requiresAi: true,
|
|
2420
2426
|
steps: ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM,
|
|
2421
|
-
reportFile: REPORT_FILE,
|
|
2427
|
+
reportFile: REPORT_FILE$1,
|
|
2422
2428
|
getContentBlocks,
|
|
2423
2429
|
requires: ["posthog-integration"],
|
|
2424
2430
|
run: (session) => {
|
|
@@ -2428,8 +2434,8 @@ const errorTrackingUploadSourceMapsConfig = {
|
|
|
2428
2434
|
return Promise.resolve({
|
|
2429
2435
|
integrationLabel: "error-tracking-upload-source-maps",
|
|
2430
2436
|
successMessage: "Source maps wired up!",
|
|
2431
|
-
reportFile: REPORT_FILE,
|
|
2432
|
-
docsUrl: DOCS_URL,
|
|
2437
|
+
reportFile: REPORT_FILE$1,
|
|
2438
|
+
docsUrl: DOCS_URL$1,
|
|
2433
2439
|
spinnerMessage: "Wiring up source maps...",
|
|
2434
2440
|
estimatedDurationMinutes: 3,
|
|
2435
2441
|
abortCases: SOURCE_MAPS_ABORT_CASES,
|
|
@@ -2455,14 +2461,363 @@ const errorTrackingUploadSourceMapsConfig = {
|
|
|
2455
2461
|
return {
|
|
2456
2462
|
kind: "success",
|
|
2457
2463
|
message: "Source maps wired up!",
|
|
2458
|
-
reportFile: REPORT_FILE,
|
|
2459
|
-
docsUrl: DOCS_URL
|
|
2464
|
+
reportFile: REPORT_FILE$1,
|
|
2465
|
+
docsUrl: DOCS_URL$1
|
|
2460
2466
|
};
|
|
2461
2467
|
}
|
|
2462
2468
|
});
|
|
2463
2469
|
}
|
|
2464
2470
|
};
|
|
2465
2471
|
//#endregion
|
|
2472
|
+
//#region src/lib/programs/self-driving/detect.ts
|
|
2473
|
+
/**
|
|
2474
|
+
* Self-driving prerequisite detection + abort vocabulary.
|
|
2475
|
+
*
|
|
2476
|
+
* The only thing worth verifying before auth is local and cheap: that
|
|
2477
|
+
* `session.installDir` is a real, readable directory. We deliberately do
|
|
2478
|
+
* NOT require the base posthog-integration report to be present — it is a
|
|
2479
|
+
* report many users never commit, and `requires: ['posthog-integration']`
|
|
2480
|
+
* is metadata, not a hard runtime gate. Real readiness (integration state
|
|
2481
|
+
* + beta access) is established by the agent's STEP 1 Signals API probe at
|
|
2482
|
+
* the start of the run. The beta gates (the `product-autonomy` access flag
|
|
2483
|
+
* and `signals-scout` enrollment — PostHog-side flag names, unchanged by
|
|
2484
|
+
* the wizard-side "self-driving" rename) are PostHog-internal flags with no
|
|
2485
|
+
* customer-facing read API, which is why that probe lives in the run and
|
|
2486
|
+
* emits a structured `[ABORT]` when the product is not available.
|
|
2487
|
+
*/
|
|
2488
|
+
/**
|
|
2489
|
+
* `[ABORT] <reason>` cases the self-driving skill can emit. The
|
|
2490
|
+
* reason strings are part of the skill contract — the context-mill
|
|
2491
|
+
* `self-driving-setup` skill emits these exact strings.
|
|
2492
|
+
*/
|
|
2493
|
+
const SELF_DRIVING_ABORT_CASES = [
|
|
2494
|
+
{
|
|
2495
|
+
match: /^self-driving is not available for this project$/i,
|
|
2496
|
+
message: "PostHog Self-driving is not available for this project",
|
|
2497
|
+
body: "Self-driving is in beta and is enabled per team by PostHog. This project does not appear to have access yet. Reach out to your PostHog contact (or wizard@posthog.com) to join the beta, then run the wizard again."
|
|
2498
|
+
},
|
|
2499
|
+
{
|
|
2500
|
+
match: /^github connection declined$/i,
|
|
2501
|
+
message: "GitHub connection required",
|
|
2502
|
+
body: "Self-driving needs GitHub access to research issues in your code and open fixes, so setup cannot finish without it. Nothing was left half-configured. When you are ready to install the PostHog GitHub App, run the wizard again."
|
|
2503
|
+
},
|
|
2504
|
+
{
|
|
2505
|
+
match: /^requires-interactive-mode$/i,
|
|
2506
|
+
message: "Interactive terminal required",
|
|
2507
|
+
body: "Self-driving setup asks questions along the way (GitHub and issue trackers), so it needs an interactive terminal. Run the wizard outside CI / non-interactive mode."
|
|
2508
|
+
},
|
|
2509
|
+
{
|
|
2510
|
+
match: /^requirements-incomplete$/i,
|
|
2511
|
+
message: "Setup needs your input",
|
|
2512
|
+
body: "The wizard could not collect the answers this setup needs (the environment was non-interactive, or the question budget ran out). Nothing was left half-configured. Run the wizard again in an interactive terminal."
|
|
2513
|
+
}
|
|
2514
|
+
];
|
|
2515
|
+
/**
|
|
2516
|
+
* Verify `session.installDir` is a readable directory. Writes a
|
|
2517
|
+
* `SelfDrivingDetectError` to frameworkContext on failure — the intro
|
|
2518
|
+
* screen renders it and blocks.
|
|
2519
|
+
*/
|
|
2520
|
+
function detectSelfDrivingPrerequisites(session, setFrameworkContext) {
|
|
2521
|
+
const fail = (error) => setFrameworkContext("detectError", error);
|
|
2522
|
+
const installDir = session.installDir;
|
|
2523
|
+
if (!existsSync(installDir)) {
|
|
2524
|
+
fail({
|
|
2525
|
+
kind: "bad-directory",
|
|
2526
|
+
path: installDir,
|
|
2527
|
+
reason: "missing"
|
|
2528
|
+
});
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
try {
|
|
2532
|
+
if (!statSync(installDir).isDirectory()) {
|
|
2533
|
+
fail({
|
|
2534
|
+
kind: "bad-directory",
|
|
2535
|
+
path: installDir,
|
|
2536
|
+
reason: "not-dir"
|
|
2537
|
+
});
|
|
2538
|
+
return;
|
|
2539
|
+
}
|
|
2540
|
+
} catch {
|
|
2541
|
+
fail({
|
|
2542
|
+
kind: "bad-directory",
|
|
2543
|
+
path: installDir,
|
|
2544
|
+
reason: "unreadable"
|
|
2545
|
+
});
|
|
2546
|
+
return;
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
//#endregion
|
|
2550
|
+
//#region src/lib/programs/self-driving/steps.ts
|
|
2551
|
+
const SELF_DRIVING_PROGRAM = [
|
|
2552
|
+
{
|
|
2553
|
+
id: "detect",
|
|
2554
|
+
label: "Detecting prerequisites",
|
|
2555
|
+
onReady: (ctx) => detectSelfDrivingPrerequisites(ctx.session, ctx.setFrameworkContext)
|
|
2556
|
+
},
|
|
2557
|
+
{
|
|
2558
|
+
id: "intro",
|
|
2559
|
+
label: "Welcome",
|
|
2560
|
+
screenId: "self-driving-intro",
|
|
2561
|
+
gate: (session) => session.setupConfirmed
|
|
2562
|
+
},
|
|
2563
|
+
HEALTH_CHECK_STEP,
|
|
2564
|
+
{
|
|
2565
|
+
id: "auth",
|
|
2566
|
+
label: "Authentication",
|
|
2567
|
+
screenId: "auth",
|
|
2568
|
+
isComplete: (session) => session.credentials !== null
|
|
2569
|
+
},
|
|
2570
|
+
{
|
|
2571
|
+
id: "run",
|
|
2572
|
+
label: "Self-driving",
|
|
2573
|
+
screenId: "run",
|
|
2574
|
+
isComplete: (session) => session.runPhase === "completed" || session.runPhase === "error"
|
|
2575
|
+
},
|
|
2576
|
+
{
|
|
2577
|
+
id: "outro",
|
|
2578
|
+
label: "Done",
|
|
2579
|
+
screenId: "outro",
|
|
2580
|
+
isComplete: (session) => session.outroDismissed
|
|
2581
|
+
}
|
|
2582
|
+
];
|
|
2583
|
+
//#endregion
|
|
2584
|
+
//#region src/lib/programs/self-driving/prompt.ts
|
|
2585
|
+
/**
|
|
2586
|
+
* Build the self-driving run prompt. The installed
|
|
2587
|
+
* `self-driving-setup` skill is the source of truth for the HOW of
|
|
2588
|
+
* every step (which MCP tools to call, which sources/scouts apply, how
|
|
2589
|
+
* to verify); this prompt carries the order, the wizard-specific
|
|
2590
|
+
* mechanics (wizard_ask, abort signals), and the project URLs.
|
|
2591
|
+
*/
|
|
2592
|
+
function buildSelfDrivingPrompt(ctx) {
|
|
2593
|
+
const uiHost = getUiHostFromHost(ctx.host).replace(/\/$/, "");
|
|
2594
|
+
const projectBase = `${uiHost}/project/${ctx.projectId}`;
|
|
2595
|
+
const integrationsSettingsUrl = `${projectBase}/settings/environment-integrations`;
|
|
2596
|
+
const orgAiSettingsUrl = `${uiHost}/settings/organization#organization-ai-consent`;
|
|
2597
|
+
const newWarehouseSourceUrl = `${projectBase}/pipeline/new/source`;
|
|
2598
|
+
const inboxUrl = `${projectBase}/inbox`;
|
|
2599
|
+
const optIn = (value) => value === true ? "ON" : value === false ? "OFF" : "unknown";
|
|
2600
|
+
const optIns = ctx.teamProductOptIns;
|
|
2601
|
+
return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout fleet, design custom scouts for what this product uniquely needs, and hand the user a configured inbox.
|
|
2602
|
+
|
|
2603
|
+
Project URLs:
|
|
2604
|
+
- Integrations settings (GitHub App install): ${integrationsSettingsUrl}
|
|
2605
|
+
- Organization AI settings: ${orgAiSettingsUrl}
|
|
2606
|
+
- New data warehouse source (Linear / Zendesk / GitHub issues / pganalyze): ${newWarehouseSourceUrl}
|
|
2607
|
+
- Self-driving inbox: ${inboxUrl}
|
|
2608
|
+
|
|
2609
|
+
Project state read at auth time (PostHog project settings — authoritative
|
|
2610
|
+
for whether a product is enabled, regardless of what this repo
|
|
2611
|
+
instruments; products are often instrumented from other repos or the
|
|
2612
|
+
snippet, so repo evidence may rule a product IN but never OUT):
|
|
2613
|
+
- Session replay recording: ${optIn(optIns?.sessionReplay)}
|
|
2614
|
+
- Exception autocapture (error tracking): ${optIn(optIns?.exceptionAutocapture)}
|
|
2615
|
+
- Surveys: ${optIn(optIns?.surveys)}
|
|
2616
|
+
|
|
2617
|
+
The installed skill is the source of truth for the HOW of every step:
|
|
2618
|
+
which MCP tools to call, which sources and scouts apply to this product,
|
|
2619
|
+
and how to verify each change. The STEPS below give the order and the
|
|
2620
|
+
wizard-specific mechanics — read the matching skill reference before
|
|
2621
|
+
doing the work, and do not invent steps the skill doesn't describe.
|
|
2622
|
+
|
|
2623
|
+
Before doing any work, create your FULL task list in a single TaskCreate
|
|
2624
|
+
call so the user can follow your progress in the TUI. Use exactly these
|
|
2625
|
+
tasks, in this order:
|
|
2626
|
+
1. Check Self-driving access
|
|
2627
|
+
2. Read project and current Self-driving state
|
|
2628
|
+
3. Connect GitHub (required)
|
|
2629
|
+
4. Enable signal sources
|
|
2630
|
+
5. Offer issue-tracker integrations
|
|
2631
|
+
6. Configure the scout fleet
|
|
2632
|
+
7. Design custom scouts
|
|
2633
|
+
8. Write report and hand off
|
|
2634
|
+
Drive the list with TaskUpdate — mark a task in_progress when you start
|
|
2635
|
+
it and completed when done. If a step turns out to be a no-op (e.g.
|
|
2636
|
+
GitHub is already connected), still mark its task completed.
|
|
2637
|
+
|
|
2638
|
+
Wizard mechanics:
|
|
2639
|
+
- Ask the user things ONLY with the wizard_ask MCP tool, and batch
|
|
2640
|
+
related questions (e.g. one multi-select for all issue trackers, not
|
|
2641
|
+
one ask per tool). The per-run ask budget is limited.
|
|
2642
|
+
- If wizard_ask is unavailable (CI / non-interactive), emit
|
|
2643
|
+
${AgentSignals.ABORT} requires-interactive-mode and halt.
|
|
2644
|
+
- When a step requires the user to do something in the browser, give
|
|
2645
|
+
them the exact URL inside the wizard_ask prompt text — do not try to
|
|
2646
|
+
open a browser yourself.
|
|
2647
|
+
- Emit ${AgentSignals.STATUS} lines as you complete each step so the
|
|
2648
|
+
user sees progress.
|
|
2649
|
+
|
|
2650
|
+
Follow these steps IN ORDER. Do not skip or reorder.
|
|
2651
|
+
|
|
2652
|
+
STEP 1 — Check Self-driving access. (skill: "Check access")
|
|
2653
|
+
Probe the Signals API as the skill describes. If the API is not
|
|
2654
|
+
available for this project (permission or not-found errors), emit
|
|
2655
|
+
${AgentSignals.ABORT} self-driving is not available for this project
|
|
2656
|
+
and halt.
|
|
2657
|
+
|
|
2658
|
+
STEP 2 — Read project and current Signals state. (skill: "Read context")
|
|
2659
|
+
If ./posthog-setup-report.md exists, read it as a strong hint for what
|
|
2660
|
+
THIS repo instruments — but it is often absent (users frequently don't
|
|
2661
|
+
commit it), so do NOT depend on it. Combine whatever you find with the
|
|
2662
|
+
project-state block above and the skill's server-side usage probes —
|
|
2663
|
+
repo evidence rules products in, never out. Do a light scan ONLY for
|
|
2664
|
+
what neither covers. List the currently enabled signal sources so every
|
|
2665
|
+
later write is idempotent.
|
|
2666
|
+
|
|
2667
|
+
STEP 3 — Connect GitHub. REQUIRED. (skill: "Connect GitHub")
|
|
2668
|
+
Signals cannot research or fix issues without code access. Check for
|
|
2669
|
+
an existing GitHub integration first; if absent, send the user to
|
|
2670
|
+
${integrationsSettingsUrl} via wizard_ask and verify the connection
|
|
2671
|
+
after they confirm. If the user cannot connect now, emit
|
|
2672
|
+
${AgentSignals.ABORT} github connection declined
|
|
2673
|
+
and halt — never finish setup without GitHub.
|
|
2674
|
+
|
|
2675
|
+
STEP 4 — Enable signal sources. (skill: "Enable sources")
|
|
2676
|
+
Enable the sources that match what this product actually uses, per
|
|
2677
|
+
the skill. Never enable a source for a tool the user hasn't
|
|
2678
|
+
confirmed they use.
|
|
2679
|
+
|
|
2680
|
+
STEP 5 — Offer issue-tracker integrations. (skill: "Connected tools")
|
|
2681
|
+
One batched multi-select wizard_ask for the external tools the skill
|
|
2682
|
+
lists. The run auto-connects the ones it can (GitHub Issues, and
|
|
2683
|
+
Linear via a one-click OAuth link), verifying each with a single
|
|
2684
|
+
silent check — never nudge. It arms the rest as dormant responders to
|
|
2685
|
+
finish later: for tools it can't auto-connect (Zendesk, pganalyze) it
|
|
2686
|
+
never sends the user to paste credentials and never re-prompts. Enable
|
|
2687
|
+
a source only for a tool the user picked.
|
|
2688
|
+
|
|
2689
|
+
STEP 6 — Configure the scout fleet. (skill: "Scouts")
|
|
2690
|
+
Materialize the fleet and disable the scouts whose product surface
|
|
2691
|
+
this project lacks, per the skill.
|
|
2692
|
+
|
|
2693
|
+
STEP 7 — Design custom scouts for this product. (skill: "Custom scouts")
|
|
2694
|
+
You are the only actor that has read this repo — turn that into
|
|
2695
|
+
coverage per the skill: a real gap analysis of the project's
|
|
2696
|
+
watchable surfaces against what the canonical fleet already covers,
|
|
2697
|
+
then custom scouts for the uncovered ones. Keep scout bodies
|
|
2698
|
+
high-level: describe the behavior and signal conditions to watch,
|
|
2699
|
+
referencing repo evidence by file/function name — never paste raw
|
|
2700
|
+
source, secrets, env values, or customer data into a scout body.
|
|
2701
|
+
Never edit canonical scout bodies. Propose all candidates in ONE
|
|
2702
|
+
batched wizard_ask
|
|
2703
|
+
before creating anything; the user declining everything (or finding
|
|
2704
|
+
no gap at all) is a valid outcome, not an abort. Mark the task
|
|
2705
|
+
completed either way.
|
|
2706
|
+
|
|
2707
|
+
STEP 8 — Write the report and hand off. (skill: "Report")
|
|
2708
|
+
Write the report per the skill, including follow-ups for anything
|
|
2709
|
+
deferred. Tell the user findings will start appearing in their inbox
|
|
2710
|
+
at ${inboxUrl} within about 30 minutes.`;
|
|
2711
|
+
}
|
|
2712
|
+
//#endregion
|
|
2713
|
+
//#region src/lib/programs/self-driving/content/tips.ts
|
|
2714
|
+
const SELF_DRIVING_TIPS = [
|
|
2715
|
+
{
|
|
2716
|
+
id: "what-is-a-signal-source",
|
|
2717
|
+
title: "What's a signal source?",
|
|
2718
|
+
description: "A signal source is a PostHog product or connected tool — errors, session replays, support, GitHub or Linear issues — that feeds findings into your Self-driving inbox."
|
|
2719
|
+
},
|
|
2720
|
+
{
|
|
2721
|
+
id: "what-is-a-scout",
|
|
2722
|
+
title: "What's a scout?",
|
|
2723
|
+
description: "Scouts are scheduled checks that scan your data and flag issues — a spike in errors, a dropping funnel — straight to your inbox."
|
|
2724
|
+
},
|
|
2725
|
+
{
|
|
2726
|
+
id: "findings-in-inbox",
|
|
2727
|
+
title: "Findings land in your inbox",
|
|
2728
|
+
description: "Once setup finishes, PostHog starts scanning within ~30 minutes and surfaces what it finds in your Self-driving inbox — grouped, researched, and ready to act on."
|
|
2729
|
+
}
|
|
2730
|
+
];
|
|
2731
|
+
const getTips = () => SELF_DRIVING_TIPS;
|
|
2732
|
+
//#endregion
|
|
2733
|
+
//#region src/lib/programs/self-driving/index.ts
|
|
2734
|
+
const SELF_DRIVING_SKILL_ID = "self-driving-setup";
|
|
2735
|
+
const REPORT_FILE = "posthog-self-driving-report.md";
|
|
2736
|
+
const DOCS_URL = "https://posthog.com/docs";
|
|
2737
|
+
const SUCCESS_MESSAGE = "Self-driving is on! PostHog will start scanning within ~30 minutes and surface findings in your inbox.";
|
|
2738
|
+
const WIZARD_MARKER = ".posthog-wizard";
|
|
2739
|
+
/**
|
|
2740
|
+
* Remove the installed setup skill. It is transient orchestration
|
|
2741
|
+
* knowledge (unlike integration skills such as the Next.js one, which
|
|
2742
|
+
* are worth keeping for the user's coding agents), so the program
|
|
2743
|
+
* cleans it up instead of showing the keep-skills prompt. Marker-
|
|
2744
|
+
* guarded: only directories the wizard installed are touched.
|
|
2745
|
+
*/
|
|
2746
|
+
async function removeInstalledSkill(installDir) {
|
|
2747
|
+
const skillDir = join(installDir, ".claude", "skills", SELF_DRIVING_SKILL_ID);
|
|
2748
|
+
try {
|
|
2749
|
+
await access(join(skillDir, WIZARD_MARKER));
|
|
2750
|
+
} catch {
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
await rm(skillDir, {
|
|
2754
|
+
recursive: true,
|
|
2755
|
+
force: true
|
|
2756
|
+
}).catch(() => void 0);
|
|
2757
|
+
}
|
|
2758
|
+
const run = {
|
|
2759
|
+
skillId: SELF_DRIVING_SKILL_ID,
|
|
2760
|
+
integrationLabel: SELF_DRIVING_SKILL_ID,
|
|
2761
|
+
customPrompt: buildSelfDrivingPrompt,
|
|
2762
|
+
successMessage: SUCCESS_MESSAGE,
|
|
2763
|
+
reportFile: REPORT_FILE,
|
|
2764
|
+
docsUrl: DOCS_URL,
|
|
2765
|
+
spinnerMessage: "Setting up PostHog Self-driving...",
|
|
2766
|
+
estimatedDurationMinutes: 10,
|
|
2767
|
+
abortCases: SELF_DRIVING_ABORT_CASES,
|
|
2768
|
+
maxQuestions: 13,
|
|
2769
|
+
richLinks: true,
|
|
2770
|
+
askTimeoutMs: 1800 * 1e3,
|
|
2771
|
+
postRun: async (session) => {
|
|
2772
|
+
await removeInstalledSkill(session.installDir);
|
|
2773
|
+
},
|
|
2774
|
+
buildOutroData: (_session, credentials) => {
|
|
2775
|
+
return {
|
|
2776
|
+
kind: "success",
|
|
2777
|
+
message: "Self-driving is on. PostHog is scanning your project — first findings hit your inbox within ~30 minutes.",
|
|
2778
|
+
primaryLink: {
|
|
2779
|
+
label: "Your Self-driving inbox",
|
|
2780
|
+
url: `${getUiHostFromHost(credentials.host).replace(/\/$/, "")}/project/${credentials.projectId}/inbox`
|
|
2781
|
+
},
|
|
2782
|
+
nextSteps: {
|
|
2783
|
+
heading: "In your inbox you can:",
|
|
2784
|
+
items: [
|
|
2785
|
+
"Review the findings PostHog surfaces",
|
|
2786
|
+
"Triage what matters and dismiss the noise",
|
|
2787
|
+
"Kick off fixes and open issues"
|
|
2788
|
+
]
|
|
2789
|
+
},
|
|
2790
|
+
reportFile: REPORT_FILE
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
};
|
|
2794
|
+
const selfDrivingConfig = {
|
|
2795
|
+
...createSkillProgram({
|
|
2796
|
+
skillId: SELF_DRIVING_SKILL_ID,
|
|
2797
|
+
command: "self-driving",
|
|
2798
|
+
id: "self-driving",
|
|
2799
|
+
description: "Set up PostHog Self-driving for this project",
|
|
2800
|
+
integrationLabel: SELF_DRIVING_SKILL_ID,
|
|
2801
|
+
successMessage: SUCCESS_MESSAGE,
|
|
2802
|
+
reportFile: REPORT_FILE,
|
|
2803
|
+
docsUrl: DOCS_URL,
|
|
2804
|
+
spinnerMessage: "Setting up PostHog Self-driving...",
|
|
2805
|
+
estimatedDurationMinutes: 10,
|
|
2806
|
+
requires: ["posthog-integration"],
|
|
2807
|
+
abortCases: SELF_DRIVING_ABORT_CASES
|
|
2808
|
+
}),
|
|
2809
|
+
steps: SELF_DRIVING_PROGRAM,
|
|
2810
|
+
run,
|
|
2811
|
+
getTips,
|
|
2812
|
+
getContentBlocks: (store) => {
|
|
2813
|
+
const blocks = getContentBlocks$2(store);
|
|
2814
|
+
return blocks.map((b, i) => i === blocks.length - 1 && typeof b === "object" ? {
|
|
2815
|
+
...b,
|
|
2816
|
+
pause: 5e3
|
|
2817
|
+
} : b);
|
|
2818
|
+
}
|
|
2819
|
+
};
|
|
2820
|
+
//#endregion
|
|
2466
2821
|
//#region src/lib/programs/mcp/index.ts
|
|
2467
2822
|
const mcpAddConfig = {
|
|
2468
2823
|
id: "mcp-add",
|
|
@@ -2584,6 +2939,7 @@ const PROGRAM_REGISTRY = [
|
|
|
2584
2939
|
posthogDoctorConfig,
|
|
2585
2940
|
webAnalyticsDoctorConfig,
|
|
2586
2941
|
migrationConfig,
|
|
2942
|
+
selfDrivingConfig,
|
|
2587
2943
|
agentSkillConfig,
|
|
2588
2944
|
mcpAddConfig,
|
|
2589
2945
|
mcpRemoveConfig,
|
|
@@ -2604,6 +2960,7 @@ const Program = {
|
|
|
2604
2960
|
EventsAudit: eventsAuditConfig.id,
|
|
2605
2961
|
PosthogDoctor: posthogDoctorConfig.id,
|
|
2606
2962
|
WebAnalyticsDoctor: webAnalyticsDoctorConfig.id,
|
|
2963
|
+
SelfDriving: selfDrivingConfig.id,
|
|
2607
2964
|
AgentSkill: agentSkillConfig.id,
|
|
2608
2965
|
McpAdd: mcpAddConfig.id,
|
|
2609
2966
|
McpRemove: mcpRemoveConfig.id,
|
|
@@ -2648,7 +3005,7 @@ function runMcpAdd(argv) {
|
|
|
2648
3005
|
const debug = argv.debug;
|
|
2649
3006
|
const localMcp = argv.local;
|
|
2650
3007
|
try {
|
|
2651
|
-
const { startTUI } = await import("./start-tui-
|
|
3008
|
+
const { startTUI } = await import("./start-tui-CS802Ww9.js");
|
|
2652
3009
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2653
3010
|
const tui = startTUI(VERSION, Program.McpAdd);
|
|
2654
3011
|
tui.store.session = buildSession({
|
|
@@ -2660,7 +3017,7 @@ function runMcpAdd(argv) {
|
|
|
2660
3017
|
} catch (error) {
|
|
2661
3018
|
if (!isTUIUnavailable(error)) throw error;
|
|
2662
3019
|
setUI(new LoggingUI());
|
|
2663
|
-
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-
|
|
3020
|
+
const { addMCPServerToClientsStep } = await import("./add-mcp-server-to-clients-C58l_KpV.js").then((n) => n.r);
|
|
2664
3021
|
await addMCPServerToClientsStep({
|
|
2665
3022
|
local: localMcp,
|
|
2666
3023
|
features,
|
|
@@ -2699,7 +3056,7 @@ function runMcpRemove(argv) {
|
|
|
2699
3056
|
const debug = argv.debug;
|
|
2700
3057
|
const localMcp = argv.local;
|
|
2701
3058
|
try {
|
|
2702
|
-
const { startTUI } = await import("./start-tui-
|
|
3059
|
+
const { startTUI } = await import("./start-tui-CS802Ww9.js");
|
|
2703
3060
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2704
3061
|
const tui = startTUI(VERSION, Program.McpRemove);
|
|
2705
3062
|
tui.store.session = buildSession({
|
|
@@ -2708,7 +3065,7 @@ function runMcpRemove(argv) {
|
|
|
2708
3065
|
});
|
|
2709
3066
|
} catch {
|
|
2710
3067
|
setUI(new LoggingUI());
|
|
2711
|
-
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-
|
|
3068
|
+
const { removeMCPServerFromClientsStep } = await import("./add-mcp-server-to-clients-C58l_KpV.js").then((n) => n.r);
|
|
2712
3069
|
await removeMCPServerFromClientsStep({ local: localMcp });
|
|
2713
3070
|
}
|
|
2714
3071
|
})();
|
|
@@ -2730,7 +3087,7 @@ function runMcpTutorial(argv) {
|
|
|
2730
3087
|
const debug = argv.debug;
|
|
2731
3088
|
const localMcp = argv.local;
|
|
2732
3089
|
try {
|
|
2733
|
-
const { startTUI } = await import("./start-tui-
|
|
3090
|
+
const { startTUI } = await import("./start-tui-CS802Ww9.js");
|
|
2734
3091
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2735
3092
|
const tui = startTUI(VERSION, Program.McpTutorial);
|
|
2736
3093
|
tui.store.session = buildSession({
|
|
@@ -2785,9 +3142,9 @@ function runWizard(config, options) {
|
|
|
2785
3142
|
(async () => {
|
|
2786
3143
|
try {
|
|
2787
3144
|
const installDir = options.installDir || process.cwd();
|
|
2788
|
-
const { startTUI } = await import("./start-tui-
|
|
3145
|
+
const { startTUI } = await import("./start-tui-CS802Ww9.js");
|
|
2789
3146
|
const { buildSession, RunPhase } = await import("./wizard-session-wPJtNl4c.js");
|
|
2790
|
-
const { TaskStreamPush } = await import("./task-stream-
|
|
3147
|
+
const { TaskStreamPush } = await import("./task-stream-BQNSp0qR.js");
|
|
2791
3148
|
const { PostHogDestination } = await import("./posthog-Cr37rnla.js");
|
|
2792
3149
|
tui = startTUI(WIZARD_VERSION, config.id);
|
|
2793
3150
|
const activeTui = tui;
|
|
@@ -2841,7 +3198,7 @@ function runWizard(config, options) {
|
|
|
2841
3198
|
await activeTui.store.getGate("health-check");
|
|
2842
3199
|
const skipAgent = config.run == null;
|
|
2843
3200
|
if (skipAgent) {
|
|
2844
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
3201
|
+
const { getOrAskForProjectData } = await import("./setup-utils-CNWIMZ-d.js").then((n) => n.r);
|
|
2845
3202
|
const { projectApiKey, host, accessToken, projectId } = await getOrAskForProjectData({
|
|
2846
3203
|
signup: session.signup,
|
|
2847
3204
|
ci: session.ci,
|
|
@@ -2856,7 +3213,7 @@ function runWizard(config, options) {
|
|
|
2856
3213
|
projectId
|
|
2857
3214
|
});
|
|
2858
3215
|
} else {
|
|
2859
|
-
const { runAgent } = await import("./agent-runner-
|
|
3216
|
+
const { runAgent } = await import("./agent-runner-BNGW3osc.js");
|
|
2860
3217
|
await runAgent(config, activeTui.store.session);
|
|
2861
3218
|
}
|
|
2862
3219
|
const isDone = () => skipAgent ? activeTui.store.session.outroDismissed : activeTui.store.session.skillsComplete;
|
|
@@ -2933,10 +3290,10 @@ function runWizardCI(config, options) {
|
|
|
2933
3290
|
(async () => {
|
|
2934
3291
|
const path = await import("path");
|
|
2935
3292
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
2936
|
-
const { readEnvironment } = await import("./environment-
|
|
3293
|
+
const { readEnvironment } = await import("./environment-DS5Pq9Wm.js").then((n) => n.t);
|
|
2937
3294
|
const { readApiKeyFromEnv } = await import("./env-api-key-MlzJYAvt.js").then((n) => n.t);
|
|
2938
|
-
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-
|
|
2939
|
-
const { wizardAbort, WizardError } = await import("./wizard-abort-
|
|
3295
|
+
const { configureLogFileFromEnvironment, logToFile } = await import("./debug-fg4BAKKA.js");
|
|
3296
|
+
const { wizardAbort, WizardError } = await import("./wizard-abort-CR3w2Efg.js");
|
|
2940
3297
|
configureLogFileFromEnvironment();
|
|
2941
3298
|
const env = readEnvironment();
|
|
2942
3299
|
const apiKey = options.apiKey ?? readApiKeyFromEnv() ?? void 0;
|
|
@@ -2987,7 +3344,7 @@ function runWizardCI(config, options) {
|
|
|
2987
3344
|
})
|
|
2988
3345
|
});
|
|
2989
3346
|
}
|
|
2990
|
-
const { runAgent } = await import("./agent-runner-
|
|
3347
|
+
const { runAgent } = await import("./agent-runner-BNGW3osc.js");
|
|
2991
3348
|
await runAgent(config, session);
|
|
2992
3349
|
} catch (error) {
|
|
2993
3350
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -3205,6 +3562,34 @@ const PromptLabel = ({ message }) => {
|
|
|
3205
3562
|
}) });
|
|
3206
3563
|
};
|
|
3207
3564
|
//#endregion
|
|
3565
|
+
//#region src/ui/tui/primitives/ConfirmButton.tsx
|
|
3566
|
+
/**
|
|
3567
|
+
* ConfirmButton — the confirm row used to submit a selection.
|
|
3568
|
+
*
|
|
3569
|
+
* Pure render. Multi-select menus (PickerMenu mode="multi", GroupedPickerMenu)
|
|
3570
|
+
* append this below their options as the final focusable row: the user toggles
|
|
3571
|
+
* options with enter, then arrows down onto this row and presses enter to
|
|
3572
|
+
* submit. This replaces the older "enter anywhere submits" pattern, which
|
|
3573
|
+
* confused people who expected enter to toggle the focused item.
|
|
3574
|
+
*
|
|
3575
|
+
* Renders flat, mirroring the option rows — a focus triangle and the label,
|
|
3576
|
+
* accent and bold when focused, dimmed otherwise — so it lines up under the
|
|
3577
|
+
* options instead of sitting in a separate boxed target.
|
|
3578
|
+
*/
|
|
3579
|
+
const ConfirmButton = ({ label = "Confirm", focused, count }) => {
|
|
3580
|
+
const text = count && count > 0 ? `${label} (${count})` : label;
|
|
3581
|
+
return /* @__PURE__ */ jsxs(Text, {
|
|
3582
|
+
color: focused ? Colors.accent : void 0,
|
|
3583
|
+
bold: focused,
|
|
3584
|
+
dimColor: !focused,
|
|
3585
|
+
children: [
|
|
3586
|
+
focused ? Icons.triangleSmallRight : " ",
|
|
3587
|
+
" ",
|
|
3588
|
+
text
|
|
3589
|
+
]
|
|
3590
|
+
});
|
|
3591
|
+
};
|
|
3592
|
+
//#endregion
|
|
3208
3593
|
//#region src/ui/tui/hooks/keyboard-hints-utils.ts
|
|
3209
3594
|
/** Default priorities by key type. */
|
|
3210
3595
|
const DEFAULT_PRIORITY = {
|
|
@@ -3340,8 +3725,10 @@ function useKeyBindings(id, bindings) {
|
|
|
3340
3725
|
//#region src/ui/tui/primitives/PickerMenu.tsx
|
|
3341
3726
|
/**
|
|
3342
3727
|
* PickerMenu — Single and multi select.
|
|
3343
|
-
* Single mode: custom renderer with small triangle indicator.
|
|
3344
|
-
* Multi mode: checkbox glyphs with
|
|
3728
|
+
* Single mode: custom renderer with small triangle indicator; enter selects.
|
|
3729
|
+
* Multi mode: checkbox glyphs toggled with enter, plus a focusable
|
|
3730
|
+
* Confirm button below the options. The cursor moves onto the button and
|
|
3731
|
+
* enter submits — see MultiPickerMenu for the rationale.
|
|
3345
3732
|
*
|
|
3346
3733
|
* Key bindings are declared via useKeyBindings, which auto-registers
|
|
3347
3734
|
* hints in the KeyboardHintsBar.
|
|
@@ -3367,6 +3754,12 @@ function firstEnabled(options) {
|
|
|
3367
3754
|
const idx = options.findIndex((o) => !o.disabled);
|
|
3368
3755
|
return idx === -1 ? 0 : idx;
|
|
3369
3756
|
}
|
|
3757
|
+
/** Index of the last enabled option, for wrapping from the button onto
|
|
3758
|
+
* the bottom of the grid. */
|
|
3759
|
+
function lastEnabled(options) {
|
|
3760
|
+
for (let i = options.length - 1; i >= 0; i--) if (!options[i]?.disabled) return i;
|
|
3761
|
+
return options.length - 1;
|
|
3762
|
+
}
|
|
3370
3763
|
const PickerMenu = ({ message, options, mode = "single", centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
|
|
3371
3764
|
if (mode === "multi") return /* @__PURE__ */ jsx(MultiPickerMenu, {
|
|
3372
3765
|
message,
|
|
@@ -3470,60 +3863,90 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
|
|
|
3470
3863
|
})]
|
|
3471
3864
|
});
|
|
3472
3865
|
};
|
|
3473
|
-
/**
|
|
3866
|
+
/**
|
|
3867
|
+
* Custom multi-select with checkbox glyphs and accent highlight.
|
|
3868
|
+
*
|
|
3869
|
+
* Interaction model (shared with GroupedPickerMenu):
|
|
3870
|
+
* - \u2191\u2193 move the cursor through the options AND onto the Confirm button,
|
|
3871
|
+
* which lives just past the last option.
|
|
3872
|
+
* - enter toggles the focused option (no more "space toggles but enter
|
|
3873
|
+
* advances" split that tripped people up). Space is kept as an
|
|
3874
|
+
* undocumented alias, but the hints bar advertises only enter.
|
|
3875
|
+
* - moving onto the Confirm button and pressing enter submits the
|
|
3876
|
+
* current selection.
|
|
3877
|
+
*/
|
|
3474
3878
|
const MultiPickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
|
|
3475
3879
|
const [focused, setFocused] = useState(() => firstEnabled(options));
|
|
3880
|
+
const [onButton, setOnButton] = useState(false);
|
|
3476
3881
|
const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
|
|
3477
3882
|
const rows = Math.ceil(options.length / columns);
|
|
3478
3883
|
useEffect(() => {
|
|
3479
3884
|
if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
|
|
3480
3885
|
}, [options, focused]);
|
|
3481
|
-
const
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3886
|
+
const confirm = () => {
|
|
3887
|
+
onSelect([...selected].sort((a, b) => a - b).map((i) => options[i].value));
|
|
3888
|
+
};
|
|
3889
|
+
const bindings = [{
|
|
3890
|
+
match: ["upArrow", "downArrow"],
|
|
3891
|
+
label: "↑↓",
|
|
3892
|
+
action: "navigate",
|
|
3893
|
+
handler: (_input, key) => {
|
|
3894
|
+
if (key.upArrow) {
|
|
3895
|
+
if (onButton) {
|
|
3896
|
+
setOnButton(false);
|
|
3897
|
+
setFocused(lastEnabled(options));
|
|
3898
|
+
return;
|
|
3899
|
+
}
|
|
3900
|
+
const col = Math.floor(focused / rows);
|
|
3901
|
+
let r = focused % rows - 1;
|
|
3902
|
+
while (r >= 0 && options[col * rows + r]?.disabled) r--;
|
|
3903
|
+
if (r >= 0) setFocused(col * rows + r);
|
|
3904
|
+
else setOnButton(true);
|
|
3489
3905
|
}
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
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
|
-
});
|
|
3906
|
+
if (key.downArrow) {
|
|
3907
|
+
if (onButton) {
|
|
3908
|
+
setOnButton(false);
|
|
3909
|
+
setFocused(firstEnabled(options));
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
const col = Math.floor(focused / rows);
|
|
3913
|
+
const row = focused % rows;
|
|
3914
|
+
const colLen = Math.min(rows, options.length - col * rows);
|
|
3915
|
+
let r = row + 1;
|
|
3916
|
+
while (r < colLen && options[col * rows + r]?.disabled) r++;
|
|
3917
|
+
if (r < colLen) setFocused(col * rows + r);
|
|
3918
|
+
else setOnButton(true);
|
|
3508
3919
|
}
|
|
3509
|
-
}
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
} else onSelect([...selected].sort().map((i) => options[i].value));
|
|
3920
|
+
}
|
|
3921
|
+
}, {
|
|
3922
|
+
match: ["space", "return"],
|
|
3923
|
+
label: "enter",
|
|
3924
|
+
action: "select",
|
|
3925
|
+
handler: () => {
|
|
3926
|
+
if (onButton) {
|
|
3927
|
+
confirm();
|
|
3928
|
+
return;
|
|
3519
3929
|
}
|
|
3930
|
+
if (options[focused]?.disabled) return;
|
|
3931
|
+
setSelected((prev) => {
|
|
3932
|
+
const next = new Set(prev);
|
|
3933
|
+
if (next.has(focused)) {
|
|
3934
|
+
next.delete(focused);
|
|
3935
|
+
return next;
|
|
3936
|
+
}
|
|
3937
|
+
if (options[focused]?.exclusive) return new Set([focused]);
|
|
3938
|
+
for (const i of next) if (options[i]?.exclusive) next.delete(i);
|
|
3939
|
+
next.add(focused);
|
|
3940
|
+
return next;
|
|
3941
|
+
});
|
|
3520
3942
|
}
|
|
3521
|
-
];
|
|
3943
|
+
}];
|
|
3522
3944
|
if (columns > 1) bindings.splice(1, 0, {
|
|
3523
3945
|
match: ["leftArrow", "rightArrow"],
|
|
3524
3946
|
label: "←→",
|
|
3525
3947
|
action: "navigate",
|
|
3526
3948
|
handler: (_input, key) => {
|
|
3949
|
+
if (onButton) return;
|
|
3527
3950
|
const col = Math.floor(focused / rows);
|
|
3528
3951
|
const row = focused % rows;
|
|
3529
3952
|
let next = focused;
|
|
@@ -3545,43 +3968,65 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
|
|
|
3545
3968
|
return /* @__PURE__ */ jsxs(Box, {
|
|
3546
3969
|
flexDirection: "column",
|
|
3547
3970
|
alignItems: centered ? "center" : void 0,
|
|
3548
|
-
children: [
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
children:
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
children:
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3971
|
+
children: [
|
|
3972
|
+
/* @__PURE__ */ jsx(PromptLabel, { message }),
|
|
3973
|
+
/* @__PURE__ */ jsx(Box, {
|
|
3974
|
+
flexDirection: "row",
|
|
3975
|
+
gap: 4,
|
|
3976
|
+
marginLeft: centered ? 0 : 2,
|
|
3977
|
+
marginTop: 1,
|
|
3978
|
+
children: columnArrays.map((colOpts, colIdx) => /* @__PURE__ */ jsx(Box, {
|
|
3979
|
+
flexDirection: "column",
|
|
3980
|
+
children: colOpts.map((opt, rowIdx) => {
|
|
3981
|
+
const flatIdx = colIdx * rows + rowIdx;
|
|
3982
|
+
const isFocused = !onButton && flatIdx === focused;
|
|
3983
|
+
const isSelected = selected.has(flatIdx);
|
|
3984
|
+
const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;
|
|
3985
|
+
const checkbox = isSelected ? Icons.squareFilled : Icons.squareOpen;
|
|
3986
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3987
|
+
flexDirection: "column",
|
|
3988
|
+
marginBottom: optionMarginBottom,
|
|
3989
|
+
children: [/* @__PURE__ */ jsxs(Box, {
|
|
3990
|
+
gap: 1,
|
|
3991
|
+
children: [
|
|
3992
|
+
/* @__PURE__ */ jsx(Text, {
|
|
3993
|
+
color: isSelected ? "white" : Colors.muted,
|
|
3994
|
+
dimColor: !isFocused && !isSelected,
|
|
3995
|
+
children: checkbox
|
|
3996
|
+
}),
|
|
3997
|
+
opt.icon && /* @__PURE__ */ jsx(Text, {
|
|
3998
|
+
color: opt.icon.color,
|
|
3999
|
+
children: opt.icon.glyph
|
|
4000
|
+
}),
|
|
4001
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4002
|
+
color: opt.disabled ? Colors.muted : isFocused ? Colors.accent : void 0,
|
|
4003
|
+
bold: isFocused && !opt.disabled,
|
|
4004
|
+
dimColor: !isFocused || opt.disabled,
|
|
4005
|
+
children: label
|
|
4006
|
+
})
|
|
4007
|
+
]
|
|
4008
|
+
}), opt.description && /* @__PURE__ */ jsx(Box, {
|
|
4009
|
+
marginLeft: 4,
|
|
4010
|
+
width: 56,
|
|
4011
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
4012
|
+
dimColor: true,
|
|
4013
|
+
wrap: "wrap",
|
|
4014
|
+
children: opt.description
|
|
4015
|
+
})
|
|
4016
|
+
})]
|
|
4017
|
+
}, flatIdx);
|
|
4018
|
+
})
|
|
4019
|
+
}, colIdx))
|
|
4020
|
+
}),
|
|
4021
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4022
|
+
marginTop: 1,
|
|
4023
|
+
marginLeft: centered ? 0 : 2,
|
|
4024
|
+
children: /* @__PURE__ */ jsx(ConfirmButton, {
|
|
4025
|
+
focused: onButton,
|
|
4026
|
+
count: selected.size
|
|
3582
4027
|
})
|
|
3583
|
-
}
|
|
3584
|
-
|
|
4028
|
+
})
|
|
4029
|
+
]
|
|
3585
4030
|
});
|
|
3586
4031
|
};
|
|
3587
4032
|
//#endregion
|
|
@@ -3766,7 +4211,7 @@ async function runDoctorCI(options) {
|
|
|
3766
4211
|
getUI().intro("Welcome to the PostHog setup wizard");
|
|
3767
4212
|
getUI().log.info("Running posthog-doctor in CI mode");
|
|
3768
4213
|
try {
|
|
3769
|
-
const { getOrAskForProjectData } = await import("./setup-utils-
|
|
4214
|
+
const { getOrAskForProjectData } = await import("./setup-utils-CNWIMZ-d.js").then((n) => n.r);
|
|
3770
4215
|
const { host, accessToken, projectId } = await getOrAskForProjectData({
|
|
3771
4216
|
signup: false,
|
|
3772
4217
|
ci: true,
|
|
@@ -3783,7 +4228,7 @@ async function runDoctorCI(options) {
|
|
|
3783
4228
|
for (const issue of sorted) getUI().log.info(` • [${issue.severity}] ${getKindMeta(issue.kind).title}`);
|
|
3784
4229
|
process.exit(1);
|
|
3785
4230
|
} catch (error) {
|
|
3786
|
-
const { ApiError } = await import("./api-
|
|
4231
|
+
const { ApiError } = await import("./api-DCHci5SD.js").then((n) => n.n);
|
|
3787
4232
|
const message = error instanceof ApiError && error.statusCode === 401 ? "Your PostHog API key is invalid or expired." : error instanceof Error ? error.message : String(error);
|
|
3788
4233
|
getUI().log.error(`Doctor failed: ${message}`);
|
|
3789
4234
|
process.exit(1);
|
|
@@ -3831,6 +4276,30 @@ const migrateCommand = nativeCommandFactory(migrationConfig);
|
|
|
3831
4276
|
*/
|
|
3832
4277
|
const revenueCommand = nativeCommandFactory(revenueAnalyticsConfig);
|
|
3833
4278
|
//#endregion
|
|
4279
|
+
//#region src/commands/self-driving.ts
|
|
4280
|
+
const selfDrivingCommand = {
|
|
4281
|
+
name: "self-driving",
|
|
4282
|
+
description: selfDrivingConfig.description,
|
|
4283
|
+
options: {
|
|
4284
|
+
...skillProgramOptions,
|
|
4285
|
+
...selfDrivingConfig.cliOptions ?? {}
|
|
4286
|
+
},
|
|
4287
|
+
check: (argv) => {
|
|
4288
|
+
if (argv.signup) throw new Error("`self-driving` cannot run with --signup. It builds on an existing PostHog integration — run the base `wizard` to create your account and set up PostHog first, then run `wizard self-driving`.");
|
|
4289
|
+
if (argv.ci) throw new Error("`self-driving` cannot run in CI mode — it requires interactive steps (GitHub connect, issue-tracker selection, custom-scout approval).");
|
|
4290
|
+
return true;
|
|
4291
|
+
},
|
|
4292
|
+
handler: (argv) => {
|
|
4293
|
+
const extras = selfDrivingConfig.mapCliOptions?.(argv) ?? {};
|
|
4294
|
+
const options = {
|
|
4295
|
+
...argv,
|
|
4296
|
+
...extras
|
|
4297
|
+
};
|
|
4298
|
+
if (options.ci) runWizardCI(selfDrivingConfig, options);
|
|
4299
|
+
else runWizard(selfDrivingConfig, options);
|
|
4300
|
+
}
|
|
4301
|
+
};
|
|
4302
|
+
//#endregion
|
|
3834
4303
|
//#region src/commands/slack.ts
|
|
3835
4304
|
const slackCommand = {
|
|
3836
4305
|
name: "slack",
|
|
@@ -3846,7 +4315,7 @@ function runSlackConnect(argv) {
|
|
|
3846
4315
|
(async () => {
|
|
3847
4316
|
const debug = argv.debug;
|
|
3848
4317
|
try {
|
|
3849
|
-
const { startTUI } = await import("./start-tui-
|
|
4318
|
+
const { startTUI } = await import("./start-tui-CS802Ww9.js");
|
|
3850
4319
|
const { buildSession } = await import("./wizard-session-wPJtNl4c.js");
|
|
3851
4320
|
const tui = startTUI(VERSION, Program.SlackConnect);
|
|
3852
4321
|
tui.store.session = buildSession({ debug });
|
|
@@ -3967,6 +4436,247 @@ const skillCommand = {
|
|
|
3967
4436
|
}
|
|
3968
4437
|
};
|
|
3969
4438
|
//#endregion
|
|
4439
|
+
//#region src/steps/install-cli-steering/index.ts
|
|
4440
|
+
const dirExists = (...segments) => {
|
|
4441
|
+
try {
|
|
4442
|
+
return fs$1.existsSync(path$1.join(os.homedir(), ...segments));
|
|
4443
|
+
} catch {
|
|
4444
|
+
return false;
|
|
4445
|
+
}
|
|
4446
|
+
};
|
|
4447
|
+
const CLI_STEERING_TARGETS = [
|
|
4448
|
+
{
|
|
4449
|
+
id: "claude-code",
|
|
4450
|
+
name: "Claude Code",
|
|
4451
|
+
instructionsPath: () => path$1.join(os.homedir(), ".claude", "CLAUDE.md"),
|
|
4452
|
+
isDetected: () => dirExists(".claude")
|
|
4453
|
+
},
|
|
4454
|
+
{
|
|
4455
|
+
id: "codex",
|
|
4456
|
+
name: "Codex",
|
|
4457
|
+
instructionsPath: () => path$1.join(os.homedir(), ".codex", "AGENTS.md"),
|
|
4458
|
+
isDetected: () => dirExists(".codex")
|
|
4459
|
+
},
|
|
4460
|
+
{
|
|
4461
|
+
id: "gemini",
|
|
4462
|
+
name: "Gemini CLI",
|
|
4463
|
+
instructionsPath: () => path$1.join(os.homedir(), ".gemini", "GEMINI.md"),
|
|
4464
|
+
isDetected: () => dirExists(".gemini")
|
|
4465
|
+
}
|
|
4466
|
+
];
|
|
4467
|
+
function findTarget(id) {
|
|
4468
|
+
return CLI_STEERING_TARGETS.find((target) => target.id === id);
|
|
4469
|
+
}
|
|
4470
|
+
function detectTargets() {
|
|
4471
|
+
return CLI_STEERING_TARGETS.filter((target) => target.isDetected());
|
|
4472
|
+
}
|
|
4473
|
+
const spawnOptions = {
|
|
4474
|
+
encoding: "utf-8",
|
|
4475
|
+
shell: process.platform === "win32"
|
|
4476
|
+
};
|
|
4477
|
+
/**
|
|
4478
|
+
* Install or update the PostHog CLI in the user's environment. `npm install
|
|
4479
|
+
* --global @posthog/cli@latest` covers both first-time installs and upgrades
|
|
4480
|
+
* for existing npm-installed CLIs.
|
|
4481
|
+
*/
|
|
4482
|
+
function installOrUpdatePostHogCli() {
|
|
4483
|
+
const args = [
|
|
4484
|
+
"install",
|
|
4485
|
+
"--global",
|
|
4486
|
+
"@posthog/cli@latest"
|
|
4487
|
+
];
|
|
4488
|
+
debug(`Running npm ${args.join(" ")}`);
|
|
4489
|
+
const result = spawnSync("npm", args, spawnOptions);
|
|
4490
|
+
if (result.error) return {
|
|
4491
|
+
success: false,
|
|
4492
|
+
error: `Failed to run npm: ${result.error.message}. Is Node.js installed?`
|
|
4493
|
+
};
|
|
4494
|
+
if (result.status !== 0) return {
|
|
4495
|
+
success: false,
|
|
4496
|
+
error: (result.stderr || result.stdout || "").trim() || `npm install --global @posthog/cli@latest exited with status ${result.status ?? "unknown"}`
|
|
4497
|
+
};
|
|
4498
|
+
return { success: true };
|
|
4499
|
+
}
|
|
4500
|
+
/**
|
|
4501
|
+
* Delegate the actual write to the installed `posthog-cli api agents-md
|
|
4502
|
+
* install`. The steering snippet lives in the CLI (its single source of truth),
|
|
4503
|
+
* so the command should run only after `installOrUpdatePostHogCli` refreshes
|
|
4504
|
+
* the CLI to the latest release.
|
|
4505
|
+
*/
|
|
4506
|
+
function installSteeringSnippet(filePath) {
|
|
4507
|
+
const args = [
|
|
4508
|
+
"api",
|
|
4509
|
+
"agents-md",
|
|
4510
|
+
"install",
|
|
4511
|
+
"--path",
|
|
4512
|
+
filePath
|
|
4513
|
+
];
|
|
4514
|
+
debug(`Running posthog-cli ${args.join(" ")}`);
|
|
4515
|
+
const result = spawnSync("posthog-cli", args, {
|
|
4516
|
+
...spawnOptions,
|
|
4517
|
+
env: {
|
|
4518
|
+
...process.env,
|
|
4519
|
+
POSTHOG_CLI_EXPERIMENTAL_API: "1"
|
|
4520
|
+
}
|
|
4521
|
+
});
|
|
4522
|
+
if (result.error) return {
|
|
4523
|
+
success: false,
|
|
4524
|
+
filePath,
|
|
4525
|
+
error: `Failed to run posthog-cli: ${result.error.message}. Make sure npm's global bin directory is on your PATH.`
|
|
4526
|
+
};
|
|
4527
|
+
if (result.status !== 0) return {
|
|
4528
|
+
success: false,
|
|
4529
|
+
filePath,
|
|
4530
|
+
error: (result.stderr || result.stdout || "").trim() || `posthog-cli exited with status ${result.status ?? "unknown"}`
|
|
4531
|
+
};
|
|
4532
|
+
return {
|
|
4533
|
+
success: true,
|
|
4534
|
+
filePath
|
|
4535
|
+
};
|
|
4536
|
+
}
|
|
4537
|
+
//#endregion
|
|
4538
|
+
//#region src/commands/cli/add.ts
|
|
4539
|
+
const cliAddCommand = {
|
|
4540
|
+
name: "add",
|
|
4541
|
+
description: "Install or update PostHog CLI and add steering instructions to your coding agent's global instructions file",
|
|
4542
|
+
options: {
|
|
4543
|
+
agent: {
|
|
4544
|
+
describe: "Agent to install the instructions for",
|
|
4545
|
+
choices: CLI_STEERING_TARGETS.map((target) => target.id),
|
|
4546
|
+
type: "string"
|
|
4547
|
+
},
|
|
4548
|
+
path: {
|
|
4549
|
+
describe: "Write to an explicit instructions file instead of a detected agent",
|
|
4550
|
+
type: "string"
|
|
4551
|
+
},
|
|
4552
|
+
all: {
|
|
4553
|
+
default: false,
|
|
4554
|
+
describe: "Install for every detected agent without prompting",
|
|
4555
|
+
type: "boolean"
|
|
4556
|
+
}
|
|
4557
|
+
},
|
|
4558
|
+
examples: [
|
|
4559
|
+
["wizard cli add", "Detect your coding agents and pick one"],
|
|
4560
|
+
["wizard cli add --agent claude-code", "Install for Claude Code (~/.claude/CLAUDE.md)"],
|
|
4561
|
+
["wizard cli add --all", "Install for every detected agent"],
|
|
4562
|
+
["wizard cli add --path ./AGENTS.md", "Install into a specific instructions file"]
|
|
4563
|
+
],
|
|
4564
|
+
check: (argv) => {
|
|
4565
|
+
if (argv.all && (argv.agent || argv.path)) throw new Error("--all cannot be combined with --agent or --path");
|
|
4566
|
+
return true;
|
|
4567
|
+
},
|
|
4568
|
+
handler: (argv) => {
|
|
4569
|
+
runCliAdd(argv);
|
|
4570
|
+
}
|
|
4571
|
+
};
|
|
4572
|
+
async function runCliAdd(argv) {
|
|
4573
|
+
setUI(new LoggingUI());
|
|
4574
|
+
const ui = getUI();
|
|
4575
|
+
ui.intro("PostHog CLI setup");
|
|
4576
|
+
const files = await resolveTargetFiles(argv);
|
|
4577
|
+
if (files.length === 0) {
|
|
4578
|
+
process.exit(1);
|
|
4579
|
+
return;
|
|
4580
|
+
}
|
|
4581
|
+
ui.log.info("Installing or updating PostHog CLI...");
|
|
4582
|
+
const cliInstallResult = installOrUpdatePostHogCli();
|
|
4583
|
+
if (!cliInstallResult.success) {
|
|
4584
|
+
ui.log.error(`Failed to install or update PostHog CLI: ${cliInstallResult.error ?? ""}`);
|
|
4585
|
+
analytics.wizardCapture("cli steering installed", {
|
|
4586
|
+
files: files.length,
|
|
4587
|
+
failures: files.length,
|
|
4588
|
+
cli_install_failed: true,
|
|
4589
|
+
agent: typeof argv.agent === "string" ? argv.agent : void 0
|
|
4590
|
+
});
|
|
4591
|
+
process.exit(1);
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
ui.log.success("Installed or updated PostHog CLI.");
|
|
4595
|
+
let failures = 0;
|
|
4596
|
+
for (const file of files) {
|
|
4597
|
+
const result = installSteeringSnippet(file);
|
|
4598
|
+
if (result.success) ui.log.success(`Installed PostHog steering instructions in ${file}`);
|
|
4599
|
+
else {
|
|
4600
|
+
failures += 1;
|
|
4601
|
+
ui.log.error(`Failed to update ${file}: ${result.error ?? ""}`);
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
analytics.wizardCapture("cli steering installed", {
|
|
4605
|
+
files: files.length,
|
|
4606
|
+
failures,
|
|
4607
|
+
agent: typeof argv.agent === "string" ? argv.agent : void 0
|
|
4608
|
+
});
|
|
4609
|
+
if (failures > 0) {
|
|
4610
|
+
process.exit(1);
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
ui.outro("Done. PostHog CLI is installed and your agent will now use `posthog-cli api` for PostHog tasks.");
|
|
4614
|
+
process.exit(0);
|
|
4615
|
+
}
|
|
4616
|
+
/** Resolve which instruction files to write, from flags, detection, or a prompt. */
|
|
4617
|
+
async function resolveTargetFiles(argv) {
|
|
4618
|
+
const ui = getUI();
|
|
4619
|
+
if (typeof argv.path === "string" && argv.path.trim()) return [path$1.resolve(argv.path.trim())];
|
|
4620
|
+
if (typeof argv.agent === "string") {
|
|
4621
|
+
const target = findTarget(argv.agent);
|
|
4622
|
+
if (!target) {
|
|
4623
|
+
ui.log.error(`Unsupported agent: ${argv.agent}`);
|
|
4624
|
+
return [];
|
|
4625
|
+
}
|
|
4626
|
+
return [target.instructionsPath()];
|
|
4627
|
+
}
|
|
4628
|
+
const detected = detectTargets();
|
|
4629
|
+
if (detected.length === 0) {
|
|
4630
|
+
ui.log.error("No supported coding agents detected. Pass --agent <id> or --path <file> to choose a target.");
|
|
4631
|
+
ui.log.info(`Supported agents: ${CLI_STEERING_TARGETS.map((t) => t.id).join(", ")}`);
|
|
4632
|
+
return [];
|
|
4633
|
+
}
|
|
4634
|
+
if (argv.all === true) {
|
|
4635
|
+
ui.log.info(`Installing for all detected agents: ${detected.map((t) => t.name).join(", ")}`);
|
|
4636
|
+
return detected.map((target) => target.instructionsPath());
|
|
4637
|
+
}
|
|
4638
|
+
if (detected.length === 1) {
|
|
4639
|
+
ui.log.info(`Detected ${detected[0].name} (${detected[0].instructionsPath()})`);
|
|
4640
|
+
return [detected[0].instructionsPath()];
|
|
4641
|
+
}
|
|
4642
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
4643
|
+
ui.log.info(`Installing for all detected agents: ${detected.map((t) => t.name).join(", ")}`);
|
|
4644
|
+
return detected.map((target) => target.instructionsPath());
|
|
4645
|
+
}
|
|
4646
|
+
return (await promptForTargets(detected)).map((target) => target.instructionsPath());
|
|
4647
|
+
}
|
|
4648
|
+
/** Minimal numbered selection — this command is intentionally not a TUI flow. */
|
|
4649
|
+
async function promptForTargets(detected) {
|
|
4650
|
+
const ui = getUI();
|
|
4651
|
+
ui.log.info("Which coding agent are you using?");
|
|
4652
|
+
detected.forEach((target, index) => {
|
|
4653
|
+
ui.log.info(` ${index + 1}) ${target.name} (${target.instructionsPath()})`);
|
|
4654
|
+
});
|
|
4655
|
+
ui.log.info(` ${detected.length + 1}) All of the above`);
|
|
4656
|
+
const rl = readline.createInterface({
|
|
4657
|
+
input: process.stdin,
|
|
4658
|
+
output: process.stdout
|
|
4659
|
+
});
|
|
4660
|
+
try {
|
|
4661
|
+
for (;;) {
|
|
4662
|
+
const answer = (await rl.question(`Select 1-${detected.length + 1}: `)).trim();
|
|
4663
|
+
const choice = Number(answer);
|
|
4664
|
+
if (Number.isInteger(choice) && choice >= 1 && choice <= detected.length) return [detected[choice - 1]];
|
|
4665
|
+
if (choice === detected.length + 1) return detected;
|
|
4666
|
+
ui.log.warn(`Enter a number between 1 and ${detected.length + 1}.`);
|
|
4667
|
+
}
|
|
4668
|
+
} finally {
|
|
4669
|
+
rl.close();
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
//#endregion
|
|
4673
|
+
//#region src/commands/cli/index.ts
|
|
4674
|
+
const cliCommand = {
|
|
4675
|
+
name: "cli",
|
|
4676
|
+
description: "PostHog CLI agent integration commands",
|
|
4677
|
+
children: [cliAddCommand]
|
|
4678
|
+
};
|
|
4679
|
+
//#endregion
|
|
3970
4680
|
//#region bin.ts
|
|
3971
4681
|
const NODE_VERSION_RANGE = ">=18.17.0";
|
|
3972
4682
|
if (!satisfies(process.version, NODE_VERSION_RANGE)) {
|
|
@@ -3982,8 +4692,8 @@ function resolveInstallDir() {
|
|
|
3982
4692
|
if (inline) return inline.slice(14);
|
|
3983
4693
|
return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd();
|
|
3984
4694
|
}
|
|
3985
|
-
Wizard.use(basicIntegrationCommand).use(mcpCommand).use(auditCommand).use(doctorCommand).use(migrateCommand).use(revenueCommand).use(slackCommand).use(uploadSourcemapsCommand).use(skillCommand).init();
|
|
4695
|
+
Wizard.use(basicIntegrationCommand).use(mcpCommand).use(cliCommand).use(auditCommand).use(doctorCommand).use(migrateCommand).use(revenueCommand).use(selfDrivingCommand).use(slackCommand).use(uploadSourcemapsCommand).use(skillCommand).init();
|
|
3986
4696
|
//#endregion
|
|
3987
|
-
export { POSTHOG_SDKS$1 as _,
|
|
4697
|
+
export { POSTHOG_SDKS$1 as _, ConfirmButton as a, runWizard as c, getProgramConfig as d, DISPLAY_NAME as f, getContentBlocks$2 as g, fetchHealthIssues as h, useKeyboardHintsContext as i, PROGRAM_REGISTRY as l, getKindMeta as m, useKeyBindings as n, PromptLabel as o, SOURCE_MAPS_CONTEXT_KEYS as p, KeyboardHintsProvider as r, runWizardCI as s, PickerMenu as t, Program as u, STRIPE_SDKS as v };
|
|
3988
4698
|
|
|
3989
4699
|
//# sourceMappingURL=bin.js.map
|