@posthog/wizard 2.20.0 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/{slides-BEshbXqG.js → AiOptInRequiredScreen-N6L80szR.js} +741 -33
- package/dist/AiOptInRequiredScreen-N6L80szR.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-iV7BuQpD.js → add-mcp-server-to-clients-DqHCkHqM.js} +12 -10
- package/dist/add-mcp-server-to-clients-DqHCkHqM.js.map +1 -0
- package/dist/{agent-interface-B-LAvrNL.js → agent-interface-DZmVoik2.js} +5 -5
- package/dist/{agent-interface-B-LAvrNL.js.map → agent-interface-DZmVoik2.js.map} +1 -1
- package/dist/{agent-runner-w2Qu9M13.js → agent-runner-CGFUXR97.js} +13 -9
- package/dist/{agent-runner-w2Qu9M13.js.map → agent-runner-CGFUXR97.js.map} +1 -1
- package/dist/{analytics-C8lJzXjY.js → analytics-C_lVPZQT.js} +28 -4
- package/dist/analytics-C_lVPZQT.js.map +1 -0
- package/dist/{api-eUlUinVy.js → api-QI1lO_Bz.js} +3 -3
- package/dist/{api-eUlUinVy.js.map → api-QI1lO_Bz.js.map} +1 -1
- package/dist/bin.js +160 -49
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-CSo7Q1pK.js → ci-install-CXkKR4A-.js} +4 -4
- package/dist/{ci-install-CSo7Q1pK.js.map → ci-install-CXkKR4A-.js.map} +1 -1
- package/dist/{debug-BJu_sS4l.js → debug-D8QAez2V.js} +58 -13
- package/dist/debug-D8QAez2V.js.map +1 -0
- package/dist/{debug-CTViFiF-.js → debug-lPpecs0J.js} +1 -1
- package/dist/{environment-Dk_dWk3t.js → environment-CMmzgZkN.js} +3 -3
- package/dist/{environment-Dk_dWk3t.js.map → environment-CMmzgZkN.js.map} +1 -1
- package/dist/{interactive-BS2rIf1v.js → interactive-Bu8YchJG.js} +2 -2
- package/dist/{interactive-BS2rIf1v.js.map → interactive-Bu8YchJG.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-BiMrlLl0.js → mcp-prompt-streaming-mYw2LPZZ.js} +4 -4
- package/dist/{mcp-prompt-streaming-BiMrlLl0.js.map → mcp-prompt-streaming-mYw2LPZZ.js.map} +1 -1
- package/dist/{non-interactive-C39d_KIp.js → non-interactive-De3tJM1y.js} +2 -2
- package/dist/{non-interactive-C39d_KIp.js.map → non-interactive-De3tJM1y.js.map} +1 -1
- package/dist/{package-manager-BfOTvFt-.js → package-manager-BVJnbp1u.js} +2 -2
- package/dist/{package-manager-BfOTvFt-.js.map → package-manager-BVJnbp1u.js.map} +1 -1
- package/dist/{playground-3OeRB7JU.js → playground-wyoq1yIH.js} +205 -4
- package/dist/playground-wyoq1yIH.js.map +1 -0
- package/dist/{posthog-integration-8iTgqy2J.js → posthog-integration-mrMF-2IP.js} +48 -16
- package/dist/posthog-integration-mrMF-2IP.js.map +1 -0
- package/dist/{provisioning-DxaT7bWw.js → provisioning-4zipVpbq.js} +3 -3
- package/dist/{provisioning-DxaT7bWw.js.map → provisioning-4zipVpbq.js.map} +1 -1
- package/dist/{registry-apQfB3rf.js → registry-BGUo4PlM.js} +7 -20
- package/dist/registry-BGUo4PlM.js.map +1 -0
- package/dist/{setup-utils-B9xqAXXl.js → setup-utils-DmhPyWkp.js} +114 -57
- package/dist/setup-utils-DmhPyWkp.js.map +1 -0
- package/dist/{start-tui-CCpKnZOY.js → start-tui-DaQiY_EB.js} +310 -452
- package/dist/start-tui-DaQiY_EB.js.map +1 -0
- package/dist/{steps-DKbDDnVH.js → steps-CrUceWR5.js} +6 -6
- package/dist/{steps-DKbDDnVH.js.map → steps-CrUceWR5.js.map} +1 -1
- package/dist/telemetry-CCVjGq7l.js +68 -0
- package/dist/telemetry-CCVjGq7l.js.map +1 -0
- package/dist/{urls-B6wBIwr1.js → urls-BNFpfcN8.js} +2 -2
- package/dist/{urls-B6wBIwr1.js.map → urls-BNFpfcN8.js.map} +1 -1
- package/dist/{wizard-abort-DhGgTlUA.js → wizard-abort-BmYb0bG2.js} +3 -3
- package/dist/{wizard-abort-DhGgTlUA.js.map → wizard-abort-BmYb0bG2.js.map} +1 -1
- package/dist/{wizard-abort-D8XZdVAR.js → wizard-abort-Bp2yxYAy.js} +1 -1
- package/dist/wizard-session-G3VWD6hv.js.map +1 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
- package/package.json +1 -1
- package/dist/add-mcp-server-to-clients-iV7BuQpD.js.map +0 -1
- package/dist/analytics-C8lJzXjY.js.map +0 -1
- package/dist/debug-BJu_sS4l.js.map +0 -1
- package/dist/playground-3OeRB7JU.js.map +0 -1
- package/dist/posthog-integration-8iTgqy2J.js.map +0 -1
- package/dist/registry-apQfB3rf.js.map +0 -1
- package/dist/setup-utils-B9xqAXXl.js.map +0 -1
- package/dist/slides-BEshbXqG.js.map +0 -1
- package/dist/start-tui-CCpKnZOY.js.map +0 -1
- package/dist/telemetry-DUeOcmpo.js +0 -13
- package/dist/telemetry-DUeOcmpo.js.map +0 -1
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import { g as SERVICE_LABELS, s as logToFile } from "./debug-
|
|
1
|
+
import { M as POSTHOG_APP_URL, Q as getSkillsBaseUrl, g as SERVICE_LABELS, s as logToFile } from "./debug-D8QAez2V.js";
|
|
2
2
|
import { n as isTaskStatus } from "./wizard-ui-YdGFRyu_.js";
|
|
3
|
-
import { r as sessionProperties, t as analytics } from "./analytics-
|
|
3
|
+
import { r as sessionProperties, t as analytics } from "./analytics-C_lVPZQT.js";
|
|
4
|
+
import { i as withUtm, n as openTrackedLink } from "./telemetry-CCVjGq7l.js";
|
|
5
|
+
import { n as getCloudUrlFromRegion } from "./urls-BNFpfcN8.js";
|
|
6
|
+
import { a as fetchUserData, i as fetchSlackConnected } from "./api-QI1lO_Bz.js";
|
|
4
7
|
import { i as buildSession } from "./wizard-session-G3VWD6hv.js";
|
|
5
|
-
import { y as AUDIT_SEVERITY_STYLE } from "./agent-interface-
|
|
6
|
-
import { c as computeVisibleRange, d as isObjectBlock, f as Colors, l as isClearBlock, p as Icons, s as TextBlock, u as isLinesBlock } from "./posthog-integration-
|
|
8
|
+
import { m as fetchSkillMenu, y as AUDIT_SEVERITY_STYLE } from "./agent-interface-DZmVoik2.js";
|
|
9
|
+
import { c as computeVisibleRange, d as isObjectBlock, f as Colors, l as isClearBlock, p as Icons, s as TextBlock, u as isLinesBlock } from "./posthog-integration-mrMF-2IP.js";
|
|
7
10
|
import { a as getProgramConfig, i as Program, l as getKindMeta, r as PROGRAM_REGISTRY } from "./bin.js";
|
|
8
11
|
import { n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, t as ALL_FEATURE_VALUES } from "./defaults-BNWIWzjc.js";
|
|
9
|
-
import * as fs$1 from "fs";
|
|
10
12
|
import opn from "opn";
|
|
13
|
+
import * as fs$1 from "fs";
|
|
11
14
|
import { Box, Text, measureElement, useInput, useStdout } from "ink";
|
|
12
15
|
import { Component, Fragment, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
13
16
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -40,9 +43,40 @@ function createProgramSequence(steps) {
|
|
|
40
43
|
return entries;
|
|
41
44
|
}
|
|
42
45
|
//#endregion
|
|
46
|
+
//#region src/lib/programs/ai-opt-in-gate.ts
|
|
47
|
+
/** Step id — also the ScreenId.AiOptIn enum value in screen-sequences. */
|
|
48
|
+
const AI_OPT_IN_STEP_ID = "ai-opt-in";
|
|
49
|
+
function aiApproved(session) {
|
|
50
|
+
return !!session.apiUser?.organization?.is_ai_data_processing_approved;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the program's steps with the AI opt-in gate injected after
|
|
54
|
+
* `auth`. Programs with `requiresAi: false` or no auth step pass
|
|
55
|
+
* through unchanged — without auth, `apiUser` would never be populated
|
|
56
|
+
* for evaluation anyway.
|
|
57
|
+
*/
|
|
58
|
+
function withAiOptInGate(config) {
|
|
59
|
+
if (config.requiresAi === false) return config.steps;
|
|
60
|
+
const authIdx = config.steps.findIndex((s) => s.id === "auth");
|
|
61
|
+
if (authIdx === -1) return config.steps;
|
|
62
|
+
const gateStep = {
|
|
63
|
+
id: AI_OPT_IN_STEP_ID,
|
|
64
|
+
label: "AI opt-in check",
|
|
65
|
+
screenId: AI_OPT_IN_STEP_ID,
|
|
66
|
+
show: (session) => !session.ci && session.apiUser != null && !aiApproved(session),
|
|
67
|
+
isComplete: (session) => session.ci || aiApproved(session),
|
|
68
|
+
gate: (session) => session.ci || aiApproved(session)
|
|
69
|
+
};
|
|
70
|
+
return [
|
|
71
|
+
...config.steps.slice(0, authIdx + 1),
|
|
72
|
+
gateStep,
|
|
73
|
+
...config.steps.slice(authIdx + 1)
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
//#endregion
|
|
43
77
|
//#region src/ui/tui/screen-sequences.ts
|
|
44
78
|
/** All program screen sequences keyed by program id. */
|
|
45
|
-
const PROGRAM_SEQUENCES = Object.fromEntries(PROGRAM_REGISTRY.map((c) => [c.id, createProgramSequence(c
|
|
79
|
+
const PROGRAM_SEQUENCES = Object.fromEntries(PROGRAM_REGISTRY.map((c) => [c.id, createProgramSequence(withAiOptInGate(c))]));
|
|
46
80
|
//#endregion
|
|
47
81
|
//#region src/ui/tui/router.ts
|
|
48
82
|
var WizardRouter = class {
|
|
@@ -161,9 +195,15 @@ var WizardStore = class {
|
|
|
161
195
|
}
|
|
162
196
|
/**
|
|
163
197
|
* Scan program steps for gate predicates and create gate promises.
|
|
198
|
+
*
|
|
199
|
+
* Steps are wrapped with withAiOptInGate so the injected ai-opt-in
|
|
200
|
+
* step's gate registers here — the agent runner awaits it (via
|
|
201
|
+
* WizardUI.waitForAiOptIn) before any source leaves the machine.
|
|
202
|
+
* Same wrapper screen-sequences.ts uses, so the gate and its screen
|
|
203
|
+
* can't drift apart.
|
|
164
204
|
*/
|
|
165
205
|
_initFromProgram(program) {
|
|
166
|
-
const steps = getProgramConfig(program)
|
|
206
|
+
const steps = withAiOptInGate(getProgramConfig(program));
|
|
167
207
|
for (const step of steps) if (step.gate) {
|
|
168
208
|
let resolve;
|
|
169
209
|
const promise = new Promise((r) => {
|
|
@@ -209,6 +249,7 @@ var WizardStore = class {
|
|
|
209
249
|
setFrameworkContext: (k, v) => this.setFrameworkContext(k, v),
|
|
210
250
|
setFrameworkConfig: (i, c) => this.setFrameworkConfig(i, c),
|
|
211
251
|
setDetectedFramework: (l) => this.setDetectedFramework(l),
|
|
252
|
+
setSkillId: (id) => this.setSkillId(id),
|
|
212
253
|
setUnsupportedVersion: (info) => this.setUnsupportedVersion(info),
|
|
213
254
|
addDiscoveredFeature: (f) => this.addDiscoveredFeature(f),
|
|
214
255
|
setDetectionComplete: () => this.setDetectionComplete()
|
|
@@ -311,6 +352,10 @@ var WizardStore = class {
|
|
|
311
352
|
this.$session.setKey("detectedFrameworkLabel", label);
|
|
312
353
|
this.emitChange();
|
|
313
354
|
}
|
|
355
|
+
setSkillId(skillId) {
|
|
356
|
+
this.$session.setKey("skillId", skillId);
|
|
357
|
+
this.emitChange();
|
|
358
|
+
}
|
|
314
359
|
setUnsupportedVersion(info) {
|
|
315
360
|
this.$session.setKey("unsupportedVersion", info);
|
|
316
361
|
this.emitChange();
|
|
@@ -455,6 +500,10 @@ var WizardStore = class {
|
|
|
455
500
|
this.$session.setKey("authErrorDetail", detail ?? null);
|
|
456
501
|
this.pushOverlay("auth-error");
|
|
457
502
|
}
|
|
503
|
+
/** Push the session-timeout overlay (no dismiss — user must exit). */
|
|
504
|
+
showSessionTimeout() {
|
|
505
|
+
this.pushOverlay("session-timeout");
|
|
506
|
+
}
|
|
458
507
|
addDiscoveredFeature(feature) {
|
|
459
508
|
if (!this.session.discoveredFeatures.includes(feature)) {
|
|
460
509
|
this.session.discoveredFeatures.push(feature);
|
|
@@ -583,6 +632,7 @@ var WizardStore = class {
|
|
|
583
632
|
_detectTransition() {
|
|
584
633
|
const next = this.router.resolve(this.session);
|
|
585
634
|
const prev = this._lastScreen;
|
|
635
|
+
if (next !== prev) analytics.setTag("$screen_name", next);
|
|
586
636
|
if (prev !== null && next !== prev) {
|
|
587
637
|
const hooks = this._enterScreenHooks.get(next);
|
|
588
638
|
if (hooks) for (const fn of hooks) fn();
|
|
@@ -1988,6 +2038,8 @@ const TabContainer = ({ tabs, statusMessage, expandableStatus = false, store })
|
|
|
1988
2038
|
/* @__PURE__ */ jsx(Box, {
|
|
1989
2039
|
gap: 1,
|
|
1990
2040
|
paddingX: 1,
|
|
2041
|
+
flexWrap: "wrap",
|
|
2042
|
+
flexShrink: 0,
|
|
1991
2043
|
children: tabs.map((tab, i) => /* @__PURE__ */ jsx(Text, {
|
|
1992
2044
|
inverse: i === activeTab,
|
|
1993
2045
|
color: i === activeTab ? Colors.accent : Colors.muted,
|
|
@@ -2385,7 +2437,7 @@ const TIPS = [
|
|
|
2385
2437
|
id: "slack",
|
|
2386
2438
|
title: "Use PostHog in Slack",
|
|
2387
2439
|
description: "Connect the PostHog Slack app to analyze data and ship product changes — deploy flags, open PRs, run queries — just by tagging @PostHog:",
|
|
2388
|
-
url: "https://posthog.com/slack
|
|
2440
|
+
url: "https://posthog.com/slack"
|
|
2389
2441
|
},
|
|
2390
2442
|
{
|
|
2391
2443
|
id: "stripe",
|
|
@@ -3807,10 +3859,10 @@ var neutralCrossSell = [{
|
|
|
3807
3859
|
"description": "Built-in error tracking — no separate tool."
|
|
3808
3860
|
}];
|
|
3809
3861
|
var slackApp = {
|
|
3810
|
-
"learnMoreUrl": "https://posthog.com/slack
|
|
3862
|
+
"learnMoreUrl": "https://posthog.com/slack",
|
|
3811
3863
|
"setupUrl": "https://app.posthog.com/settings/project-integrations#integration-slack",
|
|
3812
|
-
"headline": "
|
|
3813
|
-
"pitch": "
|
|
3864
|
+
"headline": "@PostHog in Slack",
|
|
3865
|
+
"pitch": "Ask about your product data, debug issues, and generate PRs without leaving the thread.",
|
|
3814
3866
|
"capabilities": ["Tag @PostHog with a bug, edit, or a feature idea. It will spin up a sandboxed environment, plan, edit files, run tests, and open a draft PR.", "Tag @PostHog with any data question. It's the same SQL-writing, statistically-minded assistant as PostHog AI, but it responds where you send work memes."]
|
|
3815
3867
|
};
|
|
3816
3868
|
//#endregion
|
|
@@ -4015,25 +4067,6 @@ function getSlackAppCard() {
|
|
|
4015
4067
|
* forces a successful login first). A defensive throw protects the
|
|
4016
4068
|
* Running useEffect against a state-machine bug.
|
|
4017
4069
|
*/
|
|
4018
|
-
var Phase = /* @__PURE__ */ function(Phase) {
|
|
4019
|
-
Phase["Choose"] = "choose";
|
|
4020
|
-
Phase["Authenticating"] = "authenticating";
|
|
4021
|
-
Phase["Greeting"] = "greeting";
|
|
4022
|
-
Phase["PromptPicker"] = "prompt-picker";
|
|
4023
|
-
Phase["Running"] = "running";
|
|
4024
|
-
Phase["FollowUp"] = "follow-up";
|
|
4025
|
-
/** Final beat on every dismissal — reminds the user how to keep
|
|
4026
|
-
* talking to PostHog after the tutorial ends. */
|
|
4027
|
-
Phase["Goodbye"] = "goodbye";
|
|
4028
|
-
Phase["Done"] = "done";
|
|
4029
|
-
return Phase;
|
|
4030
|
-
}(Phase || {});
|
|
4031
|
-
var ChoiceValue = /* @__PURE__ */ function(ChoiceValue) {
|
|
4032
|
-
ChoiceValue["Login"] = "login";
|
|
4033
|
-
ChoiceValue["ConnectSlack"] = "connect-slack";
|
|
4034
|
-
ChoiceValue["Exit"] = "exit";
|
|
4035
|
-
return ChoiceValue;
|
|
4036
|
-
}(ChoiceValue || {});
|
|
4037
4070
|
const MAX_PROMPT_RUNS = 5;
|
|
4038
4071
|
const FOLLOW_UP_DELAY_MS = 3e3;
|
|
4039
4072
|
const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
@@ -4195,7 +4228,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
|
4195
4228
|
setPhase(session.credentials ? "greeting" : "authenticating");
|
|
4196
4229
|
} else if (choice === "connect-slack") {
|
|
4197
4230
|
analytics.wizardCapture("mcp suggested prompts choose", { choice: "connect-slack" });
|
|
4198
|
-
|
|
4231
|
+
openTrackedLink(getSlackAppCard().setupUrl, "mcp-prompts-slack-setup");
|
|
4199
4232
|
} else {
|
|
4200
4233
|
analytics.wizardCapture("mcp suggested prompts choose", { choice: "exit" });
|
|
4201
4234
|
enterGoodbye();
|
|
@@ -5640,6 +5673,681 @@ const AUDIT_3000_AREA_SLIDES = [
|
|
|
5640
5673
|
}
|
|
5641
5674
|
];
|
|
5642
5675
|
//#endregion
|
|
5643
|
-
|
|
5676
|
+
//#region src/ui/tui/screens/SlackConnectScreen.tsx
|
|
5677
|
+
/**
|
|
5678
|
+
* SlackConnectScreen — the dedicated "Connect Slack" step shown after the
|
|
5679
|
+
* MCP tutorial (`wizard mcp tutorial`), after a successful install
|
|
5680
|
+
* (`wizard mcp add`), at the end of the integration flow, and as the whole
|
|
5681
|
+
* program in the standalone `wizard slack` flow.
|
|
5682
|
+
*
|
|
5683
|
+
* Presents the PostHog Slack app plus role-tailored use-cases. The copy
|
|
5684
|
+
* adapts to whether Slack is already connected (polled while the screen
|
|
5685
|
+
* is up, held as local state):
|
|
5686
|
+
* • not connected (or unknown) — nudge + "Open Slack setup", which
|
|
5687
|
+
* launches the browser at the integration settings page and keeps
|
|
5688
|
+
* the screen alive; the poll flips it to connected once the user
|
|
5689
|
+
* finishes the manual OAuth step in the browser.
|
|
5690
|
+
* • already connected — confirm it and skip the connect CTA, so users
|
|
5691
|
+
* who already have it aren't nagged.
|
|
5692
|
+
* "Skip" / "Done" / esc dismiss the step (`slackStepDismissed`) and let
|
|
5693
|
+
* the router advance to exit.
|
|
5694
|
+
*
|
|
5695
|
+
* The mcp and integration flows arrive here already authenticated. In the
|
|
5696
|
+
* standalone `wizard slack` flow the program's `onInit` runs the OAuth
|
|
5697
|
+
* while this screen renders the auth-wait state.
|
|
5698
|
+
*/
|
|
5699
|
+
const POLL_INTERVAL_MS = 3e3;
|
|
5700
|
+
const SlackConnectScreen = ({ store }) => {
|
|
5701
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
5702
|
+
const role = store.session.roleAtOrganization;
|
|
5703
|
+
const slack = getSlackAppCard();
|
|
5704
|
+
const setupUrl = withUtm(slack.setupUrl, "slack-connect-setup");
|
|
5705
|
+
const learnMoreUrl = withUtm(slack.learnMoreUrl, "slack-connect-learn-more");
|
|
5706
|
+
const credentials = store.session.credentials;
|
|
5707
|
+
const awaitingLogin = store.router.activeProgram === Program.SlackConnect && !credentials;
|
|
5708
|
+
const connectedState = store.session.slackConnected;
|
|
5709
|
+
const connected = connectedState === true;
|
|
5710
|
+
const known = connectedState !== null || !credentials && !awaitingLogin;
|
|
5711
|
+
const impressionFired = useRef(false);
|
|
5712
|
+
useEffect(() => {
|
|
5713
|
+
if (!known || impressionFired.current) return;
|
|
5714
|
+
impressionFired.current = true;
|
|
5715
|
+
analytics.wizardCapture("slack connect shown", {
|
|
5716
|
+
role,
|
|
5717
|
+
already_connected: connected
|
|
5718
|
+
});
|
|
5719
|
+
}, [
|
|
5720
|
+
known,
|
|
5721
|
+
connected,
|
|
5722
|
+
role
|
|
5723
|
+
]);
|
|
5724
|
+
useEffect(() => {
|
|
5725
|
+
if (!credentials || connected) return;
|
|
5726
|
+
let cancelled = false;
|
|
5727
|
+
let timer;
|
|
5728
|
+
const controller = new AbortController();
|
|
5729
|
+
const check = () => {
|
|
5730
|
+
fetchSlackConnected(credentials.accessToken, credentials.projectId, credentials.host, controller.signal).then((isConnected) => {
|
|
5731
|
+
if (cancelled) return;
|
|
5732
|
+
if (isConnected) {
|
|
5733
|
+
if (store.session.slackConnected === false) analytics.wizardCapture("slack connect completed", { role });
|
|
5734
|
+
store.setSlackConnected(true);
|
|
5735
|
+
} else {
|
|
5736
|
+
if (store.session.slackConnected === null) store.setSlackConnected(false);
|
|
5737
|
+
timer = setTimeout(check, POLL_INTERVAL_MS);
|
|
5738
|
+
}
|
|
5739
|
+
}).catch((err) => {
|
|
5740
|
+
if (cancelled) return;
|
|
5741
|
+
if (store.session.slackConnected === null) store.setSlackConnected(false);
|
|
5742
|
+
analytics.captureException(err instanceof Error ? err : new Error(String(err)), { step: "slack_connected_check" });
|
|
5743
|
+
});
|
|
5744
|
+
};
|
|
5745
|
+
check();
|
|
5746
|
+
return () => {
|
|
5747
|
+
cancelled = true;
|
|
5748
|
+
if (timer) clearTimeout(timer);
|
|
5749
|
+
controller.abort();
|
|
5750
|
+
};
|
|
5751
|
+
}, [
|
|
5752
|
+
credentials,
|
|
5753
|
+
connected,
|
|
5754
|
+
store
|
|
5755
|
+
]);
|
|
5756
|
+
const dismiss = () => {
|
|
5757
|
+
analytics.wizardCapture(connected ? "slack connect done" : "slack connect skipped", {
|
|
5758
|
+
role,
|
|
5759
|
+
connected
|
|
5760
|
+
});
|
|
5761
|
+
store.setSlackStepDismissed();
|
|
5762
|
+
};
|
|
5763
|
+
const handleSelect = (value) => {
|
|
5764
|
+
if ((Array.isArray(value) ? value[0] : value) === "open") {
|
|
5765
|
+
analytics.wizardCapture("slack connect opened", { role });
|
|
5766
|
+
openTrackedLink(setupUrl, "slack-connect-setup");
|
|
5767
|
+
return;
|
|
5768
|
+
}
|
|
5769
|
+
dismiss();
|
|
5770
|
+
};
|
|
5771
|
+
useKeyBindings("slack-connect", [{
|
|
5772
|
+
match: "escape",
|
|
5773
|
+
label: "esc",
|
|
5774
|
+
action: connected ? "done" : "skip",
|
|
5775
|
+
handler: () => dismiss()
|
|
5776
|
+
}]);
|
|
5777
|
+
if (awaitingLogin) return /* @__PURE__ */ jsxs(Box, {
|
|
5778
|
+
flexDirection: "column",
|
|
5779
|
+
flexGrow: 1,
|
|
5780
|
+
marginTop: 1,
|
|
5781
|
+
children: [/* @__PURE__ */ jsx(LoadingBox, { message: "Waiting for authentication..." }), store.session.loginUrl && /* @__PURE__ */ jsx(Box, {
|
|
5782
|
+
marginTop: 1,
|
|
5783
|
+
flexDirection: "column",
|
|
5784
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5785
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5786
|
+
dimColor: true,
|
|
5787
|
+
children: "If the browser didn't open, copy and paste:"
|
|
5788
|
+
}),
|
|
5789
|
+
"\n\n",
|
|
5790
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5791
|
+
color: "cyan",
|
|
5792
|
+
children: store.session.loginUrl
|
|
5793
|
+
})
|
|
5794
|
+
] })
|
|
5795
|
+
})]
|
|
5796
|
+
});
|
|
5797
|
+
if (credentials && connectedState === null) return /* @__PURE__ */ jsx(Box, {
|
|
5798
|
+
flexDirection: "column",
|
|
5799
|
+
flexGrow: 1,
|
|
5800
|
+
marginTop: 1,
|
|
5801
|
+
children: /* @__PURE__ */ jsx(LoadingBox, { message: "Checking for an existing Slack connection..." })
|
|
5802
|
+
});
|
|
5803
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
5804
|
+
flexDirection: "column",
|
|
5805
|
+
flexGrow: 1,
|
|
5806
|
+
children: /* @__PURE__ */ jsxs(Box, {
|
|
5807
|
+
marginTop: 1,
|
|
5808
|
+
flexDirection: "column",
|
|
5809
|
+
children: [
|
|
5810
|
+
connected ? /* @__PURE__ */ jsxs(Text, {
|
|
5811
|
+
bold: true,
|
|
5812
|
+
color: Colors.success,
|
|
5813
|
+
children: [Icons.check, " Slack connected"]
|
|
5814
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
5815
|
+
bold: true,
|
|
5816
|
+
color: Colors.accent,
|
|
5817
|
+
children: slack.headline
|
|
5818
|
+
}),
|
|
5819
|
+
/* @__PURE__ */ jsx(Box, {
|
|
5820
|
+
marginTop: 1,
|
|
5821
|
+
children: /* @__PURE__ */ jsx(Text, { children: connected ? "Slack is connected — here's what you can do:" : slack.pitch })
|
|
5822
|
+
}),
|
|
5823
|
+
/* @__PURE__ */ jsx(Box, {
|
|
5824
|
+
marginTop: 1,
|
|
5825
|
+
flexDirection: "column",
|
|
5826
|
+
children: slack.capabilities.map((capability, i) => /* @__PURE__ */ jsx(Box, {
|
|
5827
|
+
marginTop: i === 0 ? 0 : 1,
|
|
5828
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
5829
|
+
color: "cyan",
|
|
5830
|
+
children: [Icons.diamond, " "]
|
|
5831
|
+
}), capability] })
|
|
5832
|
+
}, i))
|
|
5833
|
+
}),
|
|
5834
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
5835
|
+
marginTop: 1,
|
|
5836
|
+
flexDirection: "column",
|
|
5837
|
+
children: [!connected && /* @__PURE__ */ jsxs(Text, {
|
|
5838
|
+
dimColor: true,
|
|
5839
|
+
children: ["Connect it: ", /* @__PURE__ */ jsx(Text, {
|
|
5840
|
+
color: "cyan",
|
|
5841
|
+
children: setupUrl
|
|
5842
|
+
})]
|
|
5843
|
+
}), /* @__PURE__ */ jsxs(Text, {
|
|
5844
|
+
dimColor: true,
|
|
5845
|
+
children: ["Learn more: ", /* @__PURE__ */ jsx(Text, {
|
|
5846
|
+
color: "cyan",
|
|
5847
|
+
children: learnMoreUrl
|
|
5848
|
+
})]
|
|
5849
|
+
})]
|
|
5850
|
+
}),
|
|
5851
|
+
/* @__PURE__ */ jsx(Box, {
|
|
5852
|
+
marginTop: 1,
|
|
5853
|
+
children: /* @__PURE__ */ jsx(PickerMenu, {
|
|
5854
|
+
options: connected ? [{
|
|
5855
|
+
label: "Done",
|
|
5856
|
+
value: "skip"
|
|
5857
|
+
}] : [{
|
|
5858
|
+
label: "Open Slack setup",
|
|
5859
|
+
value: "open"
|
|
5860
|
+
}, {
|
|
5861
|
+
label: "Skip / Continue",
|
|
5862
|
+
value: "skip"
|
|
5863
|
+
}],
|
|
5864
|
+
onSelect: handleSelect
|
|
5865
|
+
})
|
|
5866
|
+
})
|
|
5867
|
+
]
|
|
5868
|
+
})
|
|
5869
|
+
});
|
|
5870
|
+
};
|
|
5871
|
+
//#endregion
|
|
5872
|
+
//#region src/ui/tui/screens/OutroScreen.tsx
|
|
5873
|
+
/**
|
|
5874
|
+
* OutroScreen — Default post-run summary.
|
|
5875
|
+
*
|
|
5876
|
+
* Renders the success / error / cancel views from `outroData`. Programs
|
|
5877
|
+
* that need a different success view (e.g. with extra summary content)
|
|
5878
|
+
* ship their own screen component (see audit/AuditOutroScreen.tsx).
|
|
5879
|
+
*/
|
|
5880
|
+
const OutroScreen = ({ store }) => {
|
|
5881
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
5882
|
+
useInput(() => {
|
|
5883
|
+
store.setOutroDismissed();
|
|
5884
|
+
});
|
|
5885
|
+
const outroData = store.session.outroData;
|
|
5886
|
+
if (!outroData) return /* @__PURE__ */ jsx(Box, {
|
|
5887
|
+
flexDirection: "column",
|
|
5888
|
+
flexGrow: 1,
|
|
5889
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
5890
|
+
dimColor: true,
|
|
5891
|
+
children: "Finishing up..."
|
|
5892
|
+
})
|
|
5893
|
+
});
|
|
5894
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
5895
|
+
flexDirection: "column",
|
|
5896
|
+
flexGrow: 1,
|
|
5897
|
+
children: [
|
|
5898
|
+
outroData.kind === "success" && /* @__PURE__ */ jsxs(Box, {
|
|
5899
|
+
flexDirection: "column",
|
|
5900
|
+
children: [
|
|
5901
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
5902
|
+
color: "green",
|
|
5903
|
+
bold: true,
|
|
5904
|
+
children: ["✔ ", outroData.message || "Done!"]
|
|
5905
|
+
}),
|
|
5906
|
+
outroData.body && /* @__PURE__ */ jsx(Box, {
|
|
5907
|
+
marginTop: 1,
|
|
5908
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
5909
|
+
dimColor: true,
|
|
5910
|
+
children: outroData.body
|
|
5911
|
+
})
|
|
5912
|
+
}),
|
|
5913
|
+
outroData.reportFile && /* @__PURE__ */ jsx(Box, {
|
|
5914
|
+
marginTop: 1,
|
|
5915
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5916
|
+
"Check ",
|
|
5917
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
5918
|
+
bold: true,
|
|
5919
|
+
children: ["./", outroData.reportFile]
|
|
5920
|
+
}),
|
|
5921
|
+
" for details"
|
|
5922
|
+
] })
|
|
5923
|
+
}),
|
|
5924
|
+
outroData.changes && outroData.changes.length > 0 && /* @__PURE__ */ jsxs(Box, {
|
|
5925
|
+
flexDirection: "column",
|
|
5926
|
+
marginTop: 1,
|
|
5927
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
5928
|
+
color: "cyan",
|
|
5929
|
+
bold: true,
|
|
5930
|
+
children: "What the agent did:"
|
|
5931
|
+
}), outroData.changes.map((change, i) => /* @__PURE__ */ jsxs(Text, { children: ["• ", change] }, i))]
|
|
5932
|
+
}),
|
|
5933
|
+
store.eventPlan.length > 0 && /* @__PURE__ */ jsxs(Box, {
|
|
5934
|
+
flexDirection: "column",
|
|
5935
|
+
marginTop: 1,
|
|
5936
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
5937
|
+
color: "cyan",
|
|
5938
|
+
bold: true,
|
|
5939
|
+
children: "Events added:"
|
|
5940
|
+
}), store.eventPlan.map((event) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
5941
|
+
"• ",
|
|
5942
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5943
|
+
bold: true,
|
|
5944
|
+
children: event.name
|
|
5945
|
+
}),
|
|
5946
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
5947
|
+
dimColor: true,
|
|
5948
|
+
children: [" ", event.description]
|
|
5949
|
+
})
|
|
5950
|
+
] }, event.name))]
|
|
5951
|
+
}),
|
|
5952
|
+
outroData.dashboardUrl && /* @__PURE__ */ jsx(Box, {
|
|
5953
|
+
marginTop: 1,
|
|
5954
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5955
|
+
"We've also made you a dashboard:",
|
|
5956
|
+
" ",
|
|
5957
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5958
|
+
color: "cyan",
|
|
5959
|
+
children: withUtm(outroData.dashboardUrl, "outro-dashboard")
|
|
5960
|
+
})
|
|
5961
|
+
] })
|
|
5962
|
+
}),
|
|
5963
|
+
outroData.notebookUrl && /* @__PURE__ */ jsx(Box, {
|
|
5964
|
+
marginTop: 1,
|
|
5965
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5966
|
+
"And uploaded the report to a PostHog notebook:",
|
|
5967
|
+
" ",
|
|
5968
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5969
|
+
color: "cyan",
|
|
5970
|
+
children: withUtm(outroData.notebookUrl, "outro-notebook")
|
|
5971
|
+
})
|
|
5972
|
+
] })
|
|
5973
|
+
}),
|
|
5974
|
+
outroData.docsUrl && /* @__PURE__ */ jsx(Box, {
|
|
5975
|
+
marginTop: 1,
|
|
5976
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5977
|
+
"Learn more:",
|
|
5978
|
+
" ",
|
|
5979
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5980
|
+
color: "cyan",
|
|
5981
|
+
children: withUtm(outroData.docsUrl, "outro-docs")
|
|
5982
|
+
})
|
|
5983
|
+
] })
|
|
5984
|
+
}),
|
|
5985
|
+
outroData.continueUrl && /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
5986
|
+
"Continue onboarding:",
|
|
5987
|
+
" ",
|
|
5988
|
+
/* @__PURE__ */ jsx(Text, {
|
|
5989
|
+
color: "cyan",
|
|
5990
|
+
children: withUtm(outroData.continueUrl, "outro-continue")
|
|
5991
|
+
})
|
|
5992
|
+
] }) }),
|
|
5993
|
+
/* @__PURE__ */ jsx(Box, {
|
|
5994
|
+
marginTop: 1,
|
|
5995
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
5996
|
+
dimColor: true,
|
|
5997
|
+
children: "Note: This wizard uses an LLM agent to analyze and modify your project. Please review the changes made."
|
|
5998
|
+
})
|
|
5999
|
+
}),
|
|
6000
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6001
|
+
dimColor: true,
|
|
6002
|
+
children: "How did this work for you? Drop us a line: wizard@posthog.com"
|
|
6003
|
+
})
|
|
6004
|
+
]
|
|
6005
|
+
}),
|
|
6006
|
+
outroData.kind === "error" && /* @__PURE__ */ jsxs(Box, {
|
|
6007
|
+
flexDirection: "column",
|
|
6008
|
+
children: [
|
|
6009
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
6010
|
+
color: "red",
|
|
6011
|
+
bold: true,
|
|
6012
|
+
children: ["✘ ", outroData.message || "An error occurred"]
|
|
6013
|
+
}),
|
|
6014
|
+
outroData.body && /* @__PURE__ */ jsx(Box, {
|
|
6015
|
+
marginTop: 1,
|
|
6016
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6017
|
+
dimColor: true,
|
|
6018
|
+
children: outroData.body
|
|
6019
|
+
})
|
|
6020
|
+
}),
|
|
6021
|
+
outroData.docsUrl && /* @__PURE__ */ jsx(Box, {
|
|
6022
|
+
marginTop: 1,
|
|
6023
|
+
children: /* @__PURE__ */ jsxs(Text, { children: ["Docs: ", /* @__PURE__ */ jsx(Text, {
|
|
6024
|
+
color: "cyan",
|
|
6025
|
+
children: outroData.docsUrl
|
|
6026
|
+
})] })
|
|
6027
|
+
})
|
|
6028
|
+
]
|
|
6029
|
+
}),
|
|
6030
|
+
outroData.kind === "cancel" && /* @__PURE__ */ jsx(Box, {
|
|
6031
|
+
flexDirection: "column",
|
|
6032
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
6033
|
+
color: "yellow",
|
|
6034
|
+
children: ["■ ", outroData.message || "Cancelled"]
|
|
6035
|
+
})
|
|
6036
|
+
}),
|
|
6037
|
+
/* @__PURE__ */ jsx(Box, {
|
|
6038
|
+
marginTop: 1,
|
|
6039
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6040
|
+
color: Colors.muted,
|
|
6041
|
+
children: "Press any key to continue"
|
|
6042
|
+
})
|
|
6043
|
+
})
|
|
6044
|
+
]
|
|
6045
|
+
});
|
|
6046
|
+
};
|
|
6047
|
+
//#endregion
|
|
6048
|
+
//#region src/ui/tui/screens/SkillSourceInfo.tsx
|
|
6049
|
+
/**
|
|
6050
|
+
* Shared "Skill: <id> / URL: <downloadUrl>" block for intro screens.
|
|
6051
|
+
*
|
|
6052
|
+
* `useSkillEntry` fetches the entry from the skill menu and re-runs when
|
|
6053
|
+
* `skillId` or `local` change. The previous fetch is cancelled (its result
|
|
6054
|
+
* is ignored) so a session that flips `local=false → true` mid-mount picks
|
|
6055
|
+
* up the right base URL.
|
|
6056
|
+
*
|
|
6057
|
+
* `<SkillSourceInfo>` renders the block, taking the entry as a prop so the
|
|
6058
|
+
* caller can reuse the same hook result for additional UI (e.g. showing
|
|
6059
|
+
* `skillEntry.name`) without invoking the hook twice.
|
|
6060
|
+
*/
|
|
6061
|
+
/**
|
|
6062
|
+
* Resolve a session skillId against the skill-menu entries.
|
|
6063
|
+
*
|
|
6064
|
+
* `session.skillId` is seeded with the raw integration id during
|
|
6065
|
+
* detection (e.g. 'python'), but the menu publishes integration skills
|
|
6066
|
+
* under prefixed ids ('integration-python'); frameworks with variants
|
|
6067
|
+
* publish several ('integration-nextjs-app-router', '-pages-router').
|
|
6068
|
+
* Match chain: exact id → `integration-<id>` → unique
|
|
6069
|
+
* `integration-<id>-*` prefix. Ambiguous variants (≥2 prefix matches)
|
|
6070
|
+
* return null — the caller should point at the skills repo instead of
|
|
6071
|
+
* guessing the wrong variant.
|
|
6072
|
+
*/
|
|
6073
|
+
function resolveSkillEntry(entries, skillId) {
|
|
6074
|
+
const exact = entries.find((s) => s.id === skillId);
|
|
6075
|
+
if (exact) return exact;
|
|
6076
|
+
const prefixed = entries.find((s) => s.id === `integration-${skillId}`);
|
|
6077
|
+
if (prefixed) return prefixed;
|
|
6078
|
+
const variants = entries.filter((s) => s.id.startsWith(`integration-${skillId}-`));
|
|
6079
|
+
return variants.length === 1 ? variants[0] : null;
|
|
6080
|
+
}
|
|
6081
|
+
function useSkillEntry(skillId, local) {
|
|
6082
|
+
const [skillEntry, setSkillEntry] = useState(null);
|
|
6083
|
+
const [fetchFailed, setFetchFailed] = useState(false);
|
|
6084
|
+
useEffect(() => {
|
|
6085
|
+
if (!skillId) {
|
|
6086
|
+
setFetchFailed(true);
|
|
6087
|
+
return;
|
|
6088
|
+
}
|
|
6089
|
+
let cancelled = false;
|
|
6090
|
+
setSkillEntry(null);
|
|
6091
|
+
setFetchFailed(false);
|
|
6092
|
+
fetchSkillMenu(getSkillsBaseUrl(local)).then((menu) => {
|
|
6093
|
+
if (cancelled) return;
|
|
6094
|
+
if (!menu) {
|
|
6095
|
+
setFetchFailed(true);
|
|
6096
|
+
return;
|
|
6097
|
+
}
|
|
6098
|
+
const match = resolveSkillEntry(Object.values(menu.categories).flat(), skillId);
|
|
6099
|
+
if (match) setSkillEntry(match);
|
|
6100
|
+
else setFetchFailed(true);
|
|
6101
|
+
});
|
|
6102
|
+
return () => {
|
|
6103
|
+
cancelled = true;
|
|
6104
|
+
};
|
|
6105
|
+
}, [skillId, local]);
|
|
6106
|
+
return {
|
|
6107
|
+
skillEntry,
|
|
6108
|
+
fetchFailed
|
|
6109
|
+
};
|
|
6110
|
+
}
|
|
6111
|
+
const SkillSourceInfo = ({ skillId, skillEntry, fetchFailed }) => /* @__PURE__ */ jsxs(Box, {
|
|
6112
|
+
flexDirection: "column",
|
|
6113
|
+
children: [/* @__PURE__ */ jsxs(Text, { children: [
|
|
6114
|
+
"Skill:",
|
|
6115
|
+
" ",
|
|
6116
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6117
|
+
italic: true,
|
|
6118
|
+
color: "cyan",
|
|
6119
|
+
children: skillId ?? "unknown"
|
|
6120
|
+
})
|
|
6121
|
+
] }), /* @__PURE__ */ jsxs(Text, { children: [
|
|
6122
|
+
"URL:",
|
|
6123
|
+
" ",
|
|
6124
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6125
|
+
color: "cyan",
|
|
6126
|
+
children: skillEntry?.downloadUrl ?? (fetchFailed ? "https://github.com/PostHog/context-mill/releases/latest" : "Loading...")
|
|
6127
|
+
})
|
|
6128
|
+
] })]
|
|
6129
|
+
});
|
|
6130
|
+
//#endregion
|
|
6131
|
+
//#region src/ui/tui/screens/AiOptInRequiredScreen.tsx
|
|
6132
|
+
/**
|
|
6133
|
+
* AiOptInRequiredScreen — Renders when the wizard authenticates against an
|
|
6134
|
+
* org whose `is_ai_data_processing_approved` is not `true`. Mirrors Max's
|
|
6135
|
+
* strict reading: `null`, `undefined`, and `false` all block.
|
|
6136
|
+
*
|
|
6137
|
+
* Two variants selected from `apiUser.organization.membership_level`:
|
|
6138
|
+
* - Admin (>= 8): can fix it themselves — [O] opens settings in browser.
|
|
6139
|
+
* - Non-admin: needs to escalate — settings URL is displayed prominently
|
|
6140
|
+
* to copy and share with the admin.
|
|
6141
|
+
*
|
|
6142
|
+
* Both variants offer [S] (show skill source for BYOAI), [R] (retry —
|
|
6143
|
+
* re-fetches user data and re-evaluates the gate without restarting), and
|
|
6144
|
+
* [E] (exit).
|
|
6145
|
+
*/
|
|
6146
|
+
const ORG_ADMIN_LEVEL = 8;
|
|
6147
|
+
const SETTINGS_PATH = "settings/organization-details";
|
|
6148
|
+
const SETTINGS_ANCHOR = "#organization-ai-consent";
|
|
6149
|
+
const AiOptInRequiredScreen = ({ store }) => {
|
|
6150
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
6151
|
+
const { session } = store;
|
|
6152
|
+
const isAdmin = ((session.apiUser?.organization)?.membership_level ?? 0) >= ORG_ADMIN_LEVEL;
|
|
6153
|
+
const variant = isAdmin ? "admin" : "non-admin";
|
|
6154
|
+
const region = session.region ?? "us";
|
|
6155
|
+
const projectId = session.credentials?.projectId;
|
|
6156
|
+
const settingsUrl = projectId != null ? `${POSTHOG_APP_URL}/project/${projectId}/${SETTINGS_PATH}${SETTINGS_ANCHOR}` : `${POSTHOG_APP_URL}/${SETTINGS_PATH}${SETTINGS_ANCHOR}`;
|
|
6157
|
+
const [showSkill, setShowSkill] = useState(false);
|
|
6158
|
+
const [retrying, setRetrying] = useState(false);
|
|
6159
|
+
const [retryError, setRetryError] = useState(null);
|
|
6160
|
+
const { skillEntry } = useSkillEntry(session.skillId, session.localMcp);
|
|
6161
|
+
useEffect(() => {
|
|
6162
|
+
analytics.wizardCapture("ai opt-in shown", { variant });
|
|
6163
|
+
}, [variant]);
|
|
6164
|
+
const handleOpenSettings = () => {
|
|
6165
|
+
analytics.wizardCapture("ai opt-in action", {
|
|
6166
|
+
variant,
|
|
6167
|
+
action: "open_settings"
|
|
6168
|
+
});
|
|
6169
|
+
opn(settingsUrl, { wait: false }).catch(() => {});
|
|
6170
|
+
};
|
|
6171
|
+
const handleShowSkill = () => {
|
|
6172
|
+
analytics.wizardCapture("ai opt-in action", {
|
|
6173
|
+
variant,
|
|
6174
|
+
action: "show_skill"
|
|
6175
|
+
});
|
|
6176
|
+
setShowSkill(true);
|
|
6177
|
+
};
|
|
6178
|
+
const handleRetry = () => {
|
|
6179
|
+
analytics.wizardCapture("ai opt-in action", {
|
|
6180
|
+
variant,
|
|
6181
|
+
action: "retry"
|
|
6182
|
+
});
|
|
6183
|
+
const accessToken = session.credentials?.accessToken;
|
|
6184
|
+
if (!accessToken) {
|
|
6185
|
+
setRetryError("Missing credentials — cannot retry.");
|
|
6186
|
+
return;
|
|
6187
|
+
}
|
|
6188
|
+
setRetrying(true);
|
|
6189
|
+
setRetryError(null);
|
|
6190
|
+
fetchUserData(accessToken, getCloudUrlFromRegion(region)).then((user) => {
|
|
6191
|
+
store.setApiUser(user);
|
|
6192
|
+
}).catch((err) => {
|
|
6193
|
+
setRetryError(err instanceof Error ? err.message : "Retry failed.");
|
|
6194
|
+
}).finally(() => {
|
|
6195
|
+
setRetrying(false);
|
|
6196
|
+
});
|
|
6197
|
+
};
|
|
6198
|
+
const handleExit = () => {
|
|
6199
|
+
analytics.wizardCapture("ai opt-in action", {
|
|
6200
|
+
variant,
|
|
6201
|
+
action: "exit"
|
|
6202
|
+
});
|
|
6203
|
+
process.exit(0);
|
|
6204
|
+
};
|
|
6205
|
+
useKeyBindings("ai-opt-in", [
|
|
6206
|
+
...isAdmin ? [{
|
|
6207
|
+
match: ["o", "O"],
|
|
6208
|
+
label: "O",
|
|
6209
|
+
action: "open settings",
|
|
6210
|
+
handler: handleOpenSettings
|
|
6211
|
+
}] : [],
|
|
6212
|
+
{
|
|
6213
|
+
match: ["s", "S"],
|
|
6214
|
+
label: "S",
|
|
6215
|
+
action: "show skill",
|
|
6216
|
+
handler: handleShowSkill
|
|
6217
|
+
},
|
|
6218
|
+
{
|
|
6219
|
+
match: ["r", "R"],
|
|
6220
|
+
label: "R",
|
|
6221
|
+
action: "retry",
|
|
6222
|
+
handler: handleRetry
|
|
6223
|
+
},
|
|
6224
|
+
{
|
|
6225
|
+
match: ["e", "E"],
|
|
6226
|
+
label: "E",
|
|
6227
|
+
action: "exit",
|
|
6228
|
+
handler: handleExit
|
|
6229
|
+
}
|
|
6230
|
+
]);
|
|
6231
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
6232
|
+
flexDirection: "column",
|
|
6233
|
+
flexGrow: 1,
|
|
6234
|
+
children: [
|
|
6235
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
6236
|
+
flexDirection: "column",
|
|
6237
|
+
marginBottom: 1,
|
|
6238
|
+
children: [/* @__PURE__ */ jsx(Text, {
|
|
6239
|
+
bold: true,
|
|
6240
|
+
color: Colors.accent,
|
|
6241
|
+
children: "PostHog Setup Wizard"
|
|
6242
|
+
}), session.apiUser?.email && /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
6243
|
+
color: "green",
|
|
6244
|
+
children: ["✔", " "]
|
|
6245
|
+
}), /* @__PURE__ */ jsxs(Text, { children: ["Authenticated as ", session.apiUser.email] })] })]
|
|
6246
|
+
}),
|
|
6247
|
+
/* @__PURE__ */ jsx(Box, {
|
|
6248
|
+
flexDirection: "column",
|
|
6249
|
+
marginBottom: 1,
|
|
6250
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6251
|
+
color: "yellow",
|
|
6252
|
+
bold: true,
|
|
6253
|
+
children: "⚠ PostHog AI services are disabled for your organization"
|
|
6254
|
+
})
|
|
6255
|
+
}),
|
|
6256
|
+
/* @__PURE__ */ jsx(Box, {
|
|
6257
|
+
flexDirection: "column",
|
|
6258
|
+
marginBottom: 1,
|
|
6259
|
+
width: 68,
|
|
6260
|
+
children: isAdmin ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
6261
|
+
"The wizard uses Anthropic Claude. To proceed, enable",
|
|
6262
|
+
" ",
|
|
6263
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6264
|
+
italic: true,
|
|
6265
|
+
children: "\"Enable PostHog features that use third-party AI services\""
|
|
6266
|
+
}),
|
|
6267
|
+
" ",
|
|
6268
|
+
"in your organization settings."
|
|
6269
|
+
] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, { children: [
|
|
6270
|
+
"The wizard uses Anthropic Claude. Your organization admin needs to enable",
|
|
6271
|
+
" ",
|
|
6272
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6273
|
+
italic: true,
|
|
6274
|
+
children: "\"Enable PostHog features that use third-party AI services\""
|
|
6275
|
+
}),
|
|
6276
|
+
" ",
|
|
6277
|
+
"in organization settings."
|
|
6278
|
+
] }), /* @__PURE__ */ jsx(Box, {
|
|
6279
|
+
marginTop: 1,
|
|
6280
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6281
|
+
dimColor: true,
|
|
6282
|
+
children: "Share this link with your admin:"
|
|
6283
|
+
})
|
|
6284
|
+
})] })
|
|
6285
|
+
}),
|
|
6286
|
+
/* @__PURE__ */ jsx(Box, {
|
|
6287
|
+
marginBottom: 1,
|
|
6288
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6289
|
+
color: "cyan",
|
|
6290
|
+
children: settingsUrl
|
|
6291
|
+
})
|
|
6292
|
+
}),
|
|
6293
|
+
showSkill && /* @__PURE__ */ jsxs(Box, {
|
|
6294
|
+
marginBottom: 1,
|
|
6295
|
+
flexDirection: "column",
|
|
6296
|
+
children: [/* @__PURE__ */ jsxs(Text, { children: [
|
|
6297
|
+
"Prefer your own AI? Download",
|
|
6298
|
+
" ",
|
|
6299
|
+
skillEntry ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6300
|
+
"the ",
|
|
6301
|
+
/* @__PURE__ */ jsx(Text, {
|
|
6302
|
+
bold: true,
|
|
6303
|
+
children: skillEntry.id
|
|
6304
|
+
}),
|
|
6305
|
+
" skill"
|
|
6306
|
+
] }) : "the skill for your framework",
|
|
6307
|
+
" ",
|
|
6308
|
+
"and run it in your own agent:"
|
|
6309
|
+
] }), /* @__PURE__ */ jsx(Text, {
|
|
6310
|
+
color: "cyan",
|
|
6311
|
+
children: "https://github.com/PostHog/context-mill/releases/latest"
|
|
6312
|
+
})]
|
|
6313
|
+
}),
|
|
6314
|
+
retrying && /* @__PURE__ */ jsx(Box, {
|
|
6315
|
+
marginBottom: 1,
|
|
6316
|
+
children: /* @__PURE__ */ jsx(LoadingBox, { message: "Re-checking organization settings..." })
|
|
6317
|
+
}),
|
|
6318
|
+
retryError && /* @__PURE__ */ jsx(Box, {
|
|
6319
|
+
marginBottom: 1,
|
|
6320
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6321
|
+
color: "red",
|
|
6322
|
+
children: retryError
|
|
6323
|
+
})
|
|
6324
|
+
}),
|
|
6325
|
+
/* @__PURE__ */ jsxs(Box, {
|
|
6326
|
+
flexDirection: "column",
|
|
6327
|
+
marginTop: 1,
|
|
6328
|
+
children: [
|
|
6329
|
+
isAdmin && /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
6330
|
+
color: Colors.accent,
|
|
6331
|
+
children: "[O]"
|
|
6332
|
+
}), " Open settings in browser"] }),
|
|
6333
|
+
/* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
6334
|
+
color: Colors.accent,
|
|
6335
|
+
children: "[S]"
|
|
6336
|
+
}), " Show how to use your own AI"] }),
|
|
6337
|
+
/* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
6338
|
+
color: Colors.accent,
|
|
6339
|
+
children: "[R]"
|
|
6340
|
+
}), " Retry (after the toggle is enabled)"] }),
|
|
6341
|
+
/* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
6342
|
+
color: Colors.accent,
|
|
6343
|
+
children: "[E]"
|
|
6344
|
+
}), " Exit"] })
|
|
6345
|
+
]
|
|
6346
|
+
})
|
|
6347
|
+
]
|
|
6348
|
+
});
|
|
6349
|
+
};
|
|
6350
|
+
//#endregion
|
|
6351
|
+
export { useKeyBindings as A, EventPlanViewer as C, GroupedPickerMenu as D, ConfirmationInput as E, WizardStore as F, LoadingBox as M, SplitView as N, useStdoutDimensions as O, CardLayout as P, ScreenContainer as S, ModalOverlay as T, TipsCard as _, SlackConnectScreen as a, HNViewer as b, VisualBox as c, TAILORED_ROLES as d, McpScreen as f, ServiceHealthList as g, SEVERITY_ORDER as h, OutroScreen as i, ProgressList as j, PickerMenu as k, AuditChecksViewer as l, SEVERITY_LABEL as m, SkillSourceInfo as n, AUDIT_3000_AREA_SLIDES as o, IssueTable as p, useSkillEntry as r, AUDIT_AREA_SLIDES as s, AiOptInRequiredScreen as t, McpSuggestedPromptsScreen as u, LearnCard as v, LogViewer as w, TabContainer as x, ContentSequencer as y };
|
|
5644
6352
|
|
|
5645
|
-
//# sourceMappingURL=
|
|
6353
|
+
//# sourceMappingURL=AiOptInRequiredScreen-N6L80szR.js.map
|