@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.
Files changed (65) hide show
  1. package/README.md +14 -1
  2. package/dist/{slides-BEshbXqG.js → AiOptInRequiredScreen-N6L80szR.js} +741 -33
  3. package/dist/AiOptInRequiredScreen-N6L80szR.js.map +1 -0
  4. package/dist/{add-mcp-server-to-clients-iV7BuQpD.js → add-mcp-server-to-clients-DqHCkHqM.js} +12 -10
  5. package/dist/add-mcp-server-to-clients-DqHCkHqM.js.map +1 -0
  6. package/dist/{agent-interface-B-LAvrNL.js → agent-interface-DZmVoik2.js} +5 -5
  7. package/dist/{agent-interface-B-LAvrNL.js.map → agent-interface-DZmVoik2.js.map} +1 -1
  8. package/dist/{agent-runner-w2Qu9M13.js → agent-runner-CGFUXR97.js} +13 -9
  9. package/dist/{agent-runner-w2Qu9M13.js.map → agent-runner-CGFUXR97.js.map} +1 -1
  10. package/dist/{analytics-C8lJzXjY.js → analytics-C_lVPZQT.js} +28 -4
  11. package/dist/analytics-C_lVPZQT.js.map +1 -0
  12. package/dist/{api-eUlUinVy.js → api-QI1lO_Bz.js} +3 -3
  13. package/dist/{api-eUlUinVy.js.map → api-QI1lO_Bz.js.map} +1 -1
  14. package/dist/bin.js +160 -49
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{ci-install-CSo7Q1pK.js → ci-install-CXkKR4A-.js} +4 -4
  17. package/dist/{ci-install-CSo7Q1pK.js.map → ci-install-CXkKR4A-.js.map} +1 -1
  18. package/dist/{debug-BJu_sS4l.js → debug-D8QAez2V.js} +58 -13
  19. package/dist/debug-D8QAez2V.js.map +1 -0
  20. package/dist/{debug-CTViFiF-.js → debug-lPpecs0J.js} +1 -1
  21. package/dist/{environment-Dk_dWk3t.js → environment-CMmzgZkN.js} +3 -3
  22. package/dist/{environment-Dk_dWk3t.js.map → environment-CMmzgZkN.js.map} +1 -1
  23. package/dist/{interactive-BS2rIf1v.js → interactive-Bu8YchJG.js} +2 -2
  24. package/dist/{interactive-BS2rIf1v.js.map → interactive-Bu8YchJG.js.map} +1 -1
  25. package/dist/{mcp-prompt-streaming-BiMrlLl0.js → mcp-prompt-streaming-mYw2LPZZ.js} +4 -4
  26. package/dist/{mcp-prompt-streaming-BiMrlLl0.js.map → mcp-prompt-streaming-mYw2LPZZ.js.map} +1 -1
  27. package/dist/{non-interactive-C39d_KIp.js → non-interactive-De3tJM1y.js} +2 -2
  28. package/dist/{non-interactive-C39d_KIp.js.map → non-interactive-De3tJM1y.js.map} +1 -1
  29. package/dist/{package-manager-BfOTvFt-.js → package-manager-BVJnbp1u.js} +2 -2
  30. package/dist/{package-manager-BfOTvFt-.js.map → package-manager-BVJnbp1u.js.map} +1 -1
  31. package/dist/{playground-3OeRB7JU.js → playground-wyoq1yIH.js} +205 -4
  32. package/dist/playground-wyoq1yIH.js.map +1 -0
  33. package/dist/{posthog-integration-8iTgqy2J.js → posthog-integration-mrMF-2IP.js} +48 -16
  34. package/dist/posthog-integration-mrMF-2IP.js.map +1 -0
  35. package/dist/{provisioning-DxaT7bWw.js → provisioning-4zipVpbq.js} +3 -3
  36. package/dist/{provisioning-DxaT7bWw.js.map → provisioning-4zipVpbq.js.map} +1 -1
  37. package/dist/{registry-apQfB3rf.js → registry-BGUo4PlM.js} +7 -20
  38. package/dist/registry-BGUo4PlM.js.map +1 -0
  39. package/dist/{setup-utils-B9xqAXXl.js → setup-utils-DmhPyWkp.js} +114 -57
  40. package/dist/setup-utils-DmhPyWkp.js.map +1 -0
  41. package/dist/{start-tui-CCpKnZOY.js → start-tui-DaQiY_EB.js} +310 -452
  42. package/dist/start-tui-DaQiY_EB.js.map +1 -0
  43. package/dist/{steps-DKbDDnVH.js → steps-CrUceWR5.js} +6 -6
  44. package/dist/{steps-DKbDDnVH.js.map → steps-CrUceWR5.js.map} +1 -1
  45. package/dist/telemetry-CCVjGq7l.js +68 -0
  46. package/dist/telemetry-CCVjGq7l.js.map +1 -0
  47. package/dist/{urls-B6wBIwr1.js → urls-BNFpfcN8.js} +2 -2
  48. package/dist/{urls-B6wBIwr1.js.map → urls-BNFpfcN8.js.map} +1 -1
  49. package/dist/{wizard-abort-DhGgTlUA.js → wizard-abort-BmYb0bG2.js} +3 -3
  50. package/dist/{wizard-abort-DhGgTlUA.js.map → wizard-abort-BmYb0bG2.js.map} +1 -1
  51. package/dist/{wizard-abort-D8XZdVAR.js → wizard-abort-Bp2yxYAy.js} +1 -1
  52. package/dist/wizard-session-G3VWD6hv.js.map +1 -1
  53. package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
  54. package/package.json +1 -1
  55. package/dist/add-mcp-server-to-clients-iV7BuQpD.js.map +0 -1
  56. package/dist/analytics-C8lJzXjY.js.map +0 -1
  57. package/dist/debug-BJu_sS4l.js.map +0 -1
  58. package/dist/playground-3OeRB7JU.js.map +0 -1
  59. package/dist/posthog-integration-8iTgqy2J.js.map +0 -1
  60. package/dist/registry-apQfB3rf.js.map +0 -1
  61. package/dist/setup-utils-B9xqAXXl.js.map +0 -1
  62. package/dist/slides-BEshbXqG.js.map +0 -1
  63. package/dist/start-tui-CCpKnZOY.js.map +0 -1
  64. package/dist/telemetry-DUeOcmpo.js +0 -13
  65. package/dist/telemetry-DUeOcmpo.js.map +0 -1
@@ -1,13 +1,16 @@
1
- import { g as SERVICE_LABELS, s as logToFile } from "./debug-BJu_sS4l.js";
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-C8lJzXjY.js";
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-B-LAvrNL.js";
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-8iTgqy2J.js";
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.steps)]));
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).steps;
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-app"
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-app",
3862
+ "learnMoreUrl": "https://posthog.com/slack",
3811
3863
  "setupUrl": "https://app.posthog.com/settings/project-integrations#integration-slack",
3812
- "headline": "Take PostHog to Slack",
3813
- "pitch": "You can also analyze product data and ship changes.",
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
- opn(getSlackAppCard().setupUrl, { wait: false }).catch(() => {});
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
- export { CardLayout as A, GroupedPickerMenu as C, ProgressList as D, useKeyBindings as E, LoadingBox as O, ConfirmationInput as S, PickerMenu as T, TabContainer as _, McpSuggestedPromptsScreen as a, LogViewer as b, McpScreen as c, SEVERITY_ORDER as d, ServiceHealthList as f, HNViewer as g, ContentSequencer as h, AuditChecksViewer as i, WizardStore as j, SplitView as k, IssueTable as l, LearnCard as m, AUDIT_AREA_SLIDES as n, TAILORED_ROLES as o, TipsCard as p, VisualBox as r, getSlackAppCard as s, AUDIT_3000_AREA_SLIDES as t, SEVERITY_LABEL as u, ScreenContainer as v, useStdoutDimensions as w, ModalOverlay as x, EventPlanViewer as y };
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=slides-BEshbXqG.js.map
6353
+ //# sourceMappingURL=AiOptInRequiredScreen-N6L80szR.js.map