@posthog/wizard 2.16.1 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-mcp-server-to-clients-BS6Rjcwh.js → add-mcp-server-to-clients-DnPwZl1P.js} +38 -5
- package/dist/add-mcp-server-to-clients-DnPwZl1P.js.map +1 -0
- package/dist/{agent-interface-B4eUlMso.js → agent-interface-C2VEF-BD.js} +110 -54
- package/dist/agent-interface-C2VEF-BD.js.map +1 -0
- package/dist/{agent-runner-BxqiKVEf.js → agent-runner-Dw8cjZoN.js} +11 -8
- package/dist/{agent-runner-BxqiKVEf.js.map → agent-runner-Dw8cjZoN.js.map} +1 -1
- package/dist/{analytics-DUuUurR3.js → analytics-C-zcTO6g.js} +26 -4
- package/dist/analytics-C-zcTO6g.js.map +1 -0
- package/dist/{api-CGJ1iGps.js → api-B3MWP3vm.js} +14 -4
- package/dist/{api-CGJ1iGps.js.map → api-B3MWP3vm.js.map} +1 -1
- package/dist/bin.js +238 -82
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-DD7WMmIF.js → ci-install-DLuSmSq6.js} +4 -4
- package/dist/{ci-install-DD7WMmIF.js.map → ci-install-DLuSmSq6.js.map} +1 -1
- package/dist/{debug-Cd0hPlZy.js → debug--gQGudnY.js} +1 -1
- package/dist/{debug-ubpO6102.js → debug-BorYMfpE.js} +2 -2
- package/dist/{debug-ubpO6102.js.map → debug-BorYMfpE.js.map} +1 -1
- package/dist/{defaults-zrYmZ2ID.js → defaults-DA3-9dHT.js} +1 -1
- package/dist/{defaults-zrYmZ2ID.js.map → defaults-DA3-9dHT.js.map} +1 -1
- package/dist/{env-api-key-DEl3LJBv.js → env-api-key-MlzJYAvt.js} +1 -1
- package/dist/{env-api-key-DEl3LJBv.js.map → env-api-key-MlzJYAvt.js.map} +1 -1
- package/dist/{environment-BAaC5THg.js → environment-DIOtLqTQ.js} +3 -3
- package/dist/{environment-BAaC5THg.js.map → environment-DIOtLqTQ.js.map} +1 -1
- package/dist/{file-utils-DPmgn9Vm.js → file-utils-VAXoyXVA.js} +1 -1
- package/dist/{file-utils-DPmgn9Vm.js.map → file-utils-VAXoyXVA.js.map} +1 -1
- package/dist/{interactive-BaMAq88Q.js → interactive-DjGjlvY3.js} +2 -2
- package/dist/{interactive-BaMAq88Q.js.map → interactive-DjGjlvY3.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-clGsVw8q.js → mcp-prompt-streaming-Dm47tmiy.js} +62 -12
- package/dist/mcp-prompt-streaming-Dm47tmiy.js.map +1 -0
- package/dist/{non-interactive-l2AKE3jD.js → non-interactive-C2f3Gwva.js} +2 -2
- package/dist/{non-interactive-l2AKE3jD.js.map → non-interactive-C2f3Gwva.js.map} +1 -1
- package/dist/{package-json-Cynjr9k4.js → package-json-DCuoye-H.js} +8 -2
- package/dist/{package-json-Cynjr9k4.js.map → package-json-DCuoye-H.js.map} +1 -1
- package/dist/{package-manager-BqsJK3ej.js → package-manager-Bl2KOUFK.js} +2 -2
- package/dist/{package-manager-BqsJK3ej.js.map → package-manager-Bl2KOUFK.js.map} +1 -1
- package/dist/{playground-DlE5RNfE.js → playground-ZLG68cvx.js} +21 -10
- package/dist/playground-ZLG68cvx.js.map +1 -0
- package/dist/{posthog-DWL8uOcl.js → posthog-Cr37rnla.js} +1 -1
- package/dist/{posthog-DWL8uOcl.js.map → posthog-Cr37rnla.js.map} +1 -1
- package/dist/{posthog-integration-Bf_vtWI9.js → posthog-integration-B_DLodqr.js} +282 -14
- package/dist/posthog-integration-B_DLodqr.js.map +1 -0
- package/dist/{provisioning-D_hAuxUN.js → provisioning-Bk4E6VYn.js} +9 -4
- package/dist/{provisioning-D_hAuxUN.js.map → provisioning-Bk4E6VYn.js.map} +1 -1
- package/dist/{registry-DKgYqROt.js → registry-DMM3UmZD.js} +5 -5
- package/dist/{registry-DKgYqROt.js.map → registry-DMM3UmZD.js.map} +1 -1
- package/dist/{setup-utils-D-uTycLX.js → setup-utils-Df9ezAjZ.js} +86 -38
- package/dist/setup-utils-Df9ezAjZ.js.map +1 -0
- package/dist/{slides-CL1mv_Kq.js → slides-DwvXZ8iS.js} +1583 -322
- package/dist/slides-DwvXZ8iS.js.map +1 -0
- package/dist/{start-tui-DXrv6cof.js → start-tui-P9aMwBzt.js} +28 -18
- package/dist/start-tui-P9aMwBzt.js.map +1 -0
- package/dist/{steps-CgScwqso.js → steps-RCRZbLjZ.js} +6 -6
- package/dist/{steps-CgScwqso.js.map → steps-RCRZbLjZ.js.map} +1 -1
- package/dist/{task-stream-CF6QMVMv.js → task-stream-CZRj6auI.js} +3 -3
- package/dist/{task-stream-CF6QMVMv.js.map → task-stream-CZRj6auI.js.map} +1 -1
- package/dist/{telemetry-v6O12Bep.js → telemetry-CMbVbpaY.js} +2 -2
- package/dist/{telemetry-v6O12Bep.js.map → telemetry-CMbVbpaY.js.map} +1 -1
- package/dist/urls-BzG_Jtw9.js +35 -0
- package/dist/urls-BzG_Jtw9.js.map +1 -0
- package/dist/{wizard-abort-BGoBKgvC.js → wizard-abort-Dl8WJQgJ.js} +1 -1
- package/dist/{wizard-abort-iTaJ8wC8.js → wizard-abort-QuKm_B5z.js} +3 -3
- package/dist/{wizard-abort-iTaJ8wC8.js.map → wizard-abort-QuKm_B5z.js.map} +1 -1
- package/dist/{wizard-session-gsn8Z3bZ.js → wizard-session-d27JGRGi.js} +1 -1
- package/dist/{wizard-session-gsn8Z3bZ.js.map → wizard-session-d27JGRGi.js.map} +1 -1
- package/dist/{wizard-session-7tMjgOvP.js → wizard-session-y304gEEI.js} +1 -1
- package/package.json +1 -1
- package/dist/TextBlock-CdeZog_6.js +0 -275
- package/dist/TextBlock-CdeZog_6.js.map +0 -1
- package/dist/add-mcp-server-to-clients-BS6Rjcwh.js.map +0 -1
- package/dist/agent-interface-B4eUlMso.js.map +0 -1
- package/dist/analytics-DUuUurR3.js.map +0 -1
- package/dist/api-B8OR0N1V.js +0 -2
- package/dist/mcp-prompt-streaming-clGsVw8q.js.map +0 -1
- package/dist/package-json-CumwmZpv.js +0 -2
- package/dist/playground-DlE5RNfE.js.map +0 -1
- package/dist/posthog-integration-Bf_vtWI9.js.map +0 -1
- package/dist/provisioning-BlBnlcFd.js +0 -2
- package/dist/setup-utils-BHZEdkNZ.js +0 -2
- package/dist/setup-utils-D-uTycLX.js.map +0 -1
- package/dist/skill-CnOQAZXp.js +0 -29
- package/dist/skill-CnOQAZXp.js.map +0 -1
- package/dist/slides-CL1mv_Kq.js.map +0 -1
- package/dist/start-tui-DXrv6cof.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { g as SERVICE_LABELS, s as logToFile } from "./debug-
|
|
1
|
+
import { g as SERVICE_LABELS, s as logToFile } from "./debug-BorYMfpE.js";
|
|
2
2
|
import { n as isTaskStatus } from "./wizard-ui-YdGFRyu_.js";
|
|
3
|
-
import {
|
|
4
|
-
import { i as buildSession } from "./wizard-session-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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";
|
|
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-
|
|
8
|
+
import { n as AVAILABLE_FEATURES, t as ALL_FEATURE_VALUES } from "./defaults-DA3-9dHT.js";
|
|
9
9
|
import * as fs$1 from "fs";
|
|
10
10
|
import { Box, Text, measureElement, useInput, useStdout } from "ink";
|
|
11
11
|
import { Component, Fragment, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
@@ -120,6 +120,12 @@ var WizardRouter = class {
|
|
|
120
120
|
* All session mutations that affect screen resolution go through
|
|
121
121
|
* explicit setters so emitChange() is always called.
|
|
122
122
|
*/
|
|
123
|
+
/**
|
|
124
|
+
* FIFO cap on retained status lines. The status bar is the only consumer and
|
|
125
|
+
* renders at most EXPANDED_COUNT lines, so there is no reason to retain more —
|
|
126
|
+
* the cap is tied to the window it feeds.
|
|
127
|
+
*/
|
|
128
|
+
const MAX_STATUS_MESSAGES = 10;
|
|
123
129
|
var WizardStore = class {
|
|
124
130
|
$session = map(buildSession({}));
|
|
125
131
|
$statusMessages = atom([]);
|
|
@@ -571,7 +577,8 @@ var WizardStore = class {
|
|
|
571
577
|
pushStatus(message) {
|
|
572
578
|
const msgs = this.$statusMessages.get();
|
|
573
579
|
if (msgs.length > 0 && msgs[msgs.length - 1] === message) return;
|
|
574
|
-
|
|
580
|
+
const next = msgs.length >= MAX_STATUS_MESSAGES ? [...msgs.slice(msgs.length - MAX_STATUS_MESSAGES + 1), message] : [...msgs, message];
|
|
581
|
+
this.$statusMessages.set(next);
|
|
575
582
|
this.emitChange();
|
|
576
583
|
}
|
|
577
584
|
setTasks(tasks) {
|
|
@@ -1840,6 +1847,15 @@ const ScreenContainer = ({ store, screens }) => {
|
|
|
1840
1847
|
}) })
|
|
1841
1848
|
});
|
|
1842
1849
|
};
|
|
1850
|
+
//#endregion
|
|
1851
|
+
//#region src/ui/tui/primitives/TabContainer.tsx
|
|
1852
|
+
/**
|
|
1853
|
+
* TabContainer — Self-contained tabbed interface.
|
|
1854
|
+
* Absorbs BottomTabBar + StatusPanel functionality.
|
|
1855
|
+
*
|
|
1856
|
+
* Key bindings are declared via useKeyBindings, which auto-registers
|
|
1857
|
+
* hints in the KeyboardHintsBar (rendered by ScreenContainer).
|
|
1858
|
+
*/
|
|
1843
1859
|
const TabContainer = ({ tabs, statusMessage, expandableStatus = false, store }) => {
|
|
1844
1860
|
const [activeTab, setActiveTab] = useState(0);
|
|
1845
1861
|
const [localExpanded, setLocalExpanded] = useState(false);
|
|
@@ -2628,8 +2644,17 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2628
2644
|
}, [installer]);
|
|
2629
2645
|
const proceedToFeatureSelectOrInstall = (clientNames) => {
|
|
2630
2646
|
setSelectedClientNames(clientNames);
|
|
2631
|
-
if (store.session.mcpFeatures)
|
|
2632
|
-
|
|
2647
|
+
if (store.session.mcpFeatures) {
|
|
2648
|
+
doInstall(clientNames, store.session.mcpFeatures);
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
if (!clientNames.some((name) => {
|
|
2652
|
+
return !clients.find((c) => c.name === name)?.finish;
|
|
2653
|
+
})) {
|
|
2654
|
+
doInstall(clientNames, []);
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
setPhase("feature-select");
|
|
2633
2658
|
};
|
|
2634
2659
|
const handleConfirm = () => {
|
|
2635
2660
|
if (isRemove) doRemove();
|
|
@@ -2668,6 +2693,17 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2668
2693
|
const outcome = result.length > 0 ? "installed" : "failed";
|
|
2669
2694
|
setTimeout(() => markDone(store, outcome, result), 2e3);
|
|
2670
2695
|
};
|
|
2696
|
+
const installValueBullets = [
|
|
2697
|
+
"Ask your agent: \"List my feature flags\" — and it does.",
|
|
2698
|
+
"Run SQL, build dashboards, ship flags, all from your IDE.",
|
|
2699
|
+
"No copy-pasting tokens or context. Your agent has the keys."
|
|
2700
|
+
];
|
|
2701
|
+
const finishNotes = clients.flatMap((c) => c.finish && resultClients.includes(c.name) ? [{
|
|
2702
|
+
name: c.name,
|
|
2703
|
+
url: c.finish.url,
|
|
2704
|
+
instruction: c.finish.instruction
|
|
2705
|
+
}] : []);
|
|
2706
|
+
const installedNow = resultClients.filter((name) => !finishNotes.some((n) => n.name === name));
|
|
2671
2707
|
return /* @__PURE__ */ jsxs(Box, {
|
|
2672
2708
|
flexDirection: "column",
|
|
2673
2709
|
flexGrow: 1,
|
|
@@ -2695,11 +2731,7 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2695
2731
|
!isRemove && /* @__PURE__ */ jsx(Box, {
|
|
2696
2732
|
flexDirection: "column",
|
|
2697
2733
|
marginBottom: 1,
|
|
2698
|
-
children:
|
|
2699
|
-
"Ask your agent: \"List my feature flags\" — and it does.",
|
|
2700
|
-
"Run SQL, build dashboards, ship flags, all from your IDE.",
|
|
2701
|
-
"No copy-pasting tokens or context. Your agent has the keys."
|
|
2702
|
-
].map((bullet) => /* @__PURE__ */ jsxs(Text, {
|
|
2734
|
+
children: installValueBullets.map((bullet) => /* @__PURE__ */ jsxs(Text, {
|
|
2703
2735
|
dimColor: true,
|
|
2704
2736
|
children: [
|
|
2705
2737
|
"•",
|
|
@@ -2748,7 +2780,10 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2748
2780
|
}),
|
|
2749
2781
|
phase === "done" && /* @__PURE__ */ jsx(Box, {
|
|
2750
2782
|
flexDirection: "column",
|
|
2751
|
-
children:
|
|
2783
|
+
children: installedNow.length === 0 && finishNotes.length === 0 ? /* @__PURE__ */ jsxs(Text, {
|
|
2784
|
+
dimColor: true,
|
|
2785
|
+
children: [isRemove ? "Removal" : "Installation", " skipped."]
|
|
2786
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [installedNow.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
2752
2787
|
color: "green",
|
|
2753
2788
|
bold: true,
|
|
2754
2789
|
children: [
|
|
@@ -2759,258 +2794,1325 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2759
2794
|
isRemove ? "removed from" : "installed for",
|
|
2760
2795
|
":"
|
|
2761
2796
|
]
|
|
2762
|
-
}),
|
|
2797
|
+
}), installedNow.map((name, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
2763
2798
|
" ",
|
|
2764
2799
|
"•",
|
|
2765
2800
|
" ",
|
|
2766
2801
|
name
|
|
2767
|
-
] }, i))] })
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
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
|
|
2817
|
+
})
|
|
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))] })
|
|
2771
2829
|
})
|
|
2772
2830
|
]
|
|
2773
2831
|
})]
|
|
2774
2832
|
});
|
|
2775
2833
|
};
|
|
2776
2834
|
//#endregion
|
|
2777
|
-
//#region src/lib/mcp-role-prompts.
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2835
|
+
//#region src/lib/mcp-role-prompts.copy.json
|
|
2836
|
+
var pinnedFirstPrompt = {
|
|
2837
|
+
"prompt": "Show me my top 5 events from the last 7 days",
|
|
2838
|
+
"description": "A safe first pick — works on any project regardless of role or setup."
|
|
2839
|
+
};
|
|
2840
|
+
var defaultKit = [
|
|
2841
|
+
{
|
|
2842
|
+
"key": "verify",
|
|
2843
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2844
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2845
|
+
},
|
|
2846
|
+
{
|
|
2847
|
+
"key": "top-events",
|
|
2848
|
+
"prompt": "Show me my top 5 events from the last 7 days",
|
|
2849
|
+
"description": "Get a feel for what your project is tracking."
|
|
2850
|
+
},
|
|
2791
2851
|
{
|
|
2792
|
-
|
|
2793
|
-
|
|
2852
|
+
"key": "main-funnel",
|
|
2853
|
+
"prompt": "Build me a funnel for my main user journey and show where the drop-off is",
|
|
2854
|
+
"description": "Insight discovery — your agent picks the events."
|
|
2794
2855
|
},
|
|
2795
2856
|
{
|
|
2796
|
-
|
|
2797
|
-
|
|
2857
|
+
"key": "flags-inventory",
|
|
2858
|
+
"prompt": "Show me my feature flags and what each is currently rolled out to",
|
|
2859
|
+
"description": "Inventory the rollout state of every flag in your project."
|
|
2798
2860
|
},
|
|
2799
2861
|
{
|
|
2800
|
-
|
|
2801
|
-
|
|
2862
|
+
"key": "error-trend",
|
|
2863
|
+
"prompt": "Show me daily error count for the last 30 days and flag anything that looks like a spike",
|
|
2864
|
+
"description": "Pulse-check on stability — no dashboard setup required."
|
|
2802
2865
|
}
|
|
2803
2866
|
];
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
* before getting there). A defensive throw protects the Running
|
|
2831
|
-
* useEffect against a state-machine bug.
|
|
2832
|
-
*/
|
|
2833
|
-
const MAX_PROMPT_RUNS = 3;
|
|
2834
|
-
const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
2835
|
-
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
2836
|
-
const session = store.session;
|
|
2837
|
-
const kit = STOCK_MCP_SUGGESTED_PROMPTS;
|
|
2838
|
-
const [phase, setPhase] = useState("choose");
|
|
2839
|
-
const [loginError, setLoginError] = useState(null);
|
|
2840
|
-
const [runningPrompt, setRunningPrompt] = useState(null);
|
|
2841
|
-
const [runChunks, setRunChunks] = useState([]);
|
|
2842
|
-
const [runStartedAt, setRunStartedAt] = useState(null);
|
|
2843
|
-
const [runCount, setRunCount] = useState(0);
|
|
2844
|
-
const canPickAnother = runCount < MAX_PROMPT_RUNS;
|
|
2845
|
-
const runAbortRef = useRef(null);
|
|
2846
|
-
useEffect(() => {
|
|
2847
|
-
if (phase !== "authenticating") return;
|
|
2848
|
-
let cancelled = false;
|
|
2849
|
-
(async () => {
|
|
2850
|
-
try {
|
|
2851
|
-
const { credentials, roleAtOrganization, user } = await services.performLogin();
|
|
2852
|
-
if (cancelled) return;
|
|
2853
|
-
store.setCredentials(credentials);
|
|
2854
|
-
store.setRoleAtOrganization(roleAtOrganization);
|
|
2855
|
-
store.setApiUser(user);
|
|
2856
|
-
store.setLoginUrl(null);
|
|
2857
|
-
setPhase("prompt-picker");
|
|
2858
|
-
} catch (err) {
|
|
2859
|
-
if (cancelled) return;
|
|
2860
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
2861
|
-
logToFile(`[McpSuggestedPromptsScreen] login failed: ${message}`);
|
|
2862
|
-
store.setLoginUrl(null);
|
|
2863
|
-
setLoginError(message);
|
|
2864
|
-
setPhase("choose");
|
|
2865
|
-
}
|
|
2866
|
-
})();
|
|
2867
|
-
return () => {
|
|
2868
|
-
cancelled = true;
|
|
2869
|
-
};
|
|
2870
|
-
}, [
|
|
2871
|
-
phase,
|
|
2872
|
-
services,
|
|
2873
|
-
store
|
|
2874
|
-
]);
|
|
2875
|
-
useEffect(() => {
|
|
2876
|
-
if (phase !== "running") return;
|
|
2877
|
-
if (!runningPrompt) return;
|
|
2878
|
-
if (!session.credentials) throw new Error("[McpSuggestedPromptsScreen] Running phase reached without credentials. The Choose gate should have prevented this.");
|
|
2879
|
-
const controller = new AbortController();
|
|
2880
|
-
runAbortRef.current = controller;
|
|
2881
|
-
const startedAt = Date.now();
|
|
2882
|
-
setRunStartedAt(startedAt);
|
|
2883
|
-
setRunChunks([]);
|
|
2884
|
-
(async () => {
|
|
2885
|
-
const credentials = session.credentials;
|
|
2886
|
-
if (!credentials) return;
|
|
2887
|
-
try {
|
|
2888
|
-
for await (const chunk of services.runPromptStreaming({
|
|
2889
|
-
prompt: runningPrompt,
|
|
2890
|
-
credentials,
|
|
2891
|
-
signal: controller.signal
|
|
2892
|
-
})) {
|
|
2893
|
-
if (controller.signal.aborted) return;
|
|
2894
|
-
setRunChunks((prev) => [...prev, chunk]);
|
|
2895
|
-
if (chunk.kind === "done") {
|
|
2896
|
-
analytics.wizardCapture("mcp suggested prompts run", {
|
|
2897
|
-
prompt: runningPrompt,
|
|
2898
|
-
durationMs: Date.now() - startedAt
|
|
2899
|
-
});
|
|
2900
|
-
return;
|
|
2901
|
-
}
|
|
2902
|
-
if (chunk.kind === "error") {
|
|
2903
|
-
analytics.wizardCapture("mcp suggested prompts run failed", {
|
|
2904
|
-
prompt: runningPrompt,
|
|
2905
|
-
error: chunk.text
|
|
2906
|
-
});
|
|
2907
|
-
return;
|
|
2908
|
-
}
|
|
2909
|
-
}
|
|
2910
|
-
} catch (err) {
|
|
2911
|
-
if (controller.signal.aborted) return;
|
|
2912
|
-
const text = err instanceof Error ? err.message : String(err);
|
|
2913
|
-
setRunChunks((prev) => [...prev, {
|
|
2914
|
-
kind: "error",
|
|
2915
|
-
text
|
|
2916
|
-
}]);
|
|
2917
|
-
analytics.wizardCapture("mcp suggested prompts run failed", {
|
|
2918
|
-
prompt: runningPrompt,
|
|
2919
|
-
error: text
|
|
2920
|
-
});
|
|
2921
|
-
}
|
|
2922
|
-
})();
|
|
2923
|
-
return () => {
|
|
2924
|
-
controller.abort();
|
|
2925
|
-
if (runAbortRef.current === controller) runAbortRef.current = null;
|
|
2926
|
-
};
|
|
2927
|
-
}, [
|
|
2928
|
-
phase,
|
|
2929
|
-
runningPrompt,
|
|
2930
|
-
services,
|
|
2931
|
-
session.credentials
|
|
2932
|
-
]);
|
|
2933
|
-
const dismiss = () => {
|
|
2934
|
-
setPhase("done");
|
|
2935
|
-
setTimeout(() => {
|
|
2936
|
-
store.setMcpSuggestedPromptsDismissed();
|
|
2937
|
-
}, 0);
|
|
2938
|
-
};
|
|
2939
|
-
const handleChoice = (value) => {
|
|
2940
|
-
const choice = Array.isArray(value) ? value[0] : value;
|
|
2941
|
-
setLoginError(null);
|
|
2942
|
-
if (choice === "login") {
|
|
2943
|
-
analytics.wizardCapture("mcp suggested prompts choose", { choice: "login" });
|
|
2944
|
-
setPhase("authenticating");
|
|
2945
|
-
} else {
|
|
2946
|
-
analytics.wizardCapture("mcp suggested prompts choose", { choice: "exit" });
|
|
2947
|
-
dismiss();
|
|
2867
|
+
var roleKits = {
|
|
2868
|
+
"founder": [
|
|
2869
|
+
{
|
|
2870
|
+
"key": "verify",
|
|
2871
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2872
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2873
|
+
},
|
|
2874
|
+
{
|
|
2875
|
+
"key": "exec-dashboard",
|
|
2876
|
+
"prompt": "Build me an exec dashboard with MRR, MAU, churn, and top events, then save it",
|
|
2877
|
+
"description": "A one-glance view of the business you can pin and share."
|
|
2878
|
+
},
|
|
2879
|
+
{
|
|
2880
|
+
"key": "wau",
|
|
2881
|
+
"prompt": "Show me weekly active users for the last 90 days",
|
|
2882
|
+
"description": "The trendline you actually care about."
|
|
2883
|
+
},
|
|
2884
|
+
{
|
|
2885
|
+
"key": "mau-trend",
|
|
2886
|
+
"prompt": "Show me weekly MAU for the last 12 weeks and where the inflection points are",
|
|
2887
|
+
"description": "See where growth bent — up or down — without setting up alerts."
|
|
2888
|
+
},
|
|
2889
|
+
{
|
|
2890
|
+
"key": "nps-summary",
|
|
2891
|
+
"prompt": "Show me NPS responses from my paid users and summarize the themes",
|
|
2892
|
+
"description": "Pulse-check on the people paying you."
|
|
2948
2893
|
}
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2894
|
+
],
|
|
2895
|
+
"product": [
|
|
2896
|
+
{
|
|
2897
|
+
"key": "verify",
|
|
2898
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2899
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2900
|
+
},
|
|
2901
|
+
{
|
|
2902
|
+
"key": "onboarding",
|
|
2903
|
+
"prompt": "Build a funnel for my onboarding flow and show me the biggest drop-off step",
|
|
2904
|
+
"description": "See where new users drop off in their first session."
|
|
2905
|
+
},
|
|
2906
|
+
{
|
|
2907
|
+
"key": "pricing-flag-state",
|
|
2908
|
+
"prompt": "Show me feature flags scoped to the pricing page and who's currently in each",
|
|
2909
|
+
"description": "Inspect rollout state of pricing experiments without changing anything."
|
|
2910
|
+
},
|
|
2911
|
+
{
|
|
2912
|
+
"key": "cta-compare",
|
|
2913
|
+
"prompt": "Show me how my upgrade CTA variants are converting across my recent experiments",
|
|
2914
|
+
"description": "Read the verdict on CTA tests without spinning up a new one."
|
|
2915
|
+
},
|
|
2916
|
+
{
|
|
2917
|
+
"key": "retention",
|
|
2918
|
+
"prompt": "Compute week-1 retention split by acquisition channel",
|
|
2919
|
+
"description": "Find the channel that actually retains users."
|
|
2964
2920
|
}
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2921
|
+
],
|
|
2922
|
+
"leadership": [
|
|
2923
|
+
{
|
|
2924
|
+
"key": "verify",
|
|
2925
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2926
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2927
|
+
},
|
|
2928
|
+
{
|
|
2929
|
+
"key": "board-dashboard",
|
|
2930
|
+
"prompt": "Build a board dashboard with revenue, MAU, churn, and support backlog, then save it",
|
|
2931
|
+
"description": "Pre-board prep in one prompt."
|
|
2932
|
+
},
|
|
2933
|
+
{
|
|
2934
|
+
"key": "mau-growth",
|
|
2935
|
+
"prompt": "Show MAU growth over the last 4 quarters",
|
|
2936
|
+
"description": "The chart for the next leadership slide."
|
|
2937
|
+
},
|
|
2938
|
+
{
|
|
2939
|
+
"key": "churn-trend",
|
|
2940
|
+
"prompt": "Show me churn over the last 8 weeks and where it moved most",
|
|
2941
|
+
"description": "See the trend without configuring a notification."
|
|
2942
|
+
},
|
|
2943
|
+
{
|
|
2944
|
+
"key": "upgrade-drivers",
|
|
2945
|
+
"prompt": "Which features drive the most upgrades?",
|
|
2946
|
+
"description": "Ranked breakdown of what actually moves the needle."
|
|
2974
2947
|
}
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
2948
|
+
],
|
|
2949
|
+
"marketing": [
|
|
2950
|
+
{
|
|
2951
|
+
"key": "verify",
|
|
2952
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2953
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2954
|
+
},
|
|
2955
|
+
{
|
|
2956
|
+
"key": "pricing-leavers",
|
|
2957
|
+
"prompt": "Show me users who saw pricing but didn't sign up — what did they do next?",
|
|
2958
|
+
"description": "Identify high-intent visitors and what they bounced to."
|
|
2959
|
+
},
|
|
2960
|
+
{
|
|
2961
|
+
"key": "hero-compare",
|
|
2962
|
+
"prompt": "Show me how my landing page hero variants performed — which group converted best?",
|
|
2963
|
+
"description": "Read the verdict on hero copy tests."
|
|
2964
|
+
},
|
|
2965
|
+
{
|
|
2966
|
+
"key": "newsletter-clicks",
|
|
2967
|
+
"prompt": "Find users who clicked our last newsletter and show me what they did next",
|
|
2968
|
+
"description": "See the downstream behavior of your last campaign."
|
|
2969
|
+
},
|
|
2970
|
+
{
|
|
2971
|
+
"key": "landing-annotation",
|
|
2972
|
+
"prompt": "Annotate today as the launch of the new landing page",
|
|
2973
|
+
"description": "Pin the deploy on every chart so future you can find it."
|
|
2974
|
+
}
|
|
2975
|
+
],
|
|
2976
|
+
"engineering": [
|
|
2977
|
+
{
|
|
2978
|
+
"key": "verify",
|
|
2979
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
2980
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
2981
|
+
},
|
|
2982
|
+
{
|
|
2983
|
+
"key": "stale-flags",
|
|
2984
|
+
"prompt": "List flags rolled out to 100% — they're probably safe to delete",
|
|
2985
|
+
"description": "Dead-code hunt for your feature flag config."
|
|
2986
|
+
},
|
|
2987
|
+
{
|
|
2988
|
+
"key": "top-errors",
|
|
2989
|
+
"prompt": "Show me the top 5 unresolved errors this week",
|
|
2990
|
+
"description": "Triage queue without opening another tab."
|
|
2991
|
+
},
|
|
2992
|
+
{
|
|
2993
|
+
"key": "reliability-trend",
|
|
2994
|
+
"prompt": "Show me 5xx error rate over the last 24 hours by endpoint",
|
|
2995
|
+
"description": "See where reliability is drifting, no alert setup."
|
|
2996
|
+
},
|
|
2997
|
+
{
|
|
2998
|
+
"key": "zero-rollout-flags",
|
|
2999
|
+
"prompt": "Show me feature flags currently rolled out at 0% — anything ready to retire?",
|
|
3000
|
+
"description": "Find dead kill-switch flags you can clean up later."
|
|
3001
|
+
}
|
|
3002
|
+
],
|
|
3003
|
+
"data": [
|
|
3004
|
+
{
|
|
3005
|
+
"key": "verify",
|
|
3006
|
+
"prompt": "Annotate today with 'PostHog wizard install'",
|
|
3007
|
+
"description": "Creates a dated note on your project — visible on every chart. Delete anytime from PostHog."
|
|
3008
|
+
},
|
|
3009
|
+
{
|
|
3010
|
+
"key": "top-events-24h",
|
|
3011
|
+
"prompt": "Top 5 events by volume in the last 24 hours",
|
|
3012
|
+
"description": "Smoke test for ingestion + a sanity check on volumes."
|
|
3013
|
+
},
|
|
3014
|
+
{
|
|
3015
|
+
"key": "paid-retention",
|
|
3016
|
+
"prompt": "Retention curve for paid users by signup month",
|
|
3017
|
+
"description": "The cohort chart you'd build first anyway."
|
|
3018
|
+
},
|
|
3019
|
+
{
|
|
3020
|
+
"key": "full-funnel",
|
|
3021
|
+
"prompt": "Funnel: signup → activated → first power feature → paid",
|
|
3022
|
+
"description": "Drop-off across the full journey, ready to slice."
|
|
3023
|
+
},
|
|
3024
|
+
{
|
|
3025
|
+
"key": "power-users-query",
|
|
3026
|
+
"prompt": "Show me users with 5+ sessions per week over the last month and what they have in common",
|
|
3027
|
+
"description": "Profile your power-user segment without materializing a cohort."
|
|
3028
|
+
}
|
|
3029
|
+
]
|
|
3011
3030
|
};
|
|
3012
|
-
|
|
3013
|
-
|
|
3031
|
+
var roleFamilyOverrides = {
|
|
3032
|
+
"product": {
|
|
3033
|
+
"frontend-web": { "cta-compare": {
|
|
3034
|
+
"prompt": "Compare conversion across the variants of my last upgrade CTA experiment (control, red, green)",
|
|
3035
|
+
"description": "Read the verdict on a three-arm frontend experiment."
|
|
3036
|
+
} },
|
|
3037
|
+
"mobile": {
|
|
3038
|
+
"onboarding": {
|
|
3039
|
+
"prompt": "Build a funnel app_open → onboarding_complete → first_session_complete and show me the drop-off",
|
|
3040
|
+
"description": "Mobile-flavored onboarding funnel with sensible defaults."
|
|
3041
|
+
},
|
|
3042
|
+
"cta-compare": {
|
|
3043
|
+
"prompt": "Show me feature flags gated on app version — who's in each release tier?",
|
|
3044
|
+
"description": "See which clients see what, without changing anything."
|
|
3045
|
+
}
|
|
3046
|
+
},
|
|
3047
|
+
"backend": { "onboarding": {
|
|
3048
|
+
"prompt": "Funnel of signup → first API call → paid for last 30 days",
|
|
3049
|
+
"description": "Backend funnel that reflects what your service actually sees."
|
|
3050
|
+
} }
|
|
3051
|
+
},
|
|
3052
|
+
"engineering": {
|
|
3053
|
+
"frontend-web": { "top-errors": {
|
|
3054
|
+
"prompt": "Top 5 JS errors by occurrence count this week, with affected URLs",
|
|
3055
|
+
"description": "Frontend-specific error triage — sorted by blast radius."
|
|
3056
|
+
} },
|
|
3057
|
+
"mobile": {
|
|
3058
|
+
"top-errors": {
|
|
3059
|
+
"prompt": "Top crashes this week by app version, sorted by affected users",
|
|
3060
|
+
"description": "Mobile crash triage straight from the same data PostHog has."
|
|
3061
|
+
},
|
|
3062
|
+
"reliability-trend": {
|
|
3063
|
+
"prompt": "Show me crash-free sessions over the last 7 days by app version",
|
|
3064
|
+
"description": "Crash-free trend per release — the one mobile metric that matters."
|
|
3065
|
+
}
|
|
3066
|
+
},
|
|
3067
|
+
"backend": {
|
|
3068
|
+
"top-errors": {
|
|
3069
|
+
"prompt": "Top 5 server-side errors this week, grouped by endpoint",
|
|
3070
|
+
"description": "Backend error triage by route, sorted by frequency."
|
|
3071
|
+
},
|
|
3072
|
+
"reliability-trend": {
|
|
3073
|
+
"prompt": "Show me p95 response time over the last 24 hours by endpoint",
|
|
3074
|
+
"description": "Latency trend from the data you already collect."
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
},
|
|
3078
|
+
"data": { "backend": { "full-funnel": {
|
|
3079
|
+
"prompt": "Funnel: api_signup → first_api_call → first_paid_event over last 30 days",
|
|
3080
|
+
"description": "Backend conversion funnel — captures the value your service delivers."
|
|
3081
|
+
} } }
|
|
3082
|
+
};
|
|
3083
|
+
var roleGreetings = {
|
|
3084
|
+
"founder": {
|
|
3085
|
+
"headline": "Founders use MCP to keep a hand on growth.",
|
|
3086
|
+
"bullets": [
|
|
3087
|
+
"Weekly active users, retention, and revenue without leaving your IDE.",
|
|
3088
|
+
"Spot stalls in your trends without setting up dashboards by hand.",
|
|
3089
|
+
"Pin annotations on every chart so you remember what shipped."
|
|
3090
|
+
],
|
|
3091
|
+
"outro": "Pick a prompt — your agent will run it on your project's real data."
|
|
3092
|
+
},
|
|
3093
|
+
"product": {
|
|
3094
|
+
"headline": "PMs use MCP to learn faster and decide quicker.",
|
|
3095
|
+
"bullets": [
|
|
3096
|
+
"Funnels for every onboarding flow you want to inspect.",
|
|
3097
|
+
"Inspect feature flags and experiment outcomes without leaving your IDE.",
|
|
3098
|
+
"Retention sliced by acquisition channel in seconds."
|
|
3099
|
+
],
|
|
3100
|
+
"outro": "Pick a prompt — your agent will do the legwork."
|
|
3101
|
+
},
|
|
3102
|
+
"leadership": {
|
|
3103
|
+
"headline": "Read the business from your terminal.",
|
|
3104
|
+
"bullets": [
|
|
3105
|
+
"Board-ready dashboards in one prompt.",
|
|
3106
|
+
"Trend lines for MAU, churn, and revenue, one query away.",
|
|
3107
|
+
"The numbers for the next leadership slide, on tap."
|
|
3108
|
+
],
|
|
3109
|
+
"outro": "Pick a prompt to see PostHog work for you."
|
|
3110
|
+
},
|
|
3111
|
+
"marketing": {
|
|
3112
|
+
"headline": "Inspect campaigns, end to end.",
|
|
3113
|
+
"bullets": [
|
|
3114
|
+
"Find high-intent visitors and what they did next.",
|
|
3115
|
+
"Compare landing-copy experiments and see which arm is winning.",
|
|
3116
|
+
"Tie every campaign to revenue with annotated launches."
|
|
3117
|
+
],
|
|
3118
|
+
"outro": "Pick a prompt to try it on your data."
|
|
3119
|
+
},
|
|
3120
|
+
"engineering": {
|
|
3121
|
+
"headline": "MCP is your shortest path from bug to root cause.",
|
|
3122
|
+
"bullets": [
|
|
3123
|
+
"Top errors this week, sorted by blast radius.",
|
|
3124
|
+
"Latency and crash-free trends checked against real data.",
|
|
3125
|
+
"Audit which flags are stale or fully rolled out."
|
|
3126
|
+
],
|
|
3127
|
+
"outro": "Pick a prompt — your agent has read access across your project."
|
|
3128
|
+
},
|
|
3129
|
+
"data": {
|
|
3130
|
+
"headline": "Data work without leaving the terminal.",
|
|
3131
|
+
"bullets": [
|
|
3132
|
+
"Profile any segment in seconds.",
|
|
3133
|
+
"Retention curves by signup month, sliced any way you want.",
|
|
3134
|
+
"Run SQL against your event stream — no copy-paste, no exports."
|
|
3135
|
+
],
|
|
3136
|
+
"outro": "Pick a prompt — every result is real data from your project."
|
|
3137
|
+
}
|
|
3138
|
+
};
|
|
3139
|
+
var neutralGreeting = {
|
|
3140
|
+
"headline": "PostHog MCP turns your agent into a product analyst.",
|
|
3141
|
+
"bullets": [
|
|
3142
|
+
"Run queries, build insights, save dashboards — straight from your IDE.",
|
|
3143
|
+
"Every result is real data from your project.",
|
|
3144
|
+
"No copy-pasting tokens, no context switching."
|
|
3145
|
+
],
|
|
3146
|
+
"outro": "Pick a prompt to see what MCP can do."
|
|
3147
|
+
};
|
|
3148
|
+
var toolFollowUps = {
|
|
3149
|
+
"query-error-tracking-issue": [
|
|
3150
|
+
{
|
|
3151
|
+
"label": "Stack trace for the top error",
|
|
3152
|
+
"prompt": "Show me the stack trace and recent occurrences for the top error."
|
|
3153
|
+
},
|
|
3154
|
+
{
|
|
3155
|
+
"label": "Who is most affected?",
|
|
3156
|
+
"prompt": "Which users have hit that error most often in the last 7 days?"
|
|
3157
|
+
},
|
|
3158
|
+
{
|
|
3159
|
+
"label": "When did it start?",
|
|
3160
|
+
"prompt": "Show me when that error first appeared and any deploy that landed nearby."
|
|
3161
|
+
},
|
|
3162
|
+
{
|
|
3163
|
+
"label": "Find related sessions",
|
|
3164
|
+
"prompt": "Find session recordings that hit that error so I can see what users were doing."
|
|
3165
|
+
},
|
|
3166
|
+
{
|
|
3167
|
+
"label": "Save the top-errors view",
|
|
3168
|
+
"prompt": "Save this top-errors view as an insight I can come back to."
|
|
3169
|
+
},
|
|
3170
|
+
{
|
|
3171
|
+
"label": "Pin to engineering dashboard",
|
|
3172
|
+
"prompt": "Pin this errors view to my engineering dashboard."
|
|
3173
|
+
}
|
|
3174
|
+
],
|
|
3175
|
+
"query-trends": [
|
|
3176
|
+
{
|
|
3177
|
+
"label": "Break down by property",
|
|
3178
|
+
"prompt": "Break that trend down by the most common user property."
|
|
3179
|
+
},
|
|
3180
|
+
{
|
|
3181
|
+
"label": "Find the outlier day",
|
|
3182
|
+
"prompt": "Which day stood out the most and what else was going on?"
|
|
3183
|
+
},
|
|
3184
|
+
{
|
|
3185
|
+
"label": "Compare to last month",
|
|
3186
|
+
"prompt": "Compare that against the same period last month."
|
|
3187
|
+
},
|
|
3188
|
+
{
|
|
3189
|
+
"label": "Build a funnel from it",
|
|
3190
|
+
"prompt": "Build a funnel using the top events from that trend."
|
|
3191
|
+
},
|
|
3192
|
+
{
|
|
3193
|
+
"label": "Save as an insight",
|
|
3194
|
+
"prompt": "Save that trend as an insight named 'Trends'."
|
|
3195
|
+
},
|
|
3196
|
+
{
|
|
3197
|
+
"label": "Pin to main dashboard",
|
|
3198
|
+
"prompt": "Pin that trend to my main dashboard."
|
|
3199
|
+
}
|
|
3200
|
+
],
|
|
3201
|
+
"query-funnel": [
|
|
3202
|
+
{
|
|
3203
|
+
"label": "Biggest drop-off",
|
|
3204
|
+
"prompt": "Which step has the biggest drop-off, and who falls out there?"
|
|
3205
|
+
},
|
|
3206
|
+
{
|
|
3207
|
+
"label": "Completion time",
|
|
3208
|
+
"prompt": "How long does it take users who complete that funnel?"
|
|
3209
|
+
},
|
|
3210
|
+
{
|
|
3211
|
+
"label": "Slice by platform",
|
|
3212
|
+
"prompt": "Show that funnel split by mobile vs desktop."
|
|
3213
|
+
},
|
|
3214
|
+
{
|
|
3215
|
+
"label": "Find drop-off sessions",
|
|
3216
|
+
"prompt": "Find session recordings of users who dropped out at the biggest step."
|
|
3217
|
+
},
|
|
3218
|
+
{
|
|
3219
|
+
"label": "Save the funnel",
|
|
3220
|
+
"prompt": "Save that funnel as an insight."
|
|
3221
|
+
},
|
|
3222
|
+
{
|
|
3223
|
+
"label": "Pin to dashboard",
|
|
3224
|
+
"prompt": "Pin that funnel to my main dashboard."
|
|
3225
|
+
}
|
|
3226
|
+
],
|
|
3227
|
+
"query-retention": [
|
|
3228
|
+
{
|
|
3229
|
+
"label": "Best-retaining cohort",
|
|
3230
|
+
"prompt": "Which cohort retains the longest in that curve?"
|
|
3231
|
+
},
|
|
3232
|
+
{
|
|
3233
|
+
"label": "Worst-retaining cohort",
|
|
3234
|
+
"prompt": "Which cohort drops off fastest in that curve?"
|
|
3235
|
+
},
|
|
3236
|
+
{
|
|
3237
|
+
"label": "Slice by acquisition channel",
|
|
3238
|
+
"prompt": "Re-run that retention split by acquisition channel."
|
|
3239
|
+
},
|
|
3240
|
+
{
|
|
3241
|
+
"label": "Find churned users",
|
|
3242
|
+
"prompt": "Find session recordings of users who churned during week 1."
|
|
3243
|
+
},
|
|
3244
|
+
{
|
|
3245
|
+
"label": "Save the retention chart",
|
|
3246
|
+
"prompt": "Save that retention chart as an insight."
|
|
3247
|
+
},
|
|
3248
|
+
{
|
|
3249
|
+
"label": "Pin to growth dashboard",
|
|
3250
|
+
"prompt": "Pin that retention chart to my growth dashboard."
|
|
3251
|
+
}
|
|
3252
|
+
],
|
|
3253
|
+
"query-feature-flag": [
|
|
3254
|
+
{
|
|
3255
|
+
"label": "Who's in this flag?",
|
|
3256
|
+
"prompt": "Show me which users are currently in the rollout for that flag."
|
|
3257
|
+
},
|
|
3258
|
+
{
|
|
3259
|
+
"label": "What changed recently?",
|
|
3260
|
+
"prompt": "Show me the rollout history for that flag — when did it last change?"
|
|
3261
|
+
},
|
|
3262
|
+
{
|
|
3263
|
+
"label": "Compare against another flag",
|
|
3264
|
+
"prompt": "Show me the audience overlap between that flag and one related flag."
|
|
3265
|
+
},
|
|
3266
|
+
{
|
|
3267
|
+
"label": "Find sessions for that flag",
|
|
3268
|
+
"prompt": "Find recent session recordings from users currently in that flag."
|
|
3269
|
+
},
|
|
3270
|
+
{
|
|
3271
|
+
"label": "Save flag inventory",
|
|
3272
|
+
"prompt": "Save this flag inventory as an insight."
|
|
3273
|
+
},
|
|
3274
|
+
{
|
|
3275
|
+
"label": "Pin to release dashboard",
|
|
3276
|
+
"prompt": "Pin this flag view to my release dashboard."
|
|
3277
|
+
}
|
|
3278
|
+
],
|
|
3279
|
+
"query-survey-responses": [
|
|
3280
|
+
{
|
|
3281
|
+
"label": "Summarize the themes",
|
|
3282
|
+
"prompt": "Summarize the themes from those survey responses."
|
|
3283
|
+
},
|
|
3284
|
+
{
|
|
3285
|
+
"label": "Score distribution",
|
|
3286
|
+
"prompt": "Show me the score distribution across those responses."
|
|
3287
|
+
},
|
|
3288
|
+
{
|
|
3289
|
+
"label": "Who are the detractors?",
|
|
3290
|
+
"prompt": "Show me users who left a low score and what they did next."
|
|
3291
|
+
},
|
|
3292
|
+
{
|
|
3293
|
+
"label": "Find their sessions",
|
|
3294
|
+
"prompt": "Find session recordings from users who left a low score."
|
|
3295
|
+
},
|
|
3296
|
+
{
|
|
3297
|
+
"label": "Save the response summary",
|
|
3298
|
+
"prompt": "Save this response summary as an insight."
|
|
3299
|
+
},
|
|
3300
|
+
{
|
|
3301
|
+
"label": "Add to research notebook",
|
|
3302
|
+
"prompt": "Add this survey summary to my user research notebook."
|
|
3303
|
+
}
|
|
3304
|
+
],
|
|
3305
|
+
"query-experiment": [
|
|
3306
|
+
{
|
|
3307
|
+
"label": "Which variant is winning?",
|
|
3308
|
+
"prompt": "Show me the conversion rate of each variant in that experiment."
|
|
3309
|
+
},
|
|
3310
|
+
{
|
|
3311
|
+
"label": "Slice by segment",
|
|
3312
|
+
"prompt": "Show me how each variant performed by user segment."
|
|
3313
|
+
},
|
|
3314
|
+
{
|
|
3315
|
+
"label": "Statistical significance",
|
|
3316
|
+
"prompt": "Has that experiment reached statistical significance yet?"
|
|
3317
|
+
},
|
|
3318
|
+
{
|
|
3319
|
+
"label": "Find variant sessions",
|
|
3320
|
+
"prompt": "Find session recordings from users in the winning variant."
|
|
3321
|
+
},
|
|
3322
|
+
{
|
|
3323
|
+
"label": "Save the readout",
|
|
3324
|
+
"prompt": "Save that experiment readout as an insight."
|
|
3325
|
+
},
|
|
3326
|
+
{
|
|
3327
|
+
"label": "Add to experiment notebook",
|
|
3328
|
+
"prompt": "Add this experiment readout to my experiments notebook."
|
|
3329
|
+
}
|
|
3330
|
+
],
|
|
3331
|
+
"query-session-recordings-list": [
|
|
3332
|
+
{
|
|
3333
|
+
"label": "Summarize what users did",
|
|
3334
|
+
"prompt": "Summarize what users did in those sessions."
|
|
3335
|
+
},
|
|
3336
|
+
{
|
|
3337
|
+
"label": "Find common drop-offs",
|
|
3338
|
+
"prompt": "What's the most common step where users got stuck in those sessions?"
|
|
3339
|
+
},
|
|
3340
|
+
{
|
|
3341
|
+
"label": "Errors in those sessions",
|
|
3342
|
+
"prompt": "Which errors fired most often across those sessions?"
|
|
3343
|
+
},
|
|
3344
|
+
{
|
|
3345
|
+
"label": "Properties of those users",
|
|
3346
|
+
"prompt": "Show me the most common user properties across those sessions."
|
|
3347
|
+
},
|
|
3348
|
+
{
|
|
3349
|
+
"label": "Save the session summary",
|
|
3350
|
+
"prompt": "Save the summary of those sessions as an insight."
|
|
3351
|
+
},
|
|
3352
|
+
{
|
|
3353
|
+
"label": "Add to UX notebook",
|
|
3354
|
+
"prompt": "Add these session findings to my UX research notebook."
|
|
3355
|
+
}
|
|
3356
|
+
],
|
|
3357
|
+
"execute-sql": [
|
|
3358
|
+
{
|
|
3359
|
+
"label": "Add p50/p90/p99",
|
|
3360
|
+
"prompt": "Re-run that query with p50/p90/p99 added."
|
|
3361
|
+
},
|
|
3362
|
+
{
|
|
3363
|
+
"label": "Slice differently",
|
|
3364
|
+
"prompt": "Re-run that query grouped by the most common user property."
|
|
3365
|
+
},
|
|
3366
|
+
{
|
|
3367
|
+
"label": "Find the outliers",
|
|
3368
|
+
"prompt": "Re-run that query and surface the top 5 outliers."
|
|
3369
|
+
},
|
|
3370
|
+
{
|
|
3371
|
+
"label": "Compare to last week",
|
|
3372
|
+
"prompt": "Compare that query result to the same window last week."
|
|
3373
|
+
},
|
|
3374
|
+
{
|
|
3375
|
+
"label": "Save as an insight",
|
|
3376
|
+
"prompt": "Turn that query result into a saved insight."
|
|
3377
|
+
},
|
|
3378
|
+
{
|
|
3379
|
+
"label": "Pin to data dashboard",
|
|
3380
|
+
"prompt": "Pin that query result to my data dashboard."
|
|
3381
|
+
}
|
|
3382
|
+
],
|
|
3383
|
+
"create-dashboard": [
|
|
3384
|
+
{
|
|
3385
|
+
"label": "Add another tile",
|
|
3386
|
+
"prompt": "Add a tile showing daily active users to that dashboard."
|
|
3387
|
+
},
|
|
3388
|
+
{
|
|
3389
|
+
"label": "Add a leaderboard tile",
|
|
3390
|
+
"prompt": "Add a top-5 users tile to that dashboard."
|
|
3391
|
+
},
|
|
3392
|
+
{
|
|
3393
|
+
"label": "Annotate today",
|
|
3394
|
+
"prompt": "Annotate today on that dashboard as the launch baseline."
|
|
3395
|
+
},
|
|
3396
|
+
{
|
|
3397
|
+
"label": "Compare to last quarter",
|
|
3398
|
+
"prompt": "Add a tile comparing this quarter to the last on the same dashboard."
|
|
3399
|
+
},
|
|
3400
|
+
{
|
|
3401
|
+
"label": "Add an errors tile",
|
|
3402
|
+
"prompt": "Add a tile showing the top 3 errors this week to that dashboard."
|
|
3403
|
+
},
|
|
3404
|
+
{
|
|
3405
|
+
"label": "Add to dashboards notebook",
|
|
3406
|
+
"prompt": "Add a link to that dashboard in my dashboards notebook."
|
|
3407
|
+
}
|
|
3408
|
+
],
|
|
3409
|
+
"create-insight": [
|
|
3410
|
+
{
|
|
3411
|
+
"label": "Pin to main dashboard",
|
|
3412
|
+
"prompt": "Pin that insight to my main dashboard."
|
|
3413
|
+
},
|
|
3414
|
+
{
|
|
3415
|
+
"label": "Split by user property",
|
|
3416
|
+
"prompt": "Re-run that insight split by the most common user property."
|
|
3417
|
+
},
|
|
3418
|
+
{
|
|
3419
|
+
"label": "Compare to a control",
|
|
3420
|
+
"prompt": "Re-run that insight comparing paid vs free users side-by-side."
|
|
3421
|
+
},
|
|
3422
|
+
{
|
|
3423
|
+
"label": "Save the underlying query",
|
|
3424
|
+
"prompt": "Save the underlying query for that insight so I can edit it later."
|
|
3425
|
+
},
|
|
3426
|
+
{
|
|
3427
|
+
"label": "Add to notebook",
|
|
3428
|
+
"prompt": "Add that insight to my analytics notebook."
|
|
3429
|
+
},
|
|
3430
|
+
{
|
|
3431
|
+
"label": "Annotate the moment",
|
|
3432
|
+
"prompt": "Annotate today on the chart for that insight."
|
|
3433
|
+
}
|
|
3434
|
+
]
|
|
3435
|
+
};
|
|
3436
|
+
var roleFollowUps = {
|
|
3437
|
+
"founder": [
|
|
3438
|
+
{
|
|
3439
|
+
"label": "Pin to exec dashboard",
|
|
3440
|
+
"prompt": "Add that result to my exec dashboard."
|
|
3441
|
+
},
|
|
3442
|
+
{
|
|
3443
|
+
"label": "Tie it to revenue",
|
|
3444
|
+
"prompt": "How does that correlate with paid conversions?"
|
|
3445
|
+
},
|
|
3446
|
+
{
|
|
3447
|
+
"label": "Compare to last quarter",
|
|
3448
|
+
"prompt": "How does that compare against the same period last quarter?"
|
|
3449
|
+
},
|
|
3450
|
+
{
|
|
3451
|
+
"label": "Save for board update",
|
|
3452
|
+
"prompt": "Save that as an insight I can attach to the next board update."
|
|
3453
|
+
}
|
|
3454
|
+
],
|
|
3455
|
+
"product": [
|
|
3456
|
+
{
|
|
3457
|
+
"label": "Build a funnel around it",
|
|
3458
|
+
"prompt": "Build a funnel that includes that step."
|
|
3459
|
+
},
|
|
3460
|
+
{
|
|
3461
|
+
"label": "Find high-intent users",
|
|
3462
|
+
"prompt": "Show me which users in that group also completed activation."
|
|
3463
|
+
},
|
|
3464
|
+
{
|
|
3465
|
+
"label": "Check related experiments",
|
|
3466
|
+
"prompt": "Show me how this metric trended across my recent experiments."
|
|
3467
|
+
},
|
|
3468
|
+
{
|
|
3469
|
+
"label": "Save to product notebook",
|
|
3470
|
+
"prompt": "Add this finding to my product analytics notebook."
|
|
3471
|
+
}
|
|
3472
|
+
],
|
|
3473
|
+
"leadership": [
|
|
3474
|
+
{
|
|
3475
|
+
"label": "Compare to last quarter",
|
|
3476
|
+
"prompt": "How does that compare against the same period last quarter?"
|
|
3477
|
+
},
|
|
3478
|
+
{
|
|
3479
|
+
"label": "Pin to leadership dashboard",
|
|
3480
|
+
"prompt": "Pin this view to my leadership dashboard."
|
|
3481
|
+
},
|
|
3482
|
+
{
|
|
3483
|
+
"label": "Save for next meeting",
|
|
3484
|
+
"prompt": "Save this as an insight I can pull up in the next leadership meeting."
|
|
3485
|
+
}
|
|
3486
|
+
],
|
|
3487
|
+
"marketing": [
|
|
3488
|
+
{
|
|
3489
|
+
"label": "Annotate the launch",
|
|
3490
|
+
"prompt": "Annotate today as the campaign launch on that chart."
|
|
3491
|
+
},
|
|
3492
|
+
{
|
|
3493
|
+
"label": "What did they do next?",
|
|
3494
|
+
"prompt": "Show me what users in that group did next."
|
|
3495
|
+
},
|
|
3496
|
+
{
|
|
3497
|
+
"label": "Tie back to channel",
|
|
3498
|
+
"prompt": "Split that result by acquisition channel."
|
|
3499
|
+
},
|
|
3500
|
+
{
|
|
3501
|
+
"label": "Compare to landing tests",
|
|
3502
|
+
"prompt": "Compare this result across my recent landing-page experiments."
|
|
3503
|
+
}
|
|
3504
|
+
],
|
|
3505
|
+
"engineering": [
|
|
3506
|
+
{
|
|
3507
|
+
"label": "Did a deploy land?",
|
|
3508
|
+
"prompt": "Did that change land alongside a deploy in the last 24 hours?"
|
|
3509
|
+
},
|
|
3510
|
+
{
|
|
3511
|
+
"label": "Flag changes that fit",
|
|
3512
|
+
"prompt": "Show me which feature flag changes correlate with that change in metric."
|
|
3513
|
+
},
|
|
3514
|
+
{
|
|
3515
|
+
"label": "Group by release",
|
|
3516
|
+
"prompt": "Re-run that broken down by app version or release."
|
|
3517
|
+
},
|
|
3518
|
+
{
|
|
3519
|
+
"label": "Save to incident notebook",
|
|
3520
|
+
"prompt": "Save this analysis to my incident notebook."
|
|
3521
|
+
}
|
|
3522
|
+
],
|
|
3523
|
+
"data": [
|
|
3524
|
+
{
|
|
3525
|
+
"label": "Add percentiles",
|
|
3526
|
+
"prompt": "Add p50/p90/p99 distributions to that result."
|
|
3527
|
+
},
|
|
3528
|
+
{
|
|
3529
|
+
"label": "Compare to last month",
|
|
3530
|
+
"prompt": "Show me how that result trended over the last month."
|
|
3531
|
+
},
|
|
3532
|
+
{
|
|
3533
|
+
"label": "Save as an insight",
|
|
3534
|
+
"prompt": "Save that query result as an insight."
|
|
3535
|
+
},
|
|
3536
|
+
{
|
|
3537
|
+
"label": "Pin to data dashboard",
|
|
3538
|
+
"prompt": "Pin this result to my data team dashboard."
|
|
3539
|
+
}
|
|
3540
|
+
]
|
|
3541
|
+
};
|
|
3542
|
+
var genericFollowUps = [
|
|
3543
|
+
{
|
|
3544
|
+
"label": "Go one level deeper",
|
|
3545
|
+
"prompt": "Run that same question one level deeper."
|
|
3546
|
+
},
|
|
3547
|
+
{
|
|
3548
|
+
"label": "Take a different angle",
|
|
3549
|
+
"prompt": "Look at the same question from a completely different angle."
|
|
3550
|
+
},
|
|
3551
|
+
{
|
|
3552
|
+
"label": "Find the surprise",
|
|
3553
|
+
"prompt": "What's the most surprising thing in that result?"
|
|
3554
|
+
},
|
|
3555
|
+
{
|
|
3556
|
+
"label": "Slice by user",
|
|
3557
|
+
"prompt": "Re-run that split by the highest-value user segment."
|
|
3558
|
+
},
|
|
3559
|
+
{
|
|
3560
|
+
"label": "Compare with last month",
|
|
3561
|
+
"prompt": "How does that look compared to the same window a month ago?"
|
|
3562
|
+
},
|
|
3563
|
+
{
|
|
3564
|
+
"label": "Save as an insight",
|
|
3565
|
+
"prompt": "Save that result as an insight I can come back to."
|
|
3566
|
+
},
|
|
3567
|
+
{
|
|
3568
|
+
"label": "Pin to a dashboard",
|
|
3569
|
+
"prompt": "Pin this view to my main dashboard."
|
|
3570
|
+
},
|
|
3571
|
+
{
|
|
3572
|
+
"label": "Add to a notebook",
|
|
3573
|
+
"prompt": "Add this finding to my notebook."
|
|
3574
|
+
}
|
|
3575
|
+
];
|
|
3576
|
+
var deepDiveFollowUps = [
|
|
3577
|
+
{
|
|
3578
|
+
"label": "Save this exploration",
|
|
3579
|
+
"prompt": "Save the most useful chart from this session as a dashboard I can come back to."
|
|
3580
|
+
},
|
|
3581
|
+
{
|
|
3582
|
+
"label": "Summarize what we found",
|
|
3583
|
+
"prompt": "Summarize the key findings from everything we just looked at in 3 bullets."
|
|
3584
|
+
},
|
|
3585
|
+
{
|
|
3586
|
+
"label": "Pin a session summary",
|
|
3587
|
+
"prompt": "Pin a summary of this session to my main dashboard."
|
|
3588
|
+
},
|
|
3589
|
+
{
|
|
3590
|
+
"label": "Write to a notebook",
|
|
3591
|
+
"prompt": "Write everything we just covered into a notebook entry I can revisit."
|
|
3592
|
+
}
|
|
3593
|
+
];
|
|
3594
|
+
var crossSellByRole = {
|
|
3595
|
+
"founder": [{
|
|
3596
|
+
"product": "Session Replay",
|
|
3597
|
+
"prompt": "Find 3 recent sessions where a user looked at pricing but did not sign up.",
|
|
3598
|
+
"description": "Watch what users see — replay turns funnel drop-offs into video."
|
|
3599
|
+
}, {
|
|
3600
|
+
"product": "Surveys",
|
|
3601
|
+
"prompt": "Show me how my NPS results have trended over the last quarter.",
|
|
3602
|
+
"description": "Quantitative pulse check on the survey side of PostHog."
|
|
3603
|
+
}],
|
|
3604
|
+
"product": [{
|
|
3605
|
+
"product": "Experiments",
|
|
3606
|
+
"prompt": "Show me results from my latest onboarding experiment — which variant is winning?",
|
|
3607
|
+
"description": "Experiments piggyback on flags — same SDK, all readable here."
|
|
3608
|
+
}, {
|
|
3609
|
+
"product": "Session Replay",
|
|
3610
|
+
"prompt": "Find sessions where users got stuck on the empty state in onboarding.",
|
|
3611
|
+
"description": "See what funnels can't show you."
|
|
3612
|
+
}],
|
|
3613
|
+
"leadership": [{
|
|
3614
|
+
"product": "Surveys",
|
|
3615
|
+
"prompt": "Show me NPS scores from the last quarter — who are the detractors?",
|
|
3616
|
+
"description": "Read the survey data PostHog already collects for you."
|
|
3617
|
+
}, {
|
|
3618
|
+
"product": "Data Warehouse",
|
|
3619
|
+
"prompt": "Compare MRR by signup source using Stripe data joined with event data.",
|
|
3620
|
+
"description": "Query revenue alongside events when warehouse is connected."
|
|
3621
|
+
}],
|
|
3622
|
+
"marketing": [{
|
|
3623
|
+
"product": "Session Replay",
|
|
3624
|
+
"prompt": "Watch 5 sessions from users who came via our last campaign and converted.",
|
|
3625
|
+
"description": "See campaign visitors behave — beyond aggregate numbers."
|
|
3626
|
+
}, {
|
|
3627
|
+
"product": "Web Analytics",
|
|
3628
|
+
"prompt": "Show me top traffic sources to the pricing page this week.",
|
|
3629
|
+
"description": "GA-style first-party web analytics, no cookie banner."
|
|
3630
|
+
}],
|
|
3631
|
+
"engineering": [{
|
|
3632
|
+
"product": "Error Tracking",
|
|
3633
|
+
"prompt": "Show me the top 5 errors this week and who is affected.",
|
|
3634
|
+
"description": "Built-in error tracking — no Sentry subscription."
|
|
3635
|
+
}, {
|
|
3636
|
+
"product": "Session Replay",
|
|
3637
|
+
"prompt": "Replay the last 3 sessions that hit a 5xx error.",
|
|
3638
|
+
"description": "Stack trace meets replay — see what the user did."
|
|
3639
|
+
}],
|
|
3640
|
+
"data": [{
|
|
3641
|
+
"product": "Data Warehouse",
|
|
3642
|
+
"prompt": "Join my event stream with Stripe subscriptions to surface churn signals.",
|
|
3643
|
+
"description": "Connect Stripe / Salesforce / S3, query everything with SQL."
|
|
3644
|
+
}, {
|
|
3645
|
+
"product": "LLM Observability",
|
|
3646
|
+
"prompt": "Show me the top 5 LLM prompts by cost over the last 7 days.",
|
|
3647
|
+
"description": "Track LLM calls, latency, and cost next to product events."
|
|
3648
|
+
}]
|
|
3649
|
+
};
|
|
3650
|
+
var neutralCrossSell = [{
|
|
3651
|
+
"product": "Session Replay",
|
|
3652
|
+
"prompt": "Show me 5 recent sessions where users dropped off before completing signup.",
|
|
3653
|
+
"description": "Replay what users actually do — included on every plan."
|
|
3654
|
+
}, {
|
|
3655
|
+
"product": "Error Tracking",
|
|
3656
|
+
"prompt": "List the top errors my users hit this week.",
|
|
3657
|
+
"description": "Built-in error tracking — no separate tool."
|
|
3658
|
+
}];
|
|
3659
|
+
//#endregion
|
|
3660
|
+
//#region src/lib/mcp-role-prompts.ts
|
|
3661
|
+
/**
|
|
3662
|
+
* Roles that ship from `role_at_organization` on the PostHog user object.
|
|
3663
|
+
* `security` isn't in the enum upstream — the engineering kit covers
|
|
3664
|
+
* that audience.
|
|
3665
|
+
*/
|
|
3666
|
+
const TAILORED_ROLES = [
|
|
3667
|
+
"founder",
|
|
3668
|
+
"product",
|
|
3669
|
+
"leadership",
|
|
3670
|
+
"marketing",
|
|
3671
|
+
"engineering",
|
|
3672
|
+
"data"
|
|
3673
|
+
];
|
|
3674
|
+
const FOLLOW_UP_EXIT_SENTINEL = "__follow_up_exit__";
|
|
3675
|
+
/**
|
|
3676
|
+
* Always shown as the picker's first option regardless of role —
|
|
3677
|
+
* a safe generic read that works on any project setup. The screen
|
|
3678
|
+
* prepends it and dedupes against the role kit so it never appears
|
|
3679
|
+
* twice when DEFAULT_KIT happens to include it.
|
|
3680
|
+
*/
|
|
3681
|
+
const PINNED_FIRST_PROMPT = pinnedFirstPrompt;
|
|
3682
|
+
const DEFAULT_KIT = defaultKit;
|
|
3683
|
+
const ROLE_KITS = roleKits;
|
|
3684
|
+
const ROLE_FAMILY_OVERRIDES = roleFamilyOverrides;
|
|
3685
|
+
const ROLE_GREETINGS = roleGreetings;
|
|
3686
|
+
const NEUTRAL_GREETING = neutralGreeting;
|
|
3687
|
+
const TOOL_FOLLOW_UPS = toolFollowUps;
|
|
3688
|
+
const ROLE_FOLLOW_UPS = roleFollowUps;
|
|
3689
|
+
const GENERIC_FOLLOW_UPS = genericFollowUps;
|
|
3690
|
+
const DEEP_DIVE_FOLLOW_UPS = deepDiveFollowUps;
|
|
3691
|
+
const CROSS_SELL_BY_ROLE = crossSellByRole;
|
|
3692
|
+
const NEUTRAL_CROSS_SELL = neutralCrossSell;
|
|
3693
|
+
const INTEGRATION_FAMILY = {
|
|
3694
|
+
nextjs: "fullstack",
|
|
3695
|
+
nuxt: "fullstack",
|
|
3696
|
+
"tanstack-start": "fullstack",
|
|
3697
|
+
astro: "fullstack",
|
|
3698
|
+
sveltekit: "fullstack",
|
|
3699
|
+
vue: "frontend-web",
|
|
3700
|
+
angular: "frontend-web",
|
|
3701
|
+
"react-router": "frontend-web",
|
|
3702
|
+
"tanstack-router": "frontend-web",
|
|
3703
|
+
javascript_web: "frontend-web",
|
|
3704
|
+
"react-native": "mobile",
|
|
3705
|
+
swift: "mobile",
|
|
3706
|
+
android: "mobile",
|
|
3707
|
+
django: "backend",
|
|
3708
|
+
flask: "backend",
|
|
3709
|
+
fastapi: "backend",
|
|
3710
|
+
python: "backend",
|
|
3711
|
+
laravel: "backend",
|
|
3712
|
+
rails: "backend",
|
|
3713
|
+
ruby: "backend",
|
|
3714
|
+
javascript_node: "backend"
|
|
3715
|
+
};
|
|
3716
|
+
const EXIT_FOLLOW_UP = {
|
|
3717
|
+
label: "I'm done — exit",
|
|
3718
|
+
prompt: FOLLOW_UP_EXIT_SENTINEL
|
|
3719
|
+
};
|
|
3720
|
+
function isTailoredRole(role) {
|
|
3721
|
+
return typeof role === "string" && TAILORED_ROLES.includes(role);
|
|
3722
|
+
}
|
|
3723
|
+
/**
|
|
3724
|
+
* Strip MCP tool-name prefixes so lookup keys can stay short. Real MCP
|
|
3725
|
+
* tool names arrive as `mcp__<server>__<tool>`; the agent SDK also
|
|
3726
|
+
* sometimes drops the prefix. We take the substring after the last
|
|
3727
|
+
* double-underscore (or the input untouched if there's none).
|
|
3728
|
+
*/
|
|
3729
|
+
function normalizeToolName(toolName) {
|
|
3730
|
+
if (!toolName) return null;
|
|
3731
|
+
const idx = toolName.lastIndexOf("__");
|
|
3732
|
+
return idx >= 0 ? toolName.slice(idx + 2) : toolName;
|
|
3733
|
+
}
|
|
3734
|
+
/** Pick `n` items from a pool starting at a rotation offset. */
|
|
3735
|
+
function pickRotated(pool, n, rotation) {
|
|
3736
|
+
if (pool.length === 0) return [];
|
|
3737
|
+
if (pool.length <= n) return pool;
|
|
3738
|
+
const start = (Math.floor(rotation) % pool.length + pool.length) % pool.length;
|
|
3739
|
+
const result = [];
|
|
3740
|
+
for (let i = 0; i < n; i++) result.push(pool[(start + i) % pool.length]);
|
|
3741
|
+
return result;
|
|
3742
|
+
}
|
|
3743
|
+
/** Drop duplicates while preserving order (by prompt text). */
|
|
3744
|
+
function dedupeFollowUps(list) {
|
|
3745
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3746
|
+
const out = [];
|
|
3747
|
+
for (const f of list) {
|
|
3748
|
+
if (seen.has(f.prompt)) continue;
|
|
3749
|
+
seen.add(f.prompt);
|
|
3750
|
+
out.push(f);
|
|
3751
|
+
}
|
|
3752
|
+
return out;
|
|
3753
|
+
}
|
|
3754
|
+
function getFrameworkFamily(integration) {
|
|
3755
|
+
if (!integration) return "unknown";
|
|
3756
|
+
return INTEGRATION_FAMILY[integration] ?? "unknown";
|
|
3757
|
+
}
|
|
3758
|
+
/**
|
|
3759
|
+
* Resolve the right kit given everything we know about the user + project.
|
|
3760
|
+
* Always returns at least DEFAULT_KIT; never throws.
|
|
3761
|
+
*/
|
|
3762
|
+
function getRolePrompts(role, integration) {
|
|
3763
|
+
const family = getFrameworkFamily(integration);
|
|
3764
|
+
if (!isTailoredRole(role)) return DEFAULT_KIT;
|
|
3765
|
+
const baseKit = ROLE_KITS[role];
|
|
3766
|
+
const overridesForFamily = ROLE_FAMILY_OVERRIDES[role]?.[family];
|
|
3767
|
+
if (!overridesForFamily) return baseKit;
|
|
3768
|
+
return baseKit.map((entry) => {
|
|
3769
|
+
return (entry.key ? overridesForFamily[entry.key] : void 0) ?? entry;
|
|
3770
|
+
});
|
|
3771
|
+
}
|
|
3772
|
+
function getRoleGreeting(role) {
|
|
3773
|
+
if (!isTailoredRole(role)) return NEUTRAL_GREETING;
|
|
3774
|
+
return ROLE_GREETINGS[role];
|
|
3775
|
+
}
|
|
3776
|
+
/**
|
|
3777
|
+
* Resolve `FOLLOW_UP_COUNT` context-aware follow-ups + an always-present
|
|
3778
|
+
* exit entry. Pulls from up to four pools — tool-specific, role-specific,
|
|
3779
|
+
* deep-dive (only after the user has explored a few steps), and generic —
|
|
3780
|
+
* dedupes, filters out anything already in `branchHistory`, then picks
|
|
3781
|
+
* `FOLLOW_UP_COUNT` with a rotation offset driven by `branchHistory.length`
|
|
3782
|
+
* so successive visits surface different slices.
|
|
3783
|
+
*/
|
|
3784
|
+
function getFollowUps(args) {
|
|
3785
|
+
const { lastToolName, role, branchHistory } = args;
|
|
3786
|
+
const normalized = normalizeToolName(lastToolName);
|
|
3787
|
+
const depth = branchHistory.length;
|
|
3788
|
+
const candidates = [];
|
|
3789
|
+
if (normalized && TOOL_FOLLOW_UPS[normalized]) candidates.push(...TOOL_FOLLOW_UPS[normalized]);
|
|
3790
|
+
if (isTailoredRole(role)) candidates.push(...ROLE_FOLLOW_UPS[role]);
|
|
3791
|
+
if (depth >= 3) candidates.push(...DEEP_DIVE_FOLLOW_UPS);
|
|
3792
|
+
candidates.push(...GENERIC_FOLLOW_UPS);
|
|
3793
|
+
const deduped = dedupeFollowUps(candidates);
|
|
3794
|
+
const seen = new Set(branchHistory);
|
|
3795
|
+
return [...pickRotated(deduped.filter((f) => !seen.has(f.prompt)), 3, depth), EXIT_FOLLOW_UP];
|
|
3796
|
+
}
|
|
3797
|
+
/**
|
|
3798
|
+
* Cross-sell prompts to surface above the role kit in PromptPicker.
|
|
3799
|
+
* Filtered by role so the recommendations stay coherent (founders see
|
|
3800
|
+
* the "exec-friendly" cross-sells, engineers see "debug-friendly", etc).
|
|
3801
|
+
*/
|
|
3802
|
+
function getCrossSellPrompts(role) {
|
|
3803
|
+
if (!isTailoredRole(role)) return NEUTRAL_CROSS_SELL;
|
|
3804
|
+
return CROSS_SELL_BY_ROLE[role];
|
|
3805
|
+
}
|
|
3806
|
+
//#endregion
|
|
3807
|
+
//#region src/ui/tui/screens/McpSuggestedPromptsScreen.tsx
|
|
3808
|
+
/**
|
|
3809
|
+
* McpSuggestedPromptsScreen — shown after MCP install succeeds in the
|
|
3810
|
+
* standalone `wizard mcp add` program, and as the entry point for
|
|
3811
|
+
* `wizard mcp tutorial`.
|
|
3812
|
+
*
|
|
3813
|
+
* Phases:
|
|
3814
|
+
* 1. Choose — opens with a Log in / Exit picker, framed by a
|
|
3815
|
+
* teaser of what MCP can do.
|
|
3816
|
+
* 2. Authenticating — runs `services.performLogin()` (OAuth in
|
|
3817
|
+
* production, canned values in the playground).
|
|
3818
|
+
* Renders a spinner + login URL inline while the
|
|
3819
|
+
* promise is pending. Errors return to Choose
|
|
3820
|
+
* with an inline error line.
|
|
3821
|
+
* 3. Greeting — role-tuned welcome via `getRoleGreeting`. A
|
|
3822
|
+
* ContentSequencer animates the headline,
|
|
3823
|
+
* bullets, and outro, then hands off to
|
|
3824
|
+
* PromptPicker. Only fires once per session
|
|
3825
|
+
* (returning via `[p]` skips it).
|
|
3826
|
+
* 4. PromptPicker — lists the role-tailored kit from
|
|
3827
|
+
* `getRolePrompts`; user picks one to run.
|
|
3828
|
+
* 5. Running — streams the agent's response inline via
|
|
3829
|
+
* `services.runPromptStreaming`. Text chunks
|
|
3830
|
+
* typewrite in; tool calls and results render
|
|
3831
|
+
* as styled badges. `[esc]` aborts; `[p]`
|
|
3832
|
+
* returns to the picker. On `done`/`error`,
|
|
3833
|
+
* auto-advances to FollowUp.
|
|
3834
|
+
* 6. FollowUp — surfaces 3 context-aware next prompts inferred
|
|
3835
|
+
* from the last tool the agent used (via
|
|
3836
|
+
* `getFollowUps`), plus an explicit exit.
|
|
3837
|
+
* Picking a follow-up re-enters Running; the
|
|
3838
|
+
* conversation tree grows as deep as
|
|
3839
|
+
* MAX_PROMPT_RUNS allows.
|
|
3840
|
+
*
|
|
3841
|
+
* Credentials are guaranteed non-null once Greeting / PromptPicker /
|
|
3842
|
+
* Running / FollowUp are reached (the Choose → Authenticating gate
|
|
3843
|
+
* forces a successful login first). A defensive throw protects the
|
|
3844
|
+
* Running useEffect against a state-machine bug.
|
|
3845
|
+
*/
|
|
3846
|
+
const MAX_PROMPT_RUNS = 5;
|
|
3847
|
+
const FOLLOW_UP_DELAY_MS = 3e3;
|
|
3848
|
+
const McpSuggestedPromptsScreen = ({ store, services }) => {
|
|
3849
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
3850
|
+
const session = store.session;
|
|
3851
|
+
const kit = getRolePrompts(session.roleAtOrganization, session.integration);
|
|
3852
|
+
const crossSell = useMemo(() => getCrossSellPrompts(session.roleAtOrganization), [session.roleAtOrganization]);
|
|
3853
|
+
const greeting = useMemo(() => getRoleGreeting(session.roleAtOrganization), [session.roleAtOrganization]);
|
|
3854
|
+
const [phase, setPhase] = useState("choose");
|
|
3855
|
+
const [loginError, setLoginError] = useState(null);
|
|
3856
|
+
const [runningPrompt, setRunningPrompt] = useState(null);
|
|
3857
|
+
const [runChunks, setRunChunks] = useState([]);
|
|
3858
|
+
const [runStartedAt, setRunStartedAt] = useState(null);
|
|
3859
|
+
const [runDurationSecs, setRunDurationSecs] = useState(null);
|
|
3860
|
+
const [runCount, setRunCount] = useState(0);
|
|
3861
|
+
const canPickAnother = runCount < MAX_PROMPT_RUNS;
|
|
3862
|
+
const [lastToolName, setLastToolName] = useState(null);
|
|
3863
|
+
const [branchHistory, setBranchHistory] = useState([]);
|
|
3864
|
+
const runAbortRef = useRef(null);
|
|
3865
|
+
const currentSessionIdRef = useRef(null);
|
|
3866
|
+
useEffect(() => {
|
|
3867
|
+
if (phase !== "authenticating") return;
|
|
3868
|
+
let cancelled = false;
|
|
3869
|
+
(async () => {
|
|
3870
|
+
try {
|
|
3871
|
+
const { credentials, roleAtOrganization, user } = await services.performLogin();
|
|
3872
|
+
if (cancelled) return;
|
|
3873
|
+
store.setCredentials(credentials);
|
|
3874
|
+
store.setRoleAtOrganization(roleAtOrganization);
|
|
3875
|
+
store.setApiUser(user);
|
|
3876
|
+
store.setLoginUrl(null);
|
|
3877
|
+
setPhase("greeting");
|
|
3878
|
+
} catch (err) {
|
|
3879
|
+
if (cancelled) return;
|
|
3880
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3881
|
+
logToFile(`[McpSuggestedPromptsScreen] login failed: ${message}`);
|
|
3882
|
+
store.setLoginUrl(null);
|
|
3883
|
+
setLoginError(message);
|
|
3884
|
+
setPhase("choose");
|
|
3885
|
+
}
|
|
3886
|
+
})();
|
|
3887
|
+
return () => {
|
|
3888
|
+
cancelled = true;
|
|
3889
|
+
};
|
|
3890
|
+
}, [
|
|
3891
|
+
phase,
|
|
3892
|
+
services,
|
|
3893
|
+
store
|
|
3894
|
+
]);
|
|
3895
|
+
useEffect(() => {
|
|
3896
|
+
if (phase !== "running") return;
|
|
3897
|
+
if (!runningPrompt) return;
|
|
3898
|
+
if (!session.credentials) throw new Error("[McpSuggestedPromptsScreen] Running phase reached without credentials. The Choose gate should have prevented this.");
|
|
3899
|
+
const controller = new AbortController();
|
|
3900
|
+
runAbortRef.current = controller;
|
|
3901
|
+
const startedAt = Date.now();
|
|
3902
|
+
setRunStartedAt(startedAt);
|
|
3903
|
+
setRunChunks([]);
|
|
3904
|
+
setLastToolName(null);
|
|
3905
|
+
setRunDurationSecs(null);
|
|
3906
|
+
const finishStream = (kind, durationMs, errorText) => {
|
|
3907
|
+
if (controller.signal.aborted) return;
|
|
3908
|
+
setRunDurationSecs(Math.round(durationMs / 1e3));
|
|
3909
|
+
if (kind === "done") analytics.wizardCapture("mcp suggested prompts run", {
|
|
3910
|
+
prompt: runningPrompt,
|
|
3911
|
+
durationMs
|
|
3912
|
+
});
|
|
3913
|
+
else analytics.wizardCapture("mcp suggested prompts run failed", {
|
|
3914
|
+
prompt: runningPrompt,
|
|
3915
|
+
error: errorText
|
|
3916
|
+
});
|
|
3917
|
+
setTimeout(() => {
|
|
3918
|
+
if (controller.signal.aborted) return;
|
|
3919
|
+
setPhase("follow-up");
|
|
3920
|
+
}, FOLLOW_UP_DELAY_MS);
|
|
3921
|
+
};
|
|
3922
|
+
(async () => {
|
|
3923
|
+
const credentials = session.credentials;
|
|
3924
|
+
if (!credentials) return;
|
|
3925
|
+
try {
|
|
3926
|
+
for await (const chunk of services.runPromptStreaming({
|
|
3927
|
+
prompt: runningPrompt,
|
|
3928
|
+
credentials,
|
|
3929
|
+
signal: controller.signal,
|
|
3930
|
+
resumeSessionId: currentSessionIdRef.current ?? void 0
|
|
3931
|
+
})) {
|
|
3932
|
+
if (controller.signal.aborted) return;
|
|
3933
|
+
setRunChunks((prev) => [...prev, chunk]);
|
|
3934
|
+
if (chunk.kind === "tool-call") setLastToolName(chunk.toolName);
|
|
3935
|
+
if (chunk.kind === "done") {
|
|
3936
|
+
if (chunk.sessionId) currentSessionIdRef.current = chunk.sessionId;
|
|
3937
|
+
finishStream("done", Date.now() - startedAt);
|
|
3938
|
+
return;
|
|
3939
|
+
}
|
|
3940
|
+
if (chunk.kind === "error") {
|
|
3941
|
+
finishStream("error", Date.now() - startedAt, chunk.text);
|
|
3942
|
+
return;
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
} catch (err) {
|
|
3946
|
+
if (controller.signal.aborted) return;
|
|
3947
|
+
const text = err instanceof Error ? err.message : String(err);
|
|
3948
|
+
setRunChunks((prev) => [...prev, {
|
|
3949
|
+
kind: "error",
|
|
3950
|
+
text
|
|
3951
|
+
}]);
|
|
3952
|
+
finishStream("error", Date.now() - startedAt, text);
|
|
3953
|
+
}
|
|
3954
|
+
})();
|
|
3955
|
+
return () => {
|
|
3956
|
+
controller.abort();
|
|
3957
|
+
if (runAbortRef.current === controller) runAbortRef.current = null;
|
|
3958
|
+
};
|
|
3959
|
+
}, [
|
|
3960
|
+
phase,
|
|
3961
|
+
runningPrompt,
|
|
3962
|
+
services,
|
|
3963
|
+
session.credentials
|
|
3964
|
+
]);
|
|
3965
|
+
const enterGoodbye = () => {
|
|
3966
|
+
runAbortRef.current?.abort();
|
|
3967
|
+
setPhase("goodbye");
|
|
3968
|
+
};
|
|
3969
|
+
const closeWizard = () => {
|
|
3970
|
+
setPhase("done");
|
|
3971
|
+
setTimeout(() => {
|
|
3972
|
+
store.setMcpSuggestedPromptsDismissed();
|
|
3973
|
+
}, 0);
|
|
3974
|
+
};
|
|
3975
|
+
const handleChoice = (value) => {
|
|
3976
|
+
const choice = Array.isArray(value) ? value[0] : value;
|
|
3977
|
+
setLoginError(null);
|
|
3978
|
+
if (choice === "login") {
|
|
3979
|
+
analytics.wizardCapture("mcp suggested prompts choose", { choice: "login" });
|
|
3980
|
+
setPhase("authenticating");
|
|
3981
|
+
} else {
|
|
3982
|
+
analytics.wizardCapture("mcp suggested prompts choose", { choice: "exit" });
|
|
3983
|
+
enterGoodbye();
|
|
3984
|
+
}
|
|
3985
|
+
};
|
|
3986
|
+
const startRun = (prompt) => {
|
|
3987
|
+
setRunningPrompt(prompt);
|
|
3988
|
+
setRunCount((c) => c + 1);
|
|
3989
|
+
setBranchHistory((h) => [...h, prompt]);
|
|
3990
|
+
setPhase("running");
|
|
3991
|
+
};
|
|
3992
|
+
const handlePromptPick = (value) => {
|
|
3993
|
+
startRun(Array.isArray(value) ? value[0] : value);
|
|
3994
|
+
};
|
|
3995
|
+
const handleFollowUpPick = (value) => {
|
|
3996
|
+
const picked = Array.isArray(value) ? value[0] : value;
|
|
3997
|
+
if (picked === "__follow_up_exit__") {
|
|
3998
|
+
analytics.wizardCapture("mcp suggested prompts follow-up", {
|
|
3999
|
+
choice: "exit",
|
|
4000
|
+
depth: branchHistory.length
|
|
4001
|
+
});
|
|
4002
|
+
enterGoodbye();
|
|
4003
|
+
return;
|
|
4004
|
+
}
|
|
4005
|
+
analytics.wizardCapture("mcp suggested prompts follow-up", {
|
|
4006
|
+
choice: "continue",
|
|
4007
|
+
depth: branchHistory.length,
|
|
4008
|
+
lastToolName
|
|
4009
|
+
});
|
|
4010
|
+
startRun(picked);
|
|
4011
|
+
};
|
|
4012
|
+
useKeyBindings("mcp-suggested-prompts", [
|
|
4013
|
+
{
|
|
4014
|
+
match: "escape",
|
|
4015
|
+
label: "esc",
|
|
4016
|
+
action: phase === "goodbye" ? "close" : "exit",
|
|
4017
|
+
handler: () => {
|
|
4018
|
+
if (phase === "goodbye") closeWizard();
|
|
4019
|
+
else if (phase === "running" || phase === "prompt-picker" || phase === "follow-up" || phase === "greeting") enterGoodbye();
|
|
4020
|
+
}
|
|
4021
|
+
},
|
|
4022
|
+
{
|
|
4023
|
+
match: "p",
|
|
4024
|
+
label: "p",
|
|
4025
|
+
action: canPickAnother ? "pick new prompt" : "cap reached",
|
|
4026
|
+
handler: () => {
|
|
4027
|
+
if (phase !== "running" && phase !== "follow-up") return;
|
|
4028
|
+
if (!canPickAnother) return;
|
|
4029
|
+
runAbortRef.current?.abort();
|
|
4030
|
+
currentSessionIdRef.current = null;
|
|
4031
|
+
setPhase("prompt-picker");
|
|
4032
|
+
}
|
|
4033
|
+
},
|
|
4034
|
+
...phase === "greeting" ? [{
|
|
4035
|
+
match: "return",
|
|
4036
|
+
label: "enter",
|
|
4037
|
+
action: "continue",
|
|
4038
|
+
handler: () => {
|
|
4039
|
+
setPhase("prompt-picker");
|
|
4040
|
+
}
|
|
4041
|
+
}] : []
|
|
4042
|
+
]);
|
|
4043
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
4044
|
+
flexDirection: "column",
|
|
4045
|
+
flexGrow: 1,
|
|
4046
|
+
children: /* @__PURE__ */ jsxs(Box, {
|
|
4047
|
+
marginTop: 1,
|
|
4048
|
+
flexDirection: "column",
|
|
4049
|
+
children: [
|
|
4050
|
+
phase === "choose" && /* @__PURE__ */ jsx(ChoosePhase, {
|
|
4051
|
+
error: loginError,
|
|
4052
|
+
onSelect: handleChoice
|
|
4053
|
+
}),
|
|
4054
|
+
phase === "authenticating" && /* @__PURE__ */ jsx(AuthenticatingPhase, { loginUrl: session.loginUrl }),
|
|
4055
|
+
phase === "greeting" && /* @__PURE__ */ jsx(GreetingPhase, {
|
|
4056
|
+
greeting,
|
|
4057
|
+
userDisplayName: session.apiUser?.first_name || null,
|
|
4058
|
+
onComplete: () => setPhase("prompt-picker")
|
|
4059
|
+
}),
|
|
4060
|
+
phase === "prompt-picker" && /* @__PURE__ */ jsx(PromptPickerPhase, {
|
|
4061
|
+
promptKit: kit,
|
|
4062
|
+
crossSell,
|
|
4063
|
+
onSelect: handlePromptPick
|
|
4064
|
+
}),
|
|
4065
|
+
phase === "running" && runningPrompt && /* @__PURE__ */ jsx(RunningPhase, {
|
|
4066
|
+
prompt: runningPrompt,
|
|
4067
|
+
chunks: runChunks,
|
|
4068
|
+
startedAt: runStartedAt,
|
|
4069
|
+
frozenDurationSecs: runDurationSecs,
|
|
4070
|
+
runCount,
|
|
4071
|
+
maxRuns: MAX_PROMPT_RUNS
|
|
4072
|
+
}),
|
|
4073
|
+
phase === "follow-up" && /* @__PURE__ */ jsxs(Box, {
|
|
4074
|
+
flexDirection: "column",
|
|
4075
|
+
flexGrow: 1,
|
|
4076
|
+
children: [runningPrompt && /* @__PURE__ */ jsx(Box, {
|
|
4077
|
+
flexDirection: "column",
|
|
4078
|
+
flexShrink: 1,
|
|
4079
|
+
children: /* @__PURE__ */ jsx(RunningPhase, {
|
|
4080
|
+
prompt: runningPrompt,
|
|
4081
|
+
chunks: runChunks,
|
|
4082
|
+
startedAt: runStartedAt,
|
|
4083
|
+
frozenDurationSecs: runDurationSecs,
|
|
4084
|
+
runCount,
|
|
4085
|
+
maxRuns: MAX_PROMPT_RUNS
|
|
4086
|
+
})
|
|
4087
|
+
}), /* @__PURE__ */ jsx(Box, {
|
|
4088
|
+
marginTop: 1,
|
|
4089
|
+
flexShrink: 0,
|
|
4090
|
+
flexDirection: "column",
|
|
4091
|
+
children: /* @__PURE__ */ jsx(FollowUpPhase, {
|
|
4092
|
+
lastToolName,
|
|
4093
|
+
lastPrompt: runningPrompt,
|
|
4094
|
+
chunks: runChunks,
|
|
4095
|
+
role: session.roleAtOrganization,
|
|
4096
|
+
branchHistory,
|
|
4097
|
+
canPickAnother,
|
|
4098
|
+
maxRuns: MAX_PROMPT_RUNS,
|
|
4099
|
+
onSelect: handleFollowUpPick
|
|
4100
|
+
})
|
|
4101
|
+
})]
|
|
4102
|
+
}),
|
|
4103
|
+
phase === "goodbye" && /* @__PURE__ */ jsx(GoodbyePhase, {
|
|
4104
|
+
installedClients: session.mcpInstalledClients,
|
|
4105
|
+
role: session.roleAtOrganization,
|
|
4106
|
+
integration: session.integration,
|
|
4107
|
+
engaged: branchHistory.length > 0,
|
|
4108
|
+
onClose: closeWizard
|
|
4109
|
+
})
|
|
4110
|
+
]
|
|
4111
|
+
})
|
|
4112
|
+
});
|
|
4113
|
+
};
|
|
4114
|
+
const ChoosePhase = ({ error, onSelect }) => /* @__PURE__ */ jsxs(Box, {
|
|
4115
|
+
flexDirection: "column",
|
|
3014
4116
|
children: [
|
|
3015
4117
|
/* @__PURE__ */ jsx(Text, {
|
|
3016
4118
|
bold: true,
|
|
@@ -3093,56 +4195,109 @@ const AuthenticatingPhase = ({ loginUrl }) => /* @__PURE__ */ jsxs(Box, {
|
|
|
3093
4195
|
] })
|
|
3094
4196
|
})]
|
|
3095
4197
|
});
|
|
3096
|
-
const
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
4198
|
+
const GreetingPhase = ({ greeting, userDisplayName, onComplete }) => {
|
|
4199
|
+
const blocks = [];
|
|
4200
|
+
if (userDisplayName) blocks.push({
|
|
4201
|
+
content: `Hi ${userDisplayName}!`,
|
|
4202
|
+
mode: 0,
|
|
4203
|
+
animationInterval: 70,
|
|
4204
|
+
pause: 1200
|
|
4205
|
+
});
|
|
4206
|
+
blocks.push({
|
|
4207
|
+
content: greeting.headline,
|
|
4208
|
+
mode: 0,
|
|
4209
|
+
animationInterval: 45,
|
|
4210
|
+
pause: 2e3
|
|
4211
|
+
});
|
|
4212
|
+
blocks.push({
|
|
4213
|
+
type: "lines",
|
|
4214
|
+
lines: greeting.bullets.map((bullet, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
4215
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4216
|
+
color: Colors.primary,
|
|
4217
|
+
children: Icons.diamond
|
|
4218
|
+
}),
|
|
4219
|
+
" ",
|
|
4220
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4221
|
+
dimColor: true,
|
|
4222
|
+
children: bullet
|
|
4223
|
+
})
|
|
4224
|
+
] }, i)),
|
|
4225
|
+
interval: 700,
|
|
4226
|
+
pause: 2200
|
|
4227
|
+
});
|
|
4228
|
+
blocks.push({
|
|
4229
|
+
content: greeting.outro,
|
|
4230
|
+
mode: 0,
|
|
4231
|
+
animationInterval: 38,
|
|
4232
|
+
pause: 1800
|
|
4233
|
+
});
|
|
4234
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
3102
4235
|
flexDirection: "column",
|
|
3103
|
-
children: /* @__PURE__ */ jsx(
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
{
|
|
3113
|
-
content: "Pick a prompt to see the PostHog MCP in action.",
|
|
3114
|
-
mode: 0,
|
|
3115
|
-
animationInterval: 50,
|
|
3116
|
-
pause: 1e3,
|
|
3117
|
-
dimWhenComplete: false
|
|
3118
|
-
},
|
|
3119
|
-
{
|
|
3120
|
-
content: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(PickerMenu, {
|
|
3121
|
-
options,
|
|
3122
|
-
optionMarginBottom: 1,
|
|
3123
|
-
onSelect
|
|
3124
|
-
}), /* @__PURE__ */ jsx(Box, {
|
|
3125
|
-
marginTop: 2,
|
|
3126
|
-
children: /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
3127
|
-
bold: true,
|
|
3128
|
-
children: "[esc]"
|
|
3129
|
-
}), /* @__PURE__ */ jsx(Text, { children: " to exit" })] })
|
|
3130
|
-
})] }),
|
|
3131
|
-
persist: true
|
|
3132
|
-
}
|
|
3133
|
-
],
|
|
4236
|
+
children: [/* @__PURE__ */ jsx(Box, {
|
|
4237
|
+
marginBottom: 1,
|
|
4238
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
4239
|
+
bold: true,
|
|
4240
|
+
color: Colors.accent,
|
|
4241
|
+
children: "MCP tutorial"
|
|
4242
|
+
})
|
|
4243
|
+
}), /* @__PURE__ */ jsx(ContentSequencer, {
|
|
4244
|
+
blocks,
|
|
3134
4245
|
mode: 0,
|
|
3135
|
-
blockInterval:
|
|
3136
|
-
|
|
4246
|
+
blockInterval: 500,
|
|
4247
|
+
onSequenceComplete: onComplete
|
|
4248
|
+
})]
|
|
4249
|
+
});
|
|
4250
|
+
};
|
|
4251
|
+
const PromptPickerPhase = ({ promptKit, crossSell, onSelect }) => {
|
|
4252
|
+
const seenPrompts = /* @__PURE__ */ new Set();
|
|
4253
|
+
const options = [
|
|
4254
|
+
PINNED_FIRST_PROMPT,
|
|
4255
|
+
...crossSell,
|
|
4256
|
+
...promptKit
|
|
4257
|
+
].filter((o) => {
|
|
4258
|
+
if (seenPrompts.has(o.prompt)) return false;
|
|
4259
|
+
seenPrompts.add(o.prompt);
|
|
4260
|
+
return true;
|
|
4261
|
+
}).slice(0, 4).map((o) => ({
|
|
4262
|
+
label: o.product ? `Try ${o.product} — ${o.label ?? o.prompt}` : o.label ?? o.prompt,
|
|
4263
|
+
value: o.prompt
|
|
4264
|
+
}));
|
|
4265
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
4266
|
+
flexDirection: "column",
|
|
4267
|
+
children: [
|
|
4268
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4269
|
+
marginBottom: 1,
|
|
4270
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
4271
|
+
bold: true,
|
|
4272
|
+
color: Colors.accent,
|
|
4273
|
+
children: "MCP tutorial"
|
|
4274
|
+
})
|
|
4275
|
+
}),
|
|
4276
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4277
|
+
marginBottom: 1,
|
|
4278
|
+
children: /* @__PURE__ */ jsx(Text, { children: "Pick a prompt to see the PostHog MCP in action." })
|
|
4279
|
+
}),
|
|
4280
|
+
/* @__PURE__ */ jsx(PickerMenu, {
|
|
4281
|
+
options,
|
|
4282
|
+
optionMarginBottom: 1,
|
|
4283
|
+
onSelect
|
|
4284
|
+
}),
|
|
4285
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4286
|
+
marginTop: 2,
|
|
4287
|
+
children: /* @__PURE__ */ jsxs(Text, { children: [/* @__PURE__ */ jsx(Text, {
|
|
4288
|
+
bold: true,
|
|
4289
|
+
children: "[esc]"
|
|
4290
|
+
}), /* @__PURE__ */ jsx(Text, { children: " to exit" })] })
|
|
4291
|
+
})
|
|
4292
|
+
]
|
|
3137
4293
|
});
|
|
3138
4294
|
};
|
|
3139
|
-
const RunningPhase = ({ prompt, chunks, startedAt,
|
|
4295
|
+
const RunningPhase = ({ prompt, chunks, startedAt, frozenDurationSecs, runCount, maxRuns }) => {
|
|
3140
4296
|
const isDone = chunks.some((c) => c.kind === "done");
|
|
3141
4297
|
const errorChunk = chunks.find((c) => c.kind === "error");
|
|
3142
4298
|
const finished = isDone || !!errorChunk;
|
|
3143
|
-
const elapsed = startedAt ? Math.round((Date.now() - startedAt) / 1e3) : 0;
|
|
3144
|
-
const visibleChunks = finished ?
|
|
3145
|
-
const cappedChunks = finished ? capTextChunks(visibleChunks) : visibleChunks;
|
|
4299
|
+
const elapsed = frozenDurationSecs ?? (startedAt ? Math.round((Date.now() - startedAt) / 1e3) : 0);
|
|
4300
|
+
const visibleChunks = finished ? capTextChunks(collapseToFinalAnswer(chunks)) : chunks;
|
|
3146
4301
|
return /* @__PURE__ */ jsxs(Box, {
|
|
3147
4302
|
flexDirection: "column",
|
|
3148
4303
|
children: [
|
|
@@ -3181,52 +4336,63 @@ const RunningPhase = ({ prompt, chunks, startedAt, canPickAnother, runCount, max
|
|
|
3181
4336
|
/* @__PURE__ */ jsx(Box, {
|
|
3182
4337
|
marginTop: 1,
|
|
3183
4338
|
flexDirection: "column",
|
|
3184
|
-
children:
|
|
3185
|
-
}),
|
|
3186
|
-
finished && !canPickAnother && /* @__PURE__ */ jsx(Box, {
|
|
3187
|
-
marginTop: 1,
|
|
3188
|
-
children: /* @__PURE__ */ jsxs(Text, { children: [
|
|
3189
|
-
/* @__PURE__ */ jsxs(Text, {
|
|
3190
|
-
dimColor: true,
|
|
3191
|
-
children: [
|
|
3192
|
-
"You've hit the ",
|
|
3193
|
-
maxRuns,
|
|
3194
|
-
"-prompt tutorial cap. Press",
|
|
3195
|
-
" "
|
|
3196
|
-
]
|
|
3197
|
-
}),
|
|
3198
|
-
/* @__PURE__ */ jsx(Text, {
|
|
3199
|
-
bold: true,
|
|
3200
|
-
dimColor: true,
|
|
3201
|
-
children: "[esc]"
|
|
3202
|
-
}),
|
|
3203
|
-
/* @__PURE__ */ jsx(Text, {
|
|
3204
|
-
dimColor: true,
|
|
3205
|
-
children: " to exit."
|
|
3206
|
-
})
|
|
3207
|
-
] })
|
|
4339
|
+
children: visibleChunks.map((chunk, idx) => /* @__PURE__ */ jsx(ChunkLine, { chunk }, idx))
|
|
3208
4340
|
})
|
|
3209
4341
|
]
|
|
3210
4342
|
});
|
|
3211
4343
|
};
|
|
3212
4344
|
/**
|
|
4345
|
+
* Strip everything except the agent's final answer + any error chunks.
|
|
4346
|
+
* Drops tool-call / tool-result chatter (their work is done once the
|
|
4347
|
+
* stream completes) and any text blocks emitted BEFORE the last text
|
|
4348
|
+
* block — those are typically Sonnet's "I'll query X…" preamble that
|
|
4349
|
+
* arrives alongside the first tool_use and adds noise above the picker.
|
|
4350
|
+
*
|
|
4351
|
+
* If the run produced no text at all (pure tool calls, or only errors),
|
|
4352
|
+
* fall through to whatever chunks survived so the user isn't left with
|
|
4353
|
+
* a blank result.
|
|
4354
|
+
*/
|
|
4355
|
+
function collapseToFinalAnswer(chunks) {
|
|
4356
|
+
const textChunks = chunks.filter((c) => c.kind === "text");
|
|
4357
|
+
const errors = chunks.filter((c) => c.kind === "error");
|
|
4358
|
+
if (textChunks.length === 0) return errors;
|
|
4359
|
+
return [textChunks[textChunks.length - 1], ...errors];
|
|
4360
|
+
}
|
|
4361
|
+
/**
|
|
3213
4362
|
* Belt-and-suspenders fallback for runs where Claude ignored the
|
|
3214
4363
|
* terminal-fit system prompt and produced an overlong response. Joins
|
|
3215
|
-
* all text chunks,
|
|
3216
|
-
*
|
|
3217
|
-
*
|
|
3218
|
-
*
|
|
4364
|
+
* all text chunks, then walks them from the bottom keeping only as many
|
|
4365
|
+
* lines as fit in the visual row budget — wide lines that wrap to
|
|
4366
|
+
* multiple rows on a narrow terminal cost their wrapped row count, not
|
|
4367
|
+
* 1. Prepends an indicator showing how many source lines got cut. Tool
|
|
4368
|
+
* calls, results, and errors are preserved separately so they don't
|
|
4369
|
+
* disappear into the truncation.
|
|
4370
|
+
*
|
|
4371
|
+
* Visual-row-aware truncation is what makes the FollowUp picker feel
|
|
4372
|
+
* pinned: a 5-row table that wraps to 12 visual rows on a 60-col
|
|
4373
|
+
* terminal correctly counts as 12, so the cap leaves exactly the room
|
|
4374
|
+
* the picker needs.
|
|
3219
4375
|
*/
|
|
3220
4376
|
function capTextChunks(chunks) {
|
|
3221
4377
|
const rows = process.stdout.rows ?? 24;
|
|
3222
|
-
const
|
|
4378
|
+
const cols = process.stdout.columns ?? 120;
|
|
4379
|
+
const maxVisualRows = Math.max(3, rows - 19);
|
|
3223
4380
|
const textChunks = chunks.filter((c) => c.kind === "text");
|
|
3224
4381
|
const errors = chunks.filter((c) => c.kind === "error");
|
|
3225
4382
|
if (textChunks.length === 0) return chunks;
|
|
3226
4383
|
const lines = textChunks.map((c) => c.text).join("").split("\n");
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
4384
|
+
const visualRows = (line) => Math.max(1, Math.ceil(line.length / cols));
|
|
4385
|
+
let used = 0;
|
|
4386
|
+
let keepFrom = lines.length;
|
|
4387
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
4388
|
+
const cost = visualRows(lines[i]);
|
|
4389
|
+
if (used + cost > maxVisualRows) break;
|
|
4390
|
+
used += cost;
|
|
4391
|
+
keepFrom = i;
|
|
4392
|
+
}
|
|
4393
|
+
if (keepFrom === 0) return chunks;
|
|
4394
|
+
const hidden = keepFrom;
|
|
4395
|
+
const tail = lines.slice(keepFrom).join("\n");
|
|
3230
4396
|
return [{
|
|
3231
4397
|
kind: "text",
|
|
3232
4398
|
text: `[${hidden} line${hidden === 1 ? "" : "s"} above — expand terminal to see more]\n\n${tail}`
|
|
@@ -3257,6 +4423,101 @@ const ChunkLine = ({ chunk }) => {
|
|
|
3257
4423
|
});
|
|
3258
4424
|
return null;
|
|
3259
4425
|
};
|
|
4426
|
+
const FollowUpPhase = ({ lastToolName, lastPrompt, chunks, role, branchHistory, canPickAnother, maxRuns, onSelect }) => {
|
|
4427
|
+
const followUps = useMemo(() => getFollowUps({
|
|
4428
|
+
lastToolName,
|
|
4429
|
+
lastPrompt: lastPrompt || "",
|
|
4430
|
+
role,
|
|
4431
|
+
branchHistory
|
|
4432
|
+
}), [
|
|
4433
|
+
lastToolName,
|
|
4434
|
+
lastPrompt,
|
|
4435
|
+
role,
|
|
4436
|
+
branchHistory
|
|
4437
|
+
]);
|
|
4438
|
+
const options = canPickAnother ? followUps.map((f) => ({
|
|
4439
|
+
label: f.label ?? f.prompt,
|
|
4440
|
+
value: f.prompt
|
|
4441
|
+
})) : [{
|
|
4442
|
+
label: "Exit",
|
|
4443
|
+
value: FOLLOW_UP_EXIT_SENTINEL
|
|
4444
|
+
}];
|
|
4445
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
4446
|
+
flexDirection: "column",
|
|
4447
|
+
children: [/* @__PURE__ */ jsx(Text, { children: chunks.find((c) => c.kind === "error") ? "That one errored out — try a different angle?" : !canPickAnother ? `You've hit the ${maxRuns}-prompt tutorial cap.` : `Want to keep exploring? Select a follow-up prompt.` }), /* @__PURE__ */ jsx(PickerMenu, {
|
|
4448
|
+
options,
|
|
4449
|
+
onSelect
|
|
4450
|
+
})]
|
|
4451
|
+
});
|
|
4452
|
+
};
|
|
4453
|
+
const GoodbyePhase = ({ installedClients, role, integration, engaged, onClose }) => {
|
|
4454
|
+
const samples = getRolePrompts(role, integration).slice(0, 3);
|
|
4455
|
+
const headline = engaged ? "Nice work. You can keep talking to PostHog anytime." : "You're all set — PostHog MCP is here when you're ready.";
|
|
4456
|
+
const introLine = installedClients.length > 0 ? /* @__PURE__ */ jsxs(Text, { children: [
|
|
4457
|
+
"MCP is set up in",
|
|
4458
|
+
" ",
|
|
4459
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4460
|
+
bold: true,
|
|
4461
|
+
color: Colors.primary,
|
|
4462
|
+
children: installedClients.join(", ")
|
|
4463
|
+
}),
|
|
4464
|
+
". Open one and try a prompt like:"
|
|
4465
|
+
] }) : /* @__PURE__ */ jsx(Text, { children: "Wherever you have MCP set up (Claude Code, Cursor, VS Code, Windsurf, Zed, etc.), open the agent and try a prompt like:" });
|
|
4466
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
4467
|
+
flexDirection: "column",
|
|
4468
|
+
children: [
|
|
4469
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4470
|
+
marginBottom: 1,
|
|
4471
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
4472
|
+
bold: true,
|
|
4473
|
+
color: Colors.accent,
|
|
4474
|
+
children: headline
|
|
4475
|
+
})
|
|
4476
|
+
}),
|
|
4477
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4478
|
+
marginBottom: 1,
|
|
4479
|
+
children: introLine
|
|
4480
|
+
}),
|
|
4481
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4482
|
+
marginBottom: 1,
|
|
4483
|
+
flexDirection: "column",
|
|
4484
|
+
children: samples.map((p, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
4485
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4486
|
+
color: Colors.primary,
|
|
4487
|
+
children: Icons.triangleSmallRight
|
|
4488
|
+
}),
|
|
4489
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
4490
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4491
|
+
dimColor: true,
|
|
4492
|
+
children: p.prompt
|
|
4493
|
+
})
|
|
4494
|
+
] }, i))
|
|
4495
|
+
}),
|
|
4496
|
+
/* @__PURE__ */ jsx(Box, {
|
|
4497
|
+
marginBottom: 1,
|
|
4498
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
4499
|
+
dimColor: true,
|
|
4500
|
+
children: [
|
|
4501
|
+
"Re-run this tutorial anytime with",
|
|
4502
|
+
" ",
|
|
4503
|
+
/* @__PURE__ */ jsx(Text, {
|
|
4504
|
+
bold: true,
|
|
4505
|
+
children: "npx @posthog/wizard mcp tutorial"
|
|
4506
|
+
}),
|
|
4507
|
+
"."
|
|
4508
|
+
]
|
|
4509
|
+
})
|
|
4510
|
+
}),
|
|
4511
|
+
/* @__PURE__ */ jsx(PickerMenu, {
|
|
4512
|
+
options: [{
|
|
4513
|
+
label: "Close",
|
|
4514
|
+
value: "close"
|
|
4515
|
+
}],
|
|
4516
|
+
onSelect: onClose
|
|
4517
|
+
})
|
|
4518
|
+
]
|
|
4519
|
+
});
|
|
4520
|
+
};
|
|
3260
4521
|
//#endregion
|
|
3261
4522
|
//#region src/ui/tui/screens/audit/AuditChecksViewer/AreaHeaderRow.tsx
|
|
3262
4523
|
/** Sub-header row inside the scrollable body — one per area group. */
|
|
@@ -4120,4 +5381,4 @@ const AUDIT_3000_AREA_SLIDES = [
|
|
|
4120
5381
|
//#endregion
|
|
4121
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 };
|
|
4122
5383
|
|
|
4123
|
-
//# sourceMappingURL=slides-
|
|
5384
|
+
//# sourceMappingURL=slides-DwvXZ8iS.js.map
|