@posthog/wizard 2.60.0 → 2.62.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-CM30npkB.js → add-mcp-server-to-clients-Bzl7_wB3.js} +190 -60
- package/dist/add-mcp-server-to-clients-Bzl7_wB3.js.map +1 -0
- package/dist/{agent-interface-CybBFwnk.js → agent-interface-C90hyvs1.js} +7 -7
- package/dist/{agent-interface-CybBFwnk.js.map → agent-interface-C90hyvs1.js.map} +1 -1
- package/dist/{agent-prompt-loader-DL32ioJX.js → agent-prompt-loader-CBj2DWAJ.js} +38 -11
- package/dist/agent-prompt-loader-CBj2DWAJ.js.map +1 -0
- package/dist/{agent-runner-DUyxA1TQ.js → agent-runner-DA5YfjOD.js} +147 -24
- package/dist/agent-runner-DA5YfjOD.js.map +1 -0
- package/dist/{analytics-B9V7x1Ma.js → analytics-BdKBzz4M.js} +2 -2
- package/dist/{analytics-B9V7x1Ma.js.map → analytics-BdKBzz4M.js.map} +1 -1
- package/dist/analytics-CijpxQFN.js +2 -0
- package/dist/{api-OHLXhKTy.js → api-aTkzJ9vG.js} +3 -3
- package/dist/{api-OHLXhKTy.js.map → api-aTkzJ9vG.js.map} +1 -1
- package/dist/bin.js +288 -134
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-xkhfF3JS.js → bounded-fs-BU2L5mjO.js} +3 -3
- package/dist/{bounded-fs-xkhfF3JS.js.map → bounded-fs-BU2L5mjO.js.map} +1 -1
- package/dist/{ci-install-B31ciXo4.js → ci-install-BnTAUOz8.js} +4 -4
- package/dist/{ci-install-B31ciXo4.js.map → ci-install-BnTAUOz8.js.map} +1 -1
- package/dist/{debug-D3Ucw2y1.js → debug-BTPYy9p7.js} +10 -4
- package/dist/debug-BTPYy9p7.js.map +1 -0
- package/dist/{debug-Cx9Delbc.js → debug-D2L-fM_I.js} +1 -1
- package/dist/{defaults-BWLIffh5.js → defaults-mrAre0xM.js} +28 -2
- package/dist/defaults-mrAre0xM.js.map +1 -0
- package/dist/{environment-BN8ROaHv.js → environment-lV2X1gS-.js} +4 -4
- package/dist/{environment-BN8ROaHv.js.map → environment-lV2X1gS-.js.map} +1 -1
- package/dist/{file-watcher-CzBnjben.js → file-watcher-qqQBl5Em.js} +2 -2
- package/dist/{file-watcher-CzBnjben.js.map → file-watcher-qqQBl5Em.js.map} +1 -1
- package/dist/{headless-ui-DoQlIoeh.js → headless-ui-TSoOsa3j.js} +2 -2
- package/dist/{headless-ui-DoQlIoeh.js.map → headless-ui-TSoOsa3j.js.map} +1 -1
- package/dist/{interactive-DeFFwXME.js → interactive-DMoXEiKo.js} +2 -2
- package/dist/{interactive-DeFFwXME.js.map → interactive-DMoXEiKo.js.map} +1 -1
- package/dist/{mcp-CBskrEsK.js → mcp-Dqu0_QzN.js} +2 -2
- package/dist/{mcp-CBskrEsK.js.map → mcp-Dqu0_QzN.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-B1upRE9N.js → mcp-prompt-streaming-B4cYVDVP.js} +3 -3
- package/dist/{mcp-prompt-streaming-B1upRE9N.js.map → mcp-prompt-streaming-B4cYVDVP.js.map} +1 -1
- package/dist/{non-interactive-BUmW9f9P.js → non-interactive-EG_lII4R.js} +2 -2
- package/dist/{non-interactive-BUmW9f9P.js.map → non-interactive-EG_lII4R.js.map} +1 -1
- package/dist/{orchestrator-tools-bM9GOq3c.js → orchestrator-tools-DrhpNOKK.js} +3 -3
- package/dist/{orchestrator-tools-bM9GOq3c.js.map → orchestrator-tools-DrhpNOKK.js.map} +1 -1
- package/dist/{package-manager-ByVEmFPR.js → package-manager-z33XHEWO.js} +2 -2
- package/dist/{package-manager-ByVEmFPR.js.map → package-manager-z33XHEWO.js.map} +1 -1
- package/dist/{pi-C7wbP2z-.js → pi-CVJB0Ban.js} +11 -11
- package/dist/{pi-C7wbP2z-.js.map → pi-CVJB0Ban.js.map} +1 -1
- package/dist/{playground-Df_ZzalF.js → playground-BjWqoWhf.js} +25 -788
- package/dist/playground-BjWqoWhf.js.map +1 -0
- package/dist/{posthog-DLklk2yT.js → posthog-3ijs_66W.js} +2 -2
- package/dist/{posthog-DLklk2yT.js.map → posthog-3ijs_66W.js.map} +1 -1
- package/dist/{posthog-integration-CxIj49T4.js → posthog-integration-C3wuB5B1.js} +110 -33
- package/dist/posthog-integration-C3wuB5B1.js.map +1 -0
- package/dist/{provisioning-BpqrbURn.js → provisioning-IKacrvWB.js} +3 -3
- package/dist/{provisioning-BpqrbURn.js.map → provisioning-IKacrvWB.js.map} +1 -1
- package/dist/{queue-tools-QVKYMX_C.js → queue-tools-zM8_mxx6.js} +39 -8
- package/dist/queue-tools-zM8_mxx6.js.map +1 -0
- package/dist/{registry-CboWk-Ny.js → registry-DF_aKyS0.js} +5 -5
- package/dist/{registry-CboWk-Ny.js.map → registry-DF_aKyS0.js.map} +1 -1
- package/dist/{security-aWRzd8V1.js → security-CVFKNYBn.js} +5 -5
- package/dist/{security-aWRzd8V1.js.map → security-CVFKNYBn.js.map} +1 -1
- package/dist/{setup-utils-VtxhrSx8.js → setup-utils-iINkc0xu.js} +9 -9
- package/dist/setup-utils-iINkc0xu.js.map +1 -0
- package/dist/{start-tui-CzMiitZJ.js → start-tui-CjtL-ls7.js} +137 -42
- package/dist/start-tui-CjtL-ls7.js.map +1 -0
- package/dist/{steps-9PddZ-BV.js → steps-DzUGHdfY.js} +7 -7
- package/dist/{steps-9PddZ-BV.js.map → steps-DzUGHdfY.js.map} +1 -1
- package/dist/{store-V71P5KpB.js → store-DtckpbSC.js} +25 -5
- package/dist/store-DtckpbSC.js.map +1 -0
- package/dist/{subagent-CcBKBSR-.js → subagent-cD_bF490.js} +2 -2
- package/dist/{subagent-CcBKBSR-.js.map → subagent-cD_bF490.js.map} +1 -1
- package/dist/{task-BRktXvCV.js → task-eIt2iATF.js} +36 -23
- package/dist/task-eIt2iATF.js.map +1 -0
- package/dist/{task-stream-CFAXlJLv.js → task-stream-DGBUveUD.js} +5 -5
- package/dist/{task-stream-CFAXlJLv.js.map → task-stream-DGBUveUD.js.map} +1 -1
- package/dist/{tasks-CyLSHCmC.js → tasks-wQ3V6Ft6.js} +2 -2
- package/dist/{tasks-CyLSHCmC.js.map → tasks-wQ3V6Ft6.js.map} +1 -1
- package/dist/{telemetry-mi4dua6_.js → telemetry-BWYDFAwf.js} +3 -3
- package/dist/{telemetry-mi4dua6_.js.map → telemetry-BWYDFAwf.js.map} +1 -1
- package/dist/{terminal-B-37htZb.js → terminal-yKJZx1UC.js} +978 -71
- package/dist/terminal-yKJZx1UC.js.map +1 -0
- package/dist/{tools-BWaoKBAO.js → tools-CDlaJb_e.js} +6 -6
- package/dist/{tools-BWaoKBAO.js.map → tools-CDlaJb_e.js.map} +1 -1
- package/dist/{wizard-abort-D0HFMYCV.js → wizard-abort-Cjk5z73h.js} +1 -1
- package/dist/{wizard-abort-Bgx_JOfw.js → wizard-abort-CztG5WTv.js} +4 -4
- package/dist/{wizard-abort-Bgx_JOfw.js.map → wizard-abort-CztG5WTv.js.map} +1 -1
- package/dist/{wizard-session-CwgR5y3-.js → wizard-session-BUhlJ1b8.js} +2 -1
- package/dist/wizard-session-BUhlJ1b8.js.map +1 -0
- package/dist/{wizard-session-DsK16SGs.js → wizard-session-DZUDtS5d.js} +1 -1
- package/dist/yara-hooks-DVGKhwaz.js +2 -0
- package/dist/{yara-hooks-Cj8x2YV4.js → yara-hooks-DeLjTIiJ.js} +4 -4
- package/dist/{yara-hooks-Cj8x2YV4.js.map → yara-hooks-DeLjTIiJ.js.map} +1 -1
- package/package.json +2 -1
- package/dist/add-mcp-server-to-clients-CM30npkB.js.map +0 -1
- package/dist/agent-prompt-loader-DL32ioJX.js.map +0 -1
- package/dist/agent-runner-DUyxA1TQ.js.map +0 -1
- package/dist/analytics-HdW5e8_o.js +0 -2
- package/dist/debug-D3Ucw2y1.js.map +0 -1
- package/dist/defaults-BWLIffh5.js.map +0 -1
- package/dist/playground-Df_ZzalF.js.map +0 -1
- package/dist/posthog-integration-CxIj49T4.js.map +0 -1
- package/dist/queue-tools-QVKYMX_C.js.map +0 -1
- package/dist/setup-utils-VtxhrSx8.js.map +0 -1
- package/dist/start-tui-CzMiitZJ.js.map +0 -1
- package/dist/store-V71P5KpB.js.map +0 -1
- package/dist/task-BRktXvCV.js.map +0 -1
- package/dist/terminal-B-37htZb.js.map +0 -1
- package/dist/wizard-session-CwgR5y3-.js.map +0 -1
- package/dist/yara-hooks-CIQRywtg.js +0 -2
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { V as POSTHOG_APP_URL,
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import { i as withUtm, n as openTrackedLink } from "./telemetry-
|
|
4
|
-
import { t as getOrAskForProjectData } from "./setup-utils-
|
|
5
|
-
import { a as fetchUserData, i as fetchSlackConnected } from "./api-
|
|
6
|
-
import "./wizard-session-
|
|
7
|
-
import { a as
|
|
8
|
-
import { T as fetchSkillMenu } from "./agent-interface-
|
|
9
|
-
import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-
|
|
10
|
-
import { c as TextBlock, d as isClearBlock, f as isLinesBlock, h as Icons, l as computeVisibleRange, m as Colors, p as isObjectBlock } from "./posthog-integration-
|
|
11
|
-
import {
|
|
12
|
-
import { r as totalTokenCount } from "./store-
|
|
13
|
-
import { n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, t as ALL_FEATURE_VALUES } from "./defaults-
|
|
1
|
+
import { V as POSTHOG_APP_URL, h as SERVICE_LABELS, mt as getSkillsBaseUrl, pt as WIZARD_USER_AGENT, s as logToFile } from "./debug-BTPYy9p7.js";
|
|
2
|
+
import { n as analytics } from "./analytics-BdKBzz4M.js";
|
|
3
|
+
import { i as withUtm, n as openTrackedLink } from "./telemetry-BWYDFAwf.js";
|
|
4
|
+
import { t as getOrAskForProjectData } from "./setup-utils-iINkc0xu.js";
|
|
5
|
+
import { a as fetchUserData, i as fetchSlackConnected } from "./api-aTkzJ9vG.js";
|
|
6
|
+
import "./wizard-session-BUhlJ1b8.js";
|
|
7
|
+
import { a as formatCostUsd, o as formatTokenCount } from "./agent-runner-DA5YfjOD.js";
|
|
8
|
+
import { T as fetchSkillMenu } from "./agent-interface-C90hyvs1.js";
|
|
9
|
+
import { y as AUDIT_SEVERITY_STYLE } from "./yara-hooks-DeLjTIiJ.js";
|
|
10
|
+
import { c as TextBlock, d as isClearBlock, f as isLinesBlock, h as Icons, l as computeVisibleRange, m as Colors, p as isObjectBlock } from "./posthog-integration-C3wuB5B1.js";
|
|
11
|
+
import { E as getKindMeta, a as useStdoutDimensions, f as Program, i as useKeyboardHintsContext, n as useKeyBindings, o as ConfirmButton, r as KeyboardHintsProvider, s as PromptLabel, t as PickerMenu } from "./bin.js";
|
|
12
|
+
import { r as totalTokenCount } from "./store-DtckpbSC.js";
|
|
13
|
+
import { c as namesWithStatus, n as AVAILABLE_FEATURES, o as isAllFeaturesSelected, s as isOk, t as ALL_FEATURE_VALUES, u as summarizeFailure } from "./defaults-mrAre0xM.js";
|
|
14
14
|
import opn from "opn";
|
|
15
15
|
import * as fs$1 from "fs";
|
|
16
16
|
import axios from "axios";
|
|
@@ -1697,6 +1697,790 @@ const TipsCard = ({ store, tips = DEFAULT_TIPS }) => {
|
|
|
1697
1697
|
});
|
|
1698
1698
|
};
|
|
1699
1699
|
//#endregion
|
|
1700
|
+
//#region src/ui/tui/hooks/useTick.ts
|
|
1701
|
+
/**
|
|
1702
|
+
* useTick — forces a re-render every `intervalMs`. Returns a monotonically
|
|
1703
|
+
* increasing counter, which is rarely needed — most callers just want the
|
|
1704
|
+
* re-render side effect.
|
|
1705
|
+
*/
|
|
1706
|
+
function useTick(intervalMs) {
|
|
1707
|
+
const [tick, setTick] = useState(0);
|
|
1708
|
+
useEffect(() => {
|
|
1709
|
+
const id = setInterval(() => setTick((t) => t + 1), intervalMs);
|
|
1710
|
+
return () => clearInterval(id);
|
|
1711
|
+
}, [intervalMs]);
|
|
1712
|
+
return tick;
|
|
1713
|
+
}
|
|
1714
|
+
//#endregion
|
|
1715
|
+
//#region src/ui/tui/components/visualizer/palette.ts
|
|
1716
|
+
const VISUALIZER_PALETTE = {
|
|
1717
|
+
fade: "#0E7A0E",
|
|
1718
|
+
bright: "#7CFF7C",
|
|
1719
|
+
mid: "#22D622",
|
|
1720
|
+
head: "#E6FFE6",
|
|
1721
|
+
book: [
|
|
1722
|
+
"#22D622",
|
|
1723
|
+
"#7CFF7C",
|
|
1724
|
+
"#5BE05B",
|
|
1725
|
+
"#A0F0A0",
|
|
1726
|
+
"#36B536"
|
|
1727
|
+
],
|
|
1728
|
+
deleteRed: "#D63B22",
|
|
1729
|
+
upGreen: "#7CFF7C"
|
|
1730
|
+
};
|
|
1731
|
+
//#endregion
|
|
1732
|
+
//#region src/ui/tui/components/visualizer/panel.tsx
|
|
1733
|
+
/**
|
|
1734
|
+
* Shared scaffolding for the phase visuals — Matrix-green color, common
|
|
1735
|
+
* VisualProps shape, and the rounded `Panel` shell every visual sits in.
|
|
1736
|
+
*
|
|
1737
|
+
* Visuals each render their own grid then wrap it in `<Panel>` so phase
|
|
1738
|
+
* transitions stay visually continuous.
|
|
1739
|
+
*/
|
|
1740
|
+
const MATRIX_FADE = VISUALIZER_PALETTE.fade;
|
|
1741
|
+
const Panel = ({ children }) => /* @__PURE__ */ jsx(Box, {
|
|
1742
|
+
flexDirection: "column",
|
|
1743
|
+
borderStyle: "round",
|
|
1744
|
+
borderColor: MATRIX_FADE,
|
|
1745
|
+
children
|
|
1746
|
+
});
|
|
1747
|
+
//#endregion
|
|
1748
|
+
//#region src/ui/tui/components/visualizer/MatrixRain.tsx
|
|
1749
|
+
/**
|
|
1750
|
+
* MatrixRain — code-rain visual used for the codebase-scan phase.
|
|
1751
|
+
*
|
|
1752
|
+
* Independent of the phase orchestrator so it can be reused elsewhere
|
|
1753
|
+
* (e.g. standalone in a demo). `bordered` toggles the rounded green frame.
|
|
1754
|
+
*/
|
|
1755
|
+
const { head: MATRIX_HEAD, bright: MATRIX_BRIGHT, mid: MATRIX_MID } = VISUALIZER_PALETTE;
|
|
1756
|
+
const DEFAULT_TICK_MS = 110;
|
|
1757
|
+
const DEFAULT_MAX_TAIL = 7;
|
|
1758
|
+
const RAIN_GLYPHS = "ヲァィゥェォャュョッアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン0123456789Z<>=*+:.";
|
|
1759
|
+
function pickGlyph() {
|
|
1760
|
+
return RAIN_GLYPHS[Math.floor(Math.random() * 73)];
|
|
1761
|
+
}
|
|
1762
|
+
function makeRainColumn(height, maxTail) {
|
|
1763
|
+
return {
|
|
1764
|
+
headY: -Math.random() * height,
|
|
1765
|
+
speed: .3 + Math.random() * .9,
|
|
1766
|
+
tail: 3 + Math.floor(Math.random() * (maxTail - 2)),
|
|
1767
|
+
glyphs: /* @__PURE__ */ new Map(),
|
|
1768
|
+
dormant: Math.floor(Math.random() * 18)
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
function tickRainColumn(col, height, maxTail) {
|
|
1772
|
+
if (col.dormant > 0) return {
|
|
1773
|
+
...col,
|
|
1774
|
+
dormant: col.dormant - 1
|
|
1775
|
+
};
|
|
1776
|
+
const next = col.headY + col.speed;
|
|
1777
|
+
if (next > height + col.tail) return makeRainColumn(height, maxTail);
|
|
1778
|
+
const glyphs = new Map(col.glyphs);
|
|
1779
|
+
for (let y = Math.max(0, Math.ceil(col.headY)); y <= Math.min(Math.floor(next), height - 1); y++) glyphs.set(y, pickGlyph());
|
|
1780
|
+
if (glyphs.size > 0 && Math.random() < .22) {
|
|
1781
|
+
const keys = [...glyphs.keys()];
|
|
1782
|
+
const k = keys[Math.floor(Math.random() * keys.length)];
|
|
1783
|
+
glyphs.set(k, pickGlyph());
|
|
1784
|
+
}
|
|
1785
|
+
return {
|
|
1786
|
+
...col,
|
|
1787
|
+
headY: next,
|
|
1788
|
+
glyphs
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
const MatrixRain = ({ width, height, tickMs = DEFAULT_TICK_MS, maxTail = DEFAULT_MAX_TAIL, bordered = true }) => {
|
|
1792
|
+
const columnsRef = useRef(Array.from({ length: width }, () => makeRainColumn(height, maxTail)));
|
|
1793
|
+
const [, setTick] = useState(0);
|
|
1794
|
+
useEffect(() => {
|
|
1795
|
+
const interval = setInterval(() => {
|
|
1796
|
+
columnsRef.current = columnsRef.current.map((c) => tickRainColumn(c, height, maxTail));
|
|
1797
|
+
setTick((t) => t + 1);
|
|
1798
|
+
}, tickMs);
|
|
1799
|
+
return () => clearInterval(interval);
|
|
1800
|
+
}, [
|
|
1801
|
+
height,
|
|
1802
|
+
maxTail,
|
|
1803
|
+
tickMs
|
|
1804
|
+
]);
|
|
1805
|
+
const columns = columnsRef.current;
|
|
1806
|
+
const body = Array.from({ length: height }).map((_, y) => /* @__PURE__ */ jsx(Box, { children: columns.map((col, x) => {
|
|
1807
|
+
const glyph = col.glyphs.get(y);
|
|
1808
|
+
if (!glyph) return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
1809
|
+
const dist = col.headY - y;
|
|
1810
|
+
if (dist < 0 || dist > col.tail) return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
1811
|
+
if (dist < 1) return /* @__PURE__ */ jsx(Text, {
|
|
1812
|
+
bold: true,
|
|
1813
|
+
color: MATRIX_HEAD,
|
|
1814
|
+
children: glyph
|
|
1815
|
+
}, x);
|
|
1816
|
+
if (dist < 2) return /* @__PURE__ */ jsx(Text, {
|
|
1817
|
+
color: MATRIX_BRIGHT,
|
|
1818
|
+
children: glyph
|
|
1819
|
+
}, x);
|
|
1820
|
+
if (dist < col.tail * .55) return /* @__PURE__ */ jsx(Text, {
|
|
1821
|
+
color: MATRIX_MID,
|
|
1822
|
+
children: glyph
|
|
1823
|
+
}, x);
|
|
1824
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1825
|
+
color: MATRIX_FADE,
|
|
1826
|
+
dimColor: true,
|
|
1827
|
+
children: glyph
|
|
1828
|
+
}, x);
|
|
1829
|
+
}) }, y));
|
|
1830
|
+
if (!bordered) return /* @__PURE__ */ jsx(Box, {
|
|
1831
|
+
flexDirection: "column",
|
|
1832
|
+
children: body
|
|
1833
|
+
});
|
|
1834
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
1835
|
+
flexDirection: "column",
|
|
1836
|
+
borderStyle: "round",
|
|
1837
|
+
borderColor: MATRIX_FADE,
|
|
1838
|
+
children: body
|
|
1839
|
+
});
|
|
1840
|
+
};
|
|
1841
|
+
//#endregion
|
|
1842
|
+
//#region src/ui/tui/components/visualizer/grid.ts
|
|
1843
|
+
/** Allocate a blank `width`×`height` grid of spaces. Degenerate or negative
|
|
1844
|
+
* dimensions collapse to an empty grid rather than throwing. */
|
|
1845
|
+
const createGrid = (width, height) => {
|
|
1846
|
+
const h = Math.max(0, Math.floor(height));
|
|
1847
|
+
const w = Math.max(0, Math.floor(width));
|
|
1848
|
+
return Array.from({ length: h }, () => new Array(w).fill(" "));
|
|
1849
|
+
};
|
|
1850
|
+
/** Write a single cell, ignoring any coordinate outside the grid (including
|
|
1851
|
+
* negative or fractional ones). This is the one guard the visuals rely on to
|
|
1852
|
+
* never crash regardless of panel size. */
|
|
1853
|
+
const plot = (grid, x, y, ch) => {
|
|
1854
|
+
const row = grid[y];
|
|
1855
|
+
if (row === void 0) return;
|
|
1856
|
+
if (x < 0 || x >= row.length) return;
|
|
1857
|
+
row[x] = ch;
|
|
1858
|
+
};
|
|
1859
|
+
/** Write `text` left-to-right starting at (x, y). Clips at the grid edge and,
|
|
1860
|
+
* when given, after `maxW` characters. Off-grid cells are dropped by `plot`. */
|
|
1861
|
+
const writeText = (grid, x, y, text, maxW) => {
|
|
1862
|
+
const limit = maxW === void 0 ? text.length : Math.max(0, maxW);
|
|
1863
|
+
for (let i = 0; i < text.length && i < limit; i++) plot(grid, x + i, y, text[i]);
|
|
1864
|
+
};
|
|
1865
|
+
//#endregion
|
|
1866
|
+
//#region src/ui/tui/components/visualizer/LibraryShelf.tsx
|
|
1867
|
+
/**
|
|
1868
|
+
* LibraryShelf — skill-selection phase.
|
|
1869
|
+
*
|
|
1870
|
+
* A row of book spines. One spine peels forward each cycle, the chosen
|
|
1871
|
+
* title hovers next to it, then it slides home and the next one is picked.
|
|
1872
|
+
*/
|
|
1873
|
+
const BOOK_LABELS = [
|
|
1874
|
+
"nx",
|
|
1875
|
+
"rt",
|
|
1876
|
+
"sv",
|
|
1877
|
+
"fl",
|
|
1878
|
+
"jg",
|
|
1879
|
+
"rb",
|
|
1880
|
+
"go",
|
|
1881
|
+
"dj",
|
|
1882
|
+
"fa",
|
|
1883
|
+
"lv",
|
|
1884
|
+
"ts",
|
|
1885
|
+
"py"
|
|
1886
|
+
];
|
|
1887
|
+
const BOOK_COLORS = VISUALIZER_PALETTE.book;
|
|
1888
|
+
const LibraryShelf = ({ width, height }) => {
|
|
1889
|
+
const tick = useTick(380);
|
|
1890
|
+
const bookCount = Math.min(Math.floor((width - 2) / 2), BOOK_LABELS.length);
|
|
1891
|
+
const cyclePos = tick % (bookCount * 4);
|
|
1892
|
+
const selectedIdx = Math.floor(cyclePos / 4);
|
|
1893
|
+
const phase = cyclePos % 4;
|
|
1894
|
+
const offset = phase === 0 ? 0 : phase === 1 ? 1 : phase === 2 ? 2 : 1;
|
|
1895
|
+
const wobble = phase === 2 && tick % 2 === 0 ? 1 : 0;
|
|
1896
|
+
const shelfY = Math.min(Math.max(1, Math.floor(height / 2) - 1), height - 3);
|
|
1897
|
+
const rows = createGrid(width, height);
|
|
1898
|
+
for (let i = 0; i < bookCount; i++) {
|
|
1899
|
+
const x = 1 + i * 2;
|
|
1900
|
+
const isSelected = i === selectedIdx;
|
|
1901
|
+
const shift = isSelected ? offset : 0;
|
|
1902
|
+
const wob = isSelected && wobble ? -1 : 0;
|
|
1903
|
+
plot(rows, x + shift, shelfY - 1, "█");
|
|
1904
|
+
plot(rows, x + shift, shelfY, BOOK_LABELS[i][0]);
|
|
1905
|
+
plot(rows, x + shift, shelfY + 1, BOOK_LABELS[i][1]);
|
|
1906
|
+
plot(rows, x + shift, shelfY + 2 + wob, "█");
|
|
1907
|
+
}
|
|
1908
|
+
const boardY = shelfY + 3;
|
|
1909
|
+
for (let x = 0; x < width; x++) plot(rows, x, boardY, "─");
|
|
1910
|
+
if (phase === 2) {
|
|
1911
|
+
const labelStartX = 1 + selectedIdx * 2 + 4;
|
|
1912
|
+
writeText(rows, labelStartX, shelfY, BOOK_LABELS[selectedIdx] + "-app");
|
|
1913
|
+
plot(rows, labelStartX - 1, shelfY, "▶");
|
|
1914
|
+
}
|
|
1915
|
+
return /* @__PURE__ */ jsx(Panel, { children: rows.map((row, y) => /* @__PURE__ */ jsx(Box, { children: row.map((ch, x) => {
|
|
1916
|
+
if (ch === " ") return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
1917
|
+
if (ch === "─") return /* @__PURE__ */ jsx(Text, {
|
|
1918
|
+
color: MATRIX_FADE,
|
|
1919
|
+
dimColor: true,
|
|
1920
|
+
children: "─"
|
|
1921
|
+
}, x);
|
|
1922
|
+
if (ch === "▶") return /* @__PURE__ */ jsx(Text, {
|
|
1923
|
+
bold: true,
|
|
1924
|
+
color: VISUALIZER_PALETTE.head,
|
|
1925
|
+
children: "▶"
|
|
1926
|
+
}, x);
|
|
1927
|
+
const booksColor = BOOK_COLORS[(Math.floor((x - 1) / 2) + 17 * y) % BOOK_COLORS.length];
|
|
1928
|
+
const isSel = x === 1 + selectedIdx * 2 + offset;
|
|
1929
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
1930
|
+
bold: isSel,
|
|
1931
|
+
color: isSel ? VISUALIZER_PALETTE.head : booksColor,
|
|
1932
|
+
children: ch
|
|
1933
|
+
}, x);
|
|
1934
|
+
}) }, y)) });
|
|
1935
|
+
};
|
|
1936
|
+
//#endregion
|
|
1937
|
+
//#region src/ui/tui/components/visualizer/CrateStack.tsx
|
|
1938
|
+
/**
|
|
1939
|
+
* CrateStack — dependency-install phase.
|
|
1940
|
+
*
|
|
1941
|
+
* Boxes drop from the top and stack at the bottom. Each new arrival lands
|
|
1942
|
+
* with a tiny shake.
|
|
1943
|
+
*/
|
|
1944
|
+
const PACKAGE_NAMES = [
|
|
1945
|
+
"posthog-js",
|
|
1946
|
+
"posthog-py",
|
|
1947
|
+
"posthog-rb",
|
|
1948
|
+
"posthog-go",
|
|
1949
|
+
"posthog-node",
|
|
1950
|
+
"react-ph",
|
|
1951
|
+
"next-ph",
|
|
1952
|
+
"svelte-ph",
|
|
1953
|
+
"ph-mcp",
|
|
1954
|
+
"ph-ai"
|
|
1955
|
+
];
|
|
1956
|
+
const CRATE_W = Math.max(...PACKAGE_NAMES.map((n) => n.length)) + 2;
|
|
1957
|
+
const CrateStack = ({ width, height }) => {
|
|
1958
|
+
const tick = useTick(95);
|
|
1959
|
+
const state = useRef({
|
|
1960
|
+
stack: [],
|
|
1961
|
+
falling: null,
|
|
1962
|
+
spawnCooldown: 0
|
|
1963
|
+
}).current;
|
|
1964
|
+
const crateW = CRATE_W;
|
|
1965
|
+
const crateH = 1;
|
|
1966
|
+
const floorY = height - 1;
|
|
1967
|
+
if (state.falling) {
|
|
1968
|
+
state.falling.y += 1;
|
|
1969
|
+
const collisionStackHeight = state.stack.filter((c) => Math.abs(c.x - state.falling.x) < crateW - 1).length * crateH;
|
|
1970
|
+
if (state.falling.y >= floorY - collisionStackHeight) {
|
|
1971
|
+
state.stack.push({
|
|
1972
|
+
label: state.falling.label,
|
|
1973
|
+
x: state.falling.x,
|
|
1974
|
+
landedAt: tick
|
|
1975
|
+
});
|
|
1976
|
+
state.falling = null;
|
|
1977
|
+
state.spawnCooldown = 3;
|
|
1978
|
+
}
|
|
1979
|
+
} else if (state.spawnCooldown > 0) state.spawnCooldown -= 1;
|
|
1980
|
+
else if (state.stack.length < Math.floor(height / crateH) - 1) state.falling = {
|
|
1981
|
+
label: PACKAGE_NAMES[Math.floor(Math.random() * PACKAGE_NAMES.length)],
|
|
1982
|
+
x: 2 + Math.floor(Math.random() * Math.max(1, width - crateW - 4)),
|
|
1983
|
+
y: -1
|
|
1984
|
+
};
|
|
1985
|
+
else if (tick % 20 === 0) state.stack = [];
|
|
1986
|
+
const grid = createGrid(width, height);
|
|
1987
|
+
const drawCrate = (cx, cy, label, shake) => {
|
|
1988
|
+
const x = cx + shake;
|
|
1989
|
+
const padded = `[${label.slice(0, crateW - 2)}]`.padEnd(crateW, " ");
|
|
1990
|
+
for (let i = 0; i < crateW; i++) plot(grid, x + i, cy, padded[i]);
|
|
1991
|
+
};
|
|
1992
|
+
state.stack.forEach((c, idx) => {
|
|
1993
|
+
const cy = floorY - idx;
|
|
1994
|
+
const shake = tick - c.landedAt === 0 ? 1 : tick - c.landedAt === 1 ? -1 : 0;
|
|
1995
|
+
drawCrate(c.x, cy, c.label, shake);
|
|
1996
|
+
});
|
|
1997
|
+
if (state.falling) drawCrate(state.falling.x, state.falling.y, state.falling.label, 0);
|
|
1998
|
+
return /* @__PURE__ */ jsx(Panel, { children: grid.map((row, y) => /* @__PURE__ */ jsx(Box, { children: row.map((ch, x) => {
|
|
1999
|
+
if (ch === " ") return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
2000
|
+
const isFalling = state.falling && y === state.falling.y && Math.abs(x - state.falling.x) < crateW;
|
|
2001
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2002
|
+
bold: isFalling,
|
|
2003
|
+
color: isFalling ? VISUALIZER_PALETTE.head : VISUALIZER_PALETTE.mid,
|
|
2004
|
+
children: ch
|
|
2005
|
+
}, x);
|
|
2006
|
+
}) }, y)) });
|
|
2007
|
+
};
|
|
2008
|
+
//#endregion
|
|
2009
|
+
//#region src/ui/tui/components/visualizer/DiffCascade.tsx
|
|
2010
|
+
/**
|
|
2011
|
+
* DiffCascade — code-edits phase.
|
|
2012
|
+
*
|
|
2013
|
+
* + and - code lines scroll upward continuously. Occasional comment-rewrite
|
|
2014
|
+
* gag: a "// hmm…" line appears, gets - struck out, then a + replaces it.
|
|
2015
|
+
*/
|
|
2016
|
+
const CODE_SNIPPETS = [
|
|
2017
|
+
"import posthog from 'posthog-js'",
|
|
2018
|
+
"posthog.init(KEY, { host: HOST })",
|
|
2019
|
+
"<PostHogProvider client={posthog}>",
|
|
2020
|
+
" {children}",
|
|
2021
|
+
"</PostHogProvider>",
|
|
2022
|
+
"posthog.capture('page_viewed')",
|
|
2023
|
+
"posthog.capture('signup_started')",
|
|
2024
|
+
"posthog.identify(user.id, { email })",
|
|
2025
|
+
"if (process.env.NODE_ENV !== 'test') posthog.init(KEY)",
|
|
2026
|
+
"export const posthog = new PostHog(KEY)",
|
|
2027
|
+
"// TODO: enable replay",
|
|
2028
|
+
"window.posthog = posthog"
|
|
2029
|
+
];
|
|
2030
|
+
const WHIMSY_COMMENTS = [
|
|
2031
|
+
"// hmm — that should be a hook",
|
|
2032
|
+
"// wait, refactor incoming",
|
|
2033
|
+
"// posthog says hi"
|
|
2034
|
+
];
|
|
2035
|
+
const DiffCascade = ({ width, height }) => {
|
|
2036
|
+
const tick = useTick(280);
|
|
2037
|
+
const linesRef = useRef([]);
|
|
2038
|
+
if (linesRef.current.length === 0) for (let i = 0; i < height; i++) linesRef.current.push({
|
|
2039
|
+
sign: Math.random() < .75 ? "+" : "-",
|
|
2040
|
+
text: CODE_SNIPPETS[Math.floor(Math.random() * CODE_SNIPPETS.length)]
|
|
2041
|
+
});
|
|
2042
|
+
linesRef.current.shift();
|
|
2043
|
+
const whimsy = tick % 23 === 0;
|
|
2044
|
+
linesRef.current.push({
|
|
2045
|
+
sign: whimsy ? "-" : Math.random() < .78 ? "+" : "-",
|
|
2046
|
+
text: whimsy ? WHIMSY_COMMENTS[Math.floor(Math.random() * WHIMSY_COMMENTS.length)] : CODE_SNIPPETS[Math.floor(Math.random() * CODE_SNIPPETS.length)]
|
|
2047
|
+
});
|
|
2048
|
+
const lines = linesRef.current;
|
|
2049
|
+
return /* @__PURE__ */ jsx(Panel, { children: Array.from({ length: height }).map((_, y) => {
|
|
2050
|
+
const line = lines[y] ?? {
|
|
2051
|
+
sign: " ",
|
|
2052
|
+
text: ""
|
|
2053
|
+
};
|
|
2054
|
+
const cap = width - 2;
|
|
2055
|
+
const text = `${line.sign} ${line.text}`.slice(0, cap);
|
|
2056
|
+
return /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(Text, {
|
|
2057
|
+
color: line.sign === "+" ? VISUALIZER_PALETTE.mid : line.sign === "-" ? VISUALIZER_PALETTE.deleteRed : MATRIX_FADE,
|
|
2058
|
+
children: text.padEnd(cap, " ")
|
|
2059
|
+
}) }, y);
|
|
2060
|
+
}) });
|
|
2061
|
+
};
|
|
2062
|
+
//#endregion
|
|
2063
|
+
//#region src/ui/tui/components/visualizer/Tumblers.tsx
|
|
2064
|
+
/**
|
|
2065
|
+
* Tumblers — env-setup phase.
|
|
2066
|
+
*
|
|
2067
|
+
* Pins fall into a lock cylinder one by one; when all six align the bolt
|
|
2068
|
+
* pulses green for a beat, then the cycle restarts.
|
|
2069
|
+
*/
|
|
2070
|
+
const Tumblers = ({ width, height }) => {
|
|
2071
|
+
const tick = useTick(80);
|
|
2072
|
+
const pinCount = Math.min(Math.floor((width - 2) / 2), 6);
|
|
2073
|
+
const state = useRef({
|
|
2074
|
+
heights: new Array(pinCount).fill(0),
|
|
2075
|
+
current: 0,
|
|
2076
|
+
fallY: 0,
|
|
2077
|
+
pulse: 0
|
|
2078
|
+
}).current;
|
|
2079
|
+
const cylinderTop = 1;
|
|
2080
|
+
const cylinderBottom = height - 2;
|
|
2081
|
+
const targetForPin = (i) => Math.max(cylinderTop, Math.min(cylinderBottom, cylinderBottom - 1 - i % 3 - Math.floor(i / 2)));
|
|
2082
|
+
if (state.pulse > 0) {
|
|
2083
|
+
state.pulse -= 1;
|
|
2084
|
+
if (state.pulse === 0) {
|
|
2085
|
+
state.heights = new Array(pinCount).fill(0);
|
|
2086
|
+
state.current = 0;
|
|
2087
|
+
state.fallY = 0;
|
|
2088
|
+
}
|
|
2089
|
+
} else if (state.current < pinCount) {
|
|
2090
|
+
state.fallY += 1;
|
|
2091
|
+
if (state.fallY >= targetForPin(state.current)) {
|
|
2092
|
+
state.heights[state.current] = targetForPin(state.current);
|
|
2093
|
+
state.current += 1;
|
|
2094
|
+
state.fallY = cylinderTop;
|
|
2095
|
+
}
|
|
2096
|
+
} else state.pulse = 14;
|
|
2097
|
+
const grid = createGrid(width, height);
|
|
2098
|
+
for (let y = 0; y < height; y++) {
|
|
2099
|
+
plot(grid, 0, y, "│");
|
|
2100
|
+
plot(grid, width - 1, y, "│");
|
|
2101
|
+
}
|
|
2102
|
+
for (let i = 0; i < pinCount; i++) plot(grid, 1 + i * 2 + 1, 0, "▼");
|
|
2103
|
+
for (let x = 1; x < width - 1; x++) plot(grid, x, height - 1, "─");
|
|
2104
|
+
for (let i = 0; i < pinCount; i++) {
|
|
2105
|
+
const pinX = 1 + i * 2 + 1;
|
|
2106
|
+
const top = state.heights[i] || cylinderTop;
|
|
2107
|
+
for (let y = top; y <= cylinderBottom; y++) plot(grid, pinX, y, "█");
|
|
2108
|
+
}
|
|
2109
|
+
if (state.pulse === 0 && state.current < pinCount) plot(grid, 1 + state.current * 2 + 1, state.fallY, "█");
|
|
2110
|
+
const pulsing = state.pulse > 0;
|
|
2111
|
+
const pulseBright = pulsing && tick % 2 === 0;
|
|
2112
|
+
return /* @__PURE__ */ jsx(Panel, { children: grid.map((row, y) => /* @__PURE__ */ jsx(Box, { children: row.map((ch, x) => {
|
|
2113
|
+
if (ch === " ") return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
2114
|
+
if (ch === "│" || ch === "─" || ch === "▼") return /* @__PURE__ */ jsx(Text, {
|
|
2115
|
+
color: pulsing ? pulseBright ? VISUALIZER_PALETTE.bright : MATRIX_FADE : MATRIX_FADE,
|
|
2116
|
+
dimColor: !pulsing,
|
|
2117
|
+
children: ch
|
|
2118
|
+
}, x);
|
|
2119
|
+
const isFalling = state.pulse === 0 && state.current < pinCount && y === state.fallY && x === 1 + state.current * 2 + 1;
|
|
2120
|
+
const color = pulsing ? pulseBright ? VISUALIZER_PALETTE.head : VISUALIZER_PALETTE.bright : isFalling ? VISUALIZER_PALETTE.head : VISUALIZER_PALETTE.mid;
|
|
2121
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2122
|
+
bold: pulsing || isFalling,
|
|
2123
|
+
color,
|
|
2124
|
+
children: ch
|
|
2125
|
+
}, x);
|
|
2126
|
+
}) }, y)) });
|
|
2127
|
+
};
|
|
2128
|
+
//#endregion
|
|
2129
|
+
//#region src/ui/tui/components/visualizer/DashboardGrid.tsx
|
|
2130
|
+
/**
|
|
2131
|
+
* DashboardGrid — dashboards phase.
|
|
2132
|
+
*
|
|
2133
|
+
* 2×2 grid of mini-charts to evoke a real PostHog dashboard. When the area
|
|
2134
|
+
* is too small, the layout collapses to 1×2 or 1×1 so something always
|
|
2135
|
+
* renders.
|
|
2136
|
+
*/
|
|
2137
|
+
const DASHBOARD_TILES = [
|
|
2138
|
+
{
|
|
2139
|
+
title: "Visitors",
|
|
2140
|
+
kind: "bars"
|
|
2141
|
+
},
|
|
2142
|
+
{
|
|
2143
|
+
title: "Sessions",
|
|
2144
|
+
kind: "line"
|
|
2145
|
+
},
|
|
2146
|
+
{
|
|
2147
|
+
title: "Revenue",
|
|
2148
|
+
kind: "gauge"
|
|
2149
|
+
},
|
|
2150
|
+
{
|
|
2151
|
+
title: "Errors",
|
|
2152
|
+
kind: "pulse"
|
|
2153
|
+
}
|
|
2154
|
+
];
|
|
2155
|
+
const SPARK_GLYPHS = "▁▂▃▄▅▆▇█";
|
|
2156
|
+
const DashboardGrid = ({ width, height }) => {
|
|
2157
|
+
const tick = useTick(220);
|
|
2158
|
+
const grid = createGrid(width, height);
|
|
2159
|
+
const cols = width >= 22 ? 2 : 1;
|
|
2160
|
+
const rows = height >= 7 ? 2 : 1;
|
|
2161
|
+
const vSplit = cols === 2 ? Math.floor(width / 2) : -1;
|
|
2162
|
+
const hSplit = rows === 2 ? Math.floor(height / 2) : -1;
|
|
2163
|
+
if (vSplit >= 0) for (let y = 0; y < height; y++) plot(grid, vSplit, y, "│");
|
|
2164
|
+
if (hSplit >= 0) {
|
|
2165
|
+
for (let x = 0; x < width; x++) plot(grid, x, hSplit, "─");
|
|
2166
|
+
if (vSplit >= 0) plot(grid, vSplit, hSplit, "┼");
|
|
2167
|
+
}
|
|
2168
|
+
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) {
|
|
2169
|
+
const tile = DASHBOARD_TILES[r * cols + c];
|
|
2170
|
+
const tileX = c === 0 ? 0 : vSplit + 1;
|
|
2171
|
+
const tileY = r === 0 ? 0 : hSplit + 1;
|
|
2172
|
+
const tileW = cols === 2 ? c === 0 ? vSplit : width - vSplit - 1 : width;
|
|
2173
|
+
const tileH = rows === 2 ? r === 0 ? hSplit : height - hSplit - 1 : height;
|
|
2174
|
+
const innerX = tileX;
|
|
2175
|
+
const innerW = Math.max(1, tileW);
|
|
2176
|
+
const titleY = tileY;
|
|
2177
|
+
const valueY = tileY + tileH - 1;
|
|
2178
|
+
const chartY0 = tileY + 1;
|
|
2179
|
+
const chartY1 = Math.max(chartY0, valueY - 1);
|
|
2180
|
+
const chartH = Math.max(1, chartY1 - chartY0 + 1);
|
|
2181
|
+
const seed = (r * cols + c) * 13;
|
|
2182
|
+
writeText(grid, innerX, titleY, tile.title, innerW);
|
|
2183
|
+
renderTile(grid, tile.kind, innerX, chartY0, innerW, chartH, tick, seed);
|
|
2184
|
+
writeText(grid, innerX, valueY, tileValue(tile.kind, tick, seed), innerW);
|
|
2185
|
+
}
|
|
2186
|
+
return /* @__PURE__ */ jsx(Panel, { children: grid.map((row, y) => /* @__PURE__ */ jsx(Box, { children: row.map((ch, x) => {
|
|
2187
|
+
if (ch === " ") return /* @__PURE__ */ jsx(Text, { children: " " }, x);
|
|
2188
|
+
if (ch === "│" || ch === "─" || ch === "┼") return /* @__PURE__ */ jsx(Text, {
|
|
2189
|
+
color: MATRIX_FADE,
|
|
2190
|
+
dimColor: true,
|
|
2191
|
+
children: ch
|
|
2192
|
+
}, x);
|
|
2193
|
+
if (SPARK_GLYPHS.includes(ch) || ch === "█") return /* @__PURE__ */ jsx(Text, {
|
|
2194
|
+
color: VISUALIZER_PALETTE.mid,
|
|
2195
|
+
children: ch
|
|
2196
|
+
}, x);
|
|
2197
|
+
if (ch === "●" || ch === "∙" || ch === "·") {
|
|
2198
|
+
const color = ch === "●" ? VISUALIZER_PALETTE.head : ch === "∙" ? VISUALIZER_PALETTE.bright : VISUALIZER_PALETTE.mid;
|
|
2199
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2200
|
+
bold: ch === "●",
|
|
2201
|
+
color,
|
|
2202
|
+
children: ch
|
|
2203
|
+
}, x);
|
|
2204
|
+
}
|
|
2205
|
+
if (ch === "▲" || ch === "▼") return /* @__PURE__ */ jsx(Text, {
|
|
2206
|
+
bold: true,
|
|
2207
|
+
color: ch === "▲" ? VISUALIZER_PALETTE.upGreen : VISUALIZER_PALETTE.deleteRed,
|
|
2208
|
+
children: ch
|
|
2209
|
+
}, x);
|
|
2210
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
2211
|
+
color: VISUALIZER_PALETTE.bright,
|
|
2212
|
+
children: ch
|
|
2213
|
+
}, x);
|
|
2214
|
+
}) }, y)) });
|
|
2215
|
+
};
|
|
2216
|
+
function renderTile(grid, kind, x0, y0, w, h, tick, seed) {
|
|
2217
|
+
const set = (x, y, ch) => plot(grid, x, y, ch);
|
|
2218
|
+
if (kind === "bars") for (let i = 0; i < w; i++) {
|
|
2219
|
+
const t = tick * .18 + (i + seed) * .6;
|
|
2220
|
+
const level = .55 + .35 * Math.sin(t) + .1 * Math.sin(t * 2.7);
|
|
2221
|
+
const filled = Math.max(0, Math.min(h, Math.round(level * h)));
|
|
2222
|
+
for (let j = 0; j < filled; j++) set(x0 + i, y0 + h - 1 - j, "█");
|
|
2223
|
+
if (filled > 0 && filled < h) {
|
|
2224
|
+
const frac = level * h - Math.floor(level * h);
|
|
2225
|
+
const glyph = SPARK_GLYPHS[Math.floor(frac * 7)];
|
|
2226
|
+
set(x0 + i, y0 + h - filled, glyph);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
else if (kind === "line") {
|
|
2230
|
+
const spikeAt = ((tick / 12 | 0) + seed) % Math.max(1, w);
|
|
2231
|
+
for (let i = 0; i < w; i++) {
|
|
2232
|
+
const norm = i / Math.max(1, w - 1);
|
|
2233
|
+
const base = h - 1 - norm * (h - 1);
|
|
2234
|
+
let yf = base + .6 * Math.sin(i * .7 + seed + tick * .05);
|
|
2235
|
+
if (i === spikeAt) yf = Math.max(0, base - 1.5);
|
|
2236
|
+
const y = Math.max(0, Math.min(h - 1, Math.round(yf)));
|
|
2237
|
+
const dist = Math.abs(i - (w - 1));
|
|
2238
|
+
const ch = dist === 0 ? "●" : dist < 3 ? "∙" : "·";
|
|
2239
|
+
set(x0 + i, y0 + y, ch);
|
|
2240
|
+
}
|
|
2241
|
+
} else if (kind === "gauge") {
|
|
2242
|
+
const cycle = (tick + seed) % 40;
|
|
2243
|
+
const pct = cycle < 30 ? cycle / 30 : 1 - (cycle - 30) / 10;
|
|
2244
|
+
const midY = y0 + Math.floor(h / 2);
|
|
2245
|
+
const filled = Math.max(0, Math.min(w, Math.round(pct * w)));
|
|
2246
|
+
for (let i = 0; i < w; i++) set(x0 + i, midY, i < filled ? "█" : "·");
|
|
2247
|
+
} else if (kind === "pulse") for (let i = 0; i < w; i++) {
|
|
2248
|
+
const t = (i + seed + Math.floor(tick / 3)) % 17;
|
|
2249
|
+
let level;
|
|
2250
|
+
if (t === 0) level = .9;
|
|
2251
|
+
else if (t === 1 || t === 16) level = .5;
|
|
2252
|
+
else level = .12 + .06 * Math.sin((i + tick) * .5);
|
|
2253
|
+
const filled = Math.max(1, Math.min(h, Math.round(level * h)));
|
|
2254
|
+
for (let j = 0; j < filled; j++) set(x0 + i, y0 + h - 1 - j, "█");
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function tileValue(kind, tick, seed) {
|
|
2258
|
+
const wave = .5 + .5 * Math.sin(tick * .05 + seed);
|
|
2259
|
+
if (kind === "bars") return `${(Math.round(8e3 + wave * 6e3) / 1e3).toFixed(1)}k ▲`;
|
|
2260
|
+
if (kind === "line") return `${(2 + wave * 4).toFixed(1)}% ▲`;
|
|
2261
|
+
if (kind === "gauge") return `$${Math.round(20 + wave * 60)}k`;
|
|
2262
|
+
return `${Math.round(1 + wave * 5)} ▼`;
|
|
2263
|
+
}
|
|
2264
|
+
//#endregion
|
|
2265
|
+
//#region src/ui/tui/components/PhaseVisuals.tsx
|
|
2266
|
+
/**
|
|
2267
|
+
* Phase visuals — ambient ASCII visualizations of what the agent is currently
|
|
2268
|
+
* doing. The active phase is derived from the in-progress task labels (best-
|
|
2269
|
+
* effort heuristic). Each phase has its own component (under ./visualizer);
|
|
2270
|
+
* the orchestrator `PhaseVisual` picks which one to render.
|
|
2271
|
+
*
|
|
2272
|
+
* Width and height are passed in from the parent so visuals adapt to the
|
|
2273
|
+
* column they're placed in.
|
|
2274
|
+
*/
|
|
2275
|
+
const PHASE_LABELS = {
|
|
2276
|
+
["codebase-scan"]: "Reading the Code",
|
|
2277
|
+
["skill-install"]: "Picking the Right Skill",
|
|
2278
|
+
["dep-install"]: "Installing Packages",
|
|
2279
|
+
["code-edits"]: "Editing Source",
|
|
2280
|
+
["env-setup"]: "Wiring Up Secrets",
|
|
2281
|
+
["dashboards"]: "Building Dashboards"
|
|
2282
|
+
};
|
|
2283
|
+
/** Reads the active phase from the store. The agent loop pushes it in via
|
|
2284
|
+
* `getUI().setStage(...)` whenever a new tool fires. */
|
|
2285
|
+
function useAgentPhase(store) {
|
|
2286
|
+
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
2287
|
+
return store.currentStage?.stage ?? "codebase-scan";
|
|
2288
|
+
}
|
|
2289
|
+
/**
|
|
2290
|
+
* VisualizerTab — Winamp-style fullscreen take on the phase visual.
|
|
2291
|
+
* "NOW PLAYING" header, centered visual, transport bar with elapsed time.
|
|
2292
|
+
*
|
|
2293
|
+
* Sizes itself off the *measured* container rather than the raw terminal so
|
|
2294
|
+
* the tab bar / hints / status panel above don't get pushed off-screen on
|
|
2295
|
+
* short terminals. When height runs out, chrome rows drop in order:
|
|
2296
|
+
* transport bar first, then track title, then the NOW PLAYING header.
|
|
2297
|
+
*/
|
|
2298
|
+
const VisualizerTab = ({ store }) => {
|
|
2299
|
+
const phase = useAgentPhase(store);
|
|
2300
|
+
const containerRef = useRef(null);
|
|
2301
|
+
const [size, setSize] = useState({
|
|
2302
|
+
width: 0,
|
|
2303
|
+
height: 0
|
|
2304
|
+
});
|
|
2305
|
+
useEffect(() => {
|
|
2306
|
+
if (!containerRef.current) return;
|
|
2307
|
+
const m = measureElement(containerRef.current);
|
|
2308
|
+
if (m.width !== size.width || m.height !== size.height) setSize({
|
|
2309
|
+
width: m.width,
|
|
2310
|
+
height: m.height
|
|
2311
|
+
});
|
|
2312
|
+
}, [
|
|
2313
|
+
useTick(EQ_TICK_MS),
|
|
2314
|
+
size.width,
|
|
2315
|
+
size.height
|
|
2316
|
+
]);
|
|
2317
|
+
const HEADER_ROWS = 2;
|
|
2318
|
+
const TITLE_ROWS = 2;
|
|
2319
|
+
const TRANSPORT_ROWS = 2;
|
|
2320
|
+
const BORDER_ROWS = 2;
|
|
2321
|
+
const MIN_VISUAL_H = 5;
|
|
2322
|
+
const availH = size.height;
|
|
2323
|
+
const availW = size.width;
|
|
2324
|
+
let chromeBudget = BORDER_ROWS + HEADER_ROWS + TITLE_ROWS + TRANSPORT_ROWS;
|
|
2325
|
+
let showHeader = true;
|
|
2326
|
+
let showTitle = true;
|
|
2327
|
+
let showTransport = true;
|
|
2328
|
+
if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {
|
|
2329
|
+
showTransport = false;
|
|
2330
|
+
chromeBudget -= TRANSPORT_ROWS;
|
|
2331
|
+
}
|
|
2332
|
+
if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {
|
|
2333
|
+
showTitle = false;
|
|
2334
|
+
chromeBudget -= TITLE_ROWS;
|
|
2335
|
+
}
|
|
2336
|
+
if (availH > 0 && availH - chromeBudget < MIN_VISUAL_H) {
|
|
2337
|
+
showHeader = false;
|
|
2338
|
+
chromeBudget -= HEADER_ROWS;
|
|
2339
|
+
}
|
|
2340
|
+
const visualH = availH > 0 ? Math.max(MIN_VISUAL_H, Math.min(18, availH - chromeBudget)) : MIN_VISUAL_H;
|
|
2341
|
+
const visualW = availW > 0 ? Math.max(20, Math.min(64, availW - 12)) : 40;
|
|
2342
|
+
const now = Date.now();
|
|
2343
|
+
const beatTimeMs = now - (store.currentStage?.startedAt ?? now);
|
|
2344
|
+
const timeStr = formatElapsed(Math.max(0, Math.floor(beatTimeMs / 1e3)));
|
|
2345
|
+
const equalizer = renderMiniEqualizer(beatTimeMs, useRef(new Array(EQ_BARS).fill(0)).current);
|
|
2346
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2347
|
+
ref: containerRef,
|
|
2348
|
+
flexDirection: "column",
|
|
2349
|
+
flexGrow: 1,
|
|
2350
|
+
alignItems: "center",
|
|
2351
|
+
justifyContent: "center",
|
|
2352
|
+
overflow: "hidden",
|
|
2353
|
+
children: [
|
|
2354
|
+
showHeader && /* @__PURE__ */ jsxs(Box, {
|
|
2355
|
+
flexDirection: "row",
|
|
2356
|
+
marginBottom: 1,
|
|
2357
|
+
children: [
|
|
2358
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2359
|
+
color: MATRIX_FADE,
|
|
2360
|
+
children: "┌─"
|
|
2361
|
+
}),
|
|
2362
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2363
|
+
bold: true,
|
|
2364
|
+
color: VISUALIZER_PALETTE.bright,
|
|
2365
|
+
children: " ► NOW PLAYING "
|
|
2366
|
+
}),
|
|
2367
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2368
|
+
color: MATRIX_FADE,
|
|
2369
|
+
children: "─┐"
|
|
2370
|
+
})
|
|
2371
|
+
]
|
|
2372
|
+
}),
|
|
2373
|
+
showTitle && /* @__PURE__ */ jsx(Box, {
|
|
2374
|
+
marginBottom: 1,
|
|
2375
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
2376
|
+
bold: true,
|
|
2377
|
+
color: VISUALIZER_PALETTE.head,
|
|
2378
|
+
children: [PHASE_LABELS[phase], " - PostHog"]
|
|
2379
|
+
})
|
|
2380
|
+
}),
|
|
2381
|
+
/* @__PURE__ */ jsx(PhaseBody, {
|
|
2382
|
+
phase,
|
|
2383
|
+
width: visualW,
|
|
2384
|
+
height: visualH
|
|
2385
|
+
}),
|
|
2386
|
+
showTransport && /* @__PURE__ */ jsxs(Box, {
|
|
2387
|
+
flexDirection: "row",
|
|
2388
|
+
marginTop: 1,
|
|
2389
|
+
gap: 2,
|
|
2390
|
+
children: [
|
|
2391
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2392
|
+
color: VISUALIZER_PALETTE.mid,
|
|
2393
|
+
children: [
|
|
2394
|
+
"[",
|
|
2395
|
+
timeStr,
|
|
2396
|
+
"]"
|
|
2397
|
+
]
|
|
2398
|
+
}),
|
|
2399
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2400
|
+
color: MATRIX_FADE,
|
|
2401
|
+
children: equalizer
|
|
2402
|
+
}),
|
|
2403
|
+
/* @__PURE__ */ jsx(Text, {
|
|
2404
|
+
color: VISUALIZER_PALETTE.mid,
|
|
2405
|
+
children: "WizardAmp"
|
|
2406
|
+
})
|
|
2407
|
+
]
|
|
2408
|
+
})
|
|
2409
|
+
]
|
|
2410
|
+
});
|
|
2411
|
+
};
|
|
2412
|
+
function formatElapsed(totalSec) {
|
|
2413
|
+
const m = Math.floor(totalSec / 60);
|
|
2414
|
+
const s = totalSec % 60;
|
|
2415
|
+
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
2416
|
+
}
|
|
2417
|
+
const BEAT_MS = 60 / 120 * 1e3;
|
|
2418
|
+
const EQ_BARS = 12;
|
|
2419
|
+
const EQ_TICK_MS = 67;
|
|
2420
|
+
const EQ_FALL_PER_FRAME = .08;
|
|
2421
|
+
function pulse(t, periodMs, decay, phaseMs = 0) {
|
|
2422
|
+
const since = (t - phaseMs + periodMs * 100) % periodMs;
|
|
2423
|
+
return Math.exp(-decay * since / periodMs);
|
|
2424
|
+
}
|
|
2425
|
+
const EQ_GLYPHS = "▁▂▃▄▅▆▇█";
|
|
2426
|
+
function renderMiniEqualizer(beatTimeMs, levels) {
|
|
2427
|
+
const kick = pulse(beatTimeMs, BEAT_MS, 4);
|
|
2428
|
+
const bass = pulse(beatTimeMs, BEAT_MS, 1.5);
|
|
2429
|
+
const clap = pulse(beatTimeMs, BEAT_MS * 2, 5, BEAT_MS);
|
|
2430
|
+
const hat8 = pulse(beatTimeMs, BEAT_MS / 2, 8);
|
|
2431
|
+
const hat16 = pulse(beatTimeMs, BEAT_MS / 4, 12);
|
|
2432
|
+
const pad = .2 + .15 * Math.sin(2 * Math.PI * beatTimeMs / 4e3);
|
|
2433
|
+
const mix = [
|
|
2434
|
+
bass * .7 + kick * .5 + pad,
|
|
2435
|
+
bass * .6 + kick * .6 + pad * .9,
|
|
2436
|
+
bass * .4 + kick * .7 + pad * .8,
|
|
2437
|
+
kick * .6 + clap * .3 + pad * .7,
|
|
2438
|
+
kick * .4 + clap * .5 + pad * .7,
|
|
2439
|
+
clap * .7 + hat8 * .3 + pad * .6,
|
|
2440
|
+
clap * .6 + hat8 * .5 + pad * .5,
|
|
2441
|
+
hat8 * .7 + clap * .3 + pad * .5,
|
|
2442
|
+
hat8 * .5 + hat16 * .4 + pad * .4,
|
|
2443
|
+
hat8 * .4 + hat16 * .5 + pad * .4,
|
|
2444
|
+
hat16 * .6 + hat8 * .3 + pad * .3,
|
|
2445
|
+
hat16 * .7 + pad * .3
|
|
2446
|
+
];
|
|
2447
|
+
let out = "";
|
|
2448
|
+
for (let i = 0; i < EQ_BARS; i++) {
|
|
2449
|
+
const target = Math.min(1, mix[i]);
|
|
2450
|
+
levels[i] = Math.max(target, levels[i] - EQ_FALL_PER_FRAME);
|
|
2451
|
+
out += EQ_GLYPHS[Math.floor(levels[i] * 7)];
|
|
2452
|
+
}
|
|
2453
|
+
return out;
|
|
2454
|
+
}
|
|
2455
|
+
const PhaseBody = ({ phase, width, height }) => {
|
|
2456
|
+
switch (phase) {
|
|
2457
|
+
case "codebase-scan": return /* @__PURE__ */ jsx(MatrixRain, {
|
|
2458
|
+
width,
|
|
2459
|
+
height
|
|
2460
|
+
});
|
|
2461
|
+
case "skill-install": return /* @__PURE__ */ jsx(LibraryShelf, {
|
|
2462
|
+
width,
|
|
2463
|
+
height
|
|
2464
|
+
});
|
|
2465
|
+
case "dep-install": return /* @__PURE__ */ jsx(CrateStack, {
|
|
2466
|
+
width,
|
|
2467
|
+
height
|
|
2468
|
+
});
|
|
2469
|
+
case "code-edits": return /* @__PURE__ */ jsx(DiffCascade, {
|
|
2470
|
+
width,
|
|
2471
|
+
height
|
|
2472
|
+
});
|
|
2473
|
+
case "env-setup": return /* @__PURE__ */ jsx(Tumblers, {
|
|
2474
|
+
width,
|
|
2475
|
+
height
|
|
2476
|
+
});
|
|
2477
|
+
case "dashboards": return /* @__PURE__ */ jsx(DashboardGrid, {
|
|
2478
|
+
width,
|
|
2479
|
+
height
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
};
|
|
2483
|
+
//#endregion
|
|
1700
2484
|
//#region src/ui/tui/components/ServiceHealthList.tsx
|
|
1701
2485
|
/**
|
|
1702
2486
|
* ServiceHealthList — Shared component for displaying service health status.
|
|
@@ -1920,6 +2704,39 @@ const markDone = (store, outcome, clients = [], featuresSelected) => {
|
|
|
1920
2704
|
store.setMcpComplete(outcome, clients, featuresSelected);
|
|
1921
2705
|
};
|
|
1922
2706
|
const reportFeatures = (features) => isAllFeaturesSelected(features) ? "all" : features;
|
|
2707
|
+
const errorText = (err) => summarizeFailure(err instanceof Error ? err.message : String(err)) ?? "unknown error";
|
|
2708
|
+
/**
|
|
2709
|
+
* One "✔ <title>" / "✖ <title>" block with a bullet per client, plus an optional
|
|
2710
|
+
* dim explanation underneath. Rendered only when it has something to say.
|
|
2711
|
+
*/
|
|
2712
|
+
const ResultGroup = ({ title, items, color, icon, note }) => {
|
|
2713
|
+
if (items.length === 0) return null;
|
|
2714
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
2715
|
+
flexDirection: "column",
|
|
2716
|
+
marginBottom: 1,
|
|
2717
|
+
children: [
|
|
2718
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2719
|
+
color,
|
|
2720
|
+
bold: true,
|
|
2721
|
+
children: [
|
|
2722
|
+
icon,
|
|
2723
|
+
" ",
|
|
2724
|
+
title
|
|
2725
|
+
]
|
|
2726
|
+
}),
|
|
2727
|
+
items.map((item, i) => /* @__PURE__ */ jsxs(Text, { children: [
|
|
2728
|
+
" ",
|
|
2729
|
+
"•",
|
|
2730
|
+
" ",
|
|
2731
|
+
item
|
|
2732
|
+
] }, `${title}-${i}`)),
|
|
2733
|
+
note && /* @__PURE__ */ jsxs(Text, {
|
|
2734
|
+
dimColor: true,
|
|
2735
|
+
children: [" ", note]
|
|
2736
|
+
})
|
|
2737
|
+
]
|
|
2738
|
+
});
|
|
2739
|
+
};
|
|
1923
2740
|
/**
|
|
1924
2741
|
* Connector step prompt — Enter continues (opens the connector page). There's
|
|
1925
2742
|
* no skip: picking the connector commits to opening it.
|
|
@@ -1933,6 +2750,24 @@ const ConnectorContinue = ({ onContinue }) => {
|
|
|
1933
2750
|
children: ["Press enter to continue ", Icons.triangleRight]
|
|
1934
2751
|
});
|
|
1935
2752
|
};
|
|
2753
|
+
/**
|
|
2754
|
+
* Done-phase prompt — Enter dismisses the results screen and moves the flow on.
|
|
2755
|
+
* Explicit acknowledgement instead of a timeout: the previous 2s auto-dismiss
|
|
2756
|
+
* whipped past too fast to read on a normal install, especially when several
|
|
2757
|
+
* result groups were stacked.
|
|
2758
|
+
*/
|
|
2759
|
+
const DoneContinue = ({ onContinue }) => {
|
|
2760
|
+
useInput((_input, key) => {
|
|
2761
|
+
if (key.return) onContinue();
|
|
2762
|
+
});
|
|
2763
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
2764
|
+
marginTop: 1,
|
|
2765
|
+
children: /* @__PURE__ */ jsxs(Text, {
|
|
2766
|
+
color: Colors.primary,
|
|
2767
|
+
children: ["Press enter to continue ", Icons.triangleRight]
|
|
2768
|
+
})
|
|
2769
|
+
});
|
|
2770
|
+
};
|
|
1936
2771
|
const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
1937
2772
|
useSyncExternalStore((cb) => store.subscribe(cb), () => store.getSnapshot());
|
|
1938
2773
|
useInput(() => void 0);
|
|
@@ -1940,9 +2775,12 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
1940
2775
|
const [phase, setPhase] = useState("detecting");
|
|
1941
2776
|
const [clients, setClients] = useState([]);
|
|
1942
2777
|
const [selectedClientNames, setSelectedClientNames] = useState([]);
|
|
1943
|
-
const [
|
|
1944
|
-
const [
|
|
2778
|
+
const [mcpResults, setMcpResults] = useState([]);
|
|
2779
|
+
const [pluginResults, setPluginResults] = useState([]);
|
|
1945
2780
|
const [installMode, setInstallMode] = useState("custom");
|
|
2781
|
+
const [detectError, setDetectError] = useState(null);
|
|
2782
|
+
const [flowError, setFlowError] = useState(null);
|
|
2783
|
+
const finishFlow = useRef(null);
|
|
1946
2784
|
useEffect(() => {
|
|
1947
2785
|
(async () => {
|
|
1948
2786
|
try {
|
|
@@ -1954,20 +2792,21 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
1954
2792
|
setClients(detected);
|
|
1955
2793
|
setPhase("ask");
|
|
1956
2794
|
}
|
|
1957
|
-
} catch {
|
|
2795
|
+
} catch (err) {
|
|
2796
|
+
setDetectError(errorText(err));
|
|
2797
|
+
finishFlow.current = () => markDone(store, "failed");
|
|
1958
2798
|
setPhase("none");
|
|
1959
|
-
setTimeout(() => markDone(store, "failed"), 1500);
|
|
1960
2799
|
}
|
|
1961
2800
|
})();
|
|
1962
2801
|
}, [installer]);
|
|
1963
2802
|
const proceedAfterClientPick = (clientNames, chosenMode) => {
|
|
1964
2803
|
setSelectedClientNames(clientNames);
|
|
1965
2804
|
if (chosenMode === "all") {
|
|
1966
|
-
doInstall(clientNames, [...ALL_FEATURE_VALUES]);
|
|
2805
|
+
doInstall(clientNames, [...ALL_FEATURE_VALUES], chosenMode);
|
|
1967
2806
|
return;
|
|
1968
2807
|
}
|
|
1969
2808
|
if (store.session.mcpFeatures) {
|
|
1970
|
-
doInstall(clientNames, store.session.mcpFeatures);
|
|
2809
|
+
doInstall(clientNames, store.session.mcpFeatures, chosenMode);
|
|
1971
2810
|
return;
|
|
1972
2811
|
}
|
|
1973
2812
|
if (clientNames.some((name) => clients.find((c) => c.name === name)?.finish)) {
|
|
@@ -1993,54 +2832,75 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
1993
2832
|
const handleSkip = () => {
|
|
1994
2833
|
markDone(store, "skipped");
|
|
1995
2834
|
};
|
|
1996
|
-
|
|
2835
|
+
/**
|
|
2836
|
+
* `chosenMode` is passed in rather than read from `installMode`: the tri-state
|
|
2837
|
+
* picker sets that state and installs in the same tick when a single client
|
|
2838
|
+
* is detected, so the closure would still hold the previous value and a
|
|
2839
|
+
* one-editor machine would silently get the MCP-only path.
|
|
2840
|
+
*/
|
|
2841
|
+
const doInstall = async (names, features, chosenMode = installMode) => {
|
|
1997
2842
|
setPhase("working");
|
|
1998
2843
|
let mcpResult = [];
|
|
1999
2844
|
let pluginResult = [];
|
|
2000
2845
|
const pluginCapableSet = new Set(clients.filter((c) => c.supportsPlugin).map((c) => c.name));
|
|
2001
2846
|
const pluginCapableNames = names.filter((n) => pluginCapableSet.has(n));
|
|
2002
2847
|
const directNames = names.filter((n) => !pluginCapableSet.has(n));
|
|
2003
|
-
if (
|
|
2848
|
+
if (chosenMode === "all") {
|
|
2004
2849
|
try {
|
|
2005
2850
|
mcpResult = await installer.install(directNames, features, store.session.apiKey);
|
|
2006
|
-
} catch {
|
|
2851
|
+
} catch (err) {
|
|
2852
|
+
setFlowError(errorText(err));
|
|
2853
|
+
}
|
|
2007
2854
|
try {
|
|
2008
2855
|
pluginResult = await installer.installPlugins(pluginCapableNames);
|
|
2009
|
-
} catch {
|
|
2856
|
+
} catch (err) {
|
|
2857
|
+
setFlowError(errorText(err));
|
|
2858
|
+
}
|
|
2010
2859
|
} else try {
|
|
2011
2860
|
mcpResult = await installer.install(names, features, store.session.apiKey);
|
|
2012
|
-
} catch {
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2861
|
+
} catch (err) {
|
|
2862
|
+
setFlowError(errorText(err));
|
|
2863
|
+
}
|
|
2864
|
+
setMcpResults(mcpResult);
|
|
2865
|
+
setPluginResults(pluginResult);
|
|
2866
|
+
const ready = [...mcpResult, ...pluginResult].filter(isOk);
|
|
2867
|
+
const outcome = ready.length > 0 ? "installed" : "failed";
|
|
2017
2868
|
const featuresReport = reportFeatures(features ?? [...ALL_FEATURE_VALUES]);
|
|
2018
|
-
|
|
2869
|
+
finishFlow.current = () => markDone(store, outcome, ready.map((r) => r.name), featuresReport);
|
|
2870
|
+
setPhase("done");
|
|
2019
2871
|
};
|
|
2020
2872
|
const doRemove = async () => {
|
|
2021
2873
|
setPhase("working");
|
|
2022
2874
|
let result = [];
|
|
2023
2875
|
try {
|
|
2024
|
-
result = await installer.remove();
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
setResultClients([]);
|
|
2876
|
+
result = await installer.remove(store.session.localMcp);
|
|
2877
|
+
} catch (err) {
|
|
2878
|
+
setFlowError(errorText(err));
|
|
2028
2879
|
}
|
|
2880
|
+
setMcpResults(result);
|
|
2881
|
+
const removed = result.filter(isOk);
|
|
2882
|
+
const outcome = removed.length > 0 ? "installed" : "failed";
|
|
2883
|
+
finishFlow.current = () => markDone(store, outcome, removed.map((r) => r.name));
|
|
2029
2884
|
setPhase("done");
|
|
2030
|
-
const outcome = result.length > 0 ? "installed" : "failed";
|
|
2031
|
-
setTimeout(() => markDone(store, outcome, result), 2e3);
|
|
2032
2885
|
};
|
|
2033
2886
|
const installValueBullets = [
|
|
2034
2887
|
"Ask your agent: \"List my feature flags\" — and it does.",
|
|
2035
2888
|
"Run SQL, build dashboards, ship flags, all from your IDE.",
|
|
2036
2889
|
"No copy-pasting tokens or context. Your agent has the keys."
|
|
2037
2890
|
];
|
|
2038
|
-
const
|
|
2891
|
+
const okMcpNames = mcpResults.filter(isOk).map((r) => r.name);
|
|
2892
|
+
const finishNotes = clients.flatMap((c) => c.finish && okMcpNames.includes(c.name) ? [{
|
|
2039
2893
|
name: c.name,
|
|
2040
2894
|
url: c.finish.url,
|
|
2041
2895
|
instruction: c.finish.instruction
|
|
2042
2896
|
}] : []);
|
|
2043
|
-
const
|
|
2897
|
+
const isConnectorName = (name) => finishNotes.some((n) => n.name === name);
|
|
2898
|
+
const installedNow = namesWithStatus(mcpResults, "changed").filter((name) => !isConnectorName(name));
|
|
2899
|
+
const alreadyInstalled = namesWithStatus(mcpResults, "unchanged").filter((name) => !isConnectorName(name));
|
|
2900
|
+
const pluginInstalled = namesWithStatus(pluginResults, "changed");
|
|
2901
|
+
const pluginAlreadyInstalled = namesWithStatus(pluginResults, "unchanged");
|
|
2902
|
+
const failures = [...mcpResults, ...pluginResults].filter((r) => r.status === "failed").map((r) => r.detail ? `${r.name} — ${r.detail}` : r.name);
|
|
2903
|
+
const hasAnyResult = installedNow.length + alreadyInstalled.length + pluginInstalled.length + pluginAlreadyInstalled.length + failures.length + finishNotes.length > 0;
|
|
2044
2904
|
return /* @__PURE__ */ jsxs(Box, {
|
|
2045
2905
|
flexDirection: "column",
|
|
2046
2906
|
flexGrow: 1,
|
|
@@ -2056,14 +2916,32 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2056
2916
|
dimColor: true,
|
|
2057
2917
|
children: "Detecting supported editors..."
|
|
2058
2918
|
}),
|
|
2059
|
-
phase === "none" && /* @__PURE__ */ jsxs(
|
|
2919
|
+
phase === "none" && (detectError ? /* @__PURE__ */ jsxs(Box, {
|
|
2920
|
+
flexDirection: "column",
|
|
2921
|
+
children: [
|
|
2922
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2923
|
+
color: "red",
|
|
2924
|
+
bold: true,
|
|
2925
|
+
children: ["✖", " Couldn't check which editors are installed"]
|
|
2926
|
+
}),
|
|
2927
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2928
|
+
dimColor: true,
|
|
2929
|
+
children: [" ", detectError]
|
|
2930
|
+
}),
|
|
2931
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
2932
|
+
dimColor: true,
|
|
2933
|
+
children: [" ", "Run with --debug for the full output, or report it at github.com/PostHog/wizard/issues."]
|
|
2934
|
+
}),
|
|
2935
|
+
/* @__PURE__ */ jsx(DoneContinue, { onContinue: () => finishFlow.current?.() })
|
|
2936
|
+
]
|
|
2937
|
+
}) : /* @__PURE__ */ jsxs(Text, {
|
|
2060
2938
|
dimColor: true,
|
|
2061
2939
|
children: [
|
|
2062
2940
|
"No ",
|
|
2063
2941
|
isRemove ? "installed" : "supported",
|
|
2064
2942
|
" MCP clients detected. Skipping..."
|
|
2065
2943
|
]
|
|
2066
|
-
}),
|
|
2944
|
+
})),
|
|
2067
2945
|
phase === "ask" && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2068
2946
|
!isRemove && /* @__PURE__ */ jsx(Box, {
|
|
2069
2947
|
flexDirection: "column",
|
|
@@ -2146,38 +3024,42 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2146
3024
|
dimColor: true,
|
|
2147
3025
|
children: [isRemove ? "Removing" : "Installing", " MCP server..."]
|
|
2148
3026
|
}),
|
|
2149
|
-
phase === "done" && /* @__PURE__ */
|
|
3027
|
+
phase === "done" && /* @__PURE__ */ jsxs(Box, {
|
|
2150
3028
|
flexDirection: "column",
|
|
2151
|
-
children:
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
pluginClients.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
3029
|
+
children: [hasAnyResult ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
3030
|
+
/* @__PURE__ */ jsx(ResultGroup, {
|
|
3031
|
+
title: "Plugin installed for:",
|
|
3032
|
+
items: pluginInstalled,
|
|
2156
3033
|
color: "green",
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
" ",
|
|
2161
|
-
|
|
2162
|
-
" ",
|
|
2163
|
-
name
|
|
2164
|
-
] }, `p-${i}`))] }),
|
|
2165
|
-
installedNow.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Text, {
|
|
3034
|
+
icon: "✔"
|
|
3035
|
+
}),
|
|
3036
|
+
/* @__PURE__ */ jsx(ResultGroup, {
|
|
3037
|
+
title: "Plugin was already installed for:",
|
|
3038
|
+
items: pluginAlreadyInstalled,
|
|
2166
3039
|
color: "green",
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
}),
|
|
2176
|
-
|
|
2177
|
-
"
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
3040
|
+
icon: "✔",
|
|
3041
|
+
note: "It was already set up, so nothing changed. You are good to go."
|
|
3042
|
+
}),
|
|
3043
|
+
/* @__PURE__ */ jsx(ResultGroup, {
|
|
3044
|
+
title: `MCP server ${isRemove ? "removed from" : "installed for"}:`,
|
|
3045
|
+
items: installedNow,
|
|
3046
|
+
color: "green",
|
|
3047
|
+
icon: "✔"
|
|
3048
|
+
}),
|
|
3049
|
+
/* @__PURE__ */ jsx(ResultGroup, {
|
|
3050
|
+
title: isRemove ? "No PostHog entry left to remove for:" : "MCP server was already installed for:",
|
|
3051
|
+
items: alreadyInstalled,
|
|
3052
|
+
color: "green",
|
|
3053
|
+
icon: "✔",
|
|
3054
|
+
note: isRemove ? "It was already gone, so nothing was changed." : "Left as-is. To change which PostHog areas it can reach, run `wizard mcp remove` first, then `wizard mcp add`."
|
|
3055
|
+
}),
|
|
3056
|
+
/* @__PURE__ */ jsx(ResultGroup, {
|
|
3057
|
+
title: `Couldn't ${isRemove ? "remove from" : "install for"}:`,
|
|
3058
|
+
items: failures,
|
|
3059
|
+
color: "red",
|
|
3060
|
+
icon: "✖",
|
|
3061
|
+
note: "Run with --debug for the full output, or report it at github.com/PostHog/wizard/issues."
|
|
3062
|
+
}),
|
|
2181
3063
|
finishNotes.map((note) => /* @__PURE__ */ jsxs(Box, {
|
|
2182
3064
|
flexDirection: "column",
|
|
2183
3065
|
marginTop: 1,
|
|
@@ -2212,7 +3094,32 @@ const McpScreen = ({ store, installer, mode = "install" }) => {
|
|
|
2212
3094
|
})
|
|
2213
3095
|
]
|
|
2214
3096
|
}, note.name))
|
|
2215
|
-
] })
|
|
3097
|
+
] }) : flowError ? /* @__PURE__ */ jsxs(Box, {
|
|
3098
|
+
flexDirection: "column",
|
|
3099
|
+
children: [
|
|
3100
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
3101
|
+
color: "red",
|
|
3102
|
+
bold: true,
|
|
3103
|
+
children: [
|
|
3104
|
+
"✖",
|
|
3105
|
+
" ",
|
|
3106
|
+
isRemove ? "Removal" : "Installation",
|
|
3107
|
+
" failed"
|
|
3108
|
+
]
|
|
3109
|
+
}),
|
|
3110
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
3111
|
+
dimColor: true,
|
|
3112
|
+
children: [" ", flowError]
|
|
3113
|
+
}),
|
|
3114
|
+
/* @__PURE__ */ jsxs(Text, {
|
|
3115
|
+
dimColor: true,
|
|
3116
|
+
children: [" ", "Run with --debug for the full output, or report it at github.com/PostHog/wizard/issues."]
|
|
3117
|
+
})
|
|
3118
|
+
]
|
|
3119
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
3120
|
+
dimColor: true,
|
|
3121
|
+
children: isRemove ? "Nothing to remove — the PostHog MCP server wasn't configured for any editor." : "Nothing to install — no editor was selected."
|
|
3122
|
+
}), /* @__PURE__ */ jsx(DoneContinue, { onContinue: () => finishFlow.current?.() })]
|
|
2216
3123
|
})
|
|
2217
3124
|
]
|
|
2218
3125
|
})]
|
|
@@ -6306,6 +7213,6 @@ function releaseTerminal() {
|
|
|
6306
7213
|
process.stdout.write(RESET_ATTRS + LEAVE_ALT_SCREEN);
|
|
6307
7214
|
}
|
|
6308
7215
|
//#endregion
|
|
6309
|
-
export {
|
|
7216
|
+
export { EventPlanViewer as A, CardLayout as B, VisualizerTab as C, HNViewer as D, ContentSequencer as E, ConfirmationInput as F, GroupedPickerMenu as I, ProgressList as L, LinkText as M, extractUrls as N, TabContainer as O, ModalOverlay as P, LoadingBox as R, ServiceHealthList as S, LearnCard as T, TAILORED_ROLES as _, useSkillEntry as a, SEVERITY_LABEL as b, SlackConnectScreen as c, AuditChecksViewer as d, seedDemoEvents as f, probeProjectData as g, assembleProfile as h, SkillSourceInfo as i, LogViewer as j, ScreenContainer as k, AUDIT_AREA_SLIDES as l, McpSuggestedPromptsScreen as m, releaseTerminal as n, OutroScreen as o, seededProfile as p, AiOptInRequiredScreen as r, useDismissOnAnyKey as s, enterDarkTerminal as t, VisualBox as u, McpScreen as v, TipsCard as w, SEVERITY_ORDER as x, IssueTable as y, SplitView as z };
|
|
6310
7217
|
|
|
6311
|
-
//# sourceMappingURL=terminal-
|
|
7218
|
+
//# sourceMappingURL=terminal-yKJZx1UC.js.map
|