@posthog/wizard 2.18.0 → 2.20.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 (71) hide show
  1. package/README.md +11 -0
  2. package/dist/{add-mcp-server-to-clients-DnPwZl1P.js → add-mcp-server-to-clients-iV7BuQpD.js} +72 -13
  3. package/dist/add-mcp-server-to-clients-iV7BuQpD.js.map +1 -0
  4. package/dist/{agent-interface-C2VEF-BD.js → agent-interface-B-LAvrNL.js} +165 -52
  5. package/dist/agent-interface-B-LAvrNL.js.map +1 -0
  6. package/dist/{agent-runner-Dw8cjZoN.js → agent-runner-w2Qu9M13.js} +16 -11
  7. package/dist/{agent-runner-Dw8cjZoN.js.map → agent-runner-w2Qu9M13.js.map} +1 -1
  8. package/dist/{analytics-C-zcTO6g.js → analytics-C8lJzXjY.js} +2 -2
  9. package/dist/{analytics-C-zcTO6g.js.map → analytics-C8lJzXjY.js.map} +1 -1
  10. package/dist/{api-B3MWP3vm.js → api-eUlUinVy.js} +25 -4
  11. package/dist/{api-B3MWP3vm.js.map → api-eUlUinVy.js.map} +1 -1
  12. package/dist/bin.js +79 -50
  13. package/dist/bin.js.map +1 -1
  14. package/dist/check-screens.tsx +124 -0
  15. package/dist/{ci-install-DLuSmSq6.js → ci-install-CSo7Q1pK.js} +4 -4
  16. package/dist/{ci-install-DLuSmSq6.js.map → ci-install-CSo7Q1pK.js.map} +1 -1
  17. package/dist/{debug-BorYMfpE.js → debug-BJu_sS4l.js} +36 -21
  18. package/dist/debug-BJu_sS4l.js.map +1 -0
  19. package/dist/{debug--gQGudnY.js → debug-CTViFiF-.js} +1 -1
  20. package/dist/{defaults-DA3-9dHT.js → defaults-BNWIWzjc.js} +34 -8
  21. package/dist/defaults-BNWIWzjc.js.map +1 -0
  22. package/dist/{environment-DIOtLqTQ.js → environment-Dk_dWk3t.js} +3 -3
  23. package/dist/{environment-DIOtLqTQ.js.map → environment-Dk_dWk3t.js.map} +1 -1
  24. package/dist/{interactive-DjGjlvY3.js → interactive-BS2rIf1v.js} +2 -2
  25. package/dist/{interactive-DjGjlvY3.js.map → interactive-BS2rIf1v.js.map} +1 -1
  26. package/dist/{mcp-prompt-streaming-Dm47tmiy.js → mcp-prompt-streaming-BiMrlLl0.js} +4 -4
  27. package/dist/{mcp-prompt-streaming-Dm47tmiy.js.map → mcp-prompt-streaming-BiMrlLl0.js.map} +1 -1
  28. package/dist/{non-interactive-C2f3Gwva.js → non-interactive-C39d_KIp.js} +2 -2
  29. package/dist/{non-interactive-C2f3Gwva.js.map → non-interactive-C39d_KIp.js.map} +1 -1
  30. package/dist/{package-manager-Bl2KOUFK.js → package-manager-BfOTvFt-.js} +2 -2
  31. package/dist/{package-manager-Bl2KOUFK.js.map → package-manager-BfOTvFt-.js.map} +1 -1
  32. package/dist/{playground-ZLG68cvx.js → playground-3OeRB7JU.js} +23 -9
  33. package/dist/playground-3OeRB7JU.js.map +1 -0
  34. package/dist/{posthog-integration-B_DLodqr.js → posthog-integration-8iTgqy2J.js} +20 -12
  35. package/dist/posthog-integration-8iTgqy2J.js.map +1 -0
  36. package/dist/{provisioning-Bk4E6VYn.js → provisioning-DxaT7bWw.js} +3 -3
  37. package/dist/{provisioning-Bk4E6VYn.js.map → provisioning-DxaT7bWw.js.map} +1 -1
  38. package/dist/{registry-DMM3UmZD.js → registry-apQfB3rf.js} +4 -4
  39. package/dist/{registry-DMM3UmZD.js.map → registry-apQfB3rf.js.map} +1 -1
  40. package/dist/{setup-utils-Df9ezAjZ.js → setup-utils-B9xqAXXl.js} +35 -20
  41. package/dist/{setup-utils-Df9ezAjZ.js.map → setup-utils-B9xqAXXl.js.map} +1 -1
  42. package/dist/{slides-DwvXZ8iS.js → slides-BEshbXqG.js} +448 -187
  43. package/dist/slides-BEshbXqG.js.map +1 -0
  44. package/dist/{start-tui-P9aMwBzt.js → start-tui-CCpKnZOY.js} +245 -57
  45. package/dist/start-tui-CCpKnZOY.js.map +1 -0
  46. package/dist/{steps-RCRZbLjZ.js → steps-DKbDDnVH.js} +6 -6
  47. package/dist/{steps-RCRZbLjZ.js.map → steps-DKbDDnVH.js.map} +1 -1
  48. package/dist/{task-stream-CZRj6auI.js → task-stream-CZawuzlz.js} +2 -2
  49. package/dist/{task-stream-CZRj6auI.js.map → task-stream-CZawuzlz.js.map} +1 -1
  50. package/dist/{telemetry-CMbVbpaY.js → telemetry-DUeOcmpo.js} +2 -2
  51. package/dist/{telemetry-CMbVbpaY.js.map → telemetry-DUeOcmpo.js.map} +1 -1
  52. package/dist/{urls-BzG_Jtw9.js → urls-B6wBIwr1.js} +2 -2
  53. package/dist/{urls-BzG_Jtw9.js.map → urls-B6wBIwr1.js.map} +1 -1
  54. package/dist/wizard-abort-D8XZdVAR.js +2 -0
  55. package/dist/{wizard-abort-QuKm_B5z.js → wizard-abort-DhGgTlUA.js} +14 -7
  56. package/dist/wizard-abort-DhGgTlUA.js.map +1 -0
  57. package/dist/{wizard-session-d27JGRGi.js → wizard-session-G3VWD6hv.js} +3 -1
  58. package/dist/{wizard-session-d27JGRGi.js.map → wizard-session-G3VWD6hv.js.map} +1 -1
  59. package/dist/{wizard-session-y304gEEI.js → wizard-session-wPJtNl4c.js} +1 -1
  60. package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
  61. package/package.json +4 -2
  62. package/dist/add-mcp-server-to-clients-DnPwZl1P.js.map +0 -1
  63. package/dist/agent-interface-C2VEF-BD.js.map +0 -1
  64. package/dist/debug-BorYMfpE.js.map +0 -1
  65. package/dist/defaults-DA3-9dHT.js.map +0 -1
  66. package/dist/playground-ZLG68cvx.js.map +0 -1
  67. package/dist/posthog-integration-B_DLodqr.js.map +0 -1
  68. package/dist/slides-DwvXZ8iS.js.map +0 -1
  69. package/dist/start-tui-P9aMwBzt.js.map +0 -1
  70. package/dist/wizard-abort-Dl8WJQgJ.js +0 -2
  71. package/dist/wizard-abort-QuKm_B5z.js.map +0 -1
@@ -1,12 +1,13 @@
1
- import { g as SERVICE_LABELS, s as logToFile } from "./debug-BorYMfpE.js";
1
+ import { g as SERVICE_LABELS, s as logToFile } from "./debug-BJu_sS4l.js";
2
2
  import { n as isTaskStatus } from "./wizard-ui-YdGFRyu_.js";
3
- import { r as sessionProperties, t as analytics } from "./analytics-C-zcTO6g.js";
4
- import { i as buildSession } from "./wizard-session-d27JGRGi.js";
5
- import { v as AUDIT_SEVERITY_STYLE } from "./agent-interface-C2VEF-BD.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-B_DLodqr.js";
3
+ import { r as sessionProperties, t as analytics } from "./analytics-C8lJzXjY.js";
4
+ 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";
7
7
  import { a as getProgramConfig, i as Program, l as getKindMeta, r as PROGRAM_REGISTRY } from "./bin.js";
8
- import { n as AVAILABLE_FEATURES, t as ALL_FEATURE_VALUES } from "./defaults-DA3-9dHT.js";
8
+ import { n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, t as ALL_FEATURE_VALUES } from "./defaults-BNWIWzjc.js";
9
9
  import * as fs$1 from "fs";
10
+ import opn from "opn";
10
11
  import { Box, Text, measureElement, useInput, useStdout } from "ink";
11
12
  import { Component, Fragment, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
12
13
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
@@ -159,8 +160,7 @@ var WizardStore = class {
159
160
  this._initFromProgram(program);
160
161
  }
161
162
  /**
162
- * Scan program steps for gate predicates and onInit callbacks.
163
- * Creates gate promises and fires init work.
163
+ * Scan program steps for gate predicates and create gate promises.
164
164
  */
165
165
  _initFromProgram(program) {
166
166
  const steps = getProgramConfig(program).steps;
@@ -176,6 +176,15 @@ var WizardStore = class {
176
176
  resolved: false
177
177
  });
178
178
  }
179
+ }
180
+ /**
181
+ * Run the program steps' onInit callbacks. startTUI calls this once
182
+ * the screens are actually rendering — constructing a store alone
183
+ * (tests, playground) must not fire init work like the health-check
184
+ * pre-flight, whose probes belong only to flows that show its screen.
185
+ */
186
+ runInitHooks() {
187
+ const steps = getProgramConfig(this.router.activeProgram).steps;
179
188
  const getSession = () => this.session;
180
189
  const ctx = {
181
190
  get session() {
@@ -320,6 +329,7 @@ var WizardStore = class {
320
329
  }
321
330
  /** User dismissed the blocking outage screen. Gate resolves via _checkGates(). */
322
331
  dismissOutage() {
332
+ logToFile("[health-checks] user dismissed outage screen, continuing");
323
333
  this.$session.setKey("outageDismissed", true);
324
334
  this.emitChange();
325
335
  }
@@ -461,13 +471,15 @@ var WizardStore = class {
461
471
  analytics.wizardCapture("feature enabled", { feature });
462
472
  this.emitChange();
463
473
  }
464
- setMcpComplete(outcome = "skipped", installedClients = []) {
474
+ setMcpComplete(outcome = "skipped", installedClients = [], featuresSelected) {
465
475
  this.$session.setKey("mcpComplete", true);
466
476
  this.$session.setKey("mcpOutcome", outcome);
467
477
  this.$session.setKey("mcpInstalledClients", installedClients);
478
+ const featuresPayload = outcome === "installed" && featuresSelected !== void 0 ? { mcp_features_selected: featuresSelected } : {};
468
479
  analytics.wizardCapture("mcp complete", {
469
480
  mcp_outcome: outcome,
470
481
  mcp_installed_clients: installedClients,
482
+ ...featuresPayload,
471
483
  ...sessionProperties(this.session)
472
484
  });
473
485
  this.emitChange();
@@ -484,6 +496,14 @@ var WizardStore = class {
484
496
  this.$session.setKey("mcpSuggestedPromptsDismissed", true);
485
497
  this.emitChange();
486
498
  }
499
+ setSlackStepDismissed() {
500
+ this.$session.setKey("slackStepDismissed", true);
501
+ this.emitChange();
502
+ }
503
+ setSlackConnected(connected) {
504
+ this.$session.setKey("slackConnected", connected);
505
+ this.emitChange();
506
+ }
487
507
  setOutroDismissed() {
488
508
  this.$session.setKey("outroDismissed", true);
489
509
  this.emitChange();
@@ -888,6 +908,27 @@ function useKeyBindings(id, bindings) {
888
908
  * Key bindings are declared via useKeyBindings, which auto-registers
889
909
  * hints in the KeyboardHintsBar.
890
910
  */
911
+ /**
912
+ * Step through a column's options in `dir`, wrapping, until an enabled
913
+ * option is found. Returns `from` unchanged if the column is entirely
914
+ * disabled.
915
+ */
916
+ function stepEnabled(options, rows, from, dir) {
917
+ const colStart = Math.floor(from / rows) * rows;
918
+ const colLen = Math.min(rows, options.length - colStart);
919
+ let row = from % rows;
920
+ for (let i = 0; i < colLen; i++) {
921
+ row = (row + dir + colLen) % colLen;
922
+ const idx = colStart + row;
923
+ if (!options[idx]?.disabled) return idx;
924
+ }
925
+ return from;
926
+ }
927
+ /** Index of the first enabled option, for the initial focus. */
928
+ function firstEnabled(options) {
929
+ const idx = options.findIndex((o) => !o.disabled);
930
+ return idx === -1 ? 0 : idx;
931
+ }
891
932
  const PickerMenu = ({ message, options, mode = "single", centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
892
933
  if (mode === "multi") return /* @__PURE__ */ jsx(MultiPickerMenu, {
893
934
  message,
@@ -908,22 +949,18 @@ const PickerMenu = ({ message, options, mode = "single", centered = false, colum
908
949
  };
909
950
  /** Custom single-select with triangle indicator and accent highlight. */
910
951
  const SinglePickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
911
- const [focused, setFocused] = useState(0);
952
+ const [focused, setFocused] = useState(() => firstEnabled(options));
912
953
  const rows = Math.ceil(options.length / columns);
954
+ useEffect(() => {
955
+ if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
956
+ }, [options, focused]);
913
957
  const bindings = [{
914
958
  match: ["upArrow", "downArrow"],
915
959
  label: "↑↓",
916
960
  action: "navigate",
917
961
  handler: (_input, key) => {
918
- const col = Math.floor(focused / rows);
919
- const row = focused % rows;
920
- if (key.upArrow) if (row > 0) setFocused(col * rows + row - 1);
921
- else setFocused(Math.min(col * rows + rows - 1, options.length - 1));
922
- if (key.downArrow) {
923
- const next = col * rows + row + 1;
924
- if (next < options.length && row + 1 < rows) setFocused(next);
925
- else setFocused(col * rows);
926
- }
962
+ if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
963
+ if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
927
964
  }
928
965
  }, {
929
966
  match: "return",
@@ -931,7 +968,7 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
931
968
  action: "select",
932
969
  handler: () => {
933
970
  const selected = options[focused];
934
- if (selected) onSelect(selected.value);
971
+ if (selected && !selected.disabled) onSelect(selected.value);
935
972
  }
936
973
  }];
937
974
  if (columns > 1) bindings.splice(1, 0, {
@@ -941,14 +978,17 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
941
978
  handler: (_input, key) => {
942
979
  const col = Math.floor(focused / rows);
943
980
  const row = focused % rows;
981
+ let next = focused;
944
982
  if (key.leftArrow) {
945
983
  const prevCol = col > 0 ? col - 1 : columns - 1;
946
- setFocused(Math.min(prevCol * rows + row, options.length - 1));
984
+ next = Math.min(prevCol * rows + row, options.length - 1);
947
985
  }
948
986
  if (key.rightArrow) {
949
987
  const nextCol = col < columns - 1 ? col + 1 : 0;
950
- setFocused(Math.min(nextCol * rows + row, options.length - 1));
988
+ next = Math.min(nextCol * rows + row, options.length - 1);
951
989
  }
990
+ if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
991
+ setFocused(next);
952
992
  }
953
993
  });
954
994
  useKeyBindings("single-picker", bindings);
@@ -969,16 +1009,23 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
969
1009
  return /* @__PURE__ */ jsxs(Box, {
970
1010
  gap: 1,
971
1011
  marginBottom: optionMarginBottom,
972
- children: [/* @__PURE__ */ jsx(Text, {
973
- color: isFocused ? Colors.accent : void 0,
974
- dimColor: !isFocused,
975
- children: isFocused ? Icons.triangleSmallRight : " "
976
- }), /* @__PURE__ */ jsx(Text, {
977
- color: isFocused ? Colors.accent : void 0,
978
- bold: isFocused,
979
- dimColor: !isFocused,
980
- children: label
981
- })]
1012
+ children: [
1013
+ /* @__PURE__ */ jsx(Text, {
1014
+ color: isFocused ? Colors.accent : void 0,
1015
+ dimColor: !isFocused,
1016
+ children: isFocused ? Icons.triangleSmallRight : " "
1017
+ }),
1018
+ opt.icon && /* @__PURE__ */ jsx(Text, {
1019
+ color: opt.icon.color,
1020
+ children: opt.icon.glyph
1021
+ }),
1022
+ /* @__PURE__ */ jsx(Text, {
1023
+ color: opt.disabled ? Colors.muted : isFocused ? Colors.accent : void 0,
1024
+ bold: isFocused && !opt.disabled,
1025
+ dimColor: !isFocused || opt.disabled,
1026
+ children: label
1027
+ })
1028
+ ]
982
1029
  }, flatIdx);
983
1030
  })
984
1031
  }, colIdx))
@@ -987,24 +1034,20 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
987
1034
  };
988
1035
  /** Custom multi-select with checkbox glyphs and accent highlight. */
989
1036
  const MultiPickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
990
- const [focused, setFocused] = useState(0);
1037
+ const [focused, setFocused] = useState(() => firstEnabled(options));
991
1038
  const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
992
1039
  const rows = Math.ceil(options.length / columns);
1040
+ useEffect(() => {
1041
+ if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
1042
+ }, [options, focused]);
993
1043
  const bindings = [
994
1044
  {
995
1045
  match: ["upArrow", "downArrow"],
996
1046
  label: "↑↓",
997
1047
  action: "navigate",
998
1048
  handler: (_input, key) => {
999
- const col = Math.floor(focused / rows);
1000
- const row = focused % rows;
1001
- if (key.upArrow) if (row > 0) setFocused(col * rows + row - 1);
1002
- else setFocused(Math.min(col * rows + rows - 1, options.length - 1));
1003
- if (key.downArrow) {
1004
- const next = col * rows + row + 1;
1005
- if (next < options.length && row + 1 < rows) setFocused(next);
1006
- else setFocused(col * rows);
1007
- }
1049
+ if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
1050
+ if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
1008
1051
  }
1009
1052
  },
1010
1053
  {
@@ -1012,10 +1055,16 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1012
1055
  label: "space",
1013
1056
  action: "toggle",
1014
1057
  handler: () => {
1058
+ if (options[focused]?.disabled) return;
1015
1059
  setSelected((prev) => {
1016
1060
  const next = new Set(prev);
1017
- if (next.has(focused)) next.delete(focused);
1018
- else next.add(focused);
1061
+ if (next.has(focused)) {
1062
+ next.delete(focused);
1063
+ return next;
1064
+ }
1065
+ if (options[focused]?.exclusive) return new Set([focused]);
1066
+ for (const i of next) if (options[i]?.exclusive) next.delete(i);
1067
+ next.add(focused);
1019
1068
  return next;
1020
1069
  });
1021
1070
  }
@@ -1027,7 +1076,7 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1027
1076
  handler: () => {
1028
1077
  if (selected.size === 0) {
1029
1078
  const hovered = options[focused];
1030
- if (hovered) onSelect(hovered.value);
1079
+ if (hovered && !hovered.disabled) onSelect(hovered.value);
1031
1080
  } else onSelect([...selected].sort().map((i) => options[i].value));
1032
1081
  }
1033
1082
  }
@@ -1039,14 +1088,17 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1039
1088
  handler: (_input, key) => {
1040
1089
  const col = Math.floor(focused / rows);
1041
1090
  const row = focused % rows;
1091
+ let next = focused;
1042
1092
  if (key.leftArrow) {
1043
1093
  const prevCol = col > 0 ? col - 1 : columns - 1;
1044
- setFocused(Math.min(prevCol * rows + row, options.length - 1));
1094
+ next = Math.min(prevCol * rows + row, options.length - 1);
1045
1095
  }
1046
1096
  if (key.rightArrow) {
1047
1097
  const nextCol = col < columns - 1 ? col + 1 : 0;
1048
- setFocused(Math.min(nextCol * rows + row, options.length - 1));
1098
+ next = Math.min(nextCol * rows + row, options.length - 1);
1049
1099
  }
1100
+ if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
1101
+ setFocused(next);
1050
1102
  }
1051
1103
  });
1052
1104
  useKeyBindings("multi-picker", bindings);
@@ -1071,16 +1123,23 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1071
1123
  return /* @__PURE__ */ jsxs(Box, {
1072
1124
  gap: 1,
1073
1125
  marginBottom: optionMarginBottom,
1074
- children: [/* @__PURE__ */ jsx(Text, {
1075
- color: isSelected ? "white" : Colors.muted,
1076
- dimColor: !isFocused && !isSelected,
1077
- children: checkbox
1078
- }), /* @__PURE__ */ jsx(Text, {
1079
- color: isFocused ? Colors.accent : void 0,
1080
- bold: isFocused,
1081
- dimColor: !isFocused,
1082
- children: label
1083
- })]
1126
+ children: [
1127
+ /* @__PURE__ */ jsx(Text, {
1128
+ color: isSelected ? "white" : Colors.muted,
1129
+ dimColor: !isFocused && !isSelected,
1130
+ children: checkbox
1131
+ }),
1132
+ opt.icon && /* @__PURE__ */ jsx(Text, {
1133
+ color: opt.icon.color,
1134
+ children: opt.icon.glyph
1135
+ }),
1136
+ /* @__PURE__ */ jsx(Text, {
1137
+ color: opt.disabled ? Colors.muted : isFocused ? Colors.accent : void 0,
1138
+ bold: isFocused && !opt.disabled,
1139
+ dimColor: !isFocused || opt.disabled,
1140
+ children: label
1141
+ })
1142
+ ]
1084
1143
  }, flatIdx);
1085
1144
  })
1086
1145
  }, colIdx))
@@ -1748,6 +1807,7 @@ var ScreenErrorBoundary = class extends Component {
1748
1807
  }
1749
1808
  componentDidCatch(error) {
1750
1809
  const { store } = this.props;
1810
+ logToFile("[screen-error-boundary]", error);
1751
1811
  console.error("[ScreenErrorBoundary]", error.message, error.stack);
1752
1812
  store.setOutroData({
1753
1813
  kind: "error",
@@ -2321,6 +2381,12 @@ const TIPS = [
2321
2381
  title: "Get way more detail using properties",
2322
2382
  description: "Events and person records can have any properties you want. Track things like how they found your website, what subscription tier they choose, and much more."
2323
2383
  },
2384
+ {
2385
+ id: "slack",
2386
+ title: "Use PostHog in Slack",
2387
+ 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"
2389
+ },
2324
2390
  {
2325
2391
  id: "stripe",
2326
2392
  title: "You can track Stripe revenue with PostHog",
@@ -2613,8 +2679,22 @@ const IssueRow = ({ issue, docsWidth }) => {
2613
2679
  *
2614
2680
  * When done, calls store.setMcpComplete(). The router resolves to outro.
2615
2681
  */
2616
- const markDone = (store, outcome, clients = []) => {
2617
- store.setMcpComplete(outcome, clients);
2682
+ const markDone = (store, outcome, clients = [], featuresSelected) => {
2683
+ store.setMcpComplete(outcome, clients, featuresSelected);
2684
+ };
2685
+ const reportFeatures = (features) => isAllFeaturesSelected(features) ? "all" : features;
2686
+ /**
2687
+ * Connector step prompt — Enter continues (opens the connector page). There's
2688
+ * no skip: picking the connector commits to opening it.
2689
+ */
2690
+ const ConnectorContinue = ({ onContinue }) => {
2691
+ useInput((_input, key) => {
2692
+ if (key.return) onContinue();
2693
+ });
2694
+ return /* @__PURE__ */ jsxs(Text, {
2695
+ color: Colors.primary,
2696
+ children: ["Press enter to continue ", Icons.triangleRight]
2697
+ });
2618
2698
  };
2619
2699
  const McpScreen = ({ store, installer, mode = "install" }) => {
2620
2700
  useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
@@ -2625,6 +2705,7 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
2625
2705
  const [selectedClientNames, setSelectedClientNames] = useState([]);
2626
2706
  const [resultClients, setResultClients] = useState([]);
2627
2707
  const [pluginClients, setPluginClients] = useState([]);
2708
+ const [installMode, setInstallMode] = useState("custom");
2628
2709
  useEffect(() => {
2629
2710
  (async () => {
2630
2711
  try {
@@ -2642,23 +2723,34 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
2642
2723
  }
2643
2724
  })();
2644
2725
  }, [installer]);
2645
- const proceedToFeatureSelectOrInstall = (clientNames) => {
2726
+ const proceedAfterClientPick = (clientNames, chosenMode) => {
2646
2727
  setSelectedClientNames(clientNames);
2728
+ if (chosenMode === "all") {
2729
+ doInstall(clientNames, [...ALL_FEATURE_VALUES]);
2730
+ return;
2731
+ }
2647
2732
  if (store.session.mcpFeatures) {
2648
2733
  doInstall(clientNames, store.session.mcpFeatures);
2649
2734
  return;
2650
2735
  }
2651
- if (!clientNames.some((name) => {
2652
- return !clients.find((c) => c.name === name)?.finish;
2653
- })) {
2654
- doInstall(clientNames, []);
2736
+ if (clientNames.some((name) => clients.find((c) => c.name === name)?.finish)) {
2737
+ setPhase("connector");
2655
2738
  return;
2656
2739
  }
2657
2740
  setPhase("feature-select");
2658
2741
  };
2659
2742
  const handleConfirm = () => {
2660
2743
  if (isRemove) doRemove();
2661
- else if (clients.length === 1) proceedToFeatureSelectOrInstall(clients.map((c) => c.name));
2744
+ else if (clients.length === 1) proceedAfterClientPick([clients[0].name], "custom");
2745
+ else setPhase("pick");
2746
+ };
2747
+ const handleTriStateChoice = (choice) => {
2748
+ if (choice === "skip") {
2749
+ handleSkip();
2750
+ return;
2751
+ }
2752
+ setInstallMode(choice);
2753
+ if (clients.length === 1) proceedAfterClientPick([clients[0].name], choice);
2662
2754
  else setPhase("pick");
2663
2755
  };
2664
2756
  const handleSkip = () => {
@@ -2668,17 +2760,25 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
2668
2760
  setPhase("working");
2669
2761
  let mcpResult = [];
2670
2762
  let pluginResult = [];
2671
- try {
2763
+ const pluginCapableSet = new Set(clients.filter((c) => c.supportsPlugin).map((c) => c.name));
2764
+ const pluginCapableNames = names.filter((n) => pluginCapableSet.has(n));
2765
+ const directNames = names.filter((n) => !pluginCapableSet.has(n));
2766
+ if (installMode === "all") {
2767
+ try {
2768
+ mcpResult = await installer.install(directNames, features, store.session.apiKey);
2769
+ } catch {}
2770
+ try {
2771
+ pluginResult = await installer.installPlugins(pluginCapableNames);
2772
+ } catch {}
2773
+ } else try {
2672
2774
  mcpResult = await installer.install(names, features, store.session.apiKey);
2673
2775
  } catch {}
2674
- try {
2675
- pluginResult = await installer.installPlugins(names);
2676
- } catch {}
2677
2776
  setResultClients(mcpResult);
2678
2777
  setPluginClients(pluginResult);
2679
2778
  setPhase("done");
2680
- const outcome = mcpResult.length > 0 ? "installed" : "failed";
2681
- setTimeout(() => markDone(store, outcome, mcpResult), 2e3);
2779
+ const outcome = mcpResult.length + pluginResult.length > 0 ? "installed" : "failed";
2780
+ const featuresReport = reportFeatures(features ?? [...ALL_FEATURE_VALUES]);
2781
+ setTimeout(() => markDone(store, outcome, [...mcpResult, ...pluginResult], featuresReport), 2e3);
2682
2782
  };
2683
2783
  const doRemove = async () => {
2684
2784
  setPhase("working");
@@ -2746,7 +2846,26 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
2746
2846
  }),
2747
2847
  /* @__PURE__ */ jsx(Box, {
2748
2848
  marginTop: 1,
2749
- children: /* @__PURE__ */ jsx(ConfirmationInput, {
2849
+ children: !isRemove && !store.session.mcpFeatures ? /* @__PURE__ */ jsx(PickerMenu, {
2850
+ message: `Install the PostHog MCP server${clients.some((c) => c.supportsPlugin) ? " and plugin" : ""}?`,
2851
+ options: [
2852
+ {
2853
+ label: "Install with all features",
2854
+ value: "all",
2855
+ hint: "recommended"
2856
+ },
2857
+ {
2858
+ label: "Customize features",
2859
+ value: "custom"
2860
+ },
2861
+ {
2862
+ label: "No thanks",
2863
+ value: "skip"
2864
+ }
2865
+ ],
2866
+ mode: "single",
2867
+ onSelect: (choice) => handleTriStateChoice(choice)
2868
+ }) : /* @__PURE__ */ jsx(ConfirmationInput, {
2750
2869
  message: `${isRemove ? "Remove" : "Install"} the PostHog MCP server${clients.some((c) => c.supportsPlugin) ? " and plugin" : ""}?`,
2751
2870
  confirmLabel: isRemove ? "Remove" : "Install",
2752
2871
  cancelLabel: "No thanks",
@@ -2756,76 +2875,107 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
2756
2875
  })
2757
2876
  ] }),
2758
2877
  phase === "pick" && /* @__PURE__ */ jsx(PickerMenu, {
2759
- message: "Select editor to install MCP server",
2878
+ message: installMode === "all" ? "Select editor to install" : "Select editor to install MCP server",
2760
2879
  options: clients.map((c) => ({
2761
2880
  label: c.name,
2762
- value: c.name
2881
+ value: c.name,
2882
+ exclusive: Boolean(c.finish),
2883
+ hint: installMode === "all" ? c.finish ? "connector" : c.supportsPlugin ? "plugin" : "MCP" : void 0
2763
2884
  })),
2764
2885
  mode: "multi",
2765
2886
  onSelect: (selected) => {
2766
- proceedToFeatureSelectOrInstall(Array.isArray(selected) ? selected : [selected]);
2887
+ proceedAfterClientPick(Array.isArray(selected) ? selected : [selected], installMode);
2767
2888
  }
2768
2889
  }),
2769
2890
  phase === "feature-select" && /* @__PURE__ */ jsx(GroupedPickerMenu, {
2770
2891
  message: "Select features to enable",
2771
2892
  groups: AVAILABLE_FEATURES,
2772
- initialSelected: [...ALL_FEATURE_VALUES],
2893
+ initialSelected: [],
2773
2894
  onSelect: (features) => {
2774
2895
  doInstall(selectedClientNames, features);
2775
2896
  }
2776
2897
  }),
2898
+ phase === "connector" && /* @__PURE__ */ jsxs(Box, {
2899
+ flexDirection: "column",
2900
+ children: [/* @__PURE__ */ jsx(Box, {
2901
+ marginBottom: 1,
2902
+ children: /* @__PURE__ */ jsx(Text, {
2903
+ dimColor: true,
2904
+ children: "You'll choose which features and tools to enable in Claude's UI after connecting."
2905
+ })
2906
+ }), /* @__PURE__ */ jsx(ConnectorContinue, { onContinue: () => void doInstall(selectedClientNames, []) })]
2907
+ }),
2777
2908
  phase === "working" && /* @__PURE__ */ jsxs(Text, {
2778
2909
  dimColor: true,
2779
2910
  children: [isRemove ? "Removing" : "Installing", " MCP server..."]
2780
2911
  }),
2781
2912
  phase === "done" && /* @__PURE__ */ jsx(Box, {
2782
2913
  flexDirection: "column",
2783
- children: installedNow.length === 0 && finishNotes.length === 0 ? /* @__PURE__ */ jsxs(Text, {
2914
+ children: installedNow.length + pluginClients.length + finishNotes.length === 0 ? /* @__PURE__ */ jsxs(Text, {
2784
2915
  dimColor: true,
2785
2916
  children: [isRemove ? "Removal" : "Installation", " skipped."]
2786
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [installedNow.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
2787
- color: "green",
2788
- bold: true,
2789
- children: [
2790
- "✔",
2791
- " MCP server",
2792
- !isRemove && pluginClients.length > 0 ? " and plugin" : "",
2917
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
2918
+ pluginClients.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
2919
+ color: "green",
2920
+ bold: true,
2921
+ children: ["✔", " Plugin installed for:"]
2922
+ }), pluginClients.map((name, i) => /* @__PURE__ */ jsxs(Text, { children: [
2793
2923
  " ",
2794
- isRemove ? "removed from" : "installed for",
2795
- ":"
2796
- ]
2797
- }), installedNow.map((name, i) => /* @__PURE__ */ jsxs(Text, { children: [
2798
- " ",
2799
- "",
2800
- " ",
2801
- name
2802
- ] }, i))] }), finishNotes.map((note) => /* @__PURE__ */ jsxs(Box, {
2803
- flexDirection: "column",
2804
- marginTop: 1,
2805
- children: [
2806
- /* @__PURE__ */ jsxs(Text, {
2807
- color: "green",
2808
- bold: true,
2809
- children: [note.name, " \\u2014 finish in your browser:"]
2810
- }),
2811
- /* @__PURE__ */ jsxs(Text, { children: [
2812
- " ",
2813
- "Opened ",
2814
- /* @__PURE__ */ jsx(Text, {
2815
- color: "cyan",
2816
- children: note.url
2924
+ "",
2925
+ " ",
2926
+ name
2927
+ ] }, `p-${i}`))] }),
2928
+ installedNow.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
2929
+ color: "green",
2930
+ bold: true,
2931
+ children: [
2932
+ "✔",
2933
+ " MCP server",
2934
+ " ",
2935
+ isRemove ? "removed from" : "installed for",
2936
+ ":"
2937
+ ]
2938
+ }), installedNow.map((name, i) => /* @__PURE__ */ jsxs(Text, { children: [
2939
+ " ",
2940
+ "•",
2941
+ " ",
2942
+ name
2943
+ ] }, `m-${i}`))] }),
2944
+ finishNotes.map((note) => /* @__PURE__ */ jsxs(Box, {
2945
+ flexDirection: "column",
2946
+ marginTop: 1,
2947
+ children: [
2948
+ /* @__PURE__ */ jsxs(Text, {
2949
+ color: "green",
2950
+ bold: true,
2951
+ children: [
2952
+ "✔",
2953
+ " ",
2954
+ note.name,
2955
+ " ",
2956
+ "—",
2957
+ " installs a PostHog connector:"
2958
+ ]
2959
+ }),
2960
+ /* @__PURE__ */ jsxs(Text, { children: [
2961
+ " ",
2962
+ "Opened ",
2963
+ /* @__PURE__ */ jsx(Text, {
2964
+ color: "cyan",
2965
+ children: note.url
2966
+ })
2967
+ ] }),
2968
+ /* @__PURE__ */ jsxs(Text, {
2969
+ dimColor: true,
2970
+ children: [" ", note.instruction]
2971
+ }),
2972
+ /* @__PURE__ */ jsxs(Text, {
2973
+ dimColor: true,
2974
+ children: [" ", "(If it didn't open, paste the URL above.)"]
2817
2975
  })
2818
- ] }),
2819
- /* @__PURE__ */ jsxs(Text, {
2820
- dimColor: true,
2821
- children: [" ", note.instruction]
2822
- }),
2823
- /* @__PURE__ */ jsxs(Text, {
2824
- dimColor: true,
2825
- children: [" ", "(If it didn't open, paste the URL above.)"]
2826
- })
2827
- ]
2828
- }, note.name))] })
2976
+ ]
2977
+ }, note.name))
2978
+ ] })
2829
2979
  })
2830
2980
  ]
2831
2981
  })]
@@ -3656,6 +3806,13 @@ var neutralCrossSell = [{
3656
3806
  "prompt": "List the top errors my users hit this week.",
3657
3807
  "description": "Built-in error tracking — no separate tool."
3658
3808
  }];
3809
+ var slackApp = {
3810
+ "learnMoreUrl": "https://posthog.com/slack-app",
3811
+ "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.",
3814
+ "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
+ };
3659
3816
  //#endregion
3660
3817
  //#region src/lib/mcp-role-prompts.ts
3661
3818
  /**
@@ -3690,6 +3847,7 @@ const GENERIC_FOLLOW_UPS = genericFollowUps;
3690
3847
  const DEEP_DIVE_FOLLOW_UPS = deepDiveFollowUps;
3691
3848
  const CROSS_SELL_BY_ROLE = crossSellByRole;
3692
3849
  const NEUTRAL_CROSS_SELL = neutralCrossSell;
3850
+ const SLACK_APP = slackApp;
3693
3851
  const INTEGRATION_FAMILY = {
3694
3852
  nextjs: "fullstack",
3695
3853
  nuxt: "fullstack",
@@ -3803,6 +3961,20 @@ function getCrossSellPrompts(role) {
3803
3961
  if (!isTailoredRole(role)) return NEUTRAL_CROSS_SELL;
3804
3962
  return CROSS_SELL_BY_ROLE[role];
3805
3963
  }
3964
+ /**
3965
+ * Resolve the "Take PostHog to Slack" card. Role-independent — the Slack
3966
+ * agent's two capabilities (code/PR + data) describe the product itself,
3967
+ * not role-specific examples.
3968
+ */
3969
+ function getSlackAppCard() {
3970
+ return {
3971
+ headline: SLACK_APP.headline,
3972
+ pitch: SLACK_APP.pitch,
3973
+ learnMoreUrl: SLACK_APP.learnMoreUrl,
3974
+ setupUrl: SLACK_APP.setupUrl,
3975
+ capabilities: SLACK_APP.capabilities
3976
+ };
3977
+ }
3806
3978
  //#endregion
3807
3979
  //#region src/ui/tui/screens/McpSuggestedPromptsScreen.tsx
3808
3980
  /**
@@ -3843,6 +4015,25 @@ function getCrossSellPrompts(role) {
3843
4015
  * forces a successful login first). A defensive throw protects the
3844
4016
  * Running useEffect against a state-machine bug.
3845
4017
  */
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 || {});
3846
4037
  const MAX_PROMPT_RUNS = 5;
3847
4038
  const FOLLOW_UP_DELAY_MS = 3e3;
3848
4039
  const McpSuggestedPromptsScreen = ({ store, services }) => {
@@ -3851,8 +4042,9 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3851
4042
  const kit = getRolePrompts(session.roleAtOrganization, session.integration);
3852
4043
  const crossSell = useMemo(() => getCrossSellPrompts(session.roleAtOrganization), [session.roleAtOrganization]);
3853
4044
  const greeting = useMemo(() => getRoleGreeting(session.roleAtOrganization), [session.roleAtOrganization]);
3854
- const [phase, setPhase] = useState("choose");
4045
+ const [phase, setPhase] = useState(() => store.session.credentials ? "choose" : "authenticating");
3855
4046
  const [loginError, setLoginError] = useState(null);
4047
+ const startedTutorialRef = useRef(false);
3856
4048
  const [runningPrompt, setRunningPrompt] = useState(null);
3857
4049
  const [runChunks, setRunChunks] = useState([]);
3858
4050
  const [runStartedAt, setRunStartedAt] = useState(null);
@@ -3874,7 +4066,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3874
4066
  store.setRoleAtOrganization(roleAtOrganization);
3875
4067
  store.setApiUser(user);
3876
4068
  store.setLoginUrl(null);
3877
- setPhase("greeting");
4069
+ setPhase(startedTutorialRef.current ? "greeting" : "choose");
3878
4070
  } catch (err) {
3879
4071
  if (cancelled) return;
3880
4072
  const message = err instanceof Error ? err.message : String(err);
@@ -3892,6 +4084,28 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3892
4084
  services,
3893
4085
  store
3894
4086
  ]);
4087
+ const credentials = session.credentials;
4088
+ const slackConnected = session.slackConnected;
4089
+ useEffect(() => {
4090
+ if (!credentials || slackConnected !== null) return;
4091
+ let cancelled = false;
4092
+ const controller = new AbortController();
4093
+ services.checkSlackConnected(credentials, controller.signal).then((connected) => {
4094
+ if (!cancelled) store.setSlackConnected(connected);
4095
+ }).catch((err) => {
4096
+ if (cancelled) return;
4097
+ analytics.captureException(err instanceof Error ? err : new Error(String(err)), { step: "slack_connected_check" });
4098
+ });
4099
+ return () => {
4100
+ cancelled = true;
4101
+ controller.abort();
4102
+ };
4103
+ }, [
4104
+ credentials,
4105
+ slackConnected,
4106
+ services,
4107
+ store
4108
+ ]);
3895
4109
  useEffect(() => {
3896
4110
  if (phase !== "running") return;
3897
4111
  if (!runningPrompt) return;
@@ -3977,7 +4191,11 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3977
4191
  setLoginError(null);
3978
4192
  if (choice === "login") {
3979
4193
  analytics.wizardCapture("mcp suggested prompts choose", { choice: "login" });
3980
- setPhase("authenticating");
4194
+ startedTutorialRef.current = true;
4195
+ setPhase(session.credentials ? "greeting" : "authenticating");
4196
+ } else if (choice === "connect-slack") {
4197
+ analytics.wizardCapture("mcp suggested prompts choose", { choice: "connect-slack" });
4198
+ opn(getSlackAppCard().setupUrl, { wait: false }).catch(() => {});
3981
4199
  } else {
3982
4200
  analytics.wizardCapture("mcp suggested prompts choose", { choice: "exit" });
3983
4201
  enterGoodbye();
@@ -4013,9 +4231,10 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4013
4231
  {
4014
4232
  match: "escape",
4015
4233
  label: "esc",
4016
- action: phase === "goodbye" ? "close" : "exit",
4234
+ action: phase === "goodbye" ? "close" : phase === "authenticating" ? "cancel" : "exit",
4017
4235
  handler: () => {
4018
4236
  if (phase === "goodbye") closeWizard();
4237
+ else if (phase === "authenticating") setPhase("choose");
4019
4238
  else if (phase === "running" || phase === "prompt-picker" || phase === "follow-up" || phase === "greeting") enterGoodbye();
4020
4239
  }
4021
4240
  },
@@ -4049,6 +4268,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4049
4268
  children: [
4050
4269
  phase === "choose" && /* @__PURE__ */ jsx(ChoosePhase, {
4051
4270
  error: loginError,
4271
+ slackConnected,
4052
4272
  onSelect: handleChoice
4053
4273
  }),
4054
4274
  phase === "authenticating" && /* @__PURE__ */ jsx(AuthenticatingPhase, { loginUrl: session.loginUrl }),
@@ -4111,71 +4331,112 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4111
4331
  })
4112
4332
  });
4113
4333
  };
4114
- const ChoosePhase = ({ error, onSelect }) => /* @__PURE__ */ jsxs(Box, {
4115
- flexDirection: "column",
4116
- children: [
4117
- /* @__PURE__ */ jsx(Text, {
4118
- bold: true,
4119
- color: Colors.accent,
4120
- children: "PostHog MCP"
4121
- }),
4122
- /* @__PURE__ */ jsx(Box, {
4123
- marginTop: 1,
4124
- children: /* @__PURE__ */ jsx(Text, { children: "With MCP your agent works directly with the PostHog platform. You can prompt it to:" })
4125
- }),
4126
- /* @__PURE__ */ jsxs(Box, {
4127
- marginTop: 1,
4128
- flexDirection: "column",
4129
- children: [
4130
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4131
- color: "cyan",
4132
- children: Icons.diamond
4133
- }), " Build dashboards"] }),
4134
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4135
- color: "cyan",
4136
- children: Icons.diamond
4137
- }), " Run SQL queries"] }),
4138
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4139
- color: "cyan",
4140
- children: Icons.diamond
4141
- }), " Deploy feature flags"] }),
4142
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4143
- color: "cyan",
4144
- children: Icons.diamond
4145
- }), " Debug exceptions and errors"] }),
4146
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4147
- color: "cyan",
4148
- children: Icons.diamond
4149
- }), " And lots more..."] })
4150
- ]
4151
- }),
4152
- /* @__PURE__ */ jsx(Box, {
4153
- marginTop: 1,
4154
- children: /* @__PURE__ */ jsx(Text, { children: "Want a live demo using real data from your project?" })
4155
- }),
4156
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(PickerMenu, {
4157
- options: [{
4158
- label: "Start MCP tutorial",
4159
- value: "login"
4160
- }, {
4161
- label: "Exit",
4162
- value: "exit"
4163
- }],
4164
- onSelect
4165
- }) }),
4166
- error && /* @__PURE__ */ jsx(Box, {
4167
- marginTop: 1,
4168
- children: /* @__PURE__ */ jsxs(Text, {
4169
- color: "red",
4334
+ const ChoosePhase = ({ error, slackConnected, onSelect }) => {
4335
+ return /* @__PURE__ */ jsxs(Box, {
4336
+ flexDirection: "column",
4337
+ children: [
4338
+ /* @__PURE__ */ jsx(Text, {
4339
+ bold: true,
4340
+ color: Colors.accent,
4341
+ children: "PostHog MCP"
4342
+ }),
4343
+ /* @__PURE__ */ jsx(Box, {
4344
+ marginTop: 1,
4345
+ children: /* @__PURE__ */ jsx(Text, { children: "With MCP your agent works directly with the PostHog platform. You can prompt it to:" })
4346
+ }),
4347
+ /* @__PURE__ */ jsxs(Box, {
4348
+ marginTop: 1,
4349
+ flexDirection: "column",
4170
4350
  children: [
4171
- "Login failed: ",
4172
- error,
4173
- ". Try again or exit."
4351
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4352
+ color: "cyan",
4353
+ children: Icons.diamond
4354
+ }), " Build dashboards"] }),
4355
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4356
+ color: "cyan",
4357
+ children: Icons.diamond
4358
+ }), " Run SQL queries"] }),
4359
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4360
+ color: "cyan",
4361
+ children: Icons.diamond
4362
+ }), " Deploy feature flags"] }),
4363
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4364
+ color: "cyan",
4365
+ children: Icons.diamond
4366
+ }), " Debug exceptions and errors"] }),
4367
+ /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4368
+ color: "cyan",
4369
+ children: Icons.diamond
4370
+ }), " And lots more..."] })
4174
4371
  ]
4372
+ }),
4373
+ /* @__PURE__ */ jsx(Box, {
4374
+ marginTop: 1,
4375
+ flexDirection: "column",
4376
+ children: slackConnected ? /* @__PURE__ */ jsxs(Text, { children: [
4377
+ /* @__PURE__ */ jsx(Text, {
4378
+ color: Colors.success,
4379
+ children: Icons.check
4380
+ }),
4381
+ " Slack is connected — analyze data and ship product changes there by tagging",
4382
+ " ",
4383
+ /* @__PURE__ */ jsx(Text, {
4384
+ bold: true,
4385
+ children: "@PostHog"
4386
+ }),
4387
+ "."
4388
+ ] }) : /* @__PURE__ */ jsxs(Text, { children: [
4389
+ "You can also connect PostHog to Slack, so you can analyze data and ship product changes there by tagging ",
4390
+ /* @__PURE__ */ jsx(Text, {
4391
+ bold: true,
4392
+ children: "@PostHog"
4393
+ }),
4394
+ "."
4395
+ ] })
4396
+ }),
4397
+ /* @__PURE__ */ jsx(Box, {
4398
+ marginTop: 1,
4399
+ children: /* @__PURE__ */ jsx(Text, { children: "Want a live demo using real data from your project?" })
4400
+ }),
4401
+ /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(PickerMenu, {
4402
+ options: [
4403
+ {
4404
+ label: "Start MCP tutorial",
4405
+ value: "login"
4406
+ },
4407
+ slackConnected ? {
4408
+ label: "Already connected to Slack",
4409
+ value: "connect-slack",
4410
+ icon: {
4411
+ glyph: Icons.check,
4412
+ color: Colors.success
4413
+ },
4414
+ disabled: true
4415
+ } : {
4416
+ label: "Connect Slack now",
4417
+ value: "connect-slack"
4418
+ },
4419
+ {
4420
+ label: "Exit",
4421
+ value: "exit"
4422
+ }
4423
+ ],
4424
+ onSelect
4425
+ }) }),
4426
+ error && /* @__PURE__ */ jsx(Box, {
4427
+ marginTop: 1,
4428
+ children: /* @__PURE__ */ jsxs(Text, {
4429
+ color: "red",
4430
+ children: [
4431
+ "Login failed: ",
4432
+ error,
4433
+ ". Try again or exit."
4434
+ ]
4435
+ })
4175
4436
  })
4176
- })
4177
- ]
4178
- });
4437
+ ]
4438
+ });
4439
+ };
4179
4440
  const AuthenticatingPhase = ({ loginUrl }) => /* @__PURE__ */ jsxs(Box, {
4180
4441
  flexDirection: "column",
4181
4442
  children: [/* @__PURE__ */ jsx(LoadingBox, { message: "Waiting for authentication..." }), loginUrl && /* @__PURE__ */ jsx(Box, {
@@ -4513,7 +4774,7 @@ const GoodbyePhase = ({ installedClients, role, integration, engaged, onClose })
4513
4774
  label: "Close",
4514
4775
  value: "close"
4515
4776
  }],
4516
- onSelect: onClose
4777
+ onSelect: () => onClose()
4517
4778
  })
4518
4779
  ]
4519
4780
  });
@@ -5379,6 +5640,6 @@ const AUDIT_3000_AREA_SLIDES = [
5379
5640
  }
5380
5641
  ];
5381
5642
  //#endregion
5382
- export { WizardStore as A, useStdoutDimensions as C, LoadingBox as D, ProgressList as E, SplitView as O, GroupedPickerMenu as S, useKeyBindings as T, ScreenContainer as _, McpSuggestedPromptsScreen as a, ModalOverlay as b, IssueTable as c, ServiceHealthList as d, TipsCard as f, TabContainer as g, HNViewer as h, AuditChecksViewer as i, CardLayout as k, SEVERITY_LABEL as l, ContentSequencer as m, AUDIT_AREA_SLIDES as n, TAILORED_ROLES as o, LearnCard as p, VisualBox as r, McpScreen as s, AUDIT_3000_AREA_SLIDES as t, SEVERITY_ORDER as u, EventPlanViewer as v, PickerMenu as w, ConfirmationInput as x, LogViewer as y };
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 };
5383
5644
 
5384
- //# sourceMappingURL=slides-DwvXZ8iS.js.map
5645
+ //# sourceMappingURL=slides-BEshbXqG.js.map