@posthog/wizard 2.19.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 (67) hide show
  1. package/README.md +11 -0
  2. package/dist/{add-mcp-server-to-clients-CjnvTVj0.js → add-mcp-server-to-clients-iV7BuQpD.js} +4 -4
  3. package/dist/{add-mcp-server-to-clients-CjnvTVj0.js.map → add-mcp-server-to-clients-iV7BuQpD.js.map} +1 -1
  4. package/dist/{agent-interface-CQU6x4Hj.js → agent-interface-B-LAvrNL.js} +163 -52
  5. package/dist/agent-interface-B-LAvrNL.js.map +1 -0
  6. package/dist/{agent-runner-Cj7saDkL.js → agent-runner-w2Qu9M13.js} +10 -9
  7. package/dist/{agent-runner-Cj7saDkL.js.map → agent-runner-w2Qu9M13.js.map} +1 -1
  8. package/dist/{analytics-Df-Xb81i.js → analytics-C8lJzXjY.js} +2 -2
  9. package/dist/{analytics-Df-Xb81i.js.map → analytics-C8lJzXjY.js.map} +1 -1
  10. package/dist/{api-Dw6_orDE.js → api-eUlUinVy.js} +25 -4
  11. package/dist/{api-Dw6_orDE.js.map → api-eUlUinVy.js.map} +1 -1
  12. package/dist/bin.js +74 -47
  13. package/dist/bin.js.map +1 -1
  14. package/dist/check-screens.tsx +124 -0
  15. package/dist/{ci-install-BKAvFfK6.js → ci-install-CSo7Q1pK.js} +4 -4
  16. package/dist/{ci-install-BKAvFfK6.js.map → ci-install-CSo7Q1pK.js.map} +1 -1
  17. package/dist/{debug-DnMO6O8O.js → debug-BJu_sS4l.js} +2 -2
  18. package/dist/{debug-DnMO6O8O.js.map → debug-BJu_sS4l.js.map} +1 -1
  19. package/dist/{debug-Cp_wNn8i.js → debug-CTViFiF-.js} +1 -1
  20. package/dist/{environment-Ls0H9ljT.js → environment-Dk_dWk3t.js} +3 -3
  21. package/dist/{environment-Ls0H9ljT.js.map → environment-Dk_dWk3t.js.map} +1 -1
  22. package/dist/{interactive-D15byhpc.js → interactive-BS2rIf1v.js} +2 -2
  23. package/dist/{interactive-D15byhpc.js.map → interactive-BS2rIf1v.js.map} +1 -1
  24. package/dist/{mcp-prompt-streaming-DQOTQfW1.js → mcp-prompt-streaming-BiMrlLl0.js} +4 -4
  25. package/dist/{mcp-prompt-streaming-DQOTQfW1.js.map → mcp-prompt-streaming-BiMrlLl0.js.map} +1 -1
  26. package/dist/{non-interactive-DcFLJtl_.js → non-interactive-C39d_KIp.js} +2 -2
  27. package/dist/{non-interactive-DcFLJtl_.js.map → non-interactive-C39d_KIp.js.map} +1 -1
  28. package/dist/{package-manager-DUPgLGpQ.js → package-manager-BfOTvFt-.js} +2 -2
  29. package/dist/{package-manager-DUPgLGpQ.js.map → package-manager-BfOTvFt-.js.map} +1 -1
  30. package/dist/{playground-BZ0hGjbL.js → playground-3OeRB7JU.js} +15 -9
  31. package/dist/playground-3OeRB7JU.js.map +1 -0
  32. package/dist/{posthog-integration-C8qhJnI3.js → posthog-integration-8iTgqy2J.js} +17 -11
  33. package/dist/posthog-integration-8iTgqy2J.js.map +1 -0
  34. package/dist/{provisioning-C-2ExcqY.js → provisioning-DxaT7bWw.js} +3 -3
  35. package/dist/{provisioning-C-2ExcqY.js.map → provisioning-DxaT7bWw.js.map} +1 -1
  36. package/dist/{registry-hBUgaWFx.js → registry-apQfB3rf.js} +4 -4
  37. package/dist/{registry-hBUgaWFx.js.map → registry-apQfB3rf.js.map} +1 -1
  38. package/dist/{setup-utils-DetnhXo0.js → setup-utils-B9xqAXXl.js} +10 -9
  39. package/dist/setup-utils-B9xqAXXl.js.map +1 -0
  40. package/dist/{slides-mT2s9wM_.js → slides-BEshbXqG.js} +290 -122
  41. package/dist/slides-BEshbXqG.js.map +1 -0
  42. package/dist/{start-tui-BfXoErKg.js → start-tui-CCpKnZOY.js} +243 -56
  43. package/dist/start-tui-CCpKnZOY.js.map +1 -0
  44. package/dist/{steps-SoDXSUxe.js → steps-DKbDDnVH.js} +6 -6
  45. package/dist/{steps-SoDXSUxe.js.map → steps-DKbDDnVH.js.map} +1 -1
  46. package/dist/{task-stream-CZRj6auI.js → task-stream-CZawuzlz.js} +2 -2
  47. package/dist/{task-stream-CZRj6auI.js.map → task-stream-CZawuzlz.js.map} +1 -1
  48. package/dist/{telemetry-CPcMFxcO.js → telemetry-DUeOcmpo.js} +2 -2
  49. package/dist/{telemetry-CPcMFxcO.js.map → telemetry-DUeOcmpo.js.map} +1 -1
  50. package/dist/{urls-BO7doNJG.js → urls-B6wBIwr1.js} +2 -2
  51. package/dist/{urls-BO7doNJG.js.map → urls-B6wBIwr1.js.map} +1 -1
  52. package/dist/wizard-abort-D8XZdVAR.js +2 -0
  53. package/dist/{wizard-abort-CDXufkqJ.js → wizard-abort-DhGgTlUA.js} +12 -7
  54. package/dist/wizard-abort-DhGgTlUA.js.map +1 -0
  55. package/dist/{wizard-session-d27JGRGi.js → wizard-session-G3VWD6hv.js} +3 -1
  56. package/dist/{wizard-session-d27JGRGi.js.map → wizard-session-G3VWD6hv.js.map} +1 -1
  57. package/dist/{wizard-session-y304gEEI.js → wizard-session-wPJtNl4c.js} +1 -1
  58. package/dist/wizard-ui-YdGFRyu_.js.map +1 -1
  59. package/package.json +4 -2
  60. package/dist/agent-interface-CQU6x4Hj.js.map +0 -1
  61. package/dist/playground-BZ0hGjbL.js.map +0 -1
  62. package/dist/posthog-integration-C8qhJnI3.js.map +0 -1
  63. package/dist/setup-utils-DetnhXo0.js.map +0 -1
  64. package/dist/slides-mT2s9wM_.js.map +0 -1
  65. package/dist/start-tui-BfXoErKg.js.map +0 -1
  66. package/dist/wizard-abort-CDXufkqJ.js.map +0 -1
  67. package/dist/wizard-abort-CtMY57ZE.js +0 -2
@@ -1,12 +1,13 @@
1
- import { g as SERVICE_LABELS, s as logToFile } from "./debug-DnMO6O8O.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-Df-Xb81i.js";
4
- import { i as buildSession } from "./wizard-session-d27JGRGi.js";
5
- import { v as AUDIT_SEVERITY_STYLE } from "./agent-interface-CQU6x4Hj.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-C8qhJnI3.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
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() {
@@ -487,6 +496,14 @@ var WizardStore = class {
487
496
  this.$session.setKey("mcpSuggestedPromptsDismissed", true);
488
497
  this.emitChange();
489
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
+ }
490
507
  setOutroDismissed() {
491
508
  this.$session.setKey("outroDismissed", true);
492
509
  this.emitChange();
@@ -891,6 +908,27 @@ function useKeyBindings(id, bindings) {
891
908
  * Key bindings are declared via useKeyBindings, which auto-registers
892
909
  * hints in the KeyboardHintsBar.
893
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
+ }
894
932
  const PickerMenu = ({ message, options, mode = "single", centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
895
933
  if (mode === "multi") return /* @__PURE__ */ jsx(MultiPickerMenu, {
896
934
  message,
@@ -911,22 +949,18 @@ const PickerMenu = ({ message, options, mode = "single", centered = false, colum
911
949
  };
912
950
  /** Custom single-select with triangle indicator and accent highlight. */
913
951
  const SinglePickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
914
- const [focused, setFocused] = useState(0);
952
+ const [focused, setFocused] = useState(() => firstEnabled(options));
915
953
  const rows = Math.ceil(options.length / columns);
954
+ useEffect(() => {
955
+ if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
956
+ }, [options, focused]);
916
957
  const bindings = [{
917
958
  match: ["upArrow", "downArrow"],
918
959
  label: "↑↓",
919
960
  action: "navigate",
920
961
  handler: (_input, key) => {
921
- const col = Math.floor(focused / rows);
922
- const row = focused % rows;
923
- if (key.upArrow) if (row > 0) setFocused(col * rows + row - 1);
924
- else setFocused(Math.min(col * rows + rows - 1, options.length - 1));
925
- if (key.downArrow) {
926
- const next = col * rows + row + 1;
927
- if (next < options.length && row + 1 < rows) setFocused(next);
928
- else setFocused(col * rows);
929
- }
962
+ if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
963
+ if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
930
964
  }
931
965
  }, {
932
966
  match: "return",
@@ -934,7 +968,7 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
934
968
  action: "select",
935
969
  handler: () => {
936
970
  const selected = options[focused];
937
- if (selected) onSelect(selected.value);
971
+ if (selected && !selected.disabled) onSelect(selected.value);
938
972
  }
939
973
  }];
940
974
  if (columns > 1) bindings.splice(1, 0, {
@@ -944,14 +978,17 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
944
978
  handler: (_input, key) => {
945
979
  const col = Math.floor(focused / rows);
946
980
  const row = focused % rows;
981
+ let next = focused;
947
982
  if (key.leftArrow) {
948
983
  const prevCol = col > 0 ? col - 1 : columns - 1;
949
- setFocused(Math.min(prevCol * rows + row, options.length - 1));
984
+ next = Math.min(prevCol * rows + row, options.length - 1);
950
985
  }
951
986
  if (key.rightArrow) {
952
987
  const nextCol = col < columns - 1 ? col + 1 : 0;
953
- setFocused(Math.min(nextCol * rows + row, options.length - 1));
988
+ next = Math.min(nextCol * rows + row, options.length - 1);
954
989
  }
990
+ if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
991
+ setFocused(next);
955
992
  }
956
993
  });
957
994
  useKeyBindings("single-picker", bindings);
@@ -972,16 +1009,23 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
972
1009
  return /* @__PURE__ */ jsxs(Box, {
973
1010
  gap: 1,
974
1011
  marginBottom: optionMarginBottom,
975
- children: [/* @__PURE__ */ jsx(Text, {
976
- color: isFocused ? Colors.accent : void 0,
977
- dimColor: !isFocused,
978
- children: isFocused ? Icons.triangleSmallRight : " "
979
- }), /* @__PURE__ */ jsx(Text, {
980
- color: isFocused ? Colors.accent : void 0,
981
- bold: isFocused,
982
- dimColor: !isFocused,
983
- children: label
984
- })]
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
+ ]
985
1029
  }, flatIdx);
986
1030
  })
987
1031
  }, colIdx))
@@ -990,24 +1034,20 @@ const SinglePickerMenu = ({ message, options, centered = false, columns = 1, opt
990
1034
  };
991
1035
  /** Custom multi-select with checkbox glyphs and accent highlight. */
992
1036
  const MultiPickerMenu = ({ message, options, centered = false, columns = 1, optionMarginBottom = 0, onSelect }) => {
993
- const [focused, setFocused] = useState(0);
1037
+ const [focused, setFocused] = useState(() => firstEnabled(options));
994
1038
  const [selected, setSelected] = useState(/* @__PURE__ */ new Set());
995
1039
  const rows = Math.ceil(options.length / columns);
1040
+ useEffect(() => {
1041
+ if (focused >= options.length || options[focused]?.disabled) setFocused(firstEnabled(options));
1042
+ }, [options, focused]);
996
1043
  const bindings = [
997
1044
  {
998
1045
  match: ["upArrow", "downArrow"],
999
1046
  label: "↑↓",
1000
1047
  action: "navigate",
1001
1048
  handler: (_input, key) => {
1002
- const col = Math.floor(focused / rows);
1003
- const row = focused % rows;
1004
- if (key.upArrow) if (row > 0) setFocused(col * rows + row - 1);
1005
- else setFocused(Math.min(col * rows + rows - 1, options.length - 1));
1006
- if (key.downArrow) {
1007
- const next = col * rows + row + 1;
1008
- if (next < options.length && row + 1 < rows) setFocused(next);
1009
- else setFocused(col * rows);
1010
- }
1049
+ if (key.upArrow) setFocused(stepEnabled(options, rows, focused, -1));
1050
+ if (key.downArrow) setFocused(stepEnabled(options, rows, focused, 1));
1011
1051
  }
1012
1052
  },
1013
1053
  {
@@ -1015,6 +1055,7 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1015
1055
  label: "space",
1016
1056
  action: "toggle",
1017
1057
  handler: () => {
1058
+ if (options[focused]?.disabled) return;
1018
1059
  setSelected((prev) => {
1019
1060
  const next = new Set(prev);
1020
1061
  if (next.has(focused)) {
@@ -1035,7 +1076,7 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1035
1076
  handler: () => {
1036
1077
  if (selected.size === 0) {
1037
1078
  const hovered = options[focused];
1038
- if (hovered) onSelect(hovered.value);
1079
+ if (hovered && !hovered.disabled) onSelect(hovered.value);
1039
1080
  } else onSelect([...selected].sort().map((i) => options[i].value));
1040
1081
  }
1041
1082
  }
@@ -1047,14 +1088,17 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1047
1088
  handler: (_input, key) => {
1048
1089
  const col = Math.floor(focused / rows);
1049
1090
  const row = focused % rows;
1091
+ let next = focused;
1050
1092
  if (key.leftArrow) {
1051
1093
  const prevCol = col > 0 ? col - 1 : columns - 1;
1052
- setFocused(Math.min(prevCol * rows + row, options.length - 1));
1094
+ next = Math.min(prevCol * rows + row, options.length - 1);
1053
1095
  }
1054
1096
  if (key.rightArrow) {
1055
1097
  const nextCol = col < columns - 1 ? col + 1 : 0;
1056
- setFocused(Math.min(nextCol * rows + row, options.length - 1));
1098
+ next = Math.min(nextCol * rows + row, options.length - 1);
1057
1099
  }
1100
+ if (options[next]?.disabled) next = stepEnabled(options, rows, next, 1);
1101
+ setFocused(next);
1058
1102
  }
1059
1103
  });
1060
1104
  useKeyBindings("multi-picker", bindings);
@@ -1079,16 +1123,23 @@ const MultiPickerMenu = ({ message, options, centered = false, columns = 1, opti
1079
1123
  return /* @__PURE__ */ jsxs(Box, {
1080
1124
  gap: 1,
1081
1125
  marginBottom: optionMarginBottom,
1082
- children: [/* @__PURE__ */ jsx(Text, {
1083
- color: isSelected ? "white" : Colors.muted,
1084
- dimColor: !isFocused && !isSelected,
1085
- children: checkbox
1086
- }), /* @__PURE__ */ jsx(Text, {
1087
- color: isFocused ? Colors.accent : void 0,
1088
- bold: isFocused,
1089
- dimColor: !isFocused,
1090
- children: label
1091
- })]
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
+ ]
1092
1143
  }, flatIdx);
1093
1144
  })
1094
1145
  }, colIdx))
@@ -2330,6 +2381,12 @@ const TIPS = [
2330
2381
  title: "Get way more detail using properties",
2331
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."
2332
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
+ },
2333
2390
  {
2334
2391
  id: "stripe",
2335
2392
  title: "You can track Stripe revenue with PostHog",
@@ -3749,6 +3806,13 @@ var neutralCrossSell = [{
3749
3806
  "prompt": "List the top errors my users hit this week.",
3750
3807
  "description": "Built-in error tracking — no separate tool."
3751
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
+ };
3752
3816
  //#endregion
3753
3817
  //#region src/lib/mcp-role-prompts.ts
3754
3818
  /**
@@ -3783,6 +3847,7 @@ const GENERIC_FOLLOW_UPS = genericFollowUps;
3783
3847
  const DEEP_DIVE_FOLLOW_UPS = deepDiveFollowUps;
3784
3848
  const CROSS_SELL_BY_ROLE = crossSellByRole;
3785
3849
  const NEUTRAL_CROSS_SELL = neutralCrossSell;
3850
+ const SLACK_APP = slackApp;
3786
3851
  const INTEGRATION_FAMILY = {
3787
3852
  nextjs: "fullstack",
3788
3853
  nuxt: "fullstack",
@@ -3896,6 +3961,20 @@ function getCrossSellPrompts(role) {
3896
3961
  if (!isTailoredRole(role)) return NEUTRAL_CROSS_SELL;
3897
3962
  return CROSS_SELL_BY_ROLE[role];
3898
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
+ }
3899
3978
  //#endregion
3900
3979
  //#region src/ui/tui/screens/McpSuggestedPromptsScreen.tsx
3901
3980
  /**
@@ -3936,6 +4015,25 @@ function getCrossSellPrompts(role) {
3936
4015
  * forces a successful login first). A defensive throw protects the
3937
4016
  * Running useEffect against a state-machine bug.
3938
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 || {});
3939
4037
  const MAX_PROMPT_RUNS = 5;
3940
4038
  const FOLLOW_UP_DELAY_MS = 3e3;
3941
4039
  const McpSuggestedPromptsScreen = ({ store, services }) => {
@@ -3944,8 +4042,9 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3944
4042
  const kit = getRolePrompts(session.roleAtOrganization, session.integration);
3945
4043
  const crossSell = useMemo(() => getCrossSellPrompts(session.roleAtOrganization), [session.roleAtOrganization]);
3946
4044
  const greeting = useMemo(() => getRoleGreeting(session.roleAtOrganization), [session.roleAtOrganization]);
3947
- const [phase, setPhase] = useState("choose");
4045
+ const [phase, setPhase] = useState(() => store.session.credentials ? "choose" : "authenticating");
3948
4046
  const [loginError, setLoginError] = useState(null);
4047
+ const startedTutorialRef = useRef(false);
3949
4048
  const [runningPrompt, setRunningPrompt] = useState(null);
3950
4049
  const [runChunks, setRunChunks] = useState([]);
3951
4050
  const [runStartedAt, setRunStartedAt] = useState(null);
@@ -3967,7 +4066,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3967
4066
  store.setRoleAtOrganization(roleAtOrganization);
3968
4067
  store.setApiUser(user);
3969
4068
  store.setLoginUrl(null);
3970
- setPhase("greeting");
4069
+ setPhase(startedTutorialRef.current ? "greeting" : "choose");
3971
4070
  } catch (err) {
3972
4071
  if (cancelled) return;
3973
4072
  const message = err instanceof Error ? err.message : String(err);
@@ -3985,6 +4084,28 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
3985
4084
  services,
3986
4085
  store
3987
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
+ ]);
3988
4109
  useEffect(() => {
3989
4110
  if (phase !== "running") return;
3990
4111
  if (!runningPrompt) return;
@@ -4070,7 +4191,11 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4070
4191
  setLoginError(null);
4071
4192
  if (choice === "login") {
4072
4193
  analytics.wizardCapture("mcp suggested prompts choose", { choice: "login" });
4073
- 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(() => {});
4074
4199
  } else {
4075
4200
  analytics.wizardCapture("mcp suggested prompts choose", { choice: "exit" });
4076
4201
  enterGoodbye();
@@ -4106,9 +4231,10 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4106
4231
  {
4107
4232
  match: "escape",
4108
4233
  label: "esc",
4109
- action: phase === "goodbye" ? "close" : "exit",
4234
+ action: phase === "goodbye" ? "close" : phase === "authenticating" ? "cancel" : "exit",
4110
4235
  handler: () => {
4111
4236
  if (phase === "goodbye") closeWizard();
4237
+ else if (phase === "authenticating") setPhase("choose");
4112
4238
  else if (phase === "running" || phase === "prompt-picker" || phase === "follow-up" || phase === "greeting") enterGoodbye();
4113
4239
  }
4114
4240
  },
@@ -4142,6 +4268,7 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4142
4268
  children: [
4143
4269
  phase === "choose" && /* @__PURE__ */ jsx(ChoosePhase, {
4144
4270
  error: loginError,
4271
+ slackConnected,
4145
4272
  onSelect: handleChoice
4146
4273
  }),
4147
4274
  phase === "authenticating" && /* @__PURE__ */ jsx(AuthenticatingPhase, { loginUrl: session.loginUrl }),
@@ -4204,71 +4331,112 @@ const McpSuggestedPromptsScreen = ({ store, services }) => {
4204
4331
  })
4205
4332
  });
4206
4333
  };
4207
- const ChoosePhase = ({ error, onSelect }) => /* @__PURE__ */ jsxs(Box, {
4208
- flexDirection: "column",
4209
- children: [
4210
- /* @__PURE__ */ jsx(Text, {
4211
- bold: true,
4212
- color: Colors.accent,
4213
- children: "PostHog MCP"
4214
- }),
4215
- /* @__PURE__ */ jsx(Box, {
4216
- marginTop: 1,
4217
- children: /* @__PURE__ */ jsx(Text, { children: "With MCP your agent works directly with the PostHog platform. You can prompt it to:" })
4218
- }),
4219
- /* @__PURE__ */ jsxs(Box, {
4220
- marginTop: 1,
4221
- flexDirection: "column",
4222
- children: [
4223
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4224
- color: "cyan",
4225
- children: Icons.diamond
4226
- }), " Build dashboards"] }),
4227
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4228
- color: "cyan",
4229
- children: Icons.diamond
4230
- }), " Run SQL queries"] }),
4231
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4232
- color: "cyan",
4233
- children: Icons.diamond
4234
- }), " Deploy feature flags"] }),
4235
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4236
- color: "cyan",
4237
- children: Icons.diamond
4238
- }), " Debug exceptions and errors"] }),
4239
- /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
4240
- color: "cyan",
4241
- children: Icons.diamond
4242
- }), " And lots more..."] })
4243
- ]
4244
- }),
4245
- /* @__PURE__ */ jsx(Box, {
4246
- marginTop: 1,
4247
- children: /* @__PURE__ */ jsx(Text, { children: "Want a live demo using real data from your project?" })
4248
- }),
4249
- /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(PickerMenu, {
4250
- options: [{
4251
- label: "Start MCP tutorial",
4252
- value: "login"
4253
- }, {
4254
- label: "Exit",
4255
- value: "exit"
4256
- }],
4257
- onSelect
4258
- }) }),
4259
- error && /* @__PURE__ */ jsx(Box, {
4260
- marginTop: 1,
4261
- children: /* @__PURE__ */ jsxs(Text, {
4262
- 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",
4263
4350
  children: [
4264
- "Login failed: ",
4265
- error,
4266
- ". 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..."] })
4267
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
+ })
4268
4436
  })
4269
- })
4270
- ]
4271
- });
4437
+ ]
4438
+ });
4439
+ };
4272
4440
  const AuthenticatingPhase = ({ loginUrl }) => /* @__PURE__ */ jsxs(Box, {
4273
4441
  flexDirection: "column",
4274
4442
  children: [/* @__PURE__ */ jsx(LoadingBox, { message: "Waiting for authentication..." }), loginUrl && /* @__PURE__ */ jsx(Box, {
@@ -4606,7 +4774,7 @@ const GoodbyePhase = ({ installedClients, role, integration, engaged, onClose })
4606
4774
  label: "Close",
4607
4775
  value: "close"
4608
4776
  }],
4609
- onSelect: onClose
4777
+ onSelect: () => onClose()
4610
4778
  })
4611
4779
  ]
4612
4780
  });
@@ -5472,6 +5640,6 @@ const AUDIT_3000_AREA_SLIDES = [
5472
5640
  }
5473
5641
  ];
5474
5642
  //#endregion
5475
- 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 };
5476
5644
 
5477
- //# sourceMappingURL=slides-mT2s9wM_.js.map
5645
+ //# sourceMappingURL=slides-BEshbXqG.js.map